Files
云端客 ecc2de529a feat(ActivitySwitchNotice): 添加新活动通知功能 (#2831)
* feat(ActivitySwitchNotice): 添加新活动通知功能

- 新增配置文件路径定义用于存储活动数据
- 在activityMain函数中添加newActivityNotice参数控制新活动通知
- 读取历史活动配置文件并转换为Set进行对比
- 创建activityNameSet记录当前页面活动名称
- 修复OCR键值获取中的参数传递格式问题
- 实现新活动检测逻辑并与历史数据进行比较
- 添加新活动通知发送功能包括UID识别
- 更新版本号从0.0.8到0.1.0并在README中记录变更
- 在设置界面添加新活动通知的启用开关选项

* feat(ActivitySwitchNotice): 更新活动主函数调用以支持新活动通知设置

- 修改 activityMain 函数调用,传入 settings.newActivityNotice 参数
- 实现新活动通知功能的配置支持

* feat(ActivitySwitchNotice): 优化活动通知逻辑并修复数据处理问题

- 在遍历活动列表时同步更新 activityNameSet 集合
- 注释掉冗余的数组合并操作避免重复数据处理
- 重构新增活动检测逻辑提高代码可读性
- 优化通知发送后的配置文件更新时机确保数据一致性
- 改进错误处理机制并添加调试日志
- 修复当无新增活动时不执行通知发送的逻辑分支

* feat(ActivitySwitchNotice): 实现基于UID的个性化活动数据管理

- 添加UID识别功能,通过uidUtil.ocrUID()获取用户唯一标识
- 修改活动数据结构,将全局活动集合改为按UID分类存储
- 实现用户特定活动过滤,只处理当前UID相关的活动数据
- 更新活动配置文件写入逻辑,支持多用户数据分离存储
- 优化新增活动检测机制,基于用户历史活动进行精确匹配
- 重构活动数据序列化处理,确保数据格式兼容性和持久化
2026-02-02 07:27:12 +08:00

174 lines
6.0 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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 = [
"uid",
"ws",
"notice",
"campaignArea",
"activity",
"mapMission",
]
for (let util of utils) {
eval(file.readTextSync(`utils/${util}.js`));
}
// manifest = JSON.parse(file.readTextSync("manifest.json"));
await initSettings();
log.debug("main 初始化完成");
}
// 判断是否在主界面的函数
const isInMainUI = () => {
let captureRegion = captureGameRegion();
let res = captureRegion.Find(RecognitionObject.TemplateMatch(
file.ReadImageMatSync("assets/paimon_menu.png"),
0,
0,
640,
216
));
captureRegion.dispose();
return !res.isEmpty();
};
async function toMainUi() {
let ms = 300
let index = 1
await sleep(ms);
while (!isInMainUI()) {
await sleep(ms);
await genshin.returnMainUi(); // 如果未启用,则返回游戏主界面
await sleep(ms);
if (index > 3) {
throw new Error(`多次尝试返回主界面失败`);
}
index += 1
}
}
(async function () {
await init();
if (settings.toMainUi) {
await toMainUi();
}
await main();
await toMainUi();
})();
/**
* @returns {Promise<void>}
*/
async function main() {
let ms = 600
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(settings.newActivityNotice)
}