diff --git a/.gitignore b/.gitignore index 8c54df00..c1978e67 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ .idea /components/cfg.json /resources/miao-res-plus/ +/components/setting.json diff --git a/apps/character.js b/apps/character.js index a6805350..41a579d1 100644 --- a/apps/character.js +++ b/apps/character.js @@ -2,6 +2,8 @@ import { segment } from "oicq"; import lodash from "lodash"; import { Character } from "../components/models.js" import { Cfg } from "../components/index.js"; +import Profile from "../components/Profile.js"; +import Format from "../components/Format.js" import fs from "fs"; import sizeOf from "image-size"; @@ -46,25 +48,39 @@ export async function init(isUpdate = false) { let version = isUpdate ? new Date().getTime() : 0; genshin = await import(_path + `/config/genshin/roleId.js?version=${version}`); nameID = ""; + } // 查看当前角色 export async function character(e, { render, User }) { - if (!e.msg) { + let msg = e.msg; + if (!msg) { return; } + console.log(msg); if (Cfg.isDisable(e, "char.char")) { return; } - let name = e.msg.replace(/#|老婆|老公|[1|2|5][0-9]{8}/g, "").trim(); + let mode = 'card'; + if (/详情$/.test(msg)) { + mode = 'profile'; + } + let name = msg.replace(/#|老婆|老公|详情|[1|2|5][0-9]{8}/g, "").trim(); + console.log(name); let char = Character.get(name); if (!char) { return false; } - return renderAvatar(e, char.name, render); + console.log(char.id, char.name, mode); + + if (mode === "profile") { + return renderProfile(e, char, render); + } else { + return renderAvatar(e, char.name, render); + } } let _pokeCharacter = false; @@ -387,6 +403,35 @@ async function getTalent(e, avatars) { return skill; } +export async function getProfile(e) { + let MysApi = await e.getMysApi({ + auth: "cookie", + targetType: "self", + cookieType: "self", + actionName: "更新角色信息" + }); + + if (!MysApi) { + return false; + } + let selfUser = e.selfUser; + if (!selfUser.isCookieUser) { + e.reply("仅绑定cookie用户可用") + return true; + } + e.reply("开始更新用户信息,可能会需要一定时间"); + //try { + let data = await Profile.request(selfUser.uid); + //} catch (err) { + + //e.reply("更新错误"); + //} + if (data) { + e.reply("更新成功") + } + return true; +} + // 获取角色数据 function getCharacterData(avatars) { let list = []; @@ -461,3 +506,52 @@ function getCharacterData(avatars) { set: setArr, }; } + +export async function renderProfile(e, char, render) { + let MysApi = await e.getMysApi({ + auth: "cookie", + targetType: "self", + cookieType: "self", + actionName: "查询角色详情" + }); + + let selfUser = e.selfUser, + uid = selfUser.uid; + + let profile = Profile.get(uid, char.id); + if (!profile) { + return renderAvatar(e, char.name, render) + } + + let a = profile.attr; + let c = Format.comma, + p = Format.pct; + let attr = { + hp: c(a.hp), + hpPlus: c(a.hp - a.hpBase), + atk: c(a.atk), + atkPlus: c(a.atk - a.atkBase), + def: c(a.def), + defPlus: c(a.def - a.defBase), + cRate: p(a.cRate), + cDmg: p(a.cDmg), + mastery: c(a.mastery), + recharge: p(a.recharge), + dmgBonus: p(a.dmgBonus) + }; + + + + let base64 = await render("character", "detail", { + save_id: uid, + uid: uid, + data: profile, + meta: char, + attr, + talentMap: { a: "普攻", e: "战技", q: "爆发" }, + cfgScale: Cfg.scale(1.25) + }, "png"); + if (base64) { + e.reply(segment.image(`base64://${base64}`)); + } +} \ No newline at end of file diff --git a/components/Format.js b/components/Format.js new file mode 100644 index 00000000..3052ce25 --- /dev/null +++ b/components/Format.js @@ -0,0 +1,19 @@ +let Format = { + int: function (d) { + return parseInt(d); + }, + comma: function (num, fix = 0) { + num = parseFloat((num * 1).toFixed(fix)); + let [integer, decimal] = String.prototype.split.call(num, '.'); + integer = integer.replace(/\d(?=(\d{3})+$)/g, '$&,'); // 正则先行断言 + return `${integer}${decimal ? '.' + decimal : ''}`; + }, + pct: function (num, fix = 1) { + return (num * 1).toFixed(fix) + "%"; + }, + percent: function (num, fix = 1) { + return Format.pct(num * 100, fix); + } +} + +export default Format; \ No newline at end of file diff --git a/components/Profile.js b/components/Profile.js new file mode 100644 index 00000000..1b069fa8 --- /dev/null +++ b/components/Profile.js @@ -0,0 +1,258 @@ +import fs from "fs"; +import fetch from "node-fetch"; +import lodash from "lodash"; + +const _path = process.cwd(); +const cfgPath = `${_path}/plugins/miao-plugin/components/setting.json`; +let cfg = {}; +try { + if (fs.existsSync(cfgPath)) { + cfg = JSON.parse(fs.readFileSync(cfgPath, "utf8")) || {}; + } +} catch (e) { + // do nth +} + +const userPath = `${_path}/data/UserData/`; + +if (!fs.existsSync(userPath)) { + fs.mkdirSync(userPath); +} + +const artifactMap = { + '生命值': { + title: "小生命" + }, + '生命值_百分比': { + title: "大生命", + pct: true + }, + '暴击率': { + title: "暴击率", + pct: true + }, + '暴击伤害': { + title: "爆伤", + pct: true + }, + '防御力': { + title: "小防御" + }, + '防御力_百分比': { + title: "大防御", + pct: true + }, + '攻击力': { + title: "小攻击" + }, + '攻击力_百分比': { + title: "大攻击", + pct: true + }, + '元素精通': { + title: "精通" + }, + '元素充能效率': { + title: "充能", + pct: true + }, + '治疗加成': { + title: "治疗", + pct: true + } +} + +let Data = { + getData(uid, data) { + let ret = { + uid, + chars: {} + }; + + lodash.forEach({ + name: "角色名称", + avatar: "头像ID", + lv: "冒险等阶" + }, (title, key) => { + ret[key] = data[title] || ""; + }) + + console.log(data.items.length) + + lodash.forEach(data.items, (ds) => { + let char = Data.getAvatar(ds); + console.log(char) + ret.chars[char.id] = char; + }); + + return ret; + + }, + getAvatar(data) { + return { + id: data["英雄Id"], + lv: data['等级'], + attr: Data.getAttr(data), + weapon: Data.getWeapon(data), + artis: Data.getArtifact(data), + cons: data["命之座数量"] * 1 || 0, + talent: Data.getTalent(data) + }; + }, + getAttr(data) { + let ret = {}; + let attrKey = { + atk: "攻击力_总", + atkBase: "属性攻击力", + def: "防御力_总", + defBase: "属性防御力", + hp: "生命值上限_总", + hpBase: "属性生命值上限", + mastery: "属性元素精通", + cRate: { + title: "属性暴击率", + pct: true + }, + cDmg: { + title: "属性暴击伤害", + pct: true + }, + hInc: { + title: "属性治疗加成", + pct: true + }, + recharge: { + title: "属性元素充能效率", + pct: true + } + }; + lodash.forEach(attrKey, (cfg, key) => { + if (typeof (cfg) === "string") { + cfg = { title: cfg }; + } + let val = data[cfg.title] || ""; + if (cfg.pct) { + val = (val * 100).toFixed(2) + } + ret[key] = val; + }); + let maxDmg = 0; + lodash.forEach("火水草雷风冰岩".split(""), (key) => { + maxDmg = Math.max(data[`属性${key}元素伤害加成`] * 1, maxDmg); + }); + ret.dmgBonus = (maxDmg * 100).toFixed(2); + + return ret; + }, + getWeapon(data) { + return { + name: data['武器名称'], + lv: data['武器等级'], + refine: data["武器精炼"] + } + }, + getArtifact(data) { + let ret = {}; + let get = function (idx, key) { + let v = data[`圣遗物${idx}${key}`]; + let ret = /^([^\d]*)([\d\.\-]*)$/.exec(v); + if (ret && ret[1]) { + let title = ret[1], val = ret[2]; + if (artifactMap[title]) { + if (artifactMap[title].pct) { + val = (val * 100).toFixed(2); + } + title = artifactMap[title].title; + } + return [title, val]; + } + return []; + } + + for (let idx = 1; idx <= 5; idx++) { + ret[`arti${idx}`] = { + name: data[`圣遗物${idx}名称`], + type: data[`圣遗物${idx}类型`], + main: get(idx, "主词条"), + attrs: [ + get(idx, "副词条1"), + get(idx, "副词条2"), + get(idx, "副词条3"), + get(idx, "副词条4"), + ] + }; + } + return ret; + }, + getTalent(data) { + let ret = {}; + lodash.forEach({ + a: 1, + e: 2, + q: 3 + }, (idx, key) => { + let val = data[`天赋主动名称${idx}`] + let regRet = /等级(\d*)$/.exec(val); + if (regRet && regRet[1]) { + ret[key] = regRet[1] * 1 || 1 + } else { + ret[key] = 1; + } + }) + return ret; + } +} + +let Profile = { + async request(uid) { + if (!cfg.api) { + return {}; + } + const api = cfg.api + uid; + let req = await fetch(api); + let data = await req.text(); + data = data.replace(/\x00/g, ''); + console.log(data); + fs.writeFileSync(userPath + "/test.json", data); + data = JSON.parse(data); + console.log(data); + let userData = {}; + if (data && data["角色名称"]) { + userData = Profile.save(uid, data) + } + return userData; + }, + + save(uid, ds) { + let userData = {}; + const userFile = `${userPath}/${uid}.json`; + if (fs.existsSync(userFile)) { + userData = JSON.parse(fs.readFileSync(userFile, "utf8")) || {}; + } + + let data = Data.getData(uid, ds); + + lodash.assignIn(userData, lodash.pick(data, "uid,name,lv,avatar".split(","))); + + userData.chars = userData.chars || {}; + lodash.forEach(data.chars, (char, charId) => { + userData.chars[charId] = char; + }); + + fs.writeFileSync(userFile, JSON.stringify(userData), "", " "); + return userData; + }, + get(uid, charId) { + const userFile = `${userPath}/${uid}.json`; + let userData = {}; + if (fs.existsSync(userFile)) { + userData = JSON.parse(fs.readFileSync(userFile, "utf8")) || {}; + } + console.log(charId, lodash.keys(userData.chars)); + if (userData && userData.chars && userData.chars[charId]) { + return userData.chars[charId]; + } + return false; + } +}; +export default Profile; diff --git a/index.js b/index.js index f230e2a1..a2060e08 100644 --- a/index.js +++ b/index.js @@ -1,4 +1,4 @@ -import { character, wife, wifeReg } from "./apps/character.js"; +import { character, getProfile, wife, wifeReg } from "./apps/character.js"; import { consStat, abyssPct } from "./apps/stat.js"; import { wiki } from "./apps/wiki.js"; import { help } from "./apps/help.js"; @@ -6,29 +6,37 @@ import lodash from "lodash"; import { rule as adminRule, updateRes, sysCfg } from "./apps/admin.js"; -export { character, wife, consStat, abyssPct, wiki, updateRes, sysCfg, help }; +export { character, wife, consStat, abyssPct, wiki, updateRes, sysCfg, help, getProfile }; let rule = { character: { - reg: "^#(喵喵)?(.*)?$", - describe: "【#刻晴】角色详情", + reg: "^#(喵喵)?(.*)(详情)?$", + describe: "【#角色】角色详情", }, wife: { reg: wifeReg, - describe: "【#老婆,#老公,#女儿】角色详情", + describe: "【#角色】#老公 #老婆 查询", }, consStat: { reg: "^#(喵喵)?角色(持有|持有率|命座|命之座|.命)(分布|统计)?$", + describe: "【#统计】 #角色持有率 #角色5命统计", }, abyssPct: { reg: "^#(喵喵)?深渊(第?.{1,2}层)?(角色)?出场(率|统计)*$", + describe: "【#统计】 #深渊出场率 #深渊12层出场率", }, wiki: { reg: "^#(喵喵)?.*(天赋|技能|命座|命之座|资料|照片|写真|图片|插画)$", + describe: "【#资料】 #神里天赋 #夜兰命座", }, help: { - reg: "^#?(喵喵)?(命令|帮助|菜单|help|说明|功能|指令|使用说明)$" + reg: "^#?(喵喵)?(命令|帮助|菜单|help|说明|功能|指令|使用说明)$", + describe: "【#帮助】 #喵喵帮助", + }, + getProfile: { + reg: "^#获取游戏角色详情$", + describe: "【#角色】 获取游戏橱窗详情数据", }, ...adminRule }; diff --git a/resources/common/common.css b/resources/common/common.css index 95ed53ec..6b1ba77b 100644 --- a/resources/common/common.css +++ b/resources/common/common.css @@ -18,6 +18,12 @@ font-weight: normal; font-style: normal; } +@font-face { + font-family: "YS"; + src: url("../common/font/HYWenHei-55W.ttf"); + font-weight: normal; + font-style: normal; +} * { margin: 0;