优化爱可菲厨艺机关README

This commit is contained in:
秋云
2025-06-19 05:29:13 +08:00
parent f74368ee8d
commit 9c8ef7caef
8 changed files with 277 additions and 247 deletions

View File

@@ -0,0 +1,51 @@
# 爱可菲厨艺机关
## 项目简介
本脚本用于自动操作爱可菲厨艺机关,通过芭芭拉的攻击动作为机关充能,实现自动获取料理的功能。脚本支持周期性执行,可根据需要设置为每周一执行或每天执行。
## 作者信息
- **作者**LCB-茶包
- **联系方式**QQ 119996800
## 使用说明
### 必要配置
1. **队伍设置**(必填):使用前请在配置中设置要切换的队伍,否则脚本会自动结束任务
2. **队伍编排**:请确保切换的队伍中:
- 3号位爱可菲
- 4号位芭芭拉
### 执行模式
- **周一执行**(推荐):选择"是",脚本会自动判断是否为星期一从而执行
- 爱可菲厨艺机关每周限制10个料理周一更新CD
- 直接加入调度器即可自动运行
- **每天执行**:选择"每天执行"为每次都执行
- **禁用模式**:选择"否"为禁用脚本
### 功能特性
- **自动检测**脚本会自动判断是否获得10个料理后自动退出
- **时间控制**一般60秒完成最大超时默认100秒可自定义配置
- **多账号支持**支持UID禁用模式可设置不执行的UID
- 格式:用 `/` 分隔多个UID`12345/99999`
- 适用于多个账号但部分账号没有爱可菲的情况
## 技术原理
脚本通过芭芭拉的攻击动作为爱可菲厨艺机关充能,实现自动化料理制作过程。
## 注意事项
- 脚本可能存在误差,建议在测试环境中先行验证
- 执行时间受网络环境和设备性能影响
## 反馈与支持
如遇到错误或问题,请联系:
- QQ119996800
## 更新日志
### v1.3 (2025-05-12)
- 更改UID识别方法适配原神UI改变
- 修改超时默认时间
### v1.2 (2025-05-10)
- 首次发布版本

View File

