mirror of
https://github.com/ZZZure/ZZZ-Plugin.git
synced 2025-12-17 13:47:44 +00:00
部分enka面板更新能力
This commit is contained in:
parent
d6a299c275
commit
28432cd0a5
6 changed files with 1359 additions and 46 deletions
343
apps/panel.js
343
apps/panel.js
|
|
@ -10,6 +10,8 @@ import {
|
|||
import settings from '../lib/settings.js';
|
||||
import _ from 'lodash';
|
||||
import { rulePrefix } from '../lib/common.js';
|
||||
import { getZzzEnkaData } from '../lib/ekapi/query.js'
|
||||
import { _enka_data_to_mys_data } from '../lib/ekapi/enka_to_mys.js'
|
||||
|
||||
export class Panel extends ZZZPlugin {
|
||||
constructor() {
|
||||
|
|
@ -50,9 +52,251 @@ export class Panel extends ZZZPlugin {
|
|||
if (queryPanelReg.test(this.e.msg)) return await this.getCharPanel();
|
||||
return false;
|
||||
}
|
||||
// async refreshPanel() {
|
||||
// const uid = await this.getUID();
|
||||
// // ... 省略获取 lastQueryTime 和冷卻时间判断的代码 ...
|
||||
// this.result = null; // 先清空结果
|
||||
//
|
||||
// const useEnka = _.get(settings.getConfig('config'), 'useEnka', false);
|
||||
// logger.mark(`[panel.js] useEnka 设置值: ${useEnka}`); // 1. 确认是否启用 Enka 逻辑
|
||||
//
|
||||
// if (useEnka) { // 检查这个 if 是否进入
|
||||
// logger.mark('[panel.js] 进入 useEnka 逻辑块');
|
||||
// let enkaData = null; // 初始化 enkaData
|
||||
// try {
|
||||
// logger.mark(`[panel.js] 准备调用 getZzzEnkaData for UID: ${uid}`);
|
||||
// enkaData = await getZzzEnkaData(uid);
|
||||
// logger.mark('[panel.js] getZzzEnkaData 调用完成');
|
||||
//
|
||||
// // 2. 详细检查 enkaData 的状态
|
||||
// if (enkaData === null || enkaData === undefined) {
|
||||
// logger.error('[panel.js] getZzzEnkaData 返回了 null 或 undefined');
|
||||
// await this.reply('获取Enka数据失败 (返回null/undefined),请稍后再试');
|
||||
// return false;
|
||||
// } else if (enkaData === -1) {
|
||||
// logger.warn('[panel.js] getZzzEnkaData 返回了 -1 (表示获取失败)');
|
||||
// await this.reply('获取Enka数据失败 (返回-1),请稍后再试');
|
||||
// return false;
|
||||
// } else if (!enkaData.PlayerInfo || !enkaData.PlayerInfo.ShowcaseDetail || !enkaData.PlayerInfo.ShowcaseDetail.AvatarList) {
|
||||
// logger.error('[panel.js] 获取到的 enkaData 结构不完整:', enkaData);
|
||||
// await this.reply('获取到的Enka数据结构不完整,无法处理');
|
||||
// return false;
|
||||
// } else {
|
||||
// logger.mark('[panel.js] 成功获取到有效的 enkaData 结构');
|
||||
// console.log('[panel.js] enkaData.PlayerInfo.ShowcaseDetail.AvatarList:', enkaData.PlayerInfo.ShowcaseDetail.AvatarList); // 打印角色列表确认
|
||||
// }
|
||||
//
|
||||
// // 3. 检查 _enka_data_to_mys_data 函数是否已正确导入
|
||||
// if (typeof _enka_data_to_mys_data !== 'function') {
|
||||
// logger.error('[panel.js] _enka_data_to_mys_data 不是一个函数! 请检查导入语句和文件是否存在。');
|
||||
// await this.reply('内部错误:数据转换函数加载失败');
|
||||
// return false;
|
||||
// }
|
||||
//
|
||||
// logger.mark('[panel.js] _enka_data_to_mys_data 函数已找到,类型:', typeof _enka_data_to_mys_data);
|
||||
// logger.mark('[panel.js] 即将调用 _enka_data_to_mys_data...');
|
||||
//
|
||||
// // 4. 使用 try...catch 包裹调用,捕获可能的内部错误
|
||||
// try {
|
||||
// this.result = await _enka_data_to_mys_data(enkaData);
|
||||
// logger.mark('[panel.js] _enka_data_to_mys_data 调用完成。');
|
||||
// // 在这里可以检查 this.result 是否是你期望的格式
|
||||
// console.log('[panel.js] 转换后的 result (部分示例):', this.result ? JSON.stringify(this.result[0], null, 2).substring(0, 500) + '...' : 'null or empty');
|
||||
// } catch (conversionError) {
|
||||
// logger.error('[panel.js] 调用 _enka_data_to_mys_data 时发生严重错误:', conversionError);
|
||||
// // 打印详细错误堆栈
|
||||
// console.error(conversionError);
|
||||
// await this.reply(`处理Enka数据时出错: ${conversionError.message}`);
|
||||
// return false; // 出错则不再继续
|
||||
// }
|
||||
//
|
||||
// } catch (fetchError) {
|
||||
// // 这个 catch 捕获 getZzzEnkaData 自身的 await 可能抛出的错误
|
||||
// logger.error('[panel.js] 调用 getZzzEnkaData 时发生错误:', fetchError);
|
||||
// console.error(fetchError); // 打印错误堆栈
|
||||
// await this.reply(`获取Enka数据时发生网络或API错误: ${fetchError.message}`);
|
||||
// return false;
|
||||
// }
|
||||
//
|
||||
// } else { // 如果 useEnka 是 false
|
||||
// logger.mark('[panel.js] 未启用 useEnka,跳过 Enka 面板逻辑');
|
||||
// // 这里可以继续执行原有的 mysapi 逻辑(如果需要的话)
|
||||
// // logger.mark('mysapi执行');
|
||||
// // ... (原有的 mysapi 刷新逻辑) ...
|
||||
// // 注意:如果 useEnka 为 false,this.result 可能需要从 mysapi 获取
|
||||
// }
|
||||
//
|
||||
// // ----- 后续处理 this.result 的代码 -----
|
||||
// // (确保无论走 Enka 逻辑还是 mysapi 逻辑,this.result 都有合适的值)
|
||||
//
|
||||
// // 例如,原有的 newChar 计算和渲染逻辑:
|
||||
// if (this.result && Array.isArray(this.result)) { // 检查 this.result 是否有效
|
||||
// const newChar = this.result.filter(item => item.isNew); // 假设 MYS 数据结构中有 isNew
|
||||
// const finalData = {
|
||||
// newChar: newChar.length,
|
||||
// list: this.result, // 使用转换后的或 mysapi 的结果
|
||||
// };
|
||||
// await this.render('panel/refresh.html', finalData);
|
||||
// } else if (!useEnka) {
|
||||
// // 如果没用 Enka 且没有执行 mysapi 逻辑(或 mysapi 逻辑没产生 result),可能需要提示
|
||||
// logger.warn('[panel.js] 没有可用的面板数据用于渲染 (useEnka=false, result无效)');
|
||||
// // 可能需要添加回复告诉用户没有数据?
|
||||
// } else if (useEnka && (!this.result || this.result.length === 0)) {
|
||||
// logger.warn('[panel.js] Enka 数据转换后结果为空或无效');
|
||||
// // 根据需要决定是否回复用户
|
||||
// }
|
||||
//
|
||||
// }
|
||||
|
||||
// async refreshPanel() {
|
||||
// const uid = await this.getUID();
|
||||
// const lastQueryTime = await redis.get(`ZZZ:PANEL:${uid}:LASTTIME`);
|
||||
// const panelSettings = settings.getConfig('panel');
|
||||
// const coldTime = _.get(panelSettings, 'interval', 300);
|
||||
// this.result = null; // Initialize instance result
|
||||
//
|
||||
// // --- Enka Path ---
|
||||
// if(_.get(settings.getConfig('config'), 'useEnka', false)){ // Default is false if setting missing
|
||||
// logger.mark('enka面板执行')
|
||||
// const enkaData = await getZzzEnkaData(uid); // Fetch Enka data
|
||||
//
|
||||
// // --- Issue 1: Check for failure *before* processing ---
|
||||
// if (enkaData === -1) { // Check for specific failure code
|
||||
// await this.reply('获取enka数据失败,请稍后再试');
|
||||
// return false; // Exit early
|
||||
// }
|
||||
// // Add more checks for null/undefined/incomplete data if needed here
|
||||
//
|
||||
// console.log('[panel.js] 获取到 enkaData,准备转换...');
|
||||
// console.log('Enka AvatarList:', enkaData?.PlayerInfo?.ShowcaseDetail?.AvatarList);
|
||||
// console.log('[panel.js] 即将调用 _enka_data_to_mys_data...');
|
||||
//
|
||||
// // --- This is where previous errors occurred due to name_convert.js load failure ---
|
||||
// // Assuming name_convert.js path fix is applied, this should now work
|
||||
// this.result = await _enka_data_to_mys_data(enkaData); // Assign to instance variable
|
||||
// logger.mark('[panel.js] _enka_data_to_mys_data 调用完成.'); // Added log for confirmation
|
||||
//
|
||||
// // --- MYS API Path ---
|
||||
// } else {
|
||||
// logger.mark('mysapi执行')
|
||||
// if (lastQueryTime && Date.now() - lastQueryTime < 1000 * coldTime) {
|
||||
// await this.reply(`${coldTime}秒内只能刷新一次,请稍后再试`);
|
||||
// return false;
|
||||
// }
|
||||
// const { api } = await this.getAPI();
|
||||
// await redis.set(`ZZZ:PANEL:${uid}:LASTTIME`, Date.now());
|
||||
// await this.reply('正在刷新面板列表,请稍候...');
|
||||
// await this.getPlayerInfo(); // Assumed necessary for MYS panel
|
||||
//
|
||||
// // --- Issue 2: Assign result correctly ---
|
||||
// let mysResult = null; // Use a temporary variable for MYS result
|
||||
// try {
|
||||
// mysResult = await refreshPanelFunction(api); // Call the imported MYS refresh
|
||||
// console.dir('MYS API res:', mysResult); // Log MYS result
|
||||
// if (!mysResult) {
|
||||
// await this.reply('面板列表刷新失败 (MYS API),请稍后再试');
|
||||
// return false;
|
||||
// }
|
||||
// // Assign the successful MYS result to the instance variable
|
||||
// this.result = mysResult; // <<<< IMPORTANT ASSIGNMENT
|
||||
// } catch (e) {
|
||||
// this.reply(e.message);
|
||||
// // Consider logging the full error for debugging
|
||||
// logger.error("MYS API refresh failed:", e);
|
||||
// // Depending on desired behavior, you might return false or re-throw
|
||||
// return false; // Exit on MYS API error
|
||||
// }
|
||||
// } // End if/else
|
||||
//
|
||||
// // --- Post-processing: Use this.result consistently ---
|
||||
// // Ensure this.result is an array before proceeding
|
||||
// if (!this.result || !Array.isArray(this.result)) {
|
||||
// logger.error('[panel.js] 最终结果无效或不是数组:', this.result);
|
||||
// // Maybe reply to the user that no data could be processed
|
||||
// await this.reply('未能获取或处理有效的面板数据。');
|
||||
// return false;
|
||||
// }
|
||||
//
|
||||
// // --- Issue 3: Use this.result for calculations ---
|
||||
// // Filter based on the unified this.result
|
||||
// const newChar = this.result.filter(item => item && item.isNew); // Added check for item existence
|
||||
//
|
||||
// // Prepare final data using the unified this.result
|
||||
// const finalData = {
|
||||
// newChar: newChar.length,
|
||||
// list: this.result, // Use the instance variable
|
||||
// };
|
||||
//
|
||||
// // Render the result
|
||||
// await this.render('panel/refresh.html', finalData);
|
||||
// }
|
||||
async refreshPanel() {
|
||||
const uid = await this.getUID();
|
||||
// --- 获取玩家信息 (带容错处理) ---
|
||||
// ... (这部分代码保持不变,使用带有占位符逻辑的版本) ...
|
||||
logger.mark('[panel.js] 准备调用 getPlayerInfo...');
|
||||
let playerInfo = null;
|
||||
try {
|
||||
playerInfo = await this.getPlayerInfo();
|
||||
if (!playerInfo) playerInfo = this.e.player;
|
||||
if (!playerInfo) {
|
||||
logger.warn(`[panel.js] getPlayerInfo 未返回有效信息,使用默认占位。UID: ${uid}`);
|
||||
playerInfo = { uid: uid, nickname: `用户${uid}`, level: '??', region_name: '未知服务器' };
|
||||
}
|
||||
logger.mark('[panel.js] getPlayerInfo 尝试完成.');
|
||||
} catch (playerInfoError) {
|
||||
logger.error('[panel.js] 调用 getPlayerInfo 时出错 (使用占位):', playerInfoError.message);
|
||||
playerInfo = { uid: uid, nickname: `用户${uid}`, level: '??', region_name: '错误', error: playerInfoError.message };
|
||||
}
|
||||
// --- End 获取玩家信息 ---
|
||||
|
||||
this.result = null; // 初始化结果
|
||||
|
||||
// ----- 选择 Enka 或 MYS API -----
|
||||
const useEnka = _.get(settings.getConfig('config'), 'useEnka', true); // 读取配置,Enka 优先
|
||||
logger.mark(`[panel.js] useEnka 设置值: ${useEnka}`);
|
||||
// ----- End -----
|
||||
|
||||
// --- 数据获取和处理逻辑 ---
|
||||
if (useEnka) {
|
||||
logger.mark('[panel.js] 进入 Enka 逻辑块');
|
||||
try {
|
||||
const enkaData = await getZzzEnkaData(uid);
|
||||
|
||||
logger.mark('[panel.js] getZzzEnkaData 调用完成.'); // <-- 日志:调用后
|
||||
|
||||
// ----- !!! 在这里添加打印原始 Enka 数据的日志 !!! -----
|
||||
console.log('===== ZZZ Enka Raw Data Start =====');
|
||||
// 使用 JSON.stringify 完整打印,null, 2 用于格式化输出
|
||||
console.log(JSON.stringify(enkaData, null, 2));
|
||||
console.log('===== ZZZ Enka Raw Data End =====');
|
||||
// ----- !!! 日志添加结束 !!! -----
|
||||
|
||||
if (!enkaData || enkaData === -1 || !enkaData.PlayerInfo) { throw new Error('获取或验证 Enka 数据失败'); }
|
||||
logger.mark('[panel.js] 即将调用 _enka_data_to_mys_data...');
|
||||
this.result = await _enka_data_to_mys_data(enkaData); // <<< Enka 结果赋给 this.result
|
||||
logger.mark('[panel.js] _enka_data_to_mys_data 调用完成.');
|
||||
|
||||
// ----- !!! 在这里添加打印转换后数据的日志 !!! -----
|
||||
console.log('===== Enka Converted Data (First Avatar) Start =====');
|
||||
if (this.result && Array.isArray(this.result) && this.result.length > 0) {
|
||||
console.log(JSON.stringify(this.result[0], null, 2)); // 打印第一个转换后的角色
|
||||
} else {
|
||||
console.log('Converted result is empty or invalid.');
|
||||
}
|
||||
console.log('===== Enka Converted Data (First Avatar) End =====');
|
||||
// ----- !!! 日志添加结束 !!! -----
|
||||
logger.mark('[panel.js] _enka_data_to_mys_data 调用完成.');
|
||||
} catch (enkaError) {
|
||||
logger.error('[panel.js] 处理 Enka 逻辑时出错:', enkaError);
|
||||
await this.reply(`处理Enka数据时出错: ${enkaError.message}`);
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
logger.mark('[panel.js] 进入 mysapi 逻辑块');
|
||||
try {
|
||||
const { api } = await this.getAPI(); // MYS 需要 api 对象
|
||||
// MYS 逻辑需要冷却判断
|
||||
const lastQueryTime = await redis.get(`ZZZ:PANEL:${uid}:LASTTIME`);
|
||||
const panelSettings = settings.getConfig('panel');
|
||||
const coldTime = _.get(panelSettings, 'interval', 300);
|
||||
|
|
@ -60,47 +304,78 @@ export class Panel extends ZZZPlugin {
|
|||
await this.reply(`${coldTime}秒内只能刷新一次,请稍后再试`);
|
||||
return false;
|
||||
}
|
||||
const { api } = await this.getAPI();
|
||||
await redis.set(`ZZZ:PANEL:${uid}:LASTTIME`, Date.now());
|
||||
await this.reply('正在刷新面板列表,请稍候...');
|
||||
await this.getPlayerInfo();
|
||||
const result = await refreshPanelFunction(api).catch(e => {
|
||||
this.reply(e.message);
|
||||
throw e;
|
||||
});
|
||||
if (!result) {
|
||||
await this.reply('面板列表刷新失败,请稍后再试');
|
||||
await this.reply('正在刷新面板列表 (MYS API),请稍候...');
|
||||
|
||||
const mysResult = await refreshPanelFunction(api); // 调用 MYS 刷新函数
|
||||
if (!mysResult) { throw new Error('MYS API 返回空结果'); }
|
||||
this.result = mysResult; // <<< MYS 结果赋给 this.result
|
||||
logger.mark('[panel.js] MYS API refreshPanelFunction 调用完成.');
|
||||
} catch (mysError) {
|
||||
logger.error('[panel.js] MYS API 刷新出错:', mysError);
|
||||
this.reply(`MYS API 刷新出错: ${mysError.message}`);
|
||||
return false;
|
||||
}
|
||||
const newChar = result.filter(item => item.isNew);
|
||||
}
|
||||
// --- End 数据获取和处理逻辑 ---
|
||||
|
||||
|
||||
// --- !!! 关键步骤:更新面板数据缓存 !!! ---
|
||||
if (this.result && Array.isArray(this.result)) { // 确保有有效数据 (非 null, 是数组)
|
||||
// 并且至少包含一个角色数据才存,避免存空数组?(可选)
|
||||
if (this.result.length > 0) {
|
||||
try {
|
||||
logger.mark(`[panel.js] 准备调用 updatePanelData 更新缓存,包含 ${this.result.length} 个角色数据...`);
|
||||
// 调用导入的 updatePanelData 函数
|
||||
await updatePanelData(uid, this.result); // <<< 核心:写入缓存
|
||||
logger.mark('[panel.js] updatePanelData 调用完成,缓存已更新。');
|
||||
} catch (cacheError) {
|
||||
logger.error('[panel.js] 调用 updatePanelData 更新缓存时出错:', cacheError);
|
||||
// 记录错误,但可能继续
|
||||
}
|
||||
} else {
|
||||
logger.warn('[panel.js] 获取到的角色列表为空数组,不执行缓存更新。');
|
||||
// 如果是 Enka 路径且展示柜为空,这是正常情况
|
||||
}
|
||||
} else {
|
||||
logger.warn('[panel.js] 没有有效的角色列表数据 (this.result),跳过缓存更新。');
|
||||
// 如果之前的步骤没有 return false,这里可能需要提示用户
|
||||
if (!useEnka) { // MYS 失败的情况
|
||||
await this.reply('未能获取或处理有效的面板列表数据。');
|
||||
return false; // 如果 MYS 失败且结果无效,应该退出
|
||||
}
|
||||
// 如果是 Enka 路径且结果无效/非数组,也提示并退出
|
||||
await this.reply('处理后的面板数据格式无效。');
|
||||
return false;
|
||||
}
|
||||
// --- !!! End 更新缓存 !!! ---
|
||||
|
||||
|
||||
// --- 后续处理:构建 finalData 用于渲染刷新摘要 ---
|
||||
const currentResult = this.result || []; // 保证 currentResult 是数组
|
||||
|
||||
// newChar 的计算可能依赖于 MYS 的特定字段,Enka 结果可能没有
|
||||
// 保持之前的兼容逻辑,如果 Enka 结果没有 isNew,newCharCount 为 0
|
||||
const newCharCount = (currentResult.length > 0 && currentResult[0]?.isNew !== undefined)
|
||||
? currentResult.filter(item => item && item.isNew).length
|
||||
: 0;
|
||||
|
||||
const finalData = {
|
||||
newChar: newChar.length,
|
||||
list: result,
|
||||
newChar: newCharCount,
|
||||
list: currentResult,
|
||||
player: playerInfo,
|
||||
uid: uid
|
||||
};
|
||||
|
||||
logger.mark('[panel.js] 准备渲染 refresh.html 模板...');
|
||||
|
||||
// 渲染刷新摘要页面
|
||||
try {
|
||||
await this.render('panel/refresh.html', finalData);
|
||||
} catch (renderError) {
|
||||
logger.error('[panel.js] 渲染 refresh.html 模板失败:', renderError);
|
||||
await this.reply(`生成刷新结果图片时出错: ${renderError.message}`);
|
||||
}
|
||||
async getCharPanelList() {
|
||||
const uid = await this.getUID();
|
||||
const result = getPanelList(uid);
|
||||
if (!result) {
|
||||
await this.reply('未找到面板数据,请先%刷新面板');
|
||||
return false;
|
||||
}
|
||||
await this.getPlayerInfo();
|
||||
const timer = setTimeout(() => {
|
||||
if (this?.reply) {
|
||||
this.reply('查询成功,正在下载图片资源,请稍候。');
|
||||
}
|
||||
}, 5000);
|
||||
for (const item of result) {
|
||||
await item.get_basic_assets();
|
||||
}
|
||||
clearTimeout(timer);
|
||||
const finalData = {
|
||||
count: result?.length || 0,
|
||||
list: result,
|
||||
};
|
||||
await this.render('panel/list.html', finalData);
|
||||
}
|
||||
|
||||
async getCharPanelListTool(uid, origin = false) {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
render:
|
||||
scale: 100 # 渲染精度
|
||||
useEnka: true # 使用enka接口查询
|
||||
query:
|
||||
others: true # 允许查询他人信息
|
||||
update:
|
||||
|
|
|
|||
512
lib/ekapi/PartnerScore.json
Normal file
512
lib/ekapi/PartnerScore.json
Normal file
|
|
@ -0,0 +1,512 @@
|
|||
{
|
||||
"1011": {
|
||||
"生命值百分比": 0,
|
||||
"生命值": 0,
|
||||
"攻击力百分比": 1,
|
||||
"攻击力": 1,
|
||||
"防御力百分比": 0,
|
||||
"防御力": 0,
|
||||
"暴击率": 0.75,
|
||||
"暴击伤害": 0.75,
|
||||
"穿透值": 0.75,
|
||||
"穿透率": 1,
|
||||
"异常精通": 0,
|
||||
"冲击力": 0,
|
||||
"伤害加成": 1,
|
||||
"能量自动回复": 0,
|
||||
"异常掌控": 0
|
||||
},
|
||||
"1021": {
|
||||
"生命值百分比": 0,
|
||||
"生命值": 0,
|
||||
"攻击力百分比": 0.75,
|
||||
"攻击力": 0.75,
|
||||
"防御力百分比": 0,
|
||||
"防御力": 0,
|
||||
"暴击率": 1,
|
||||
"暴击伤害": 1,
|
||||
"穿透值": 0.75,
|
||||
"穿透率": 1,
|
||||
"异常精通": 0,
|
||||
"冲击力": 0,
|
||||
"伤害加成": 1,
|
||||
"能量自动回复": 0,
|
||||
"异常掌控": 0
|
||||
},
|
||||
"1031": {
|
||||
"生命值百分比": 0,
|
||||
"生命值": 0,
|
||||
"攻击力百分比": 0.75,
|
||||
"攻击力": 0.75,
|
||||
"防御力百分比": 0,
|
||||
"防御力": 0,
|
||||
"暴击率": 0.75,
|
||||
"暴击伤害": 0.75,
|
||||
"穿透值": 0.75,
|
||||
"穿透率": 1,
|
||||
"异常精通": 0.75,
|
||||
"冲击力": 0,
|
||||
"伤害加成": 1,
|
||||
"能量自动回复": 1,
|
||||
"异常掌控": 0
|
||||
},
|
||||
"1041": {
|
||||
"生命值百分比": 0,
|
||||
"生命值": 0,
|
||||
"攻击力百分比": 0.75,
|
||||
"攻击力": 0.75,
|
||||
"防御力百分比": 0,
|
||||
"防御力": 0,
|
||||
"暴击率": 1,
|
||||
"暴击伤害": 1,
|
||||
"穿透值": 0.75,
|
||||
"穿透率": 1,
|
||||
"异常精通": 0,
|
||||
"冲击力": 0,
|
||||
"伤害加成": 1,
|
||||
"能量自动回复": 0,
|
||||
"异常掌控": 0
|
||||
},
|
||||
"1061": {
|
||||
"生命值百分比": 0,
|
||||
"生命值": 0,
|
||||
"攻击力百分比": 0.75,
|
||||
"攻击力": 0.75,
|
||||
"防御力百分比": 0,
|
||||
"防御力": 0,
|
||||
"暴击率": 1,
|
||||
"暴击伤害": 1,
|
||||
"穿透值": 0.75,
|
||||
"穿透率": 1,
|
||||
"异常精通": 0,
|
||||
"冲击力": 0,
|
||||
"伤害加成": 1,
|
||||
"能量自动回复": 0,
|
||||
"异常掌控": 0
|
||||
},
|
||||
"1081": {
|
||||
"生命值百分比": 0,
|
||||
"生命值": 0,
|
||||
"攻击力百分比": 0.75,
|
||||
"攻击力": 0.75,
|
||||
"防御力百分比": 0,
|
||||
"防御力": 0,
|
||||
"暴击率": 1,
|
||||
"暴击伤害": 1,
|
||||
"穿透值": 0.75,
|
||||
"穿透率": 1,
|
||||
"异常精通": 0,
|
||||
"冲击力": 0,
|
||||
"伤害加成": 1,
|
||||
"能量自动回复": 0,
|
||||
"异常掌控": 0
|
||||
},
|
||||
"1091": {
|
||||
"生命值百分比": 0,
|
||||
"生命值": 0,
|
||||
"攻击力百分比": 0.75,
|
||||
"攻击力": 0.75,
|
||||
"防御力百分比": 0,
|
||||
"防御力": 0,
|
||||
"暴击率": 1,
|
||||
"暴击伤害": 1,
|
||||
"穿透值": 0.25,
|
||||
"穿透率": 0,
|
||||
"异常精通": 0.25,
|
||||
"冲击力": 0,
|
||||
"伤害加成": 1,
|
||||
"能量自动回复": 0,
|
||||
"异常掌控": 0
|
||||
},
|
||||
"1101": {
|
||||
"生命值百分比": 0,
|
||||
"生命值": 0,
|
||||
"攻击力百分比": 1,
|
||||
"攻击力": 1,
|
||||
"防御力百分比": 0,
|
||||
"防御力": 0,
|
||||
"暴击率": 0.75,
|
||||
"暴击伤害": 0.75,
|
||||
"穿透值": 0.75,
|
||||
"穿透率": 1,
|
||||
"异常精通": 0,
|
||||
"冲击力": 0,
|
||||
"伤害加成": 1,
|
||||
"能量自动回复": 1,
|
||||
"异常掌控": 0
|
||||
},
|
||||
"1111": {
|
||||
"生命值百分比": 0,
|
||||
"生命值": 0,
|
||||
"攻击力百分比": 0.75,
|
||||
"攻击力": 0.75,
|
||||
"防御力百分比": 0,
|
||||
"防御力": 0,
|
||||
"暴击率": 1,
|
||||
"暴击伤害": 1,
|
||||
"穿透值": 0.75,
|
||||
"穿透率": 1,
|
||||
"异常精通": 0,
|
||||
"冲击力": 0,
|
||||
"伤害加成": 1,
|
||||
"能量自动回复": 0,
|
||||
"异常掌控": 0
|
||||
},
|
||||
"1121": {
|
||||
"生命值百分比": 0,
|
||||
"生命值": 0,
|
||||
"攻击力百分比": 0,
|
||||
"攻击力": 0,
|
||||
"防御力百分比": 1,
|
||||
"防御力": 1,
|
||||
"暴击率": 0.75,
|
||||
"暴击伤害": 0.75,
|
||||
"穿透值": 0.75,
|
||||
"穿透率": 1,
|
||||
"异常精通": 0,
|
||||
"冲击力": 0,
|
||||
"伤害加成": 1,
|
||||
"能量自动回复": 1,
|
||||
"异常掌控": 0
|
||||
},
|
||||
"1131": {
|
||||
"生命值百分比": 0,
|
||||
"生命值": 0,
|
||||
"攻击力百分比": 1,
|
||||
"攻击力": 1,
|
||||
"防御力百分比": 0,
|
||||
"防御力": 0,
|
||||
"暴击率": 0.75,
|
||||
"暴击伤害": 0.75,
|
||||
"穿透值": 1,
|
||||
"穿透率": 1,
|
||||
"异常精通": 0,
|
||||
"冲击力": 0,
|
||||
"伤害加成": 1,
|
||||
"能量自动回复": 0,
|
||||
"异常掌控": 0
|
||||
},
|
||||
"1141": {
|
||||
"生命值百分比": 0,
|
||||
"生命值": 0,
|
||||
"攻击力百分比": 1,
|
||||
"攻击力": 1,
|
||||
"防御力百分比": 0,
|
||||
"防御力": 0,
|
||||
"暴击率": 0.75,
|
||||
"暴击伤害": 0.75,
|
||||
"穿透值": 0.75,
|
||||
"穿透率": 1,
|
||||
"异常精通": 0,
|
||||
"冲击力": 1,
|
||||
"伤害加成": 1,
|
||||
"能量自动回复": 0,
|
||||
"异常掌控": 0
|
||||
},
|
||||
"1151": {
|
||||
"生命值百分比": 0,
|
||||
"生命值": 0,
|
||||
"攻击力百分比": 1,
|
||||
"攻击力": 1,
|
||||
"防御力百分比": 0,
|
||||
"防御力": 0,
|
||||
"暴击率": 0.75,
|
||||
"暴击伤害": 0.75,
|
||||
"穿透值": 0.5,
|
||||
"穿透率": 1,
|
||||
"异常精通": 0.5,
|
||||
"冲击力": 0,
|
||||
"伤害加成": 1,
|
||||
"能量自动回复": 1,
|
||||
"异常掌控": 0
|
||||
},
|
||||
"1161": {
|
||||
"生命值百分比": 0,
|
||||
"生命值": 0,
|
||||
"攻击力百分比": 1,
|
||||
"攻击力": 1,
|
||||
"防御力百分比": 0,
|
||||
"防御力": 0,
|
||||
"暴击率": 0.75,
|
||||
"暴击伤害": 0.75,
|
||||
"穿透值": 0.75,
|
||||
"穿透率": 1,
|
||||
"异常精通": 0,
|
||||
"冲击力": 0,
|
||||
"伤害加成": 1,
|
||||
"能量自动回复": 0,
|
||||
"异常掌控": 0
|
||||
},
|
||||
"1181": {
|
||||
"生命值百分比": 0,
|
||||
"生命值": 0,
|
||||
"攻击力百分比": 0.75,
|
||||
"攻击力": 0.75,
|
||||
"防御力百分比": 0,
|
||||
"防御力": 0,
|
||||
"暴击率": 0.75,
|
||||
"暴击伤害": 0.75,
|
||||
"穿透值": 0.75,
|
||||
"穿透率": 1,
|
||||
"异常精通": 1,
|
||||
"冲击力": 0,
|
||||
"伤害加成": 1,
|
||||
"能量自动回复": 0,
|
||||
"异常掌控": 1
|
||||
},
|
||||
"1191": {
|
||||
"生命值百分比": 0,
|
||||
"生命值": 0,
|
||||
"攻击力百分比": 0.75,
|
||||
"攻击力": 0.75,
|
||||
"防御力百分比": 0,
|
||||
"防御力": 0,
|
||||
"暴击率": 1,
|
||||
"暴击伤害": 1,
|
||||
"穿透值": 0.75,
|
||||
"穿透率": 1,
|
||||
"异常精通": 0,
|
||||
"冲击力": 0,
|
||||
"伤害加成": 1,
|
||||
"能量自动回复": 0,
|
||||
"异常掌控": 0
|
||||
},
|
||||
"1201": {
|
||||
"生命值百分比": 0,
|
||||
"生命值": 0,
|
||||
"攻击力百分比": 1,
|
||||
"攻击力": 1,
|
||||
"防御力百分比": 0,
|
||||
"防御力": 0,
|
||||
"暴击率": 0.75,
|
||||
"暴击伤害": 0.75,
|
||||
"穿透值": 0.75,
|
||||
"穿透率": 1,
|
||||
"异常精通": 0,
|
||||
"冲击力": 0,
|
||||
"伤害加成": 1,
|
||||
"能量自动回复": 0,
|
||||
"异常掌控": 0
|
||||
},
|
||||
"1211": {
|
||||
"生命值百分比": 0,
|
||||
"生命值": 0,
|
||||
"攻击力百分比": 0.75,
|
||||
"攻击力": 0.75,
|
||||
"防御力百分比": 0,
|
||||
"防御力": 0,
|
||||
"暴击率": 0.75,
|
||||
"暴击伤害": 0.75,
|
||||
"穿透值": 1,
|
||||
"穿透率": 1,
|
||||
"异常精通": 0.5,
|
||||
"冲击力": 0,
|
||||
"伤害加成": 1,
|
||||
"能量自动回复": 1,
|
||||
"异常掌控": 0
|
||||
},
|
||||
"1221": {
|
||||
"生命值百分比": 0,
|
||||
"生命值": 0,
|
||||
"攻击力百分比": 0.75,
|
||||
"攻击力": 0.75,
|
||||
"防御力百分比": 0,
|
||||
"防御力": 0,
|
||||
"暴击率": 0,
|
||||
"暴击伤害": 0,
|
||||
"穿透值": 0.25,
|
||||
"穿透率": 0.25,
|
||||
"异常精通": 1,
|
||||
"冲击力": 0,
|
||||
"伤害加成": 1,
|
||||
"能量自动回复": 0,
|
||||
"异常掌控": 0
|
||||
},
|
||||
"1241": {
|
||||
"生命值百分比": 0,
|
||||
"生命值": 0,
|
||||
"攻击力百分比": 0.75,
|
||||
"攻击力": 0.75,
|
||||
"防御力百分比": 0,
|
||||
"防御力": 0,
|
||||
"暴击率": 1,
|
||||
"暴击伤害": 1,
|
||||
"穿透值": 0.75,
|
||||
"穿透率": 1,
|
||||
"异常精通": 0,
|
||||
"冲击力": 0,
|
||||
"伤害加成": 1,
|
||||
"能量自动回复": 0,
|
||||
"异常掌控": 0
|
||||
},
|
||||
"1251": {
|
||||
"生命值百分比": 0,
|
||||
"生命值": 0,
|
||||
"攻击力百分比": 1,
|
||||
"攻击力": 1,
|
||||
"防御力百分比": 0,
|
||||
"防御力": 0,
|
||||
"暴击率": 0.75,
|
||||
"暴击伤害": 0.75,
|
||||
"穿透值": 0.75,
|
||||
"穿透率": 1,
|
||||
"异常精通": 0,
|
||||
"冲击力": 0,
|
||||
"伤害加成": 1,
|
||||
"能量自动回复": 0,
|
||||
"异常掌控": 0
|
||||
},
|
||||
"1271": {
|
||||
"生命值百分比": 0,
|
||||
"生命值": 0,
|
||||
"攻击力百分比": 0,
|
||||
"攻击力": 0,
|
||||
"防御力百分比": 1,
|
||||
"防御力": 1,
|
||||
"暴击率": 0.75,
|
||||
"暴击伤害": 0.75,
|
||||
"穿透值": 0.75,
|
||||
"穿透率": 1,
|
||||
"异常精通": 0,
|
||||
"冲击力": 0,
|
||||
"伤害加成": 1,
|
||||
"能量自动回复": 1,
|
||||
"异常掌控": 0
|
||||
},
|
||||
"1171": {
|
||||
"生命值百分比": 0,
|
||||
"生命值": 0,
|
||||
"攻击力百分比": 0.75,
|
||||
"攻击力": 0.75,
|
||||
"防御力百分比": 0,
|
||||
"防御力": 0,
|
||||
"暴击率": 0,
|
||||
"暴击伤害": 0,
|
||||
"穿透值": 0.25,
|
||||
"穿透率": 0.25,
|
||||
"异常精通": 1,
|
||||
"冲击力": 0,
|
||||
"伤害加成": 1,
|
||||
"能量自动回复": 0,
|
||||
"异常掌控": 0
|
||||
},
|
||||
"1261": {
|
||||
"生命值百分比": 0,
|
||||
"生命值": 0,
|
||||
"攻击力百分比": 0.75,
|
||||
"攻击力": 0.75,
|
||||
"防御力百分比": 0,
|
||||
"防御力": 0,
|
||||
"暴击率": 0,
|
||||
"暴击伤害": 0,
|
||||
"穿透值": 0.25,
|
||||
"穿透率": 0.25,
|
||||
"异常精通": 1,
|
||||
"冲击力": 0,
|
||||
"伤害加成": 1,
|
||||
"能量自动回复": 0,
|
||||
"异常掌控": 0
|
||||
},
|
||||
"1281": {
|
||||
"生命值百分比": 0,
|
||||
"生命值": 0,
|
||||
"攻击力百分比": 0.75,
|
||||
"攻击力": 0.75,
|
||||
"防御力百分比": 0,
|
||||
"防御力": 0,
|
||||
"暴击率": 0.75,
|
||||
"暴击伤害": 0.75,
|
||||
"穿透值": 0.75,
|
||||
"穿透率": 1,
|
||||
"异常精通": 1,
|
||||
"冲击力": 0,
|
||||
"伤害加成": 1,
|
||||
"能量自动回复": 0,
|
||||
"异常掌控": 1
|
||||
},
|
||||
"1311": {
|
||||
"生命值百分比": 0,
|
||||
"生命值": 0,
|
||||
"攻击力百分比": 0.75,
|
||||
"攻击力": 0.75,
|
||||
"防御力百分比": 0,
|
||||
"防御力": 0,
|
||||
"暴击率": 0.75,
|
||||
"暴击伤害": 0.75,
|
||||
"穿透值": 0.75,
|
||||
"穿透率": 1,
|
||||
"异常精通": 1,
|
||||
"冲击力": 0,
|
||||
"伤害加成": 1,
|
||||
"能量自动回复": 0,
|
||||
"异常掌控": 1
|
||||
},
|
||||
"1321": {
|
||||
"生命值百分比": 0,
|
||||
"生命值": 0,
|
||||
"攻击力百分比": 0.75,
|
||||
"攻击力": 0.75,
|
||||
"防御力百分比": 0,
|
||||
"防御力": 0,
|
||||
"暴击率": 0.75,
|
||||
"暴击伤害": 0.75,
|
||||
"穿透值": 0.75,
|
||||
"穿透率": 1,
|
||||
"异常精通": 1,
|
||||
"冲击力": 0,
|
||||
"伤害加成": 1,
|
||||
"能量自动回复": 0,
|
||||
"异常掌控": 1
|
||||
},
|
||||
"1381": {
|
||||
"生命值百分比": 0,
|
||||
"生命值": 0,
|
||||
"攻击力百分比": 0.75,
|
||||
"攻击力": 0.75,
|
||||
"防御力百分比": 0,
|
||||
"防御力": 0,
|
||||
"暴击率": 0.75,
|
||||
"暴击伤害": 0.75,
|
||||
"穿透值": 0.75,
|
||||
"穿透率": 1,
|
||||
"异常精通": 1,
|
||||
"冲击力": 0,
|
||||
"伤害加成": 1,
|
||||
"能量自动回复": 0,
|
||||
"异常掌控": 1
|
||||
},
|
||||
"1291": {
|
||||
"生命值百分比": 0,
|
||||
"生命值": 0,
|
||||
"攻击力百分比": 0.75,
|
||||
"攻击力": 0.75,
|
||||
"防御力百分比": 0,
|
||||
"防御力": 0,
|
||||
"暴击率": 0.75,
|
||||
"暴击伤害": 0.75,
|
||||
"穿透值": 0.75,
|
||||
"穿透率": 1,
|
||||
"异常精通": 1,
|
||||
"冲击力": 0,
|
||||
"伤害加成": 1,
|
||||
"能量自动回复": 0,
|
||||
"异常掌控": 1
|
||||
},
|
||||
"1331": {
|
||||
"生命值百分比": 0,
|
||||
"生命值": 0,
|
||||
"攻击力百分比": 0.75,
|
||||
"攻击力": 0.75,
|
||||
"防御力百分比": 0,
|
||||
"防御力": 0,
|
||||
"暴击率": 0.75,
|
||||
"暴击伤害": 0.75,
|
||||
"穿透值": 0.75,
|
||||
"穿透率": 1,
|
||||
"异常精通": 1,
|
||||
"冲击力": 0,
|
||||
"伤害加成": 1,
|
||||
"能量自动回复": 0,
|
||||
"异常掌控": 1
|
||||
}
|
||||
}
|
||||
173
lib/ekapi/alias/char_alias.json
Normal file
173
lib/ekapi/alias/char_alias.json
Normal file
|
|
@ -0,0 +1,173 @@
|
|||
{
|
||||
"「11号」": [
|
||||
"十一号",
|
||||
"十一",
|
||||
"11号",
|
||||
"11",
|
||||
"「11号」"
|
||||
],
|
||||
"艾莲": [
|
||||
"爱莲",
|
||||
"爱怜",
|
||||
"艾莲·乔",
|
||||
"鲨鱼妹",
|
||||
"鲨鱼"
|
||||
],
|
||||
"安东": [
|
||||
"安东",
|
||||
"安东·伊万诺夫"
|
||||
],
|
||||
"本": [
|
||||
"熊本",
|
||||
"熊本熊",
|
||||
"ben",
|
||||
"比格",
|
||||
"本·比格"
|
||||
],
|
||||
"比利": [
|
||||
"比例",
|
||||
"bili",
|
||||
"比利·奇德",
|
||||
"Billy"
|
||||
],
|
||||
"苍角": [
|
||||
"苍绝",
|
||||
"仓角",
|
||||
"仓脚"
|
||||
],
|
||||
"格莉丝": [
|
||||
"格里斯",
|
||||
"格利斯",
|
||||
"格莉斯"
|
||||
],
|
||||
"珂蕾妲": [
|
||||
"柯雷妲",
|
||||
"珂雷哒",
|
||||
"柯蕾妲"
|
||||
],
|
||||
"猫又": [
|
||||
"猫猫",
|
||||
"猫妖",
|
||||
"猫怪",
|
||||
"猫鼬",
|
||||
"猫宫 又奈",
|
||||
"猫宫又奈",
|
||||
"又奈",
|
||||
"Neko",
|
||||
"neko"
|
||||
],
|
||||
"妮可": [
|
||||
"尼克",
|
||||
"妮克",
|
||||
"妮寇",
|
||||
"妮可·德玛拉",
|
||||
"Nicole"
|
||||
],
|
||||
"朱鸢": [
|
||||
"朱渊",
|
||||
"朱元"
|
||||
],
|
||||
"丽娜": [
|
||||
"莉娜",
|
||||
"李娜",
|
||||
"亚历山德丽娜·莎芭丝缇安",
|
||||
"rina"
|
||||
],
|
||||
"莱卡恩": [
|
||||
"冯·莱卡恩"
|
||||
],
|
||||
"安比": [
|
||||
"安比",
|
||||
"安笔"
|
||||
],
|
||||
"可琳": [
|
||||
"克林",
|
||||
"柯林",
|
||||
"可林"
|
||||
],
|
||||
"雅": [
|
||||
"星见雅",
|
||||
"星见"
|
||||
],
|
||||
"露西": [
|
||||
"路西",
|
||||
"露西亚娜·德·蒙特夫",
|
||||
"露西亚娜",
|
||||
"鲁西"
|
||||
],
|
||||
"莱特": [
|
||||
"赖特",
|
||||
"Lighter"
|
||||
],
|
||||
"悠真": [
|
||||
"悠",
|
||||
"浅羽悠真",
|
||||
"浅羽"
|
||||
],
|
||||
"柳": [
|
||||
"月城",
|
||||
"月城柳"
|
||||
],
|
||||
"青衣": [
|
||||
"青医",
|
||||
"轻易"
|
||||
],
|
||||
"赛斯": [
|
||||
"赛斯·洛威尔",
|
||||
"塞斯",
|
||||
"洛威尔"
|
||||
],
|
||||
"派派": [
|
||||
"拍拍",
|
||||
"韦尔",
|
||||
"派派·韦尔"
|
||||
],
|
||||
"凯撒": [
|
||||
"恺撒",
|
||||
"凯萨",
|
||||
"凯撒·金",
|
||||
"恺撒"
|
||||
],
|
||||
"简": [
|
||||
"简",
|
||||
"见",
|
||||
"简·杜"
|
||||
],
|
||||
"柏妮思": [
|
||||
"柏妮丝",
|
||||
"妮丝",
|
||||
"妮思",
|
||||
"伯尼斯",
|
||||
"博妮丝"
|
||||
],
|
||||
"哲": [
|
||||
"哲"
|
||||
],
|
||||
"铃": [
|
||||
"铃"
|
||||
],
|
||||
"波可娜": [
|
||||
"波可娜·费雷尼",
|
||||
"PulchraFeliny"
|
||||
],
|
||||
"耀嘉音": [
|
||||
"耀佳音",
|
||||
"佳音",
|
||||
"耀"
|
||||
],
|
||||
"雨果": [
|
||||
"雨果"
|
||||
],
|
||||
"薇薇安": [
|
||||
"薇薇安",
|
||||
"反舌鸟"
|
||||
],
|
||||
"零号·安比": [
|
||||
"安比零",
|
||||
"银心锡兵",
|
||||
"零号",
|
||||
"大安比",
|
||||
"sp安比",
|
||||
"s安比"
|
||||
]
|
||||
}
|
||||
313
lib/ekapi/name_convert.js
Normal file
313
lib/ekapi/name_convert.js
Normal file
|
|
@ -0,0 +1,313 @@
|
|||
// name_convert.js
|
||||
console.log('[name_convert.js] 文件开始执行'); // <--- 加入这行
|
||||
import fs from 'node:fs';
|
||||
import path from 'node:path';
|
||||
|
||||
import { fileURLToPath } from 'node:url'; // <--- 1. 导入 fileURLToPath
|
||||
|
||||
// Use import.meta.url WITH fileURLToPath
|
||||
const __filename = fileURLToPath(import.meta.url); // <--- 2. 获取当前文件的绝对路径
|
||||
const __dirname = path.dirname(__filename); // <--- 3. 获取当前文件所在的目录路径
|
||||
|
||||
const MAP_PATH = __dirname; // Data files are in the same directory
|
||||
const ALIAS_LIST_DIR = path.join(__dirname, 'alias'); // Alias directory path
|
||||
const CHAR_ALIAS_FILE = path.join(ALIAS_LIST_DIR, 'char_alias.json'); // Alias file path
|
||||
|
||||
const PartnerId2DataFile = 'PartnerId2Data.json';
|
||||
const WeaponId2DataFile = 'WeaponId2Data.json';
|
||||
const EquipId2DataFile = 'EquipId2Data.json';
|
||||
|
||||
let char_alias_data = {};
|
||||
try {
|
||||
// Ensure the alias directory exists before trying to read the file
|
||||
if (fs.existsSync(ALIAS_LIST_DIR) && fs.existsSync(CHAR_ALIAS_FILE)) {
|
||||
const charAliasContent = fs.readFileSync(CHAR_ALIAS_FILE, { encoding: 'utf-8' });
|
||||
char_alias_data = JSON.parse(charAliasContent);
|
||||
} else {
|
||||
console.warn(`Alias file not found at: ${CHAR_ALIAS_FILE}. Aliases will not be loaded.`);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error reading or parsing char_alias.json:', error);
|
||||
}
|
||||
|
||||
let partner_data = {};
|
||||
try {
|
||||
const partnerDataPath = path.join(MAP_PATH, PartnerId2DataFile);
|
||||
if (fs.existsSync(partnerDataPath)) {
|
||||
const partnerDataContent = fs.readFileSync(partnerDataPath, { encoding: 'utf-8' });
|
||||
partner_data = JSON.parse(partnerDataContent);
|
||||
console.log(`[name_convert.js] 成功解析 JSON。`);
|
||||
console.log(`[name_convert.js] 加载了 ${Object.keys(partner_data).length} 个伙伴条目。`);
|
||||
console.log(`[name_convert.js] 加载后是否存在 "1191"? ${partner_data.hasOwnProperty('1191')}`);
|
||||
console.log(`[name_convert.js] 加载后是否存在 "1021"? ${partner_data.hasOwnProperty('1021')}`);
|
||||
// Optional: Keep debug logs if needed during development
|
||||
// console.log('--- partner_data loaded successfully ---');
|
||||
// console.log(`Loaded ${Object.keys(partner_data).length} partner entries.`);
|
||||
// console.log('--- partner_data sample entry ---');
|
||||
// const sampleKey = Object.keys(partner_data)[0];
|
||||
// if (sampleKey) console.log({ [sampleKey]: partner_data[sampleKey] });
|
||||
// console.log('--- partner_data loading end ---');
|
||||
} else {
|
||||
console.error(`Partner data file not found at: ${partnerDataPath}`);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(`Error reading or parsing ${PartnerId2DataFile}:`, error);
|
||||
}
|
||||
|
||||
let weapon_data = {};
|
||||
try {
|
||||
const weaponDataPath = path.join(MAP_PATH, WeaponId2DataFile);
|
||||
if (fs.existsSync(weaponDataPath)) {
|
||||
const weaponDataContent = fs.readFileSync(weaponDataPath, { encoding: 'utf-8' });
|
||||
weapon_data = JSON.parse(weaponDataContent);
|
||||
} else {
|
||||
console.error(`Weapon data file not found at: ${weaponDataPath}`);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(`Error reading or parsing ${WeaponId2DataFile}:`, error);
|
||||
}
|
||||
|
||||
let equip_data = {};
|
||||
try {
|
||||
const equipDataPath = path.join(MAP_PATH, EquipId2DataFile);
|
||||
if (fs.existsSync(equipDataPath)) {
|
||||
const equipDataContent = fs.readFileSync(equipDataPath, { encoding: 'utf-8' });
|
||||
equip_data = JSON.parse(equipDataContent);
|
||||
} else {
|
||||
console.error(`Equipment data file not found at: ${equipDataPath}`);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(`Error reading or parsing ${EquipId2DataFile}:`, error);
|
||||
}
|
||||
|
||||
// --- Helper Functions ---
|
||||
|
||||
/**
|
||||
* Converts a character name alias to the canonical character name.
|
||||
* @param {string} char_name - The alias or canonical name entered by the user.
|
||||
* @returns {string} The canonical character name, or the original input if no alias is found.
|
||||
*/
|
||||
export function alias_to_char_name(char_name) {
|
||||
if (!char_name) return char_name; // Handle null/empty input
|
||||
const lowerCaseName = char_name.toLowerCase().trim(); // Normalize input
|
||||
|
||||
for (const canonical_name in char_alias_data) {
|
||||
// Check if the input matches the canonical name (case-insensitive)
|
||||
if (lowerCaseName === canonical_name.toLowerCase()) {
|
||||
return canonical_name;
|
||||
}
|
||||
// Check if the input matches any alias in the array (case-insensitive)
|
||||
if (Array.isArray(char_alias_data[canonical_name])) {
|
||||
for (const alias of char_alias_data[canonical_name]) {
|
||||
if (lowerCaseName === String(alias).toLowerCase()) {
|
||||
return canonical_name;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// No alias found, return the original (trimmed) name
|
||||
return char_name.trim();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Gets the sprite ID for a given character ID.
|
||||
* @param {string|number} char_id - The character ID.
|
||||
* @returns {string} The sprite ID, or a default ('28') if not found.
|
||||
*/
|
||||
export function char_id_to_sprite(char_id) {
|
||||
const charIdStr = String(char_id);
|
||||
// Corrected variable name: partner_data
|
||||
if (partner_data[charIdStr] && partner_data[charIdStr].sprite_id) {
|
||||
return partner_data[charIdStr].sprite_id;
|
||||
} else {
|
||||
// console.warn(`Sprite ID not found for character ID: ${charIdStr}. Using default.`);
|
||||
return '28'; // Default sprite ID (Rope Master?)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the full name for a given character ID.
|
||||
* @param {string|number} char_id - The character ID.
|
||||
* @returns {string} The character's full name, or a default ('绳匠') if not found.
|
||||
*/
|
||||
export function char_id_to_full_name(char_id) {
|
||||
const charIdStr = String(char_id);
|
||||
// Corrected variable name: partner_data
|
||||
if (partner_data[charIdStr] && partner_data[charIdStr].full_name) {
|
||||
return partner_data[charIdStr].full_name;
|
||||
} else {
|
||||
// console.warn(`Full name not found for character ID: ${charIdStr}. Using default.`);
|
||||
return '绳匠'; // Default name (Rope Master)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the sprite file name for a given equipment ID (relic).
|
||||
* @param {string|number} equip_id - The equipment ID.
|
||||
* @returns {string|undefined} The sprite file name, or undefined if not found.
|
||||
*/
|
||||
export function equip_id_to_sprite(equip_id) {
|
||||
const equipIdStr = String(equip_id);
|
||||
if (equipIdStr.length === 5) { // Assuming 5-digit IDs for relics
|
||||
const suit_id = equipIdStr.slice(0, 3) + '00'; // Derive suit ID
|
||||
if (equip_data[suit_id] && equip_data[suit_id].sprite_file) {
|
||||
return equip_data[suit_id].sprite_file;
|
||||
}
|
||||
}
|
||||
// console.warn(`Sprite file not found for equipment ID: ${equipIdStr}.`);
|
||||
return undefined; // Return undefined if not found
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Gets the short name for a given character ID.
|
||||
* @param {string|number} char_id - The character ID.
|
||||
* @returns {string|undefined} The character's short name, or undefined if not found.
|
||||
*/
|
||||
export function char_id_to_char_name(char_id) {
|
||||
const charIdStr = String(char_id);
|
||||
// Corrected variable name: partner_data
|
||||
if (partner_data[charIdStr] && partner_data[charIdStr].name) {
|
||||
return partner_data[charIdStr].name;
|
||||
} else {
|
||||
// console.warn(`Short name not found for character ID: ${charIdStr}.`);
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the character ID for a given character name (handles aliases).
|
||||
* @param {string} char_name - The character name or alias.
|
||||
* @returns {string|undefined} The character ID (as a string), or undefined if not found.
|
||||
*/
|
||||
export function char_name_to_char_id(char_name) {
|
||||
if (!char_name) return undefined; // Handle null/empty input
|
||||
const canonicalName = alias_to_char_name(char_name); // Resolve alias first
|
||||
|
||||
// Corrected variable name: partner_data
|
||||
for (const char_id in partner_data) {
|
||||
const charData = partner_data[char_id];
|
||||
// Compare against the canonical name from alias resolution
|
||||
if (charData && charData.name && charData.name === canonicalName) {
|
||||
return char_id; // Return the ID (key)
|
||||
}
|
||||
}
|
||||
// console.warn(`Character ID not found for name: "${char_name}" (resolved to: "${canonicalName}").`);
|
||||
return undefined; // Not found
|
||||
}
|
||||
|
||||
// Export the loaded data objects as well
|
||||
export {
|
||||
equip_data,
|
||||
weapon_data,
|
||||
partner_data,
|
||||
char_alias_data // Optionally export alias data if needed elsewhere
|
||||
};
|
||||
// import fs from 'node:fs';
|
||||
// import path from 'node:path';
|
||||
//
|
||||
// const MAP_PATH = path.dirname(new URL(import.meta.url).pathname);
|
||||
// const ALIAS_LIST = path.join(path.dirname(new URL(import.meta.url).pathname), 'alias');
|
||||
// const CHAR_ALIAS = path.join(ALIAS_LIST, 'char_alias.json');
|
||||
// const PartnerId2DataFile = 'PartnerId2Data.json';
|
||||
// const WeaponId2DataFile = 'WeaponId2Data.json';
|
||||
// const EquipId2DataFile = 'EquipId2Data.json';
|
||||
//
|
||||
// let char_alias_data = {};
|
||||
// try {
|
||||
// const charAliasContent = fs.readFileSync(CHAR_ALIAS, { encoding: 'utf-8' });
|
||||
// char_alias_data = JSON.parse(charAliasContent);
|
||||
// } catch (error) {
|
||||
// console.error('Error reading char_alias.json:', error);
|
||||
// }
|
||||
//
|
||||
// let partner_data = {};
|
||||
// try {
|
||||
// const partnerDataContent = fs.readFileSync(path.join(MAP_PATH, PartnerId2DataFile), { encoding: 'utf-8' });
|
||||
// partner_data = JSON.parse(partnerDataContent);
|
||||
// console.log('--- partner_data 内容开始 ---');
|
||||
// console.log(partner_data);
|
||||
// console.log('--- partner_data 内容结束 ---');
|
||||
// } catch (error) {
|
||||
// console.error('Error reading PartnerId2Data.json:', error);
|
||||
// }
|
||||
//
|
||||
// let weapon_data = {};
|
||||
// try {
|
||||
// const weaponDataContent = fs.readFileSync(path.join(MAP_PATH, WeaponId2DataFile), { encoding: 'utf-8' });
|
||||
// weapon_data = JSON.parse(weaponDataContent);
|
||||
// } catch (error) {
|
||||
// console.error('Error reading WeaponId2Data.json:', error);
|
||||
// }
|
||||
//
|
||||
// let equip_data = {};
|
||||
// try {
|
||||
// const equipDataContent = fs.readFileSync(path.join(MAP_PATH, EquipId2DataFile), { encoding: 'utf-8' });
|
||||
// equip_data = JSON.parse(equipDataContent);
|
||||
// } catch (error) {
|
||||
// console.error('Error reading EquipId2Data.json:', error);
|
||||
// }
|
||||
//
|
||||
// export function char_id_to_sprite(char_id) {
|
||||
// const charIdStr = String(char_id);
|
||||
// if (partener_data[charIdStr]) {
|
||||
// return partener_data[charIdStr].sprite_id;
|
||||
// } else {
|
||||
// return '28';
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// export function char_id_to_full_name(char_id) {
|
||||
// const charIdStr = String(char_id);
|
||||
// if (partener_data[charIdStr]) {
|
||||
// return partener_data[charIdStr].full_name;
|
||||
// } else {
|
||||
// return '绳匠';
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// export function equip_id_to_sprite(equip_id) {
|
||||
// const equipIdStr = String(equip_id);
|
||||
// if (equipIdStr.length === 5) {
|
||||
// const suit_id = equipIdStr.slice(0, 3) + '00';
|
||||
// if (equip_data[suit_id]) {
|
||||
// return equip_data[suit_id].sprite_file;
|
||||
// }
|
||||
// }
|
||||
// return undefined;
|
||||
// }
|
||||
//
|
||||
// export function alias_to_char_name(char_name) {
|
||||
// for (const i in char_alias_data) {
|
||||
// if (char_name === i || (Array.isArray(char_alias_data[i]) && char_alias_data[i].includes(char_name))) {
|
||||
// return i;
|
||||
// }
|
||||
// }
|
||||
// return char_name;
|
||||
// }
|
||||
//
|
||||
// export function char_id_to_char_name(char_id) {
|
||||
// if (partener_data[char_id]) {
|
||||
// return partener_data[char_id].name;
|
||||
// } else {
|
||||
// return undefined;
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// export function char_name_to_char_id(char_name) {
|
||||
// const aliasConvertedName = alias_to_char_name(char_name);
|
||||
// for (const i in partener_data) {
|
||||
// const chars = partener_data[i];
|
||||
// if (aliasConvertedName === chars.name) {
|
||||
// return i;
|
||||
// }
|
||||
// }
|
||||
// return undefined;
|
||||
// }
|
||||
//
|
||||
// export {
|
||||
// equip_data,
|
||||
// weapon_data,
|
||||
// partner_data,
|
||||
// };
|
||||
39
lib/ekapi/query.js
Normal file
39
lib/ekapi/query.js
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
import settings from '../settings.js'
|
||||
import { ENKA_API } from './api.js'
|
||||
import _ from 'request'
|
||||
|
||||
const useEnka = _.get(settings.getConfig('config'), 'useEnka', true);
|
||||
export async function getZzzEnkaData(uid) {
|
||||
if (useEnka) {
|
||||
try {
|
||||
const response = await fetch(ENKA_API.replace('{uid}', uid), {
|
||||
headers: {
|
||||
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
|
||||
'Accept': 'application/json, text/plain, */*',
|
||||
'Accept-Language': 'zh-CN,zh;q=0.9,en;q=0.8',
|
||||
'Referer': 'https://enka.network/',
|
||||
'Sec-Fetch-Dest': 'empty',
|
||||
'Sec-Fetch-Mode': 'cors',
|
||||
'Sec-Fetch-Site': 'same-origin',
|
||||
},
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
console.error(`HTTP 错误! 状态码: ${response.status}`);
|
||||
return response.status;
|
||||
}
|
||||
|
||||
const data = await response.json(); // 解析 JSON 响应
|
||||
if (typeof data === 'number') {
|
||||
return data;
|
||||
}
|
||||
return data;
|
||||
|
||||
} catch (error) {
|
||||
console.error("Error fetching ZZZ Enka data:", error);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
// 如果 useEnka 为 false,你可能需要返回一个默认值或者执行其他逻辑
|
||||
return null; // 或者其他你希望返回的值
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue