mirror of
https://github.com/babalae/bettergi-scripts-list.git
synced 2026-03-16 03:33:25 +08:00
活动期限/周本通知器 0.0.8 (#2763)
* feat(ActivitySwitchNotice): 添加地图任务识别功能 - 新增 mapMission 工具模块用于OCR地图任务识别 - 在初始化工具列表中加入 mapMission 模块 - 修改 main 函数增加异常处理和开关控制逻辑 - 优化代码格式和缩进一致性 - 添加地图任务OCR识别区域配置参数 * feat(ActivitySwitchNotice): 添加地图任务识别功能并优化配置管理 - 实现地图任务识别功能,支持伴月纪闻任务和每日委托奖励识别 - 新增initSettings函数用于统一管理配置文件读取和初始化 - 在settings.json中添加地图任务相关的多选框配置选项 - 更新manifest.json版本至0.0.8并添加最低BGI版本要求 - 重构ocrMapMission函数以支持多任务名称匹配 - 添加openMap和mapMission工具函数用于地图操作和任务识别 - 优化通知系统,移除不必要的参数并完善错误处理 - 调整设置界面布局,添加分隔符提升用户体验 * feat(map): 添加地图任务识别功能 - 实现多复选框配置映射表获取功能 - 添加根据复选框名称获取对应值的方法 - 重构OCR地图任务识别函数,优化参数和错误处理 - 集成UID识别并在通知中显示 - 更新地图任务识别流程和结果显示格式 - 添加地图任务识别数量统计日志 - 在README中更新版本历史记录 * feat(map): 添加地图任务识别功能 - 实现多复选框配置映射表获取功能 - 添加根据复选框名称获取对应值的方法 - 重构OCR地图任务识别函数,优化参数和错误处理 - 集成UID识别并在通知中显示 - 更新地图任务识别流程和结果显示格式 - 添加地图任务识别数量统计日志 - 在README中更新版本历史记录 * feat(ActivitySwitchNotice): 添加新的活动任务选项并设置默认值 - 添加探索派遣奖励选项 - 添加豪斗旅纪奖励选项 - 设置伴月纪闻任务为默认选项之一 - 设置探索派遣奖励为默认选项之一 - 设置每日委托奖励为默认选项之一 - 更新配置结构以支持多选默认值
This commit is contained in:
@@ -511,6 +511,11 @@ ActivitySwitchNotice/
|
||||
|
||||
## 版本历史
|
||||
|
||||
### 0.0.8 (2026-01-22)
|
||||
- 新增 地图识别任务提醒 如:
|
||||
|
||||

|
||||

|
||||
### 0.0.7 (2026-01-19)
|
||||
- 新增每日委托提醒
|
||||
### 0.0.6 (2026-01-06)
|
||||
|
||||
@@ -1,18 +1,108 @@
|
||||
let manifest = {};
|
||||
let manifest_json = "manifest.json";
|
||||
let configSettings = undefined
|
||||
|
||||
/**
|
||||
* 初始化设置函数
|
||||
* 从配置文件中读取设置信息并返回
|
||||
* @returns {Object} 返回解析后的JSON设置对象
|
||||
*/
|
||||
async function initSettings() {
|
||||
// 默认设置文件路径
|
||||
let settings_ui = "settings.json";
|
||||
try {
|
||||
// 读取并解析manifest.json文件
|
||||
manifest = JSON.parse(file.readTextSync(manifest_json));
|
||||
// 调试日志:输出manifest内容
|
||||
log.debug("manifest={key}", manifest);
|
||||
// 调试日志:输出manifest中的settings_ui配置
|
||||
log.debug("settings_ui={key}", manifest.settings_ui);
|
||||
log.info(`|脚本名称:{name},版本:{version}`, manifest.name, manifest.version);
|
||||
if (manifest.bgi_version) {
|
||||
log.info(`|最小可执行BGI版本:{bgi_version}`, manifest.bgi_version);
|
||||
}
|
||||
log.info(`|脚本作者:{authors}\n`, manifest.authors.map(a => a.name).join(","));
|
||||
// 更新settings_ui变量为manifest中指定的路径
|
||||
settings_ui = manifest.settings_ui
|
||||
} catch (error) {
|
||||
// 捕获并记录可能的错误
|
||||
log.warn("{error}", error.message);
|
||||
}
|
||||
// 读取并解析设置文件
|
||||
const settingsJson = JSON.parse(file.readTextSync(settings_ui));
|
||||
// 如果configSettings未定义,则将其设置为解析后的设置对象
|
||||
if (!configSettings) {
|
||||
configSettings = settingsJson
|
||||
}
|
||||
// 调试日志:输出最终解析的设置对象
|
||||
log.debug("settingsJson={key}", settingsJson);
|
||||
// 返回设置对象
|
||||
return settingsJson
|
||||
}
|
||||
/**
|
||||
* 获取多复选框的映射表
|
||||
* 该函数会从初始化的设置中提取所有类型为"multi-checkbox"的条目,
|
||||
* 并将这些条目的名称和对应的选项值存储在一个Map对象中返回
|
||||
* @returns {Promise<Map>} 返回一个Promise对象,解析为包含多复选框配置的Map
|
||||
*/
|
||||
async function getMultiCheckboxMap() {
|
||||
// 如果configSettings存在则使用它,否则调用initSettings()函数获取
|
||||
const settingsJson = configSettings ? configSettings : await initSettings();
|
||||
// 创建一个新的Map对象用于存储多复选框的配置
|
||||
// Map结构为: {名称: 选项数组}
|
||||
let multiCheckboxMap = new Map();
|
||||
// 遍历设置JSON中的每个条目
|
||||
settingsJson.forEach((entry) => {
|
||||
// 如果条目没有name属性或者类型不是"multi-checkbox",则跳过该条目
|
||||
if (!entry.name || entry.type !== "multi-checkbox") return;
|
||||
// 解构条目中的name和label属性,便于后续使用
|
||||
const {name, label} = entry;
|
||||
// 获取当前name对应的设置值,如果存在则转换为数组,否则使用空数组
|
||||
const options = settings[name] ? Array.from(settings[name]) : [];
|
||||
// 记录调试信息,包含名称、标签、选项和选项数量
|
||||
log.debug("name={key1},label={key2},options={key3},length={key4}", name, label, JSON.stringify(options), options.length);
|
||||
// 将名称和对应的选项数组存入Map
|
||||
multiCheckboxMap.set(name, options);
|
||||
})
|
||||
// 返回包含多复选框配置的Map
|
||||
return multiCheckboxMap
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据复选框组名称获取对应的值
|
||||
* 这是一个异步函数,用于从复选框映射中获取指定名称的值
|
||||
* @param {string} name - 复选框组的名称
|
||||
* @returns {Promise<any>} 返回一个Promise,解析为复选框组对应的值
|
||||
*/
|
||||
async function getValueByMultiCheckboxName(name) {
|
||||
// 获取复选框映射表,这是一个异步操作
|
||||
let multiCheckboxMap = await getMultiCheckboxMap()
|
||||
// log.debug("multiCheckboxMap={key}", JSON.stringify(multiCheckboxMap))
|
||||
// multiCheckboxMap.entries().forEach(([name, options]) => {
|
||||
// log.debug("name={key1},options={key2}", name, JSON.stringify(options))
|
||||
// })
|
||||
// 从映射表中获取并返回指定名称对应的值
|
||||
let values = multiCheckboxMap.get(name);
|
||||
log.debug("values={key}", JSON.stringify(values))
|
||||
return values
|
||||
}
|
||||
async function init() {
|
||||
let utils=[
|
||||
let utils = [
|
||||
"uid",
|
||||
"ws",
|
||||
"notice",
|
||||
"campaignArea",
|
||||
"activity",
|
||||
"mapMission",
|
||||
]
|
||||
for (let util of utils) {
|
||||
eval(file.readTextSync(`utils/${util}.js`));
|
||||
}
|
||||
manifest = JSON.parse(file.readTextSync("manifest.json"));
|
||||
// manifest = JSON.parse(file.readTextSync("manifest.json"));
|
||||
await initSettings();
|
||||
log.debug("main 初始化完成");
|
||||
}
|
||||
|
||||
// 判断是否在主界面的函数
|
||||
const isInMainUI = () => {
|
||||
let captureRegion = captureGameRegion();
|
||||
@@ -44,8 +134,7 @@ async function toMainUi() {
|
||||
|
||||
(async function () {
|
||||
await init();
|
||||
log.info(`版本:{version}`,manifest.version)
|
||||
if (settings.toMainUi){
|
||||
if (settings.toMainUi) {
|
||||
await toMainUi();
|
||||
}
|
||||
await main();
|
||||
@@ -57,10 +146,29 @@ async function toMainUi() {
|
||||
*/
|
||||
async function main() {
|
||||
let ms = 600
|
||||
await campaignAreaUtil.dailyCommissionMain()
|
||||
await sleep(ms*2);
|
||||
await campaignAreaUtil.campaignAreaMain(false)
|
||||
await sleep(ms*2);
|
||||
const mapList = await getValueByMultiCheckboxName('mapMissionKeys')|| []
|
||||
// log.info(`mapList=>{0}`,JSON.stringify(mapList))
|
||||
if (mapList.length > 0) {
|
||||
try {
|
||||
log.info(`开始识别地图任务`)
|
||||
await mapUtil.mapMission(mapList)
|
||||
} finally {
|
||||
await toMainUi()
|
||||
}
|
||||
}
|
||||
|
||||
let openKey = true
|
||||
|
||||
try {
|
||||
await campaignAreaUtil.dailyCommissionMain(openKey)
|
||||
await sleep(ms * 2);
|
||||
openKey = false
|
||||
} catch (e) {
|
||||
await toMainUi()
|
||||
throw e
|
||||
}
|
||||
await campaignAreaUtil.campaignAreaMain(openKey)
|
||||
await sleep(ms * 2);
|
||||
await toMainUi()
|
||||
await activityUtil.activityMain()
|
||||
}
|
||||
@@ -1,9 +1,10 @@
|
||||
{
|
||||
"name": "活动期限/周本通知器",
|
||||
"version": "0.0.7",
|
||||
"version": "0.0.8",
|
||||
"description": "",
|
||||
"settings_ui": "settings.json",
|
||||
"main": "main.js",
|
||||
"bgi_version": "0.55.0",
|
||||
"authors": [
|
||||
{
|
||||
"name": "云端客",
|
||||
|
||||
BIN
repo/js/ActivitySwitchNotice/md/0.0.8-map-00.jpg
Normal file
BIN
repo/js/ActivitySwitchNotice/md/0.0.8-map-00.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 119 KiB |
BIN
repo/js/ActivitySwitchNotice/md/0.0.8-map.jpg
Normal file
BIN
repo/js/ActivitySwitchNotice/md/0.0.8-map.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 6.0 KiB |
@@ -1,102 +1,135 @@
|
||||
[
|
||||
{
|
||||
"name": "toMainUi",
|
||||
"type": "checkbox",
|
||||
"label": "启用先返回主界面后执行切换",
|
||||
"default": true
|
||||
},
|
||||
{
|
||||
"name": "noticeType",
|
||||
"type": "select",
|
||||
"label": "通知模式(默认BGI通知-使用独立通知需要开启JS HTTP权限)",
|
||||
"options": [
|
||||
"BGI通知",
|
||||
"独立通知",
|
||||
"独立通知和BGI通知",
|
||||
],
|
||||
"default": "BGI通知"
|
||||
},
|
||||
{
|
||||
"name": "relationship",
|
||||
"type": "checkbox",
|
||||
"label": "剩余时间,白名单 启用`和`关系(默认`或`关系)",
|
||||
"default": false
|
||||
},
|
||||
{
|
||||
"name": "whiteActivityNameList",
|
||||
"type": "input-text",
|
||||
"label": "白名单活动名称(使用|分割)<可不填 默认推送所有有剩余时间的活动>"
|
||||
},
|
||||
{
|
||||
"name": "blackActivity",
|
||||
"type": "input-text",
|
||||
"label": "黑名单活动名称(使用|分割)<可不填,默认没有不推送的活动>(新增语法指定条件的黑名单:活动1-条件1,条件2|活动2-条件1)"
|
||||
},
|
||||
{
|
||||
"name": "notifyHoursThreshold",
|
||||
"type": "input-text",
|
||||
"label": "通知剩余时间阈值<单位:小时>(默认 8760小时=365天)",
|
||||
"default": "8760"
|
||||
},
|
||||
{
|
||||
"name": "activityKey",
|
||||
"type": "input-text",
|
||||
"label": "打开活动页面按键(不填,默认:F5)",
|
||||
"default": "F5"
|
||||
},
|
||||
{
|
||||
"name": "campaignAreaReminderDay",
|
||||
"type": "select",
|
||||
"label": "周本提醒日(0-6,0=周日,1=周一,2=周二,3=周三,4=周四,5=周五,6=周六)",
|
||||
"options": [
|
||||
"0","1","2","3","4","5","6"
|
||||
],
|
||||
"default": "0"
|
||||
},
|
||||
{
|
||||
"name": "campaignAreaKey",
|
||||
"type": "input-text",
|
||||
"label": "打开冒险之证按键(不填,默认:F1)",
|
||||
"default": "F1"
|
||||
},
|
||||
{
|
||||
"name": "ws_proxy_url",
|
||||
"type": "input-text",
|
||||
"label": "独立通知配置:\n==============================\nWebSocketProxyUrl(列:http://127.0.0.1:8081/ws-proxy/message/send)",
|
||||
"default": "http://127.0.0.1:8081/ws-proxy/message/send"
|
||||
},
|
||||
{
|
||||
"name": "ws_url",
|
||||
"type": "input-text",
|
||||
"label": "WebSocket客户端 Url(列:ws://127.0.0.1:8080)",
|
||||
"default": "ws://127.0.0.1:8080/"
|
||||
},
|
||||
{
|
||||
"name": "ws_token",
|
||||
"type": "input-text",
|
||||
"label": "WebSocket客户端 token(没有可不填)",
|
||||
"default": ""
|
||||
},
|
||||
{
|
||||
"name": "action",
|
||||
"type": "select",
|
||||
"label": "发送类型",
|
||||
"options": [
|
||||
"私聊",
|
||||
"群聊"
|
||||
],
|
||||
"default": "私聊",
|
||||
},
|
||||
{
|
||||
"name": "send_id",
|
||||
"type": "input-text",
|
||||
"label": "(发送id 群号|QQ号 对应发送类型)",
|
||||
"default": ""
|
||||
},
|
||||
{
|
||||
"name": "at_list",
|
||||
"type": "input-text",
|
||||
"label": "@某人列表使用,隔开(QQ号)",
|
||||
"default": ""
|
||||
},
|
||||
]
|
||||
{
|
||||
"name": "toMainUi",
|
||||
"type": "checkbox",
|
||||
"label": "启用先返回主界面后执行切换",
|
||||
"default": true
|
||||
},
|
||||
{
|
||||
"name": "noticeType",
|
||||
"type": "select",
|
||||
"label": "通知模式(默认BGI通知-使用独立通知需要开启JS HTTP权限)",
|
||||
"options": [
|
||||
"BGI通知",
|
||||
"独立通知",
|
||||
"独立通知和BGI通知"
|
||||
],
|
||||
"default": "BGI通知"
|
||||
},
|
||||
{
|
||||
"type": "separator"
|
||||
},
|
||||
{
|
||||
"label": "地图识别任务提醒",
|
||||
"type": "multi-checkbox",
|
||||
"name": "mapMissionKeys",
|
||||
"options": [
|
||||
"伴月纪闻任务",
|
||||
"探索派遣奖励",
|
||||
"豪斗旅纪奖励",
|
||||
"每日委托奖励"
|
||||
],
|
||||
"default": [
|
||||
"伴月纪闻任务",
|
||||
"探索派遣奖励",
|
||||
"每日委托奖励"]
|
||||
},
|
||||
{
|
||||
"type": "separator"
|
||||
},
|
||||
{
|
||||
"name": "relationship",
|
||||
"type": "checkbox",
|
||||
"label": "剩余时间,白名单 启用`和`关系(默认`或`关系)",
|
||||
"default": false
|
||||
},
|
||||
{
|
||||
"name": "whiteActivityNameList",
|
||||
"type": "input-text",
|
||||
"label": "白名单活动名称(使用|分割)<可不填 默认推送所有有剩余时间的活动>"
|
||||
},
|
||||
{
|
||||
"name": "blackActivity",
|
||||
"type": "input-text",
|
||||
"label": "黑名单活动名称(使用|分割)<可不填,默认没有不推送的活动>(新增语法指定条件的黑名单:活动1-条件1,条件2|活动2-条件1)"
|
||||
},
|
||||
{
|
||||
"name": "notifyHoursThreshold",
|
||||
"type": "input-text",
|
||||
"label": "通知剩余时间阈值<单位:小时>(默认 8760小时=365天)",
|
||||
"default": "8760"
|
||||
},
|
||||
{
|
||||
"name": "activityKey",
|
||||
"type": "input-text",
|
||||
"label": "打开活动页面按键(不填,默认:F5)",
|
||||
"default": "F5"
|
||||
},
|
||||
{
|
||||
"type": "separator"
|
||||
},
|
||||
{
|
||||
"name": "campaignAreaReminderDay",
|
||||
"type": "select",
|
||||
"label": "周本提醒日(0-6,0=周日,1=周一,2=周二,3=周三,4=周四,5=周五,6=周六)",
|
||||
"options": [
|
||||
"0",
|
||||
"1",
|
||||
"2",
|
||||
"3",
|
||||
"4",
|
||||
"5",
|
||||
"6"
|
||||
],
|
||||
"default": "0"
|
||||
},
|
||||
{
|
||||
"name": "campaignAreaKey",
|
||||
"type": "input-text",
|
||||
"label": "打开冒险之证按键(不填,默认:F1)",
|
||||
"default": "F1"
|
||||
},
|
||||
{
|
||||
"type": "separator"
|
||||
},
|
||||
{
|
||||
"name": "ws_proxy_url",
|
||||
"type": "input-text",
|
||||
"label": "独立通知配置:\n==============================\nWebSocketProxyUrl(列:http://127.0.0.1:8081/ws-proxy/message/send)",
|
||||
"default": "http://127.0.0.1:8081/ws-proxy/message/send"
|
||||
},
|
||||
{
|
||||
"name": "ws_url",
|
||||
"type": "input-text",
|
||||
"label": "WebSocket客户端 Url(列:ws://127.0.0.1:8080)",
|
||||
"default": "ws://127.0.0.1:8080/"
|
||||
},
|
||||
{
|
||||
"name": "ws_token",
|
||||
"type": "input-text",
|
||||
"label": "WebSocket客户端 token(没有可不填)",
|
||||
"default": ""
|
||||
},
|
||||
{
|
||||
"name": "action",
|
||||
"type": "select",
|
||||
"label": "发送类型",
|
||||
"options": [
|
||||
"私聊",
|
||||
"群聊"
|
||||
],
|
||||
"default": "私聊"
|
||||
},
|
||||
{
|
||||
"name": "send_id",
|
||||
"type": "input-text",
|
||||
"label": "(发送id 群号|QQ号 对应发送类型)",
|
||||
"default": ""
|
||||
},
|
||||
{
|
||||
"name": "at_list",
|
||||
"type": "input-text",
|
||||
"label": "@某人列表使用,隔开(QQ号)",
|
||||
"default": ""
|
||||
}
|
||||
]
|
||||
100
repo/js/ActivitySwitchNotice/utils/mapMission.js
Normal file
100
repo/js/ActivitySwitchNotice/utils/mapMission.js
Normal file
@@ -0,0 +1,100 @@
|
||||
const ocrRegionConfig = {
|
||||
mapMission: {x: 6, y: 8, width: 395, height: 977},//地图任务识别区域坐标和尺寸
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* OCR地图任务识别函数
|
||||
* 通过OCR技术识别游戏界面中的任务名称,并与预设的任务名称列表进行匹配
|
||||
* @param {Array<string>} [missionNameList=[]] - 需要识别的任务名称列表
|
||||
* @param {Object} [regionConfig=ocrRegionConfig.mapMission] - OCR识别区域配置对象,包含x、y、width、height属性
|
||||
* @returns {Promise<Array<Object>>} 返回识别结果数组,每个元素包含ok(boolean)和text(string)属性
|
||||
*/
|
||||
async function ocrMapMission(missionNameList = [], regionConfig = ocrRegionConfig.mapMission) {
|
||||
let jsonList = [];
|
||||
let region = null;
|
||||
|
||||
try {
|
||||
// 捕获游戏区域并创建OCR识别对象
|
||||
region = captureGameRegion();
|
||||
let recognitionObject = RecognitionObject.Ocr(regionConfig.x, regionConfig.y, regionConfig.width, regionConfig.height);
|
||||
// 执行多目标OCR识别
|
||||
let resList = region.findMulti(recognitionObject);
|
||||
// if (!resList || !resList.length) {
|
||||
// return jsonList;
|
||||
// }
|
||||
|
||||
// 遍历识别结果并匹配任务名称
|
||||
for (let i = 0; i < resList.count; i++) {
|
||||
let res = resList[i];
|
||||
log.debug(`[-]识别结果: ${res.text}, 原始坐标: x=${res.x}, y=${res.y},width:${res.width},height:${res.height}`);
|
||||
|
||||
let json = {
|
||||
ok: false,
|
||||
text: undefined
|
||||
};
|
||||
|
||||
// 检查当前识别文本是否包含任一任务名称
|
||||
let matchedMission = null;
|
||||
for (const missionName of missionNameList) {
|
||||
if (res.text.trim().includes(missionName)) {
|
||||
matchedMission = missionName;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (matchedMission) {
|
||||
log.debug(`识别成功=>${matchedMission}->${res.text}`);
|
||||
json.ok = true;
|
||||
json.text = res.text.trim();
|
||||
}
|
||||
|
||||
jsonList.push(json);
|
||||
}
|
||||
} catch (e) {
|
||||
log.error('OCR识别过程出错:', e.message);
|
||||
throw e;
|
||||
} finally {
|
||||
// 确保资源始终被释放
|
||||
if (region) {
|
||||
region.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
return jsonList;
|
||||
}
|
||||
|
||||
|
||||
//伴月纪闻任务待完成
|
||||
// 通过地图识别任务
|
||||
async function openMap() {
|
||||
const key = settings.mapKey || 'M'
|
||||
await sleep(200)
|
||||
await keyPress(key)
|
||||
}
|
||||
|
||||
async function mapMission(list = [], toOpenMap = true) {
|
||||
let ms = 600
|
||||
if (toOpenMap) {
|
||||
await openMap();
|
||||
await sleep(ms);
|
||||
}
|
||||
await sleep(ms * 2);
|
||||
let keyJsonList = await ocrMapMission(list);
|
||||
keyJsonList = keyJsonList.filter(item => item.ok)
|
||||
log.info(`识别到地图任务数量:${keyJsonList.length}`)
|
||||
if (keyJsonList.length <= 0) {
|
||||
log.warn(`未识别到地图任务`)
|
||||
return
|
||||
}
|
||||
const uid = await uidUtil.ocrUID()
|
||||
let text = ""
|
||||
keyJsonList.forEach(item => text += "|< " + item.text + " >\n")
|
||||
await noticeUtil.sendText(text, `UID:${uid}\n地图任务`)
|
||||
}
|
||||
|
||||
this.mapUtil = {
|
||||
mapMission,
|
||||
ocrMapMission,
|
||||
openMap,
|
||||
}
|
||||
@@ -59,9 +59,8 @@ async function sendNotice(map = new Map(), title, noNotice = false) {
|
||||
* 异步发送通知的函数
|
||||
* @param {string} noticeText - 通知内容文本
|
||||
* @param {string} title - 通知标题
|
||||
* @param {boolean} noNotice - 是否不发送通知的标志
|
||||
*/
|
||||
async function sendText(noticeText, title, noNotice) {
|
||||
async function sendText(noticeText, title, noNotice = false) {
|
||||
// 检查是否有通知内容且设置了不发送通知的标志
|
||||
if ((!noticeText) || noNotice) {
|
||||
log.info(`sendText 无通知内容`) // 记录日志信息
|
||||
|
||||
Reference in New Issue
Block a user