소스 검색

feat(wiki): 添加明日方舟工具箱插件支持OCR和ADB操作

添加新的wiki插件实现以下功能:
1. 支持通过OCR识别屏幕文字位置并自动点击
2. 添加ADB命令控制模拟器操作(点击、滑动、输入)
3. 实现步骤记录和批量执行功能
4. 添加截图和网格标记功能辅助调试
5. 支持干员Wiki信息查询

新增依赖:jimp、tesseract.js及相关资源文件
枫林 2 달 전
부모
커밋
d3ad0eb25f
12개의 변경된 파일2554개의 추가작업 그리고 1개의 파일을 삭제
  1. 1 1
      .gitignore
  2. 1 0
      botQQ_screenshots/test.json
  3. 1 0
      botQQ_screenshots/tests.json
  4. BIN
      chi_sim.traineddata
  5. BIN
      eng.traineddata
  6. 825 0
      package-lock.json
  7. 2 0
      package.json
  8. 595 0
      pnpm-lock.yaml
  9. 298 0
      src/font/open-sans-8-white.fnt
  10. BIN
      src/font/open-sans-8-white.png
  11. 831 0
      src/plugins/wiki.ts
  12. BIN
      tessdata/chi_sim.traineddata

+ 1 - 1
.gitignore

@@ -84,6 +84,6 @@ src/plugins/*
 !src/plugins/ecomony.ts
 !src/plugins/prop.ts
 !src/plugins/Permission.ts
-
+!src/plugins/wiki.ts
 
 /data

+ 1 - 0
botQQ_screenshots/test.json

@@ -0,0 +1 @@
+{"":{"x1":""},"好友":{"x1":567,"y1":868},"添加好友":{"x1":183,"y1":472},"同意添加":{"x1":1642,"y1":405},"搜索好友":{"x1":643,"y1":204},"返回":{"x1":112,"y1":58},"确认搜索":{"x1":1634,"y1":183},"搜索好友添加":{"x1":1744,"y1":346},"干员":{"x1":1700,"y1":500},"干员翻页":{"type":"slide","x1":650,"y1":400,"x2":250,"y2":400},"助战干员":{"type":"cilik","x1":170,"y1":640},"助战干员1":{"type":"cilik","x1":500,"y1":550},"助战":{"type":"cilik","x1":1350,"y1":400},"确认干员":{"type":"cilik","x1":1528,"y1":1069}}

+ 1 - 0
botQQ_screenshots/tests.json

@@ -0,0 +1 @@
+{"":"","添加好友":[{"type":"click","name":"好友"},{"type":"click","name":"添加好友"},{"type":"click","name":"搜索好友"},{"type":"input","name":"输入好友编号"},{"type":"click","name":"确认搜索"},{"type":"click","name":"确认搜索"},{"type":"click","name":"搜索好友添加"}]}

BIN
chi_sim.traineddata


BIN
eng.traineddata


파일 크기가 너무 크기때문에 변경 상태를 표시하지 않습니다.
+ 825 - 0
package-lock.json


+ 2 - 0
package.json

@@ -15,12 +15,14 @@
   "dependencies": {
     "art-template": "^4.13.2",
     "axios": "^1.7.8",
+    "jimp": "^1.6.0",
     "js-yaml": "^4.1.0",
     "minimist": "^1.2.8",
     "node-cron": "^3.0.3",
     "node-napcat-ts": "^0.4.0",
     "puppeteer": "^23.9.0",
     "reflect-metadata": "^0.2.2",
+    "tesseract.js": "^6.0.1",
     "winston": "^3.17.0",
     "winston-daily-rotate-file": "^5.0.0",
     "yaml": "^2.6.1"

파일 크기가 너무 크기때문에 변경 상태를 표시하지 않습니다.
+ 595 - 0
pnpm-lock.yaml


+ 298 - 0
src/font/open-sans-8-white.fnt

@@ -0,0 +1,298 @@
+<font>
+  <info face="open-sans-8-white" size="8" bold="0" italic="0" charset="" unicode="" stretchH="100" smooth="1" aa="1" padding="2,2,2,2" spacing="0,0" outline="0"/>
+  <common lineHeight="9" base="7" scaleW="1148" scaleH="11" pages="1" packed="0"/>
+  <pages>
+    <page id="0" file="open-sans-8-white.png"/>
+  </pages>
+  <chars count="190">
+    <char id="32" x="0" y="0" width="0" height="0" xoffset="0" yoffset="1" xadvance="2" page="0" chnl="15"/>
+    <char id="33" x="2" y="3" width="1" height="6" xoffset="1" yoffset="1" xadvance="2" page="0" chnl="15"/>
+    <char id="34" x="5" y="3" width="2" height="2" xoffset="0" yoffset="1" xadvance="3" page="0" chnl="15"/>
+    <char id="35" x="9" y="3" width="5" height="6" xoffset="0" yoffset="1" xadvance="4" page="0" chnl="15"/>
+    <char id="36" x="16" y="2" width="4" height="7" xoffset="0" yoffset="1" xadvance="4" page="0" chnl="15"/>
+    <char id="37" x="22" y="3" width="7" height="6" xoffset="0" yoffset="1" xadvance="7" page="0" chnl="15"/>
+    <char id="38" x="31" y="3" width="5" height="6" xoffset="0" yoffset="1" xadvance="5" page="0" chnl="15"/>
+    <char id="39" x="38" y="3" width="1" height="2" xoffset="0" yoffset="1" xadvance="2" page="0" chnl="15"/>
+    <char id="40" x="41" y="3" width="2" height="8" xoffset="0" yoffset="1" xadvance="3" page="0" chnl="15"/>
+    <char id="41" x="45" y="3" width="2" height="8" xoffset="0" yoffset="1" xadvance="3" page="0" chnl="15"/>
+    <char id="42" x="49" y="3" width="3" height="3" xoffset="0" yoffset="1" xadvance="3" page="0" chnl="15"/>
+    <char id="43" x="54" y="4" width="4" height="4" xoffset="0" yoffset="2" xadvance="5" page="0" chnl="15"/>
+    <char id="44" x="60" y="8" width="1" height="2" xoffset="1" yoffset="6" xadvance="2" page="0" chnl="15"/>
+    <char id="45" x="63" y="6" width="3" height="1" xoffset="0" yoffset="5" xadvance="3" page="0" chnl="15"/>
+    <char id="46" x="68" y="8" width="1" height="1" xoffset="1" yoffset="6" xadvance="2" page="0" chnl="15"/>
+    <char id="47" x="71" y="3" width="3" height="6" xoffset="0" yoffset="1" xadvance="2" page="0" chnl="15"/>
+    <char id="48" x="76" y="3" width="4" height="6" xoffset="0" yoffset="1" xadvance="4" page="0" chnl="15"/>
+    <char id="49" x="82" y="3" width="2" height="6" xoffset="1" yoffset="1" xadvance="4" page="0" chnl="15"/>
+    <char id="50" x="86" y="3" width="4" height="6" xoffset="0" yoffset="1" xadvance="4" page="0" chnl="15"/>
+    <char id="51" x="92" y="3" width="4" height="6" xoffset="0" yoffset="1" xadvance="4" page="0" chnl="15"/>
+    <char id="52" x="98" y="3" width="4" height="6" xoffset="0" yoffset="1" xadvance="4" page="0" chnl="15"/>
+    <char id="53" x="104" y="3" width="4" height="6" xoffset="0" yoffset="2" xadvance="4" page="0" chnl="15"/>
+    <char id="54" x="110" y="3" width="4" height="6" xoffset="0" yoffset="1" xadvance="4" page="0" chnl="15"/>
+    <char id="55" x="116" y="3" width="4" height="6" xoffset="0" yoffset="2" xadvance="4" page="0" chnl="15"/>
+    <char id="56" x="122" y="3" width="4" height="6" xoffset="0" yoffset="1" xadvance="4" page="0" chnl="15"/>
+    <char id="57" x="128" y="3" width="4" height="6" xoffset="0" yoffset="1" xadvance="4" page="0" chnl="15"/>
+    <char id="58" x="134" y="5" width="1" height="4" xoffset="1" yoffset="3" xadvance="2" page="0" chnl="15"/>
+    <char id="59" x="137" y="5" width="1" height="6" xoffset="1" yoffset="3" xadvance="2" page="0" chnl="15"/>
+    <char id="60" x="140" y="4" width="4" height="4" xoffset="0" yoffset="2" xadvance="5" page="0" chnl="15"/>
+    <char id="61" x="146" y="5" width="4" height="3" xoffset="0" yoffset="3" xadvance="5" page="0" chnl="15"/>
+    <char id="62" x="152" y="4" width="4" height="4" xoffset="0" yoffset="2" xadvance="5" page="0" chnl="15"/>
+    <char id="63" x="158" y="3" width="4" height="6" xoffset="0" yoffset="1" xadvance="4" page="0" chnl="15"/>
+    <char id="64" x="164" y="3" width="8" height="8" xoffset="0" yoffset="1" xadvance="8" page="0" chnl="15"/>
+    <char id="65" x="174" y="3" width="6" height="6" xoffset="0" yoffset="1" xadvance="5" page="0" chnl="15"/>
+    <char id="66" x="182" y="3" width="5" height="6" xoffset="1" yoffset="1" xadvance="5" page="0" chnl="15"/>
+    <char id="67" x="189" y="3" width="5" height="6" xoffset="0" yoffset="1" xadvance="6" page="0" chnl="15"/>
+    <char id="68" x="196" y="3" width="5" height="6" xoffset="1" yoffset="1" xadvance="6" page="0" chnl="15"/>
+    <char id="69" x="203" y="3" width="5" height="6" xoffset="1" yoffset="1" xadvance="5" page="0" chnl="15"/>
+    <char id="70" x="210" y="3" width="4" height="6" xoffset="1" yoffset="1" xadvance="5" page="0" chnl="15"/>
+    <char id="71" x="216" y="3" width="6" height="6" xoffset="0" yoffset="1" xadvance="6" page="0" chnl="15"/>
+    <char id="72" x="224" y="3" width="5" height="6" xoffset="1" yoffset="1" xadvance="6" page="0" chnl="15"/>
+    <char id="73" x="231" y="3" width="1" height="6" xoffset="1" yoffset="1" xadvance="2" page="0" chnl="15"/>
+    <char id="74" x="234" y="3" width="4" height="6" xoffset="0" yoffset="1" xadvance="4" page="0" chnl="15"/>
+    <char id="75" x="240" y="3" width="5" height="6" xoffset="1" yoffset="1" xadvance="5" page="0" chnl="15"/>
+    <char id="76" x="247" y="3" width="4" height="6" xoffset="1" yoffset="1" xadvance="4" page="0" chnl="15"/>
+    <char id="77" x="253" y="3" width="6" height="6" xoffset="1" yoffset="1" xadvance="7" page="0" chnl="15"/>
+    <char id="78" x="261" y="3" width="5" height="6" xoffset="1" yoffset="1" xadvance="6" page="0" chnl="15"/>
+    <char id="79" x="268" y="3" width="6" height="6" xoffset="0" yoffset="1" xadvance="6" page="0" chnl="15"/>
+    <char id="80" x="276" y="3" width="5" height="6" xoffset="1" yoffset="1" xadvance="5" page="0" chnl="15"/>
+    <char id="81" x="283" y="3" width="6" height="7" xoffset="0" yoffset="1" xadvance="6" page="0" chnl="15"/>
+    <char id="82" x="291" y="3" width="5" height="6" xoffset="1" yoffset="1" xadvance="6" page="0" chnl="15"/>
+    <char id="83" x="298" y="3" width="5" height="6" xoffset="0" yoffset="1" xadvance="5" page="0" chnl="15"/>
+    <char id="84" x="305" y="3" width="5" height="6" xoffset="0" yoffset="1" xadvance="5" page="0" chnl="15"/>
+    <char id="85" x="312" y="3" width="5" height="6" xoffset="1" yoffset="1" xadvance="6" page="0" chnl="15"/>
+    <char id="86" x="319" y="3" width="6" height="6" xoffset="0" yoffset="1" xadvance="5" page="0" chnl="15"/>
+    <char id="87" x="327" y="3" width="8" height="6" xoffset="0" yoffset="1" xadvance="8" page="0" chnl="15"/>
+    <char id="88" x="337" y="3" width="5" height="6" xoffset="0" yoffset="1" xadvance="5" page="0" chnl="15"/>
+    <char id="89" x="344" y="3" width="6" height="6" xoffset="0" yoffset="1" xadvance="5" page="0" chnl="15"/>
+    <char id="90" x="352" y="3" width="5" height="6" xoffset="0" yoffset="1" xadvance="5" page="0" chnl="15"/>
+    <char id="91" x="359" y="3" width="2" height="8" xoffset="1" yoffset="1" xadvance="2" page="0" chnl="15"/>
+    <char id="92" x="363" y="3" width="3" height="6" xoffset="0" yoffset="1" xadvance="2" page="0" chnl="15"/>
+    <char id="93" x="368" y="3" width="2" height="8" xoffset="0" yoffset="1" xadvance="2" page="0" chnl="15"/>
+    <char id="94" x="372" y="3" width="4" height="3" xoffset="0" yoffset="1" xadvance="4" page="0" chnl="15"/>
+    <char id="95" x="378" y="10" width="5" height="1" xoffset="0" yoffset="8" xadvance="4" page="0" chnl="15"/>
+    <char id="97" x="385" y="4" width="4" height="5" xoffset="0" yoffset="3" xadvance="4" page="0" chnl="15"/>
+    <char id="98" x="391" y="3" width="4" height="6" xoffset="1" yoffset="1" xadvance="4" page="0" chnl="15"/>
+    <char id="99" x="397" y="4" width="4" height="5" xoffset="0" yoffset="3" xadvance="4" page="0" chnl="15"/>
+    <char id="100" x="403" y="3" width="4" height="6" xoffset="0" yoffset="1" xadvance="4" page="0" chnl="15"/>
+    <char id="101" x="409" y="4" width="4" height="5" xoffset="0" yoffset="3" xadvance="4" page="0" chnl="15"/>
+    <char id="102" x="415" y="3" width="3" height="6" xoffset="0" yoffset="1" xadvance="2" page="0" chnl="15"/>
+    <char id="103" x="420" y="4" width="4" height="6" xoffset="0" yoffset="3" xadvance="4" page="0" chnl="15"/>
+    <char id="104" x="426" y="3" width="4" height="6" xoffset="1" yoffset="1" xadvance="4" page="0" chnl="15"/>
+    <char id="105" x="432" y="3" width="1" height="6" xoffset="1" yoffset="1" xadvance="2" page="0" chnl="15"/>
+    <char id="106" x="435" y="3" width="2" height="8" xoffset="0" yoffset="1" xadvance="2" page="0" chnl="15"/>
+    <char id="107" x="439" y="3" width="4" height="6" xoffset="1" yoffset="1" xadvance="4" page="0" chnl="15"/>
+    <char id="108" x="445" y="3" width="1" height="6" xoffset="1" yoffset="1" xadvance="2" page="0" chnl="15"/>
+    <char id="109" x="448" y="4" width="6" height="5" xoffset="1" yoffset="3" xadvance="7" page="0" chnl="15"/>
+    <char id="110" x="456" y="4" width="4" height="5" xoffset="1" yoffset="3" xadvance="4" page="0" chnl="15"/>
+    <char id="111" x="462" y="4" width="4" height="5" xoffset="0" yoffset="3" xadvance="4" page="0" chnl="15"/>
+    <char id="112" x="468" y="4" width="4" height="6" xoffset="1" yoffset="3" xadvance="4" page="0" chnl="15"/>
+    <char id="113" x="474" y="4" width="4" height="6" xoffset="0" yoffset="3" xadvance="4" page="0" chnl="15"/>
+    <char id="114" x="480" y="4" width="3" height="5" xoffset="1" yoffset="3" xadvance="3" page="0" chnl="15"/>
+    <char id="115" x="485" y="4" width="4" height="5" xoffset="0" yoffset="3" xadvance="4" page="0" chnl="15"/>
+    <char id="116" x="491" y="3" width="2" height="6" xoffset="0" yoffset="2" xadvance="2" page="0" chnl="15"/>
+    <char id="117" x="495" y="5" width="4" height="5" xoffset="1" yoffset="3" xadvance="4" page="0" chnl="15"/>
+    <char id="118" x="501" y="5" width="4" height="4" xoffset="0" yoffset="3" xadvance="4" page="0" chnl="15"/>
+    <char id="119" x="507" y="5" width="6" height="4" xoffset="0" yoffset="3" xadvance="6" page="0" chnl="15"/>
+    <char id="120" x="515" y="5" width="4" height="4" xoffset="0" yoffset="3" xadvance="4" page="0" chnl="15"/>
+    <char id="121" x="521" y="5" width="4" height="6" xoffset="0" yoffset="3" xadvance="4" page="0" chnl="15"/>
+    <char id="122" x="527" y="5" width="4" height="4" xoffset="0" yoffset="3" xadvance="4" page="0" chnl="15"/>
+    <char id="123" x="533" y="3" width="3" height="8" xoffset="0" yoffset="1" xadvance="3" page="0" chnl="15"/>
+    <char id="124" x="538" y="3" width="1" height="8" xoffset="1" yoffset="1" xadvance="2" page="0" chnl="15"/>
+    <char id="125" x="541" y="3" width="3" height="8" xoffset="0" yoffset="1" xadvance="3" page="0" chnl="15"/>
+    <char id="126" x="546" y="5" width="4" height="2" xoffset="0" yoffset="4" xadvance="5" page="0" chnl="15"/>
+    <char id="161" x="552" y="5" width="1" height="6" xoffset="1" yoffset="3" xadvance="3" page="0" chnl="15"/>
+    <char id="162" x="555" y="3" width="4" height="8" xoffset="0" yoffset="1" xadvance="4" page="0" chnl="15"/>
+    <char id="163" x="561" y="3" width="4" height="6" xoffset="0" yoffset="1" xadvance="4" page="0" chnl="15"/>
+    <char id="164" x="567" y="4" width="4" height="4" xoffset="0" yoffset="2" xadvance="4" page="0" chnl="15"/>
+    <char id="165" x="573" y="3" width="5" height="6" xoffset="0" yoffset="1" xadvance="4" page="0" chnl="15"/>
+    <char id="166" x="580" y="3" width="1" height="8" xoffset="1" yoffset="1" xadvance="2" page="0" chnl="15"/>
+    <char id="167" x="583" y="3" width="4" height="8" xoffset="0" yoffset="1" xadvance="4" page="0" chnl="15"/>
+    <char id="168" x="589" y="3" width="3" height="1" xoffset="0" yoffset="1" xadvance="3" page="0" chnl="15"/>
+    <char id="169" x="594" y="3" width="6" height="6" xoffset="0" yoffset="1" xadvance="6" page="0" chnl="15"/>
+    <char id="170" x="602" y="3" width="3" height="3" xoffset="0" yoffset="1" xadvance="3" page="0" chnl="15"/>
+    <char id="171" x="607" y="5" width="4" height="4" xoffset="1" yoffset="3" xadvance="4" page="0" chnl="15"/>
+    <char id="172" x="613" y="5" width="4" height="3" xoffset="0" yoffset="3" xadvance="5" page="0" chnl="15"/>
+    <char id="173" x="619" y="6" width="3" height="1" xoffset="0" yoffset="5" xadvance="3" page="0" chnl="15"/>
+    <char id="174" x="624" y="3" width="6" height="6" xoffset="0" yoffset="1" xadvance="6" page="0" chnl="15"/>
+    <char id="175" x="632" y="2" width="5" height="1" xoffset="0" yoffset="1" xadvance="4" page="0" chnl="15"/>
+    <char id="176" x="639" y="3" width="3" height="3" xoffset="1" yoffset="1" xadvance="3" page="0" chnl="15"/>
+    <char id="177" x="644" y="4" width="4" height="5" xoffset="0" yoffset="2" xadvance="4" page="0" chnl="15"/>
+    <char id="178" x="650" y="3" width="3" height="3" xoffset="0" yoffset="1" xadvance="3" page="0" chnl="15"/>
+    <char id="179" x="655" y="3" width="3" height="3" xoffset="0" yoffset="1" xadvance="3" page="0" chnl="15"/>
+    <char id="180" x="660" y="3" width="2" height="1" xoffset="1" yoffset="1" xadvance="3" page="0" chnl="15"/>
+    <char id="181" x="664" y="5" width="4" height="6" xoffset="1" yoffset="3" xadvance="5" page="0" chnl="15"/>
+    <char id="182" x="670" y="3" width="5" height="8" xoffset="0" yoffset="1" xadvance="4" page="0" chnl="15"/>
+    <char id="183" x="677" y="5" width="1" height="1" xoffset="1" yoffset="4" xadvance="3" page="0" chnl="15"/>
+    <char id="184" x="680" y="9" width="2" height="2" xoffset="0" yoffset="7" xadvance="3" page="0" chnl="15"/>
+    <char id="185" x="684" y="3" width="2" height="3" xoffset="0" yoffset="1" xadvance="3" page="0" chnl="15"/>
+    <char id="186" x="688" y="3" width="3" height="3" xoffset="0" yoffset="1" xadvance="3" page="0" chnl="15"/>
+    <char id="187" x="693" y="5" width="4" height="4" xoffset="1" yoffset="3" xadvance="4" page="0" chnl="15"/>
+    <char id="188" x="699" y="3" width="6" height="6" xoffset="0" yoffset="1" xadvance="7" page="0" chnl="15"/>
+    <char id="189" x="707" y="3" width="6" height="6" xoffset="0" yoffset="1" xadvance="7" page="0" chnl="15"/>
+    <char id="190" x="715" y="3" width="7" height="6" xoffset="0" yoffset="1" xadvance="7" page="0" chnl="15"/>
+    <char id="191" x="724" y="5" width="4" height="6" xoffset="1" yoffset="3" xadvance="5" page="0" chnl="15"/>
+    <char id="192" x="730" y="2" width="6" height="8" xoffset="0" yoffset="0" xadvance="5" page="0" chnl="15"/>
+    <char id="193" x="738" y="2" width="6" height="8" xoffset="0" yoffset="0" xadvance="5" page="0" chnl="15"/>
+    <char id="194" x="746" y="2" width="6" height="8" xoffset="0" yoffset="0" xadvance="5" page="0" chnl="15"/>
+    <char id="195" x="754" y="2" width="6" height="7" xoffset="0" yoffset="0" xadvance="5" page="0" chnl="15"/>
+    <char id="196" x="762" y="2" width="6" height="7" xoffset="0" yoffset="0" xadvance="5" page="0" chnl="15"/>
+    <char id="197" x="770" y="2" width="6" height="7" xoffset="0" yoffset="0" xadvance="5" page="0" chnl="15"/>
+    <char id="198" x="778" y="3" width="8" height="6" xoffset="0" yoffset="1" xadvance="8" page="0" chnl="15"/>
+    <char id="199" x="788" y="3" width="5" height="8" xoffset="0" yoffset="1" xadvance="6" page="0" chnl="15"/>
+    <char id="200" x="795" y="2" width="5" height="8" xoffset="1" yoffset="0" xadvance="5" page="0" chnl="15"/>
+    <char id="201" x="802" y="2" width="5" height="8" xoffset="1" yoffset="0" xadvance="5" page="0" chnl="15"/>
+    <char id="202" x="809" y="2" width="5" height="8" xoffset="1" yoffset="0" xadvance="5" page="0" chnl="15"/>
+    <char id="203" x="816" y="2" width="5" height="7" xoffset="1" yoffset="0" xadvance="5" page="0" chnl="15"/>
+    <char id="204" x="823" y="2" width="2" height="8" xoffset="0" yoffset="0" xadvance="2" page="0" chnl="15"/>
+    <char id="205" x="827" y="2" width="2" height="8" xoffset="1" yoffset="0" xadvance="2" page="0" chnl="15"/>
+    <char id="206" x="831" y="2" width="3" height="8" xoffset="0" yoffset="0" xadvance="2" page="0" chnl="15"/>
+    <char id="207" x="836" y="2" width="3" height="7" xoffset="0" yoffset="0" xadvance="2" page="0" chnl="15"/>
+    <char id="208" x="841" y="3" width="6" height="6" xoffset="0" yoffset="1" xadvance="6" page="0" chnl="15"/>
+    <char id="209" x="849" y="2" width="5" height="7" xoffset="1" yoffset="0" xadvance="6" page="0" chnl="15"/>
+    <char id="210" x="856" y="2" width="6" height="8" xoffset="0" yoffset="0" xadvance="6" page="0" chnl="15"/>
+    <char id="211" x="864" y="2" width="6" height="8" xoffset="0" yoffset="0" xadvance="6" page="0" chnl="15"/>
+    <char id="212" x="872" y="2" width="6" height="8" xoffset="0" yoffset="0" xadvance="6" page="0" chnl="15"/>
+    <char id="213" x="880" y="2" width="6" height="7" xoffset="0" yoffset="0" xadvance="6" page="0" chnl="15"/>
+    <char id="214" x="888" y="2" width="6" height="7" xoffset="0" yoffset="0" xadvance="6" page="0" chnl="15"/>
+    <char id="215" x="896" y="4" width="4" height="4" xoffset="1" yoffset="3" xadvance="5" page="0" chnl="15"/>
+    <char id="216" x="902" y="3" width="6" height="7" xoffset="0" yoffset="1" xadvance="6" page="0" chnl="15"/>
+    <char id="217" x="910" y="2" width="5" height="8" xoffset="1" yoffset="0" xadvance="6" page="0" chnl="15"/>
+    <char id="218" x="917" y="2" width="5" height="8" xoffset="1" yoffset="0" xadvance="6" page="0" chnl="15"/>
+    <char id="219" x="924" y="2" width="5" height="8" xoffset="1" yoffset="0" xadvance="6" page="0" chnl="15"/>
+    <char id="220" x="931" y="2" width="5" height="7" xoffset="1" yoffset="0" xadvance="6" page="0" chnl="15"/>
+    <char id="221" x="938" y="2" width="6" height="8" xoffset="0" yoffset="0" xadvance="5" page="0" chnl="15"/>
+    <char id="222" x="946" y="3" width="5" height="6" xoffset="1" yoffset="1" xadvance="5" page="0" chnl="15"/>
+    <char id="223" x="953" y="3" width="4" height="6" xoffset="1" yoffset="1" xadvance="5" page="0" chnl="15"/>
+    <char id="224" x="959" y="3" width="4" height="6" xoffset="0" yoffset="1" xadvance="4" page="0" chnl="15"/>
+    <char id="225" x="965" y="3" width="4" height="6" xoffset="0" yoffset="1" xadvance="4" page="0" chnl="15"/>
+    <char id="226" x="971" y="3" width="4" height="6" xoffset="0" yoffset="1" xadvance="4" page="0" chnl="15"/>
+    <char id="227" x="977" y="3" width="4" height="6" xoffset="0" yoffset="2" xadvance="4" page="0" chnl="15"/>
+    <char id="228" x="983" y="3" width="4" height="6" xoffset="0" yoffset="1" xadvance="4" page="0" chnl="15"/>
+    <char id="229" x="989" y="3" width="4" height="6" xoffset="0" yoffset="1" xadvance="4" page="0" chnl="15"/>
+    <char id="230" x="995" y="4" width="7" height="5" xoffset="0" yoffset="3" xadvance="7" page="0" chnl="15"/>
+    <char id="231" x="1004" y="4" width="4" height="6" xoffset="0" yoffset="3" xadvance="4" page="0" chnl="15"/>
+    <char id="232" x="1010" y="3" width="4" height="6" xoffset="0" yoffset="1" xadvance="4" page="0" chnl="15"/>
+    <char id="233" x="1016" y="3" width="4" height="6" xoffset="0" yoffset="1" xadvance="4" page="0" chnl="15"/>
+    <char id="234" x="1022" y="3" width="4" height="6" xoffset="0" yoffset="1" xadvance="4" page="0" chnl="15"/>
+    <char id="235" x="1028" y="3" width="4" height="6" xoffset="0" yoffset="1" xadvance="4" page="0" chnl="15"/>
+    <char id="236" x="1034" y="3" width="2" height="6" xoffset="0" yoffset="1" xadvance="2" page="0" chnl="15"/>
+    <char id="237" x="1038" y="3" width="2" height="6" xoffset="1" yoffset="1" xadvance="2" page="0" chnl="15"/>
+    <char id="238" x="1042" y="3" width="3" height="6" xoffset="0" yoffset="1" xadvance="2" page="0" chnl="15"/>
+    <char id="239" x="1047" y="3" width="3" height="6" xoffset="0" yoffset="1" xadvance="2" page="0" chnl="15"/>
+    <char id="240" x="1052" y="3" width="4" height="6" xoffset="0" yoffset="1" xadvance="4" page="0" chnl="15"/>
+    <char id="241" x="1058" y="3" width="4" height="6" xoffset="1" yoffset="2" xadvance="4" page="0" chnl="15"/>
+    <char id="242" x="1064" y="3" width="4" height="6" xoffset="0" yoffset="1" xadvance="4" page="0" chnl="15"/>
+    <char id="243" x="1070" y="3" width="4" height="6" xoffset="0" yoffset="1" xadvance="4" page="0" chnl="15"/>
+    <char id="244" x="1076" y="3" width="4" height="6" xoffset="0" yoffset="1" xadvance="4" page="0" chnl="15"/>
+    <char id="245" x="1082" y="3" width="4" height="6" xoffset="0" yoffset="2" xadvance="4" page="0" chnl="15"/>
+    <char id="246" x="1088" y="3" width="4" height="6" xoffset="0" yoffset="1" xadvance="4" page="0" chnl="15"/>
+    <char id="247" x="1094" y="4" width="4" height="4" xoffset="0" yoffset="3" xadvance="4" page="0" chnl="15"/>
+    <char id="248" x="1100" y="4" width="4" height="5" xoffset="1" yoffset="3" xadvance="5" page="0" chnl="15"/>
+    <char id="249" x="1106" y="3" width="4" height="6" xoffset="1" yoffset="1" xadvance="4" page="0" chnl="15"/>
+    <char id="250" x="1112" y="3" width="4" height="6" xoffset="1" yoffset="1" xadvance="4" page="0" chnl="15"/>
+    <char id="251" x="1118" y="3" width="4" height="6" xoffset="1" yoffset="1" xadvance="4" page="0" chnl="15"/>
+    <char id="252" x="1124" y="3" width="4" height="6" xoffset="1" yoffset="1" xadvance="4" page="0" chnl="15"/>
+    <char id="253" x="1130" y="3" width="4" height="8" xoffset="0" yoffset="1" xadvance="4" page="0" chnl="15"/>
+    <char id="254" x="1136" y="3" width="4" height="8" xoffset="1" yoffset="1" xadvance="4" page="0" chnl="15"/>
+    <char id="255" x="1142" y="3" width="4" height="8" xoffset="0" yoffset="1" xadvance="4" page="0" chnl="15"/>
+	<char id="8364" x="1148" y="3" width="5" height="6" xoffset="0" yoffset="1" xadvance="5" page="0" chnl="15"/>
+  </chars>
+  <kernings count="97">
+    <kerning first="32" second="65" amount="0"/>
+    <kerning first="32" second="84" amount="0"/>
+    <kerning first="32" second="89" amount="0"/>
+    <kerning first="49" second="49" amount="-1"/>
+    <kerning first="65" second="32" amount="0"/>
+    <kerning first="65" second="84" amount="-1"/>
+    <kerning first="65" second="86" amount="-1"/>
+    <kerning first="65" second="87" amount="0"/>
+    <kerning first="65" second="89" amount="-1"/>
+    <kerning first="65" second="118" amount="0"/>
+    <kerning first="65" second="119" amount="0"/>
+    <kerning first="65" second="121" amount="0"/>
+    <kerning first="70" second="44" amount="-1"/>
+    <kerning first="70" second="46" amount="-1"/>
+    <kerning first="70" second="65" amount="0"/>
+    <kerning first="76" second="32" amount="0"/>
+    <kerning first="76" second="84" amount="-1"/>
+    <kerning first="76" second="86" amount="-1"/>
+    <kerning first="76" second="87" amount="-1"/>
+    <kerning first="76" second="89" amount="-1"/>
+    <kerning first="76" second="121" amount="0"/>
+    <kerning first="80" second="32" amount="0"/>
+    <kerning first="80" second="44" amount="-1"/>
+    <kerning first="80" second="46" amount="-1"/>
+    <kerning first="80" second="65" amount="-1"/>
+    <kerning first="82" second="84" amount="0"/>
+    <kerning first="82" second="86" amount="0"/>
+    <kerning first="82" second="87" amount="0"/>
+    <kerning first="82" second="89" amount="0"/>
+    <kerning first="84" second="32" amount="0"/>
+    <kerning first="84" second="44" amount="-1"/>
+    <kerning first="84" second="173" amount="0"/>
+    <kerning first="84" second="46" amount="-1"/>
+    <kerning first="84" second="58" amount="-1"/>
+    <kerning first="84" second="59" amount="-1"/>
+    <kerning first="84" second="65" amount="-1"/>
+    <kerning first="84" second="79" amount="0"/>
+    <kerning first="84" second="97" amount="-1"/>
+    <kerning first="84" second="99" amount="-1"/>
+    <kerning first="84" second="101" amount="-1"/>
+    <kerning first="84" second="105" amount="0"/>
+    <kerning first="84" second="111" amount="-1"/>
+    <kerning first="84" second="114" amount="0"/>
+    <kerning first="84" second="115" amount="-1"/>
+    <kerning first="84" second="117" amount="0"/>
+    <kerning first="84" second="119" amount="0"/>
+    <kerning first="84" second="121" amount="0"/>
+    <kerning first="86" second="44" amount="-1"/>
+    <kerning first="86" second="173" amount="0"/>
+    <kerning first="86" second="46" amount="-1"/>
+    <kerning first="86" second="58" amount="0"/>
+    <kerning first="86" second="59" amount="0"/>
+    <kerning first="86" second="65" amount="-1"/>
+    <kerning first="86" second="97" amount="-1"/>
+    <kerning first="86" second="101" amount="0"/>
+    <kerning first="86" second="105" amount="0"/>
+    <kerning first="86" second="111" amount="0"/>
+    <kerning first="86" second="114" amount="0"/>
+    <kerning first="86" second="117" amount="0"/>
+    <kerning first="86" second="121" amount="0"/>
+    <kerning first="87" second="44" amount="0"/>
+    <kerning first="87" second="173" amount="0"/>
+    <kerning first="87" second="46" amount="0"/>
+    <kerning first="87" second="58" amount="0"/>
+    <kerning first="87" second="59" amount="0"/>
+    <kerning first="87" second="65" amount="0"/>
+    <kerning first="87" second="97" amount="0"/>
+    <kerning first="87" second="101" amount="0"/>
+    <kerning first="87" second="105" amount="0"/>
+    <kerning first="87" second="111" amount="0"/>
+    <kerning first="87" second="114" amount="0"/>
+    <kerning first="87" second="117" amount="0"/>
+    <kerning first="87" second="121" amount="0"/>
+    <kerning first="89" second="32" amount="0"/>
+    <kerning first="89" second="44" amount="-1"/>
+    <kerning first="89" second="173" amount="-1"/>
+    <kerning first="89" second="46" amount="-1"/>
+    <kerning first="89" second="58" amount="0"/>
+    <kerning first="89" second="59" amount="-1"/>
+    <kerning first="89" second="65" amount="-1"/>
+    <kerning first="89" second="97" amount="-1"/>
+    <kerning first="89" second="101" amount="-1"/>
+    <kerning first="89" second="105" amount="0"/>
+    <kerning first="89" second="111" amount="-1"/>
+    <kerning first="89" second="112" amount="-1"/>
+    <kerning first="89" second="113" amount="-1"/>
+    <kerning first="89" second="117" amount="0"/>
+    <kerning first="89" second="118" amount="0"/>
+    <kerning first="102" second="102" amount="0"/>
+    <kerning first="114" second="44" amount="0"/>
+    <kerning first="114" second="46" amount="0"/>
+    <kerning first="118" second="44" amount="-1"/>
+    <kerning first="118" second="46" amount="-1"/>
+    <kerning first="119" second="44" amount="0"/>
+    <kerning first="119" second="46" amount="0"/>
+    <kerning first="121" second="44" amount="-1"/>
+    <kerning first="121" second="46" amount="-1"/>
+  </kernings>
+</font>

BIN
src/font/open-sans-8-white.png


+ 831 - 0
src/plugins/wiki.ts

@@ -0,0 +1,831 @@
+//PLUGIN wiki.ts
+import { param, plugins, runcod } from '../lib/decorators.js';
+import 'reflect-metadata';
+import { GroupMessage, PrivateFriendMessage, PrivateGroupMessage, Receive } from 'node-napcat-ts';
+import { execSync } from 'child_process'
+import fs from 'fs'
+import path from 'path';
+import { createWorker } from 'tesseract.js';
+import { fileURLToPath } from 'url';
+import { PSM } from 'tesseract.js';
+import { Jimp, loadFont } from 'jimp'; // 假设未引入,添加引入语句
+import { Type } from 'js-yaml';
+
+
+@plugins({
+    easycmd: true,
+    name: "枫叶秋林的明日方舟工具箱",
+    version: "0.0.1",
+    describe: "日常制作不出许多有趣好玩的工具箱",
+    author: "枫叶秋林",
+    help: {
+        enabled: true,
+        description: "查看帮助信息"
+    }
+})
+export class wiki {
+
+    @runcod(["干员", "查询干员"], `干员bilibiliWiki截图`)
+    async browser(
+        @param("干员名称", 'text') name: Receive["text"],
+        @param("内容信息", 'text', { type: 'text', data: { text: '' } }, true) element: Receive["text"]
+    ) {
+        let sandbox = ''
+        switch (element?.data?.text) {
+            case '评论':
+                sandbox = '#flowthread'
+                break;
+            case '语音':
+                sandbox = '::-p-xpath(/html/body/div[2]/div[2]/div[4]/div[5]/div/div[27])'
+                break;
+            case '档案':
+                sandbox = '::-p-xpath(/html/body/div[2]/div[2]/div[4]/div[5]/div/div[24])'
+                break;
+            case '模组':
+                sandbox = '::-p-xpath(/html/body/div[2]/div[2]/div[4]/div[5]/div/div[21])'
+                break;
+            case '基建':
+                sandbox = '::-p-xpath(/html/body/div[2]/div[2]/div[4]/div[5]/div/div[19])'
+                break;
+            case '技能材料':
+                sandbox = '::-p-xpath(/html/body/div[2]/div[2]/div[4]/div[5]/div/div[17])'
+            default:
+                sandbox = ''
+        }
+        return {
+            selector: sandbox,
+            template: { // 模板配置,用于发送图片内容
+                enabled: true,//是否启用模板,启用将发送图片内容
+                sendText: false,//是否发送文本,启用将发送文本内容,如果都启用则发送两条消息
+                render: {//浏览器默认参数设置,用于打开浏览器的设置
+                    width: 600, // 模板宽度
+                    height: 1, // 模板高度
+                    type: 'png',// 模板类型
+                    quality: 100,// 模板质量
+                    fullPage: false,// 是否全屏
+                    background: true,
+                    url: `https://wiki.biligame.com/arknights/${name?.data?.text}`// 模板路径,推荐按规范放置在resources目录下
+                }
+            },
+            toString() { //重写toString方法,用于返回文本内容,启用sendText时将发送文本内容,不启用时将发送图片内容,图片发送失败时发送文字内容
+                return `访问${name?.data?.text}`;
+            }
+        }
+    }
+
+    @runcod(['方舟智能点击','智能点击'], `会自动识别文字,安卓模拟器的操作方舟点击操作,优先使用创建的点击步骤`)
+    async rig(
+        @param("点击文本", 'text') targetText: Receive["text"],
+        @param("x偏移", 'text', { type: 'text', data: { text: '' } }, true) x1: Receive["text"],
+        @param("y偏移", 'text', { type: 'text', data: { text: '' } }, true) y1: Receive["text"],
+        context: PrivateFriendMessage | PrivateGroupMessage | GroupMessage
+    ) {
+        if (!targetText?.data?.text) {
+            return '请输入文本'
+        }
+        const __dirname = path.dirname(fileURLToPath(import.meta.url));
+        const tempDir = path.resolve(__dirname, '..', '..', 'botQQ_screenshots');
+        const tempFile = path.join(tempDir, `screenshot_${Date.now()}.png`);
+        const newtempFile = path.join(tempDir, `screenshot_${Date.now()}.png`);
+        try {
+            const { adbPath, deviceList } = this.getadb();
+            const buffer = await this.getimg(adbPath, deviceList, tempFile);
+            if (!buffer) {
+                return;
+            }
+
+            const readxy = await this.readxy(targetText?.data?.text)
+            let x = 0
+            let y = 0
+            let img ='' 
+            let txst =''
+            if (readxy) {
+                x = readxy.x1;
+                y = readxy.y1;
+                txst = '记录结果'
+                img = buffer.toString('base64');
+            }else{
+                const data  = await this.recognizeTextPosition(tempFile, targetText.data.text);
+                x = data.x
+                y = data.y
+                txst = data.txst
+                img = data.img
+            }
+            if (targetText?.data?.text) {
+                if (targetText?.data?.text == '任意') {
+                    const x = Math.floor(Math.random() * 1000) + 1;
+                    const y = Math.floor(Math.random() * 1000) + 1;
+                    execSync(`${adbPath} -s ${deviceList[0]} shell input tap ${x} ${y}`);
+                } else {
+                    if (x1?.data?.text || y1?.data?.text) {
+                        execSync(`${adbPath} -s ${deviceList[0]} shell input tap ${x + Number(x1?.data?.text ?? 0)} ${y + Number(y1?.data?.text ?? 0)}`);
+                    } else {
+                        execSync(`${adbPath} -s ${deviceList[0]} shell input tap ${x} ${y}`);
+                    }
+                }
+                await new Promise((resolve) => setTimeout(resolve, 4000));
+                const buffer = await this.getimg(adbPath, deviceList, newtempFile);
+                if (!buffer) {
+                    return;
+                }
+                const base64Data = buffer.toString('base64');
+                context.quick_action([{
+                    type: 'text',
+                    data: {
+                        text: `识别结果:x:${x},y:${y}(${txst})`
+                    },
+                },{
+                    type: 'image',
+                    data: {
+                        file: `base64://${img}`
+                    }
+                },{
+                    type: 'image',
+                    data: {
+                        file: `base64://${base64Data}`
+                    }
+                }]);
+            }
+            return '截图成功';
+        } catch (error) {
+            console.error('[ADB错误]', error);
+            if (fs.existsSync(tempFile)) {
+                fs.unlinkSync(tempFile);
+            }
+            if (fs.existsSync(newtempFile)) {
+                fs.unlinkSync(newtempFile);
+            }
+            const errorMsg = error instanceof Error && error.message
+            return errorMsg;
+        } finally {
+            if (fs.existsSync(tempFile)) {
+                fs.unlinkSync(tempFile);
+            }
+            if (fs.existsSync(newtempFile)) {
+                fs.unlinkSync(newtempFile);
+            }
+        }
+    }
+    @runcod(['方舟滑动','滑动'], `滑动屏幕`)
+    async huadong(
+        @param("name", 'text') name: Receive["text"],
+        @param("type", 'text', { type: 'text', data: { text: '' } },true) type: Receive["text"],
+        @param("距离", 'text', { type: 'text', data: { text: '' } },true) distance: Receive["text"],
+        @param("X", 'text', { type: 'text', data: { text: '' } },true) x1: Receive["text"],
+        @param("y", 'text', { type: 'text', data: { text: '' } },true) y1: Receive["text"],
+        context: PrivateFriendMessage | PrivateGroupMessage | GroupMessage
+    ) {
+        if (!name?.data?.text) { return; }
+        const __dirname = path.dirname(fileURLToPath(import.meta.url));
+        const tempDir = path.resolve(__dirname, '..', '..', 'botQQ_screenshots');
+        const tempFile = path.join(tempDir, `screenshot_${Date.now()}.png`);
+        const newtempFile = path.join(tempDir, `screenshot_${Date.now()}.png`);
+        const { adbPath, deviceList } = this.getadb();
+        const xy = await this.readxy(name?.data?.text)
+        if (xy) {
+            if (!x1?.data?.text || !y1?.data?.text) {
+                execSync(`${adbPath} -s ${deviceList[0]} shell input swipe ${xy.x1} ${xy.y1} ${xy.x2} ${xy.y2}`);
+            } else {
+                if (xy.x1 != Number(x1?.data?.text) || xy.y1 != Number(y1?.data?.text) || xy.type != type?.data?.text) {
+                    try {
+                        let x2 = 0
+                        let y2 = 0
+                        switch (type?.data?.text) {
+                            case '上':
+                                x2 = Number(x1.data.text)
+                                y2 = Number(y1.data.text) + Number(distance?.data?.text ?? 100)
+                                break;
+                            case '下':
+                                x2 = Number(x1.data.text)
+                                y2 = Number(y1.data.text) - Number(distance?.data?.text ?? 100)
+                                break;
+                            case '左':
+                                x2 = Number(x1.data.text) + Number(distance?.data?.text ?? 100)
+                                y2 = Number(y1.data.text)
+                                break;
+                            case '右':
+                                x2 = Number(x1.data.text) - Number(distance?.data?.text ?? 100)
+                                y2 = Number(y1.data.text)
+                                break;
+                            default:
+                                return '请输入滑动方向'
+                        }
+                        execSync(`${adbPath} -s ${deviceList[0]} shell input swipe ${x1.data.text} ${y1.data.text} ${x2} ${y2}`);
+                        this.savetest(name?.data?.text, 'slide', Number(x1?.data?.text), Number(y1?.data?.text), x2, y2)
+                        await new Promise((resolve) => setTimeout(resolve, 4000));
+                    }
+                    catch (error) {
+                        console.error('[ADB错误]', error);
+                        if (fs.existsSync(tempFile)) {
+                            fs.unlinkSync(tempFile);
+                        }
+                        if (fs.existsSync(newtempFile)) {
+                            fs.unlinkSync(newtempFile);
+                        }
+                        const errorMsg = error instanceof Error && error.message
+                        return errorMsg;
+                    }
+                }
+            }
+        } else {
+            if (!x1?.data?.text || !y1?.data?.text) {
+                return '请输入坐标';
+            }
+            try {
+                let x2 = 0
+                let y2 = 0
+                switch (type?.data?.text) {
+                    case '上':
+                        x2 = Number(x1.data.text)
+                        y2 = Number(y1.data.text) - Number(distance?.data?.text ?? 100)
+                        break;
+                    case '下':
+                        x2 = Number(x1.data.text)
+                        y2 = Number(y1.data.text) + Number(distance?.data?.text ?? 100)
+                        break;
+                    case '左':
+                        x2 = Number(x1.data.text) - Number(distance?.data?.text ?? 100)
+                        y2 = Number(y1.data.text)
+                        break;
+                    case '右':
+                        x2 = Number(x1.data.text) + Number(distance?.data?.text ?? 100)
+                        y2 = Number(y1.data.text)
+                        break;
+                    default:
+                        return '请输入滑动方向'
+                }
+                execSync(`${adbPath} -s ${deviceList[0]} shell input swipe ${x1.data.text} ${y1.data.text} ${x2} ${y2}`);
+                this.savetest(name?.data?.text, 'slide', Number(x1?.data?.text), Number(y1?.data?.text), x2, y2)
+                await new Promise((resolve) => setTimeout(resolve, 4000));
+            }
+            catch (error) {
+                console.error('[ADB错误]', error);
+                if (fs.existsSync(tempFile)) {
+                    fs.unlinkSync(tempFile);
+                }
+                if (fs.existsSync(newtempFile)) {
+                    fs.unlinkSync(newtempFile);
+                }
+                const errorMsg = error instanceof Error && error.message
+                return errorMsg;
+            }
+        }
+        const JGbuffer = await this.getimg(adbPath, deviceList, newtempFile);
+        if (!JGbuffer) { return; }
+        const base64Data = JGbuffer.toString('base64');
+        context.quick_action([
+            {
+                type: 'image',
+                data: {
+                    file: `base64://${base64Data}`
+                }
+        }])
+        if (fs.existsSync(tempFile)) {
+            fs.unlinkSync(tempFile);
+        }
+        if (fs.existsSync(newtempFile)) {
+            fs.unlinkSync(newtempFile);
+        }
+        return '操作成功';
+    }
+    @runcod(['方舟输入','输入'], `输入文本`)
+    async input(
+        @param("输入文本", 'text') text: Receive["text"],
+        context: PrivateFriendMessage | PrivateGroupMessage | GroupMessage
+    ){
+        const __dirname = path.dirname(fileURLToPath(import.meta.url));
+        const tempDir = path.resolve(__dirname, '..', '..', 'botQQ_screenshots');
+        const tempFile = path.join(tempDir, `screenshot_${Date.now()}.png`);
+        const newtempFile = path.join(tempDir, `screenshot_${Date.now()}.png`);
+        try {
+            const { adbPath, deviceList } = this.getadb();
+            const buffer = await this.getimg(adbPath, deviceList, tempFile);
+            if (!buffer) {
+                return;
+            }
+            fs.writeFileSync(tempFile, buffer);
+            if (text?.data?.text) {
+                // 使用Base64编码处理中文
+                const encodedText = text.data.text||"";
+                const CMD = `${adbPath} -s ${deviceList[0]} shell am broadcast -a ADB_INPUT_TEXT --es msg "${encodedText}"`
+                execSync(CMD);                
+                const buffer = await this.getimg(adbPath, deviceList, newtempFile);
+                if (!buffer) {
+                    return;
+                }
+                const base64Data = buffer.toString('base64');
+                context.quick_action([{
+                    type: 'text',
+                    data: {
+                        text: `记录结果:${text.data.text}`
+                    },
+                },{
+                    type: 'image',
+                    data: {
+                        file: `base64://${base64Data}`
+                    }
+                }
+            ])
+            }
+        }
+        catch (error) {
+            if (fs.existsSync(tempFile)) {
+                fs.unlinkSync(tempFile);
+            }
+            if (fs.existsSync(newtempFile)) {
+                fs.unlinkSync(newtempFile);
+            }
+            console.error('[ADB错误]', error);
+            if (fs.existsSync(tempFile)) {
+                fs.unlinkSync(tempFile);
+            }
+        }finally  {
+            if (fs.existsSync(tempFile)) {
+                fs.unlinkSync(tempFile);
+            }
+            if (fs.existsSync(newtempFile)) {
+                fs.unlinkSync(newtempFile);
+            }
+        }
+    }
+
+    @runcod(['方舟点击','点击'], `创建一个点击步骤`)
+    async rig2(
+        @param("点击文本", 'text') targetText: Receive["text"],
+        @param("x偏移", 'text', { type: 'text', data: { text: '' } }, true) x1: Receive["text"],
+        @param("y偏移", 'text', { type: 'text', data: { text: '' } }, true) y1: Receive["text"],
+        context: PrivateFriendMessage | PrivateGroupMessage | GroupMessage
+    ){
+        const __dirname = path.dirname(fileURLToPath(import.meta.url));
+        const tempDir = path.resolve(__dirname, '..', '..', 'botQQ_screenshots');
+        const tempFile = path.join(tempDir, `screenshot_${Date.now()}.png`);
+        const newtempFile = path.join(tempDir, `screenshot_${Date.now()}.png`);
+        try {
+            const { adbPath, deviceList } = this.getadb();
+            const buffer = await this.getimg(adbPath, deviceList, tempFile);
+            if (!buffer) {
+                return;
+            }
+            fs.writeFileSync(tempFile, buffer);
+            if (targetText?.data?.text) {
+                execSync(`${adbPath} -s ${deviceList[0]} shell input tap ${x1.data.text} ${y1.data.text}`);
+                const buffer = await this.getimg(adbPath, deviceList, newtempFile);
+                if (!buffer) {
+                    return;
+                }
+                const base64Data = buffer.toString('base64');
+                await new Promise((resolve) => setTimeout(resolve, 4000));
+                context.quick_action([{
+                    type: 'text',
+                    data: {
+                        text: `记录结果:x:${x1.data.text},y:${y1.data.text}(${targetText.data.text})\n 图片记录`
+                    },
+                },{
+                    type: 'image',
+                    data: {
+                        file: `base64://${base64Data}`
+                    }
+                }]);
+                this.savetest(targetText.data.text, 'cilik' , Number(x1.data.text) , Number(y1.data.text));
+            }
+            return '操作成功';
+        } catch (error) {
+            console.error('[ADB错误]', error);
+            if (fs.existsSync(tempFile)) {
+                fs.unlinkSync(tempFile);
+            }
+            if (fs.existsSync(newtempFile)) {
+                fs.unlinkSync(newtempFile);
+            }
+            const errorMsg = error instanceof Error && error.message
+            return errorMsg;
+        } finally {
+            if (fs.existsSync(tempFile)) {
+                fs.unlinkSync(tempFile);
+            }
+            if (fs.existsSync(newtempFile)) {
+                fs.unlinkSync(newtempFile);
+            }
+        }
+    }
+
+    @runcod(['步骤','查看步骤'], `查看创建的步骤`)
+    async list(
+        context: PrivateFriendMessage | PrivateGroupMessage | GroupMessage
+    ){
+        const __dirname = path.dirname(fileURLToPath(import.meta.url));
+        const filePath = path.join(__dirname, '..', '..', 'botQQ_screenshots', 'test.json');
+        let data: any = {};
+        if (fs.existsSync(filePath)) {
+            const fileContent = fs.readFileSync(filePath, 'utf-8');
+            data = JSON.parse(fileContent);
+        }
+        let str = ''
+        for (const key in data) {
+            if (data.hasOwnProperty(key)) {
+                const element = data[key];
+                str += `${key}(${element.type?? 'click' }):x:${element.x1},y:${element.y1}\n`;
+            }
+        }
+        return str;
+    }
+    @runcod(['步骤集','查看步骤集'], `查看创建的步骤集`)
+    async lists(){
+        const __dirname = path.dirname(fileURLToPath(import.meta.url));
+        const filePath = path.join(__dirname, '..', '..', 'botQQ_screenshots', 'tests.json');
+        let str=''
+        let data: any = {};
+        if (fs.existsSync(filePath)) {
+            const fileContent = fs.readFileSync(filePath, 'utf-8');
+            data = JSON.parse(fileContent);
+        }
+        let i=1;
+        for (const key in data) {
+           const v = await this.readtests(key)
+           if (v) {
+            str+= `${i++}.${key}:`
+            for (const i in v) {
+                str+= `${v[i].name}(${v[i].type}),`
+            }
+           }
+        }
+        return str;
+    }
+    @runcod(['创建步骤集'], `创建步骤集`)
+    async createlist(
+        @param("步骤集名称", 'text') testname: Receive["text"],
+        @param("步骤,例子:步骤名称1:类别,步骤名称2:类别", 'text') texts: Receive["text"],
+        context: PrivateFriendMessage | PrivateGroupMessage | GroupMessage
+    ){
+        let str=''
+        const tests = texts?.data?.text?.split(',')
+        const datatest:{
+            name: string;
+            type: 'input' | 'click' | 'slide';
+        }[] = [];
+        if (tests) {
+            for (const test of tests) {
+                const [name, type] = test.split(':');
+                if (type == 'input') {
+                    datatest.push({type,name});
+                }else if (type == 'click'){
+                    const xy = await this.readxy(name)
+                    if (xy) {
+                        datatest.push({type,name});
+                    }else{
+                        str+= `步骤${name}未找到,请创建\n`
+                    }
+                }else{
+                    str+= `步骤${name}未找到,请创建\n`
+                }
+                
+            }
+            this.createtests(testname.data.text,datatest);
+            str+= `步骤集${testname.data.text}创建成功\n`
+        }
+        return str;
+    }
+    @runcod(['执行步骤集','runtests'], `执行步骤集`)
+    async runtest(
+        @param("步骤集名称", 'text') name: Receive["text"],
+        @param("步骤,例子:输入值1:输入值2:输入值3:", 'text',{type:'text',data:{text:''}},true) input: Receive["text"],
+        context: PrivateFriendMessage | PrivateGroupMessage | GroupMessage
+    ){
+        if (!name?.data?.text) {
+            return '步骤集名称不能为空';   
+        }
+        if (input?.data?.text == '') {
+            return '输入值不能为空';
+        }
+        let str=''
+        const inputs = input?.data?.text?.split(':')
+        const tests = await this.readtests(name.data.text)
+        const { adbPath, deviceList } = this.getadb();
+        if (tests) {
+            for (const test of  tests) {
+                if (test.type == 'input') {
+                    if (inputs) {
+                        const input = inputs.shift()
+                        if (input) {
+                            const CMD = `${adbPath} -s ${deviceList[0]} shell am broadcast -a ADB_INPUT_TEXT --es msg "${input}"`
+                            execSync(CMD);
+                            await new Promise((resolve) => setTimeout(resolve, 3000));
+                            str += `步骤${test.name}执行成功 类别:${test.type}输入值:${input}\n`
+                        }
+                    }
+                }else if (test.type == 'click'){
+                    const readxy = await this.readxy(test.name)
+                    let cmd=`${adbPath} -s ${deviceList[0]} shell input tap ${readxy?.x1?? 0} ${readxy?.y1??0}`
+                    execSync(cmd);
+                    str += `步骤${test.name}执行成功 类别:${test.type}(x:${readxy?.x1?? 0},y:${readxy?.y1??0})\n`
+                    await new Promise((resolve) => setTimeout(resolve, 3000));
+                }else if (test.type == 'slide'){
+                    const readxy = await this.readxy(test.name)
+                    let cmd=`${adbPath} -s ${deviceList[0]} shell input swipe ${readxy?.x1?? 0} ${readxy?.y1??0} ${readxy?.x2?? 0} ${readxy?.y2??0}`
+                    execSync(cmd);
+                    str += `步骤${test.name}执行成功 类别:${test.type}(x:${readxy?.x1?? 0},y:${readxy?.y1??0},x2:${readxy?.x2?? 0},y2:${readxy?.y2??0})\n`
+                    await new Promise((resolve) => setTimeout(resolve, 3000));
+                }
+            }
+            await this.tu(context);
+            return str;
+        }
+        return str??'步骤集不存在';
+    }
+    @runcod(['方舟状态','截图','状态'], `当前方舟运行状态`)
+    async tu(
+        context: PrivateFriendMessage | PrivateGroupMessage | GroupMessage
+    ){
+        if (!context) {
+            return;
+        }
+        const __dirname = path.dirname(fileURLToPath(import.meta.url));
+        const tempDir = path.resolve(__dirname, '..', '..', 'botQQ_screenshots');
+        const tempFile = path.join(tempDir, `screenshot_${Date.now()}.png`);
+        const newtempFile = path.join(tempDir, `screenshot_${Date.now()}.png`);
+        try {
+            const { adbPath, deviceList } = this.getadb();
+            const buffer = await this.getimg(adbPath, deviceList, tempFile);
+            if (!buffer) {
+                return;
+            }
+            fs.writeFileSync(tempFile, buffer);
+            const GRID = (await this.drawGrid(tempFile))
+            const base64Data = buffer.toString('base64');
+            context.quick_action([{
+                type: 'image',
+                data: {
+                    file: `base64://${base64Data}`
+                }
+            }, 
+            {
+                type: 'image',
+                data: {
+                    file: `base64://${GRID}`
+                }
+            }]);
+            return '截图成功';
+        } catch (error) {
+            console.error('[ADB错误]', error);
+            if (fs.existsSync(tempFile)) {
+                fs.unlinkSync(tempFile);
+            }
+            if (fs.existsSync(newtempFile)) {
+                fs.unlinkSync(newtempFile);
+            }
+            const errorMsg = error instanceof Error && error.message
+            return errorMsg;
+        } finally {
+            if (fs.existsSync(tempFile)) {
+                fs.unlinkSync(tempFile);
+            }
+            if (fs.existsSync(newtempFile)) {
+                fs.unlinkSync(newtempFile);
+            }
+        }
+    }
+    //获取安卓模拟器设备
+    getadb() {
+        const adbPath = '/opt/homebrew/bin/adb';
+        // 获取有效设备列表
+        const devicesOutput = execSync(`${adbPath} devices`).toString();
+        const deviceList = devicesOutput.split('\n')
+            .slice(1)
+            .filter(line => line.trim().endsWith('device'))
+            .map(line => line.split('\t')[0]);
+
+        if (deviceList.length === 0) {
+            throw new Error('未检测到已连接的安卓设备');
+        }
+        return {
+            adbPath,
+            deviceList
+        };
+    }
+    async getimg(adbPath: string, deviceList: string[], tempFile: string) {
+        if (deviceList.length === 0) {
+            return   
+        }
+        if (!adbPath){
+            return
+        }
+        execSync(`${adbPath} -s ${deviceList[0]} exec-out screencap -p > ${tempFile}`);
+        const readStream = fs.createReadStream(tempFile);
+        const chunks = [];
+        for await (const chunk of readStream) {
+            chunks.push(chunk);
+        }
+        return Buffer.concat(chunks);
+    }
+    private async recognizeTextPosition(imagePath: string, text: string): Promise<{ x: number; y: number,img:string ,txst:string}> {
+        if (!imagePath || !text) {
+            return { x: 0, y: 0,img:'',txst:'' };
+        }
+        try {
+            const worker = await createWorker();
+            await worker.load('chi_sim');
+            await worker.reinitialize('chi_sim');
+
+            await worker.setParameters({
+                user_defined_dpi: '320',
+                tessedit_char_whitelist: text,
+                tessedit_pageseg_mode: PSM.SINGLE_BLOCK
+
+            });
+            //识别文本未知
+            const { data } = await worker.recognize(imagePath, {
+
+            }, { blocks: true });
+
+            if (!data || data.blocks?.length !== 1) {
+                throw new Error('未找到文本块');
+            }
+            const target = data.blocks[0];
+
+
+            await worker.terminate();
+
+            if (!target) {
+                throw new Error('未找到目标文本');
+            }
+            let words: any = []
+            let txst='';
+            target.paragraphs.forEach((paragraph) => {
+                paragraph.lines.forEach((line) => {
+                    line.words.forEach((word) => {
+                        words.push({
+                            x0: word.bbox.x0,
+                            x1: word.bbox.x1,
+                            y0: word.bbox.y0,
+                            y1: word.bbox.y1,
+                            text:  txst += `文本:${line.text}(${Math.floor(word.bbox.x0 + (word.bbox.x1 - word.bbox.x0) / 2)},${Math.floor(word.bbox.y0 + (word.bbox.y1 - word.bbox.y0) / 2)})\n`
+                        })
+                    });
+                });
+            })
+            const x = Math.floor(words[0].x0 + (words[0].x1 - words[0].x0) / 2)
+            const y = Math.floor(words[0].y0 + (words[0].y1 - words[0].y0) / 2)
+            return {x,y, img:await this.drawCircle(imagePath,x,y) ,txst};
+        } catch (error) {
+            throw new Error(`识别失败:${error instanceof Error ? error.message : '请检查OCR依赖安装'}`);
+        }
+    }
+    //绘制圆形标记
+    private async drawCircle(imagePath: string, x: number,y: number): Promise<string> {
+        if (!imagePath) {
+            return '';
+        }
+        const image = await Jimp.read(imagePath);
+            const marker = new Jimp({
+                width: 50,
+                height: 50,
+                color: 0x00000000
+            });
+            marker.scan(0, 0, marker.bitmap.width, marker.bitmap.height,  (x, y, idx) => {
+                const dx = x - 25;
+                const dy = y - 25;
+                const distance = Math.sqrt(dx * dx + dy * dy);
+                if (distance <= 25) {
+                    marker.bitmap.data[idx + 3] = 255;
+                }
+            });
+            marker.circle({ radius: 5, x: 25, y: 25 });
+            image.composite(marker, x - 10, y - 10);
+            const img =await image.getBase64('image/png');
+            return img.split(',')[1];
+    }
+    //绘制网格
+    private async drawGrid(imagePath: string): Promise<string> {
+        if (!imagePath) {
+            return '';
+        }
+        const image = await Jimp.read(imagePath);
+        const __dirname = path.dirname(fileURLToPath(import.meta.url));
+        const tempDir = path.resolve(__dirname, '..', 'font', 'open-sans-8-white.fnt');
+        const font = await loadFont(tempDir);
+        const width = image.bitmap.width;
+        const height = image.bitmap.height;
+        const gridSize = 50;
+        for (let x = 0; x < width; x += gridSize) {
+            if (typeof Jimp !== 'undefined' && image instanceof Jimp) {
+                image.scan(x, 0, 1, height, (xScan, yScan, idx) => {
+                    image.bitmap.data[idx + 0] = 0;   // R
+                    image.bitmap.data[idx + 1] = 0;   // G
+                    image.bitmap.data[idx + 2] = 0;   // B
+                    image.bitmap.data[idx + 3] = 255; // A
+                });
+            }
+        }
+        for (let y = 0; y < height; y += gridSize) {
+            // 绘制水平线
+            if (typeof Jimp!== 'undefined' && image instanceof Jimp) {
+                image.scan(0, y, width, 1, (xScan, yScan, idx) => {
+                    image.bitmap.data[idx + 0] = 0;   // R
+                    image.bitmap.data[idx + 1] = 0;   // G
+                    image.bitmap.data[idx + 2] = 0;   // B
+                    image.bitmap.data[idx + 3] = 255; // A  
+                })
+            }
+        }
+        // 线两段标注数字
+        for (let x = 0; x < width; x += gridSize) {
+            for (let y = 0; y < height; y += gridSize) {
+                if (typeof Jimp!== 'undefined' && image instanceof Jimp) {
+                    if (font) {
+                        image.print({ font, x: x - 10, y: y - 10, text: `${x},${y}` });
+                    }
+                }
+            }
+        }
+
+        const img = await image.getBase64('image/png');
+        return img.split(',')[1];
+    }
+    //保存步骤记录
+    private async savetest(test: string,type:'cilik' | 'slide', x1: number, y1: number, x2?:number, y2?:number): Promise<void> {
+        const __dirname = path.dirname(fileURLToPath(import.meta.url));
+        //json
+        const filePath = path.join(__dirname, '..', '..', 'botQQ_screenshots', 'test.json');
+        let data: any = {};
+        if (fs.existsSync(filePath)) {
+            const fileContent = fs.readFileSync(filePath, 'utf-8');
+            data = JSON.parse(fileContent);
+        }else{
+            fs.writeFileSync(filePath, JSON.stringify(data));
+        }
+        if(data[test]){
+            switch(type){
+                case 'cilik':
+                    data[test].x1=x1
+                    data[test].y1=y1
+                    break;
+                case 'slide':
+                    data[test].x1=x1
+                    data[test].y1=y1
+                    data[test].x2=x2
+                    data[test].y2=y2
+            }
+        }else{
+            switch(type){
+                case 'cilik':
+                    data[test]={type,x1,y1}
+                    break;
+                case 'slide':
+                    data[test]={type,x1,y1,x2,y2}
+            }
+            
+        }
+        fs.writeFileSync(filePath, JSON.stringify(data));
+        return;
+    }
+    //读取步骤记录
+    private async readxy(test: string): Promise< { type:'cilik' | 'slide', x1: number, y1: number, x2?:number, y2?:number } | undefined> {
+        const __dirname = path.dirname(fileURLToPath(import.meta.url));
+        const filePath = path.join(__dirname, '..', '..', 'botQQ_screenshots', 'test.json');
+        let data: any = {};
+        if (fs.existsSync(filePath)) {
+            const fileContent = fs.readFileSync(filePath, 'utf-8');
+            data = JSON.parse(fileContent);
+        }
+        if(data[test]){
+            return data[test] as { type:'cilik' | 'slide', x1: number, y1: number, x2?:number, y2?:number };
+        }
+    }
+    //创建步骤记录
+    private async createtests(name:string , test: {
+        name: string;
+        type: 'input' | 'click' | 'slide';
+        
+    }[]): Promise<void> {
+        const __dirname = path.dirname(fileURLToPath(import.meta.url));
+        const filePath = path.join(__dirname, '..', '..', 'botQQ_screenshots', 'tests.json');
+        let data: any = {};
+        if (fs.existsSync(filePath)) {
+            const fileContent = fs.readFileSync(filePath, 'utf-8');
+            data = JSON.parse(fileContent);
+        }
+        data[name]=test
+        fs.writeFileSync(filePath, JSON.stringify(data));
+        return;
+    }
+    //读取步骤记录
+    private async readtests(name:string): Promise<{
+        name: string;
+        type: 'input' | 'click' | 'slide';
+    }[] | undefined> {
+        const __dirname = path.dirname(fileURLToPath(import.meta.url));
+        const filePath = path.join(__dirname, '..', '..', 'botQQ_screenshots', 'tests.json');
+        let data: any = {};
+        if (fs.existsSync(filePath)) {
+            const fileContent = fs.readFileSync(filePath, 'utf-8');
+            data = JSON.parse(fileContent);
+            if(data[name]){
+                return data[name] ;
+            }
+        }
+        if(data[name]){
+            return data[name];
+        }
+    }
+}
+

BIN
tessdata/chi_sim.traineddata


이 변경점에서 너무 많은 파일들이 변경되어 몇몇 파일들은 표시되지 않았습니다.