@@ -1,183 +1,183 @@
(async function () { (async function () {
//初始化配置====================================================================================== //初始化配置======================================================================================
var actiontime = settings.actiontime != undefined && ~~settings.actiontime > 0 ? ~~settings.actiontime : 150; var actiontime = settings.actiontime != undefined && ~~settings.actiontime > 0 ? ~~settings.actiontime : 150;
var TEAM var TEAM
var AKF = settings.AKF !== undefined ? ( var AKF = settings.AKF !== undefined ? (
settings.AKF === "是" ? 1 : settings.AKF === "是" ? 1 :
settings.AKF === "否" ? 0 : settings.AKF === "否" ? 0 :
settings.AKF === "每天执行" ? 2 settings.AKF === "每天执行" ? 2
: 0 ) : 0; // 如果settings.AKF完全未定义也赋予AKF为0 : 0 ) : 0; // 如果settings.AKF完全未定义也赋予AKF为0
/** /**
* 文字OCR识别封装函数测试中未封装完成后续会优化逻辑 * 文字OCR识别封装函数测试中未封装完成后续会优化逻辑
* @param text 要识别的文字默认为"空参数" * @param text 要识别的文字默认为"空参数"
* @param timeout 超时时间单位为秒默认为10秒 * @param timeout 超时时间单位为秒默认为10秒
* @param afterBehavior 点击模式0表示不点击1表示点击识别到文字的位置2表示输出模式默认为0 * @param afterBehavior 点击模式0表示不点击1表示点击识别到文字的位置2表示输出模式默认为0
* @param debugmodel 调试代码0表示输入判断模式1表示输出位置信息2表示输出判断模式默认为0 * @param debugmodel 调试代码0表示输入判断模式1表示输出位置信息2表示输出判断模式默认为0
* @param x OCR识别区域的起始X坐标默认为0 * @param x OCR识别区域的起始X坐标默认为0
* @param y OCR识别区域的起始Y坐标默认为0 * @param y OCR识别区域的起始Y坐标默认为0
* @param w OCR识别区域的宽度默认为1920 * @param w OCR识别区域的宽度默认为1920
* @param h OCR识别区域的高度默认为1080 * @param h OCR识别区域的高度默认为1080
* @returns 包含识别结果的对象包括识别的文字坐标和是否找到的结果 * @returns 包含识别结果的对象包括识别的文字坐标和是否找到的结果
*/ */
async function textOCR(text="空参数",timeout=10,afterBehavior=0,debugmodel=0,x=0,y=0,w=1920,h=1080) { async function textOCR(text="空参数",timeout=10,afterBehavior=0,debugmodel=0,x=0,y=0,w=1920,h=1080) {
const startTime = new Date(); const startTime = new Date();
var Outcheak = 0 var Outcheak = 0
for (var ii = 0; ii < 10; ii++) for (var ii = 0; ii < 10; ii++)
{ {
// 获取一张截图 // 获取一张截图
var captureRegion = captureGameRegion(); var captureRegion = captureGameRegion();
var res1 var res1
var res2 var res2
var conuntcottimecot=1; var conuntcottimecot=1;
var conuntcottimecomp=1; var conuntcottimecomp=1;
// 对整个区域进行 OCR // 对整个区域进行 OCR
var resList = captureRegion.findMulti(RecognitionObject.ocr(x,y,w,h)); var resList = captureRegion.findMulti(RecognitionObject.ocr(x,y,w,h));
//log.info("OCR 全区域识别结果数量 {len}", resList.count); //log.info("OCR 全区域识别结果数量 {len}", resList.count);
if (resList.count !== 0) { if (resList.count !== 0) {
for (let i = 0; i < resList.count; i++) for (let i = 0; i < resList.count; i++)
{ // 遍历的是 C# 的 List 对象,所以要用 count而不是 length { // 遍历的是 C# 的 List 对象,所以要用 count而不是 length
let res = resList[i]; let res = resList[i];
res1=res.text res1=res.text
conuntcottimecomp++; conuntcottimecomp++;
if (res.text.includes(text) && debugmodel ==3 ) {return result = { text: res.text, x: res.x, y: res.y, found: true };} if (res.text.includes(text) && debugmodel ==3 ) {return result = { text: res.text, x: res.x, y: res.y, found: true };}
if (res.text.includes(text) && debugmodel !==2 ) { if (res.text.includes(text) && debugmodel !==2 ) {
conuntcottimecot ++; conuntcottimecot ++;
log.info(`${res1}”找到`); log.info(`${res1}”找到`);
if (debugmodel===1 & x===0 & y===0){log.info("全图代码位置:({x},{y},{h},{w})", res.x-10, res.y-10, res.width+10, res.Height+10);}else{log.info("文本OCR完成'{text}'", res.text);} if (debugmodel===1 & x===0 & y===0){log.info("全图代码位置:({x},{y},{h},{w})", res.x-10, res.y-10, res.width+10, res.Height+10);}else{log.info("文本OCR完成'{text}'", res.text);}
if (afterBehavior===1){log.info("点击模式:开");await sleep(1000);click(res.x, res.y);}else{if (debugmodel===1 & x===0 & y===0){log.info("点击模式:关")}} if (afterBehavior===1){log.info("点击模式:开");await sleep(1000);click(res.x, res.y);}else{if (debugmodel===1 & x===0 & y===0){log.info("点击模式:关")}}
if (afterBehavior===2){log.info("F模式:开");await sleep(100);keyPress("F");}else{if (debugmodel===1 & x===0 & y===0){log.info("F模式:关");}} if (afterBehavior===2){log.info("F模式:开");await sleep(100);keyPress("F");}else{if (debugmodel===1 & x===0 & y===0){log.info("F模式:关");}}
if (conuntcottimecot>=conuntcottimecomp/2){return result = { text: res.text, x: res.x, y: res.y, found: true };}else{return result = { found: false};} if (conuntcottimecot>=conuntcottimecomp/2){return result = { text: res.text, x: res.x, y: res.y, found: true };}else{return result = { found: false};}
} }
if (debugmodel ===2 ){ if (debugmodel ===2 ){
if (res1 === res2){conuntcottimecot ++;res2=res1;} if (res1 === res2){conuntcottimecot ++;res2=res1;}
//log.info("输出模式:全图代码位置:({x},{y},{h},{w},{string})", res.x-10, res.y-10, res.width+10, res.Height+10, res.text); //log.info("输出模式:全图代码位置:({x},{y},{h},{w},{string})", res.x-10, res.y-10, res.width+10, res.Height+10, res.text);
if (Outcheak===1){ if (conuntcottimecot>=conuntcottimecomp/2){return result = { text: res.text, x: res.x, y: res.y, found: true };}else{return result = { found: false};}} if (Outcheak===1){ if (conuntcottimecot>=conuntcottimecomp/2){return result = { text: res.text, x: res.x, y: res.y, found: true };}else{return result = { found: false};}}
}}} }}}
const NowTime = new Date(); const NowTime = new Date();
if ((NowTime - startTime)>timeout*1000){if (debugmodel===2){ if (resList.count === 0){return result = {found: false};} else{Outcheak=1;ii=2;} } else {Outcheak=0;if (debugmodel===1 & x===0 & y===0){log.info(`${timeout}秒超时退出,"${text}"未找到`)};return result = {found: false };}} if ((NowTime - startTime)>timeout*1000){if (debugmodel===2){ if (resList.count === 0){return result = {found: false};} else{Outcheak=1;ii=2;} } else {Outcheak=0;if (debugmodel===1 & x===0 & y===0){log.info(`${timeout}秒超时退出,"${text}"未找到`)};return result = {found: false };}}
else{ii=2;if (debugmodel===1 & x===0 & y===0){log.info(`"${text}"识别中……`); } } else{ii=2;if (debugmodel===1 & x===0 & y===0){log.info(`"${text}"识别中……`); } }
await sleep(100); await sleep(100);
} }
} }
/**====================================================================================== /**======================================================================================
* 执行质变仪的部署动作未找到质变仪时返回false结束找到质变仪时返回true * 执行质变仪的部署动作未找到质变仪时返回false结束找到质变仪时返回true
*/ */
async function deployTransformer(){ async function deployTransformer(){
await genshin.SwitchParty(TEAM); //切换到指定队伍必须进行配置4号位放芭芭拉 await genshin.SwitchParty(TEAM); //切换到指定队伍必须进行配置4号位放芭芭拉
await sleep(1000); await sleep(1000);
await keyPress("3"); await keyPress("3");
await sleep(1200); await sleep(1200);
await keyDown("e"); await keyDown("e");
await sleep(1000); await sleep(1000);
await keyUp("e"); await keyUp("e");
await sleep(1000); await sleep(1000);
return true; return true;
} }
/**====================================================================================== /**======================================================================================
* 执行芭芭拉攻击指令并等待质变仪完成提示出现 若超时则强制结束流程 * 执行芭芭拉攻击指令并等待质变仪完成提示出现 若超时则强制结束流程
*/ */
async function executeAttack(){ async function executeAttack(){
await sleep(1000); await sleep(1000);
await keyPress("4"); await keyPress("4");
await sleep(1200); await sleep(1200);
await middleButtonClick(); await middleButtonClick();
await sleep(1000); await sleep(1000);
log.info(`攻击动作开始,${actiontime}秒后超时退出一般120秒左右完成`) log.info(`攻击动作开始,${actiontime}秒后超时退出一般120秒左右完成`)
var startTime = new Date(); var startTime = new Date();
await sleep(500); await sleep(500);
var NowTime = new Date(); var NowTime = new Date();
//芭芭拉攻击指令,等待质变仪完成提示出现,若超时则强制结束流程。 //芭芭拉攻击指令,等待质变仪完成提示出现,若超时则强制结束流程。
var getshu = 0; var getshu = 0;
var lastIncrementTime = 0; // 上次增加getshu的时间 var lastIncrementTime = 0; // 上次增加getshu的时间
const intervalTime = 3000; // 3秒的时间间隔单位为毫秒 const intervalTime = 3000; // 3秒的时间间隔单位为毫秒
while ((NowTime - startTime)<actiontime*1000){ while ((NowTime - startTime)<actiontime*1000){
const result = await textOCR("获得", 0.2, 0, 3, 159, 494, 75, 44); const result = await textOCR("获得", 0.2, 0, 3, 159, 494, 75, 44);
if (result.found) { if (result.found) {
const currentTime = new Date().getTime(); const currentTime = new Date().getTime();
if (currentTime - lastIncrementTime >= intervalTime) { if (currentTime - lastIncrementTime >= intervalTime) {
getshu++; getshu++;
lastIncrementTime = currentTime; lastIncrementTime = currentTime;
log.warn(`获得料理数量: ${getshu}`); log.warn(`获得料理数量: ${getshu}`);
if (getshu >= 10) { if (getshu >= 10) {
log.warn("获得料理数量已达10结束流程"); log.warn("获得料理数量已达10结束流程");
await genshin.returnMainUi(); // 提前退出循环 await genshin.returnMainUi(); // 提前退出循环
return true; return true;
} }
} }
} }
leftButtonClick(); leftButtonClick();
await sleep(50); await sleep(50);
NowTime = new Date(); NowTime = new Date();
} }
await genshin.returnMainUi(); await genshin.returnMainUi();
throw new Error(`${actiontime}秒攻击动作超时,结束流程!`); throw new Error(`${actiontime}秒攻击动作超时,结束流程!`);
} }
let nowuidString = settings.nowuid ? settings.nowuid : ""; let nowuidString = settings.nowuid ? settings.nowuid : "";
// UID获取存在概率不成功慎用请更换背景纯色的名片提高OCR成功率 // UID获取存在概率不成功慎用请更换背景纯色的名片提高OCR成功率
let uidNumbers = nowuidString.match(/\d+/g); let uidNumbers = nowuidString.match(/\d+/g);
if (nowuidString) { if (nowuidString) {
log.debug(`DEBUG:${uidNumbers}`);//调试LOG log.debug(`DEBUG:${uidNumbers}`);//调试LOG
await genshin.returnMainUi(); await genshin.returnMainUi();
await keyPress("VK_ESCAPE"); await keyPress("VK_ESCAPE");
await sleep(500); await sleep(500);
if (uidNumbers && uidNumbers.length > 0) { if (uidNumbers && uidNumbers.length > 0) {
// 使用 for...of 循环遍历 uidNumbers 数组 // 使用 for...of 循环遍历 uidNumbers 数组
for (let number of uidNumbers) { for (let number of uidNumbers) {
var UIDnow = number; var UIDnow = number;
log.debug(`DEBUG:${UIDnow}`); log.debug(`DEBUG:${UIDnow}`);
let UIDD = await textOCR(UIDnow, 1, 0, 0, 112,177, 190, 39); let UIDD = await textOCR(UIDnow, 1, 0, 0, 112,177, 190, 39);
if (UIDD.found) { if (UIDD.found) {
await genshin.returnMainUi(); await genshin.returnMainUi();
throw new Error(`UID "${UIDnow}" 已被禁用,停止刷取!`); throw new Error(`UID "${UIDnow}" 已被禁用,停止刷取!`);
} }
} }
} }
}else{log.warn("未配置禁用UID继续进行");} }else{log.warn("未配置禁用UID继续进行");}
//main/====================================================================================== //main/======================================================================================
await genshin.returnMainUi(); await genshin.returnMainUi();
//检查用户是否配置队伍============================================ //检查用户是否配置队伍============================================
if (settings.TEAMname === undefined) { if (settings.TEAMname === undefined) {
throw new Error("必填请在配置页面填写队伍名称3号为爱可菲4号位芭芭拉"); // 没选就报错后停止 throw new Error("必填请在配置页面填写队伍名称3号为爱可菲4号位芭芭拉"); // 没选就报错后停止
}else{TEAM = settings.TEAMname} }else{TEAM = settings.TEAMname}
//爱可菲厨艺机关 //爱可菲厨艺机关
try { try {
var AKFevry = 0; var AKFevry = 0;
if (AKF == 2){AKF = 1;AKFevry = 1;} if (AKF == 2){AKF = 1;AKFevry = 1;}
if (AKF == 1){ if (AKF == 1){
const today = new Date(); const today = new Date();
// 判断是否为周一getDay()返回0-61代表周一 // 判断是否为周一getDay()返回0-61代表周一
if (today.getDay() == 1 || AKFevry == 1) { if (today.getDay() == 1 || AKFevry == 1) {
log.info("执行爱可菲烹饪任务"); log.info("执行爱可菲烹饪任务");
if ((await deployTransformer())) {//部署厨艺机关 if ((await deployTransformer())) {//部署厨艺机关
log.info("厨艺机关部署成功!"); log.info("厨艺机关部署成功!");
} }
if ((await executeAttack())) {//芭芭拉攻击指令流程 if ((await executeAttack())) {//芭芭拉攻击指令流程
log.info("爱可菲烹饪任务执行完成,结束!!"); log.info("爱可菲烹饪任务执行完成,结束!!");
} }
}else{ }else{
log.info("不执行爱可菲烹饪任务"); log.info("不执行爱可菲烹饪任务");
} }
}else{ }else{
log.info("爱可菲烹饪任务禁用"); log.info("爱可菲烹饪任务禁用");
} }
} catch (error) { } catch (error) {
log.error(`执行过程中发生错误:${error.message}`); log.error(`执行过程中发生错误:${error.message}`);
} finally { } finally {
await genshin.returnMainUi(); await genshin.returnMainUi();
} }
//main/**====================================================================================== //main/**======================================================================================
})(); })();

