/* * 胡桃数据库的统计 * * */ import { HutaoApi, Character } from "../components/models.js"; import { Cfg } from "../components/index.js"; import lodash from "lodash"; import { segment } from "oicq"; import fs from "fs"; export async function consStat(e, { render }) { if (Cfg.isDisable(e, "wiki.abyss")) { return; } let consData = await HutaoApi.getCons(); if (!consData) { e.reply("角色持有数据获取失败,请稍后重试~"); return true; } let msg = e.msg; let mode = /持有/.test(msg) ? "char" : "cons"; let conNum = -1; if (mode === "cons") { lodash.forEach([/0|零/, /1|一/, /2|二/, /3|三/, /4|四/, /5|五/, /6|六|满/], (reg, idx) => { if (reg.test(msg)) { conNum = idx; return false; } }) } if (!consData && !consData.data) { return true; } let ret = []; lodash.forEach(consData.data, (ds) => { let char = Character.get(ds.avatar); let data = { name: char.name || ds.avatar, star: char.star || 3, hold: ds.holdingRate }; if (mode === "char") { data.cons = lodash.map(ds.rate, (c) => { c.value = c.value * ds.holdingRate; return c; }); } else { data.cons = ds.rate } ret.push(data); }); if (conNum > -1) { ret = lodash.sortBy(ret, [`cons[${conNum}].value`]); ret.reverse(); } else { ret = lodash.sortBy(ret, ['hold']); } let base64 = await render("stat", "character", { chars: ret, abbr: Character.getAbbr(), mode: mode, conNum, lastUpdate: consData.lastUpdate, pct: function (num) { return (num * 100).toFixed(2); }, cfgScale: Cfg.scale(1.5) }); if (base64) { e.reply(segment.image(`base64://${base64}`)); } return true; } export async function abyssPct(e, { render }) { if (Cfg.isDisable(e, "wiki.abyss")) { return; } let abyssData = await HutaoApi.getAbyssPct(); if (!abyssData) { e.reply("深渊出场数据获取失败,请稍后重试~"); return true; } let ret = [], chooseFloor = -1, msg = e.msg; const floorName = { "12": "十二层", "11": "十一层", "10": "十层", "9": "九层" }; // 匹配深渊楼层信息 lodash.forEach(floorName, (cn, num) => { let reg = new RegExp(`${cn}|${num}`); if (reg.test(msg)) { chooseFloor = num; return false; } }); lodash.forEach(abyssData.data, (floorData) => { let floor = { floor: floorData.floor, }; let avatars = []; lodash.forEach(floorData.avatarUsage, (ds) => { let char = Character.get(ds.id); if (char) { avatars.push({ name: char.name, star: char.rarity, value: ds.value * 8 }) } }) avatars = lodash.sortBy(avatars, "value", ["asc"]); avatars.reverse(); if (chooseFloor === -1) { avatars = avatars.slice(0, 14); } ret.push({ floor: floorData.floor, avatars }); }) let base64 = await render("stat", "abyss-pct", { abyss: ret, floorName, chooseFloor, lastUpdate: abyssData.lastUpdate, pct: function (num) { return (num * 100).toFixed(2); }, cfgScale: Cfg.scale(1.5) }); if (base64) { e.reply(segment.image(`base64://${base64}`)); } return true; } async function getTalentData(e, isUpdate = false) { // 技能查询缓存 let cachePath = `./data/cache/`; if (!fs.existsSync(cachePath)) { fs.mkdirSync(cachePath); } cachePath += "talentList/"; if (!fs.existsSync(cachePath)) { fs.mkdirSync(cachePath); } let avatarRet = []; let uid = e.selfUser.uid; let hasCache = await redis.get(`cache:uid-talent-new:${uid}`); if (hasCache) { // 有缓存优先使用缓存 let jsonRet = fs.readFileSync(cachePath + `${uid}.json`, "utf8"); avatarRet = JSON.parse(jsonRet); return avatarRet; } else if (!isUpdate) { e.noReplyTalentList = true; await YunzaiApps.mysInfo.talentList(e); return await getTalentData(e, true); } return false; } export async function abyssTeam(e, { render }) { let MysApi = await e.getMysApi({ auth: "cookie", // 所有用户均可查询 targetType: "self", // 被查询用户可以是任意用户 cookieType: "self" // cookie可以是任意可用cookie }); if (!MysApi || !MysApi.selfUser || !MysApi.selfUser.uid) { return true; } let abyssData = await HutaoApi.getAbyssTeam(); if (!abyssData || !abyssData.data) { e.reply("深渊组队数据获取失败,请稍后重试~"); return true; } abyssData = abyssData.data; let talentData = await getTalentData(e); if (!talentData || talentData.length === 0) { e.reply("暂时未能获得角色的练度信息,请使用【#练度统计】命令尝试手工获取..."); return true; } let avatarRet = {}; let data = {}; let noAvatar = {}; lodash.forEach(talentData, (avatar) => { avatarRet[avatar.id] = Math.min(avatar.level, avatar.weapon_level) * 100 + Math.max(avatar.a_original, avatar.e_original, avatar.q_original) * 1000 }); let getTeamCfg = (str) => { let teams = str.split(","); teams.sort(); let teamMark = 0; lodash.forEach(teams, (a) => { if (!avatarRet[a]) { teamMark = -1; noAvatar[a] = true; } if (teamMark !== -1) { teamMark += avatarRet[a] * 1; } }) if (teamMark === -1) { teamMark = 1; } return { key: teams.join(","), mark: teamMark }; } let hasSame = function (team1, team2) { for (let idx = 0; idx < team1.length; idx++) { if (team2.includes(team1[idx])) { return true; } } return false; } lodash.forEach(abyssData, (ds) => { let floor = ds.level.floor; if (!data[floor]) { data[floor] = { up: {}, down: {}, teams: [] }; } lodash.forEach(ds.teams, (ds) => { lodash.forEach(['up', 'down'], (halfKey) => { let teamCfg = getTeamCfg(ds.id[`${halfKey}Half`]); if (teamCfg) { if (!data[floor][halfKey][teamCfg.key]) { data[floor][halfKey][teamCfg.key] = { count: 0, mark: 0, hasTeam: teamCfg.mark > 1 }; } data[floor][halfKey][teamCfg.key].count += ds.value; data[floor][halfKey][teamCfg.key].mark += ds.value * teamCfg.mark; } }) }); let temp = []; lodash.forEach(['up', 'down'], (halfKey) => { lodash.forEach(data[floor][halfKey], (ds, team) => { temp.push({ team, teamArr: team.split(","), half: halfKey, count: ds.count, mark: ds.mark, mark2: 1, hasTeam: ds.hasTeam }) }) temp = lodash.sortBy(temp, "mark") data[floor].teams = temp.reverse(); }); }); let ret = {}; lodash.forEach(data, (floorData, floor) => { ret[floor] = {} let ds = ret[floor]; lodash.forEach(floorData.teams, (t1) => { if (t1.mark2 <= 0) { return; } lodash.forEach(floorData.teams, (t2) => { if (t1.mark2 <= 0) { return false; } if (t1.half === t2.half || t2.mark2 <= 0) { return; } let teamKey = t1.half === "up" ? (t1.team + "+" + t2.team) : (t2.team + "+" + t1.team); if (ds[teamKey]) { return; } if (hasSame(t1.teamArr, t2.teamArr)) { return; } ds[teamKey] = { up: t1.half === "up" ? t1 : t2, down: t1.half === "up" ? t2 : t1, count: Math.min(t1.count, t2.count), mark: t1.hasTeam && t2.hasTeam ? t1.mark + t2.mark : t1.count + t2.count // 如果不存在组队则进行评分惩罚 } t1.mark2--; t2.mark2--; return false; }); if (lodash.keys(ds).length >= 20) { return false; } }) }); lodash.forEach(ret, (ds, floor) => { ds = lodash.sortBy(lodash.values(ds), 'mark'); ds = ds.reverse(); ds = ds.slice(0, 4); lodash.forEach(ds, (team) => { team.up.teamArr = Character.sortIds(team.up.teamArr); team.down.teamArr = Character.sortIds(team.down.teamArr); }) ret[floor] = ds; }) let avatarMap = {}; lodash.forEach(talentData, (ds) => { avatarMap[ds.id] = { id: ds.id, name: ds.name, star: ds.rarity, level: ds.level, cons: ds.cons } }) lodash.forEach(noAvatar, (d, id) => { let char = Character.get(id); avatarMap[id] = { id, name: char.name, star: char.star, level: 0, cons: 0, } }) let base64 = await render("stat", "abyss-team", { teams: ret, avatars: avatarMap, cfgScale: Cfg.scale(1.5) }); if (base64) { e.reply(segment.image(`base64://${base64}`)); } return true; }