archive js

This commit is contained in:
起个名字好难的喵
2025-07-28 11:30:03 +08:00
parent 6002f6b54c
commit 0f3da7a6d0
24 changed files with 181 additions and 181 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 876 B

View File

@@ -0,0 +1,103 @@
//eval(file.readTextSync("lib.js"));
const width = genshin.width;
const height = genshin.height;
function clickf(x, y) {
click(Math.round(width * x), Math.round(height * y));
}
function movetof(x, y) {
moveMouseTo(Math.round(width * x), Math.round(height * y));
}
function get_config(name, defval) {
let t = settings[name];
return typeof (t) === 'undefined' ? defval : t;
}
function get_config_int(name, defval) {
return parseInt(get_config(name, defval), 10);
}
class OCRError extends Error {
constructor(message, options) { super(message, options); }
}
setGameMetrics(genshin.width, genshin.height, 1); // 设置游戏窗口大小和DPI
function test1() {
log.info(`窗口大小: ${genshin.width} * ${genshin.height}`);
let a = captureGameRegion();
log.info(`截图x=${a.x} y=${a.y} w=${a.width} h=${a.height} l=${a.left} t=${a.top} r=${a.right} b=${a.bottom}`);
}
const global_region = captureGameRegion();
//test1();
function template(filename, x, y, w, h, center = true) {
if (center) { x = x - w / 2; y = y - h / 2; }
return RecognitionObject.TemplateMatch(file.ReadImageMatSync(filename), 1920 * x, 1080 * y, 1920 * w, 1080 * h);
//return RecognitionObject.TemplateMatch(file.ReadImageMatSync(filename), genshin.width * x, genshin.height * y, genshin.width * w, genshin.height * h);
}
function template_ocr(x, y, w, h, center = true) {
if (center) { x = x - w / 2; y = y - h / 2; }
return RecognitionObject.Ocr(1920 * x, 1080 * y, 1920 * w, 1080 * h);
}
function draw_obj(obj, name = "test") {
const r = obj.RegionOfInterest;
let s = global_region.deriveCrop(r.x, r.y, r.width, r.height);
s.DrawSelf(name);
}
async function match_click(obj, desc, click = true, timeout = 15000) {
draw_obj(obj, "match");
await sleep(1000);
const start = Date.now();
let x = 1;
while (Date.now() - start < timeout) {
let result = captureGameRegion().Find(obj);
await sleep(800);
if (result.isExist()) {
result.drawSelf("match_found");
if (click) {
result.click();
log.info(`成功识别并点击 ${desc},耗时${Date.now() - start}ms`);
} else {
log.info(`成功识别到 ${desc},耗时${Date.now() - start}ms`);
}
return result;
}
log.info(`${x}次识别并点击 ${desc} 失败,耗时${Date.now() - start}ms`);
x++;
await sleep(1000);
}
throw new OCRError(`等待超时,未找到目标 ${desc}`);
}
async function ocr_click(obj, desc, click = true, timeout = 15000) {
draw_obj(obj, "ocr");
await sleep(1000);
const start = Date.now();
let x = 1;
while (Date.now() - start < timeout) {
let results = captureGameRegion().findMulti(obj);
if (results.Count != 1) {
log.warn(`搜索到${results.Count}个结果预期为1个`);
}
await sleep(800);
if (results.Count == 1) {
results[0].drawSelf("ocr_found");
if (click) {
results[0].click();
log.info(`成功Ocr识别并点击 ${desc} 耗时${Date.now() - start}ms`);
} else {
log.info(`成功Ocr识别到 ${desc} 耗时${Date.now() - start}ms`)
}
return results[0];
}
log.info(`${x}次Ocr识别并点击 ${desc} 失败,耗时${Date.now() - start}ms`);
x++;
await sleep(1000);
}
throw new OCRError(`等待超时未找到Ocr目标 ${desc}`);
}

View File

@@ -0,0 +1,257 @@
eval(file.readTextSync("lib.js"));
const CHAR_X = get_config_int("char_x", 0);
const CHAR_Y = get_config_int("char_y", 0);
const global_region = captureGameRegion();
const btn_details = template("assets/button1.png", 0.77, 0.75, 0.04, 0.08, true);
const btn_startmatch = template("assets/button2.png", 0.832, 0.95, 0.04, 0.08, true);
const btn_acceptmatch = template("assets/button1.png", 0.528, 0.68, 0.04, 0.08, true);
const btn_closetip = template("assets/button3.png", 0.978, 0.35, 0.043, 0.075, true);
const buff_icon = template("assets/buff.png", 0.068, 0.204, 0.03, 0.05, true);
const btn_confirm = template("assets/button1.png", 0.832, 0.95, 0.04, 0.08, true);
const goal_icon = template("assets/goal.png", 0.031, 0.3125 + 0.035 * 1, 0.012, 0.018 + 0.035 * 2);
const btn_finish1 = template("assets/finish1.png", 0.5, 0.805, 0.042, 0.026, true);
const btn_finish2 = template("assets/finish2.png", 0.5, 0.805, 0.029, 0.026, true);
const score = template_ocr(0.162, 0.415, 0.1, 0.06, false);
const matching_tip = template_ocr(0.35, 0.77, 0.12, 0.08, false);
const ACT_KEYS = ["W", "S", "A", "D"];
/// Press F5 and click on Details button
async function F5_and_click() {
await keyPress("F5");
await sleep(1000);
for (let i = 0; i < 3; i++) {
clickf(0.182, 0.255);
await sleep(500);
}
await match_click(btn_details, "活动详情按钮");
await sleep(2000);
}
async function start_minigame() {
let should_retry = false;
while (true) {
// 点击开始匹配按钮
try {
await match_click(btn_startmatch, "开始匹配", true, 10000);
await sleep(2000);
} catch (e) {
log.warn("点击匹配按钮失败,暂时跳过");
}
// 匹配中,准备点击接受按钮
should_retry = false;
while (true) {
let screen = captureGameRegion();
await sleep(800);
// 确保还在匹配状态
let tip = screen.Find(matching_tip);
if (tip.isExist() && tip.text.startsWith("匹配中")) {
} else {
log.warn("匹配状态异常,即将重试");
should_retry = true;
break;
}
let btn = screen.Find(btn_acceptmatch);
if (btn.isExist()) {
log.info("匹配成功,接受");
await sleep(500);
btn.click();
break;
}
await sleep(1000);
}
if (should_retry) {
await sleep(5000);
continue;
}
await sleep(8000);
// 可能进入战斗准备界面,或匹配失败退回
should_retry = false;
log.info("等待进入选择角色界面")
while (true) {
await sleep(1000);
let screen = captureGameRegion();
draw_obj(btn_startmatch, "start");
draw_obj(btn_closetip, "close");
await sleep(800);
if (screen.Find(btn_startmatch).isExist()) {
log.warn("匹配失败,即将重试");
await sleep(3000);
should_retry = true;
break;
}
let close = screen.Find(btn_closetip);
if (close.isExist()) {
close.drawSelf("close_found");
log.info("已经进入选择角色界面");
await sleep(500);
close.click();
return;
}
}
if (should_retry) {
await sleep(5000);
continue;
}
}
throw new Error("Unreachable");
}
function click_char(x, y) {
movetof(0.057 + x * 0.073, 0.169 + y * 0.157);
clickf(0.057 + x * 0.073, 0.169 + y * 0.157);
}
async function play(times) {
for (let ii = 0; ii < times; ii++) {
keyPress("Q");
await sleep(500);
keyPress("E");
await sleep(500);
let act = Math.floor(Math.random() * 8);
let act_key = ACT_KEYS[act % 4];
switch (act) {
case 0: case 1: case 2: case 3:
keyDown("SHIFT");
keyDown(act_key);
await sleep(1000);
keyUp(act_key);
keyUp("SHIFT");
break;
case 4:
// 空格跳跃1秒
keyDown("SPACE");
await sleep(1000);
keyUp("SPACE");
break;
case 5: case 6: case 7:
// 左键连续普攻
for (let i = 0; i < 5; i++) {
leftButtonDown();
await sleep(100);
leftButtonUp();
await sleep(100);
}
middleButtonClick();
break;
default:
break;
}
await sleep(500);
}
}
async function one_shot() {
await sleep(1000);
log.info("任务开始");
await genshin.returnMainUi();
await sleep(1000);
log.info("进入活动界面");
await F5_and_click();
log.info("读取当前分数");
let score_obj = await ocr_click(score, "活动分数", false);
let score_re = score_obj.text.match(/(\d+)\s*\/\s*(\d+)/);
let cur_score = -1, max_score = -1;
if (score_re && score_re.length >= 3) {
cur_score = Number(score_re[1]);
max_score = Number(score_re[2]);
log.info(`当前分数:${cur_score}/${max_score}`);
} else {
throw new Error(`分数解析失败:${score_obj.text}`);
}
if (cur_score >= max_score) {
log.info("活动完成");
return false;
}
log.info("尝试匹配并进入小游戏");
await start_minigame();
await sleep(3000);
log.info("选择角色");
await sleep(500);
click_char(CHAR_X, CHAR_Y);
await sleep(500);
await match_click(btn_confirm, "确认角色选择");
await sleep(500);
log.info("等待buff选择界面");
while (true) {
if (captureGameRegion().Find(buff_icon).isExist()) {
break;
}
await sleep(5000);
}
await sleep(1000);
log.info("选择buff");
clickf(0.25, 0.26);
await sleep(500);
await match_click(btn_confirm, "确认buff选择");
await sleep(500);
log.info("等待游戏开始");
await sleep(5000);
log.info("等待游戏提示出现");
while (true) {
draw_obj(goal_icon);
let result = captureGameRegion().FindMulti(goal_icon);
await sleep(500);
if (result.count != 3) { await sleep(5000); continue; }
await sleep(1000);
break;
}
log.info("随机行动");
while (true) {
await play(15);
let result = captureGameRegion().Find(btn_finish1);
if (result.isExist()) {
log.info("完成点击结算按钮1");
result.click();
break;
}
await sleep(1000);
}
await sleep(1000);
await match_click(btn_finish2, "退出活动");
await sleep(10000);
return true;
}
(async function () {
let count = 0;
while (true) {
count++;
if (!await one_shot()) break;
await genshin.returnMainUi();
await sleep(2000);
await genshin.returnMainUi();
await sleep(2000);
log.info("第${count}次游戏结束,重新开始");
}
log.info("结束运行,可能是分数已满");
return;
})();

View File

@@ -0,0 +1,14 @@
{
"manifest_version": 1,
"name": "PVP活动自动化5.7",
"version": "5.7.0",
"bgi_version": "0.45.0",
"description": "自动完成5.7版本联机PVP活动。可在脚本设置中自行选择上场角色。如果之前没有玩过这个活动第一次运行建议人工监视到进入战斗界面中间弹出的教学界面需要手动关掉否则会执行失败作者为pans82@proton.me",
"authors": [
{
"name": "pans82"
}
],
"settings_ui": "settings.json",
"main": "main.js"
}

View File

@@ -0,0 +1,12 @@
[
{
"name": "char_x",
"type": "input-text",
"label": "角色列号0~3默认0"
},
{
"name": "char_y",
"type": "input-text",
"label": "角色行号0~4默认0"
}
]