View File

@@ -1,15 +1,15 @@
{ {
"manifest_version": 1, "manifest_version": 1,
"name": "爱可菲自动化", "name": "爱可菲自动化",
"version": "1.3", "version": "1.3",
"bgi_version": "0.44.0", "bgi_version": "0.44.0",
"description": "爱可菲厨艺机关自动化请注意说明文件如有BUG请联系作者QQ:119996800", "description": "爱可菲厨艺机关自动化请注意说明文件如有BUG请联系作者QQ:119996800",
"tags": ["爱可菲厨艺机关"], "tags": ["爱可菲"],
"authors": [ "authors": [
{ {
"name": "LCB-茶包" "name": "LCB-茶包"
} }
], ],
"settings_ui": "settings.json", "settings_ui": "settings.json",
"main": "main.js" "main": "main.js"
} }

View File

@@ -1,30 +1,30 @@
[ [
{ {
"name": "TEAMname", "name": "TEAMname",
"type": "input-text", "type": "input-text",
"label": "必填队伍名称3号为爱可菲4号位芭芭拉" "label": "必填队伍名称3号为爱可菲4号位芭芭拉"
}, },
{ {
"name": "AKF", "name": "AKF",
"type": "select", "type": "select",
"label": "选题,默认每天执行,可选是:周一执行,否为不执行", "label": "选题,默认每天执行,可选是:周一执行,否为不执行",
"options": [ "options": [
"是", "是",
"否", "否",
"每天执行" "每天执行"
] ]
}, },
{ {
"name": "actiontime", "name": "actiontime",
"type": "input-text", "type": "input-text",
"label": "选填爱可菲厨艺机关超时默认150秒", "label": "选填爱可菲厨艺机关超时默认150秒",
"default": "150" "default": "150"
}, },
{ {
"name": "nowuid", "name": "nowuid",
"type": "input-text", "type": "input-text",
"label": "慎用,禁止特定执行脚本,用 / 隔开如12345/99999" "label": "慎用,禁止特定执行脚本,用 / 隔开如12345/99999"
} }
] ]

View File

@@ -1,21 +0,0 @@
一、使用前请在配置中设置要切换的队伍(必填),否则会自动结束任务。
二、脚本用芭芭拉的攻击动作充能爱可菲厨艺机关请确保切换的队伍3号位爱可菲4号位为芭芭拉。
三、选择“否”为禁用建议选择周一执行选择直接加入的调度器就可以脚本会自动判断是否为星期一从而执行爱可菲厨艺机关每周10个周一更新CD
选择“每天执行”为每次都执行。
四、脚本会自动判断是否获得10个料理后自动退出可能有误差一般60秒完成最大超时默认100秒可自己配置。
五、鉴于有人多个号不一定每个号都有爱可菲加入UID禁用模式把不想执行的UID填入即可用 / 隔开如12345/99999。
六、后言
1、测试阶段如有错误请QQ119996800联系反馈。
七、更新说明
v.1.2 20250510 发布
v.1.3 20250512
1、更改UID识别方法。适配原神UI改变
2、修改超时默认时间。