mirror of
https://github.com/yoimiya-kokomi/miao-plugin.git
synced 2024-11-21 22:48:13 +00:00
底层数据结构变更
This commit is contained in:
parent
5f6669431a
commit
cf5b2253ba
@ -1,12 +1,14 @@
|
||||
import { Character, Avatar, MysApi } from '../../models/index.js'
|
||||
import { Cfg, Common, Profile } from '../../components/index.js'
|
||||
import { Character, Avatar, MysApi, Player } from '../../models/index.js'
|
||||
import { Cfg, Common } from '../../components/index.js'
|
||||
import lodash from 'lodash'
|
||||
import { segment } from 'oicq'
|
||||
import moment from 'moment'
|
||||
|
||||
export async function renderAvatar (e, avatar, renderType = 'card') {
|
||||
// 如果传递的是名字,则获取
|
||||
let uid = e.uid
|
||||
if (typeof (avatar) === 'string') {
|
||||
// 检查角色
|
||||
let char = Character.get(avatar)
|
||||
if (!char) {
|
||||
return false
|
||||
@ -17,21 +19,12 @@ export async function renderAvatar (e, avatar, renderType = 'card') {
|
||||
if (!char.isRelease) {
|
||||
avatar = { id: char.id, name: char.name, detail: false }
|
||||
} else {
|
||||
let profile = Profile.get(uid, char.id, true)
|
||||
if (profile && profile.hasData) {
|
||||
// 优先使用Profile数据
|
||||
avatar = profile
|
||||
} else {
|
||||
// 使用Mys数据兜底
|
||||
let charData = await mys.getCharacter()
|
||||
if (!charData) return true
|
||||
|
||||
let avatars = charData.avatars
|
||||
if (char.isTraveler) {
|
||||
char = await char.checkAvatars(avatars, uid)
|
||||
}
|
||||
avatars = lodash.keyBy(avatars, 'id')
|
||||
avatar = avatars[char.id] || { id: char.id, name: char.name, detail: false }
|
||||
let player = Player.create(e)
|
||||
await player.refreshMys()
|
||||
await player.refreshTalent(char.id)
|
||||
avatar = player.getAvatar(char.id)
|
||||
if (!avatar) {
|
||||
avatar = { id: char.id, name: char.name, detail: false }
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -39,8 +32,8 @@ export async function renderAvatar (e, avatar, renderType = 'card') {
|
||||
}
|
||||
|
||||
// 渲染角色卡片
|
||||
async function renderCard (e, ds, renderType = 'card') {
|
||||
let char = Character.get(ds)
|
||||
async function renderCard (e, avatar, renderType = 'card') {
|
||||
let char = Character.get(avatar.id)
|
||||
if (!char) {
|
||||
return false
|
||||
}
|
||||
@ -54,11 +47,13 @@ async function renderCard (e, ds, renderType = 'card') {
|
||||
let custom = char.isCustom
|
||||
let isRelease = char.isRelease
|
||||
if (isRelease) {
|
||||
let mys = await MysApi.init(e)
|
||||
let avatar = new Avatar(ds, uid, mys.isSelfCookie)
|
||||
data = avatar.getData('id,name,sName,level,fetter,cons,weapon,elem,artis,artisSet,imgs,dataSourceName,updateTime')
|
||||
data.talent = await avatar.getTalent(mys)
|
||||
if (data.talent) {
|
||||
data = avatar.getDetail()
|
||||
data.imgs = char.imgs
|
||||
data.source = avatar._source
|
||||
data.artis = avatar.getArtisDetail()
|
||||
data.updateTime = moment(new Date(avatar._time)).format('MM-DD HH:mm')
|
||||
if (data.hasTalent) {
|
||||
data.talent = avatar.talent
|
||||
data.talentMap = ['a', 'e', 'q']
|
||||
// 计算皇冠个数
|
||||
data.crownNum = lodash.filter(lodash.map(data.talent, (d) => d.original), (d) => d >= 10).length
|
||||
@ -66,6 +61,7 @@ async function renderCard (e, ds, renderType = 'card') {
|
||||
} else {
|
||||
data = char.getData('id,name,sName')
|
||||
}
|
||||
|
||||
let width = 600
|
||||
let imgCss = ''
|
||||
let scale = 1.2
|
||||
@ -92,33 +88,3 @@ async function renderCard (e, ds, renderType = 'card') {
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
export async function getAvatarList (e, type, mys) {
|
||||
let data = await mys.getCharacter()
|
||||
if (!data) return false
|
||||
|
||||
let avatars = data.avatars
|
||||
|
||||
if (!avatars || avatars.length <= 0) {
|
||||
return false
|
||||
}
|
||||
let list = []
|
||||
for (let val of avatars) {
|
||||
if (type !== false) {
|
||||
if (!Character.checkWifeType(val.id, type)) {
|
||||
continue
|
||||
}
|
||||
}
|
||||
if (val.rarity > 5) {
|
||||
val.rarity = 5
|
||||
}
|
||||
list.push(val)
|
||||
}
|
||||
|
||||
if (list.length <= 0) {
|
||||
return false
|
||||
}
|
||||
let sortKey = 'level,fetter,weapon_level,rarity,weapon_rarity,cons,weapon_affix_level'
|
||||
list = lodash.orderBy(list, sortKey, lodash.repeat('desc,', sortKey.length).split(','))
|
||||
return list
|
||||
}
|
||||
|
@ -1,8 +1,8 @@
|
||||
// #老婆
|
||||
import lodash from 'lodash'
|
||||
import { Common } from '../../components/index.js'
|
||||
import { Character, MysApi, AvatarList } from '../../models/index.js'
|
||||
import { getAvatarList, renderAvatar } from './AvatarCard.js'
|
||||
import { Character, MysApi, Player } from '../../models/index.js'
|
||||
import { renderAvatar } from './AvatarCard.js'
|
||||
|
||||
const relationMap = {
|
||||
wife: {
|
||||
@ -74,6 +74,7 @@ export async function wife (e) {
|
||||
if (!mys || !mys.uid) {
|
||||
return true
|
||||
}
|
||||
let player = Player.create(e)
|
||||
let selfUser = mys.selfUser
|
||||
let isSelf = true
|
||||
let renderType = (action === '卡片' ? 'card' : 'photo')
|
||||
@ -92,7 +93,7 @@ export async function wife (e) {
|
||||
if (wifeList && wifeList.length > 0 && isSelf && !e.isPoke) {
|
||||
if (wifeList[0] === '随机') {
|
||||
// 如果选择为全部,则从列表中随机选择一个
|
||||
avatarList = await getAvatarList(e, targetCfg.type, mys)
|
||||
avatarList = await getAvatarList(player, targetCfg.type, mys)
|
||||
let avatar = lodash.sample(avatarList)
|
||||
return renderAvatar(e, avatar, renderType)
|
||||
} else {
|
||||
@ -101,20 +102,12 @@ export async function wife (e) {
|
||||
}
|
||||
}
|
||||
}
|
||||
// 如果未指定过,则从列表中排序并随机选择前5个
|
||||
if (e.isPoke) {
|
||||
avatarList = await getAvatarList(e, false, mys)
|
||||
// 如果未指定过,则从列表中排序并随机选择
|
||||
avatarList = await getAvatarList(player, e.isPoke ? false : targetCfg.type, mys)
|
||||
if (avatarList && avatarList.length > 0) {
|
||||
avatar = lodash.sample(avatarList)
|
||||
return await renderAvatar(e, avatar, renderType)
|
||||
}
|
||||
} else {
|
||||
avatarList = await getAvatarList(e, targetCfg.type, mys)
|
||||
if (avatarList && avatarList.length > 0) {
|
||||
avatar = lodash.sample(avatarList.slice(0, 5))
|
||||
return await renderAvatar(e, avatar, renderType)
|
||||
}
|
||||
}
|
||||
e.reply('在当前米游社公开展示的角色中未能找到适合展示的角色..')
|
||||
return true
|
||||
case '设置':
|
||||
@ -169,3 +162,23 @@ export async function wife (e) {
|
||||
export async function pokeWife (e, components) {
|
||||
return await wife(e, components)
|
||||
}
|
||||
|
||||
async function getAvatarList (player, type, mys) {
|
||||
await player.refreshMys()
|
||||
let list = []
|
||||
player.forEachAvatar((avatar) => {
|
||||
if (type !== false) {
|
||||
if (!Character.checkWifeType(avatar.id, type)) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
list.push(avatar)
|
||||
})
|
||||
|
||||
if (list.length <= 0) {
|
||||
return false
|
||||
}
|
||||
let sortKey = 'level,fetter,weapon_level,rarity,weapon_rarity,cons,weapon_affix_level'
|
||||
list = lodash.orderBy(list, sortKey, lodash.repeat('desc,', sortKey.length).split(','))
|
||||
return list
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { Common, App, Data, Cfg } from '../components/index.js'
|
||||
import { Character } from '../models/index.js'
|
||||
import { Character, Player } from '../models/index.js'
|
||||
import { getTargetUid, getProfile, profileHelp } from './profile/ProfileCommon.js'
|
||||
import { profileArtis, profileArtisList } from './profile/ProfileArtis.js'
|
||||
import { renderProfile } from './profile/ProfileDetail.js'
|
||||
|
@ -3,9 +3,9 @@
|
||||
*
|
||||
* */
|
||||
import lodash from 'lodash'
|
||||
import { Cfg, Profile, Common } from '../../components/index.js'
|
||||
import { Cfg, Common } from '../../components/index.js'
|
||||
import { getTargetUid, profileHelp, autoGetProfile } from './ProfileCommon.js'
|
||||
import { Artifact, Character, ProfileArtis } from '../../models/index.js'
|
||||
import { Artifact, Character, ProfileArtis, Player } from '../../models/index.js'
|
||||
|
||||
/*
|
||||
* 角色圣遗物面板
|
||||
@ -64,14 +64,12 @@ export async function profileArtisList (e) {
|
||||
}
|
||||
|
||||
let artis = []
|
||||
let profiles = Profile.getAll(uid) || {}
|
||||
|
||||
if (!profiles || profiles.length === 0) {
|
||||
e.reply('暂无角色圣遗物详情')
|
||||
let player = Player.create(uid)
|
||||
player.forEachAvatar((avatar) => {
|
||||
let profile = avatar.getProfile()
|
||||
if (!profile) {
|
||||
return true
|
||||
}
|
||||
|
||||
lodash.forEach(profiles || [], (profile) => {
|
||||
let name = profile.name
|
||||
let char = Character.get(name)
|
||||
if (!profile.hasData || !profile.hasArtis()) {
|
||||
|
@ -2,8 +2,8 @@
|
||||
* 面板数据替换相关逻辑
|
||||
*/
|
||||
import lodash from 'lodash'
|
||||
import { Profile, Data } from '../../components/index.js'
|
||||
import { Character, ProfileData, Weapon } from '../../models/index.js'
|
||||
import { Data } from '../../components/index.js'
|
||||
import { Character, ProfileData, Weapon,Player } from '../../models/index.js'
|
||||
|
||||
const keyMap = {
|
||||
artis: '圣遗物',
|
||||
@ -153,8 +153,9 @@ const ProfileChange = {
|
||||
if (!charid) {
|
||||
return false
|
||||
}
|
||||
let player = Player.create(uid)
|
||||
|
||||
let source = Profile.get(uid, charid)
|
||||
let source = player.getProfile(charid)
|
||||
let dc = ds.char || {}
|
||||
if (!source || !source.hasData) {
|
||||
source = {}
|
||||
@ -168,7 +169,7 @@ const ProfileChange = {
|
||||
|
||||
let profiles = {}
|
||||
if (source && source.id) {
|
||||
profiles[`${source.uid}:${source.id}`] = source
|
||||
profiles[`${player.uid}:${source.id}`] = source
|
||||
}
|
||||
// 获取source
|
||||
let getSource = function (cfg) {
|
||||
@ -176,10 +177,11 @@ const ProfileChange = {
|
||||
return source
|
||||
}
|
||||
let cuid = cfg.uid || uid
|
||||
let cPlayer = Player.create(uid)
|
||||
let id = cfg.char || source.id
|
||||
let key = cuid + ':' + id
|
||||
if (!profiles[key]) {
|
||||
profiles[key] = Profile.get(cuid, id) || {}
|
||||
profiles[key] = cPlayer.getProfile(id) || {}
|
||||
}
|
||||
return profiles[key]?.id ? profiles[key] : source
|
||||
}
|
||||
|
@ -4,8 +4,8 @@
|
||||
import lodash from 'lodash'
|
||||
import { segment } from 'oicq'
|
||||
import { profileList } from './ProfileList.js'
|
||||
import { Profile, Version } from '../../components/index.js'
|
||||
import { Character, MysApi } from '../../models/index.js'
|
||||
import { Version } from '../../components/index.js'
|
||||
import { Character, MysApi, Player } from '../../models/index.js'
|
||||
|
||||
/*
|
||||
* 获取面板查询的 目标uid
|
||||
@ -87,7 +87,8 @@ export async function autoRefresh (e) {
|
||||
e.isRefreshed = true
|
||||
|
||||
// 数据更新
|
||||
let data = await Profile.request(uid, e)
|
||||
let player = Player.create(uid)
|
||||
let data = await player.refreshProfile(e)
|
||||
if (!data) {
|
||||
return false
|
||||
}
|
||||
@ -127,7 +128,7 @@ export async function autoGetProfile (e, uid, avatar, callback) {
|
||||
return { err: true }
|
||||
}
|
||||
|
||||
let profile = Profile.get(uid, char.id)
|
||||
let profile = Player.getAvatar(uid, char.id)
|
||||
if (!profile || !profile.hasData) {
|
||||
if (await refresh()) {
|
||||
return { err: true }
|
||||
@ -155,17 +156,18 @@ export async function getProfile (e) {
|
||||
}
|
||||
|
||||
// 数据更新
|
||||
let data = await Profile.request(uid, e)
|
||||
if (!data) {
|
||||
let player = Player.create(uid)
|
||||
let ret = await player.refreshProfile(e)
|
||||
if (!ret) {
|
||||
return true
|
||||
}
|
||||
|
||||
if (!data.chars) {
|
||||
if (!player._update.length === 0) {
|
||||
e.reply('获取角色面板数据失败,请确认角色已在游戏内橱窗展示,并开放了查看详情。设置完毕后请5分钟后再进行请求~')
|
||||
} else {
|
||||
let ret = {}
|
||||
lodash.forEach(data.chars, (ds) => {
|
||||
let char = Character.get(ds.id)
|
||||
lodash.forEach(player._update, (id) => {
|
||||
let char = Character.get(id)
|
||||
if (char) {
|
||||
ret[char.name] = true
|
||||
}
|
||||
@ -180,41 +182,6 @@ export async function getProfile (e) {
|
||||
return true
|
||||
}
|
||||
|
||||
/*
|
||||
* 获取面板列表
|
||||
* */
|
||||
export async function getProfileAll (e) {
|
||||
let uid = await getTargetUid(e)
|
||||
if (!uid) {
|
||||
return true
|
||||
}
|
||||
|
||||
let profiles = Profile.getAll(uid) || {}
|
||||
|
||||
let chars = []
|
||||
lodash.forEach(profiles || [], (ds) => {
|
||||
if (!['enka', 'miao'].includes(ds.dataSource)) {
|
||||
return true
|
||||
}
|
||||
ds.name && chars.push(ds.name)
|
||||
})
|
||||
|
||||
if (chars.length === 0) {
|
||||
if (await autoRefresh(e)) {
|
||||
await getProfileAll(e)
|
||||
return true
|
||||
} else {
|
||||
e.reply('尚未获取任何角色数据')
|
||||
await profileHelp(e)
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
e.reply(`uid${uid} 已获取面板角色: ` + chars.join(', '))
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
/*
|
||||
* 面板帮助
|
||||
* */
|
||||
|
@ -1,7 +1,7 @@
|
||||
import lodash from 'lodash'
|
||||
import { autoRefresh } from './ProfileCommon.js'
|
||||
import { Common, Format, Profile } from '../../components/index.js'
|
||||
import { MysApi, Avatar, ProfileRank, ProfileArtis } from '../../models/index.js'
|
||||
import { Common, Format } from '../../components/index.js'
|
||||
import { MysApi, Avatar, ProfileRank, ProfileArtis, Player } from '../../models/index.js'
|
||||
|
||||
export async function renderProfile (e, char, mode = 'profile', params = {}) {
|
||||
let selfUser = await MysApi.initUser(e)
|
||||
@ -18,7 +18,8 @@ export async function renderProfile (e, char, mode = 'profile', params = {}) {
|
||||
return true
|
||||
}
|
||||
|
||||
let profile = e._profile || Profile.get(uid, char.id)
|
||||
let player = Player.create(uid)
|
||||
let profile = e._profile || player.getProfile(char.id)
|
||||
|
||||
let refresh = async () => {
|
||||
let refreshRet = await autoRefresh(e)
|
||||
@ -116,7 +117,7 @@ export async function renderProfile (e, char, mode = 'profile', params = {}) {
|
||||
bodyClass: `char-${char.name}`,
|
||||
mode,
|
||||
changeProfile: e._profileMsg
|
||||
}, { e, scale: 1.6,retMsgId: true })
|
||||
}, { e, scale: 1.6, retMsgId: true })
|
||||
if (msgRes && msgRes.message_id) {
|
||||
// 如果消息发送成功,就将message_id和图片路径存起来,3小时过期
|
||||
await redis.set(`miao:original-picture:${msgRes.message_id}`, imgs.splash0, { EX: 3600 * 3 })
|
||||
|
@ -1,7 +1,7 @@
|
||||
import lodash from 'lodash'
|
||||
import { autoRefresh, getTargetUid } from './ProfileCommon.js'
|
||||
import { ProfileRank } from '../../models/index.js'
|
||||
import { Common, Profile, Data } from '../../components/index.js'
|
||||
import { ProfileRank, Player } from '../../models/index.js'
|
||||
import { Common, Data } from '../../components/index.js'
|
||||
|
||||
export async function profileList (e) {
|
||||
let uid = await getTargetUid(e)
|
||||
@ -14,7 +14,7 @@ export async function profileList (e) {
|
||||
isSelfUid = uids.join(',').split(',').includes(uid + '')
|
||||
}
|
||||
let rank = false
|
||||
let servName = Profile.getServName(uid)
|
||||
let servName = Player.getProfileServName(uid)
|
||||
let hasNew = false
|
||||
let newCount = 0
|
||||
|
||||
@ -27,7 +27,8 @@ export async function profileList (e) {
|
||||
}
|
||||
const cfg = await Data.importCfg('cfg')
|
||||
// 获取面板数据
|
||||
let profiles = Profile.getAll(uid)
|
||||
let player = Player.create(uid)
|
||||
let profiles = player.getProfiles()
|
||||
// 检测标志位
|
||||
let qq = (e.at && !e.atBot) ? e.at : e.qq
|
||||
await ProfileRank.setUidInfo({ uid, profiles, qq, uidType: isSelfUid ? 'ck' : 'bind' })
|
||||
@ -38,8 +39,9 @@ export async function profileList (e) {
|
||||
}
|
||||
const rankCfg = await ProfileRank.getGroupCfg(groupId)
|
||||
const groupRank = rank && (cfg?.diyCfg?.groupRank || false) && rankCfg.status !== 1
|
||||
await Profile.forEach(uid, async function (profile) {
|
||||
if (!profile.hasData) {
|
||||
await player.forEachAvatarAsync(async function (avatar) {
|
||||
let profile = avatar.getProfile()
|
||||
if (!profile) {
|
||||
return true
|
||||
}
|
||||
let char = profile.char
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { Character, ProfileRank, ProfileDmg, Avatar } from '../../models/index.js'
|
||||
import { Character, ProfileRank, ProfileDmg, Avatar, Player } from '../../models/index.js'
|
||||
import { renderProfile } from './ProfileDetail.js'
|
||||
import { Data, Profile, Common, Format } from '../../components/index.js'
|
||||
import { Data, Common, Format } from '../../components/index.js'
|
||||
import lodash from 'lodash'
|
||||
|
||||
export async function groupRank (e) {
|
||||
@ -115,7 +115,8 @@ export async function refreshRank (e) {
|
||||
let count = 0
|
||||
for (let qq in groupUids) {
|
||||
for (let { uid, type } of groupUids[qq]) {
|
||||
let profiles = Profile.getAll(uid)
|
||||
let player = new Player(uid)
|
||||
let profiles = player.getProfiles()
|
||||
// 刷新rankLimit
|
||||
await ProfileRank.setUidInfo({ uid, profiles, qq, uidType: type })
|
||||
let rank = await ProfileRank.create({ groupId, uid, qq })
|
||||
@ -156,13 +157,14 @@ async function renderCharRankList ({ e, uids, char, mode, groupId }) {
|
||||
let list = []
|
||||
for (let ds of uids) {
|
||||
let uid = ds.uid || ds.value
|
||||
let profile = Profile.get(uid, ds.charId || char.id)
|
||||
let player = Player.create(uid)
|
||||
let avatar = player.getAvatar(ds.charId || char.id)
|
||||
let profile = avatar.getProfile()
|
||||
|
||||
if (profile) {
|
||||
let profileRank = await ProfileRank.create({ groupId, uid })
|
||||
let data = await profileRank.getRank(profile, true)
|
||||
let mark = data?.mark?.data
|
||||
let avatar = new Avatar(profile, uid)
|
||||
let tmp = {
|
||||
uid,
|
||||
isMax: !char,
|
||||
|
@ -1,41 +1,52 @@
|
||||
import lodash from 'lodash'
|
||||
import {Cfg, Common, Data } from '../../components/index.js'
|
||||
import { AvatarList, ProfileRank } from '../../models/index.js'
|
||||
import { Cfg, Common, Data } from '../../components/index.js'
|
||||
import { MysApi, ProfileRank, Player } from '../../models/index.js'
|
||||
|
||||
export async function profileStat (e) {
|
||||
let isMatch = /^#(面板|喵喵|角色|武器|天赋|技能|圣遗物)练度统计?$/.test(e.original_msg || e.msg || '')
|
||||
if (!Cfg.get('profileStat', false) && !isMatch) {
|
||||
return false
|
||||
}
|
||||
// 缓存时间,单位小时
|
||||
}
|
||||
|
||||
// 缓存时间,单位小时
|
||||
let msg = e.msg.replace('#', '').trim()
|
||||
if (msg === '角色统计' || msg === '武器统计') {
|
||||
// 暂时避让一下抽卡分析的关键词
|
||||
return false
|
||||
}
|
||||
|
||||
let avatars = await AvatarList.getAll(e)
|
||||
if (!avatars) {
|
||||
return true
|
||||
}
|
||||
let uid = avatars.uid
|
||||
let mys = await MysApi.init(e)
|
||||
if (!mys || !mys.uid) return false
|
||||
|
||||
const uid = mys.uid
|
||||
|
||||
let player = Player.create(e)
|
||||
// 更新角色信息
|
||||
await player.refreshMys()
|
||||
|
||||
// 更新天赋信息
|
||||
await player.refreshTalent()
|
||||
|
||||
let rank = false
|
||||
if (e.group_id) {
|
||||
rank = await ProfileRank.create({ group: e.group_id, uid, qq: e.user_id })
|
||||
}
|
||||
let talentData = await avatars.getTalentData()
|
||||
// 天赋等级背景
|
||||
|
||||
let avatarRet = []
|
||||
lodash.forEach(talentData, (avatar) => {
|
||||
let { talent, id } = avatar
|
||||
avatar.aeq = talent?.a?.original + talent?.e?.original + talent?.q?.original || 3
|
||||
avatarRet.push(avatar)
|
||||
let profile = avatars.getProfile(id)
|
||||
player.forEachAvatar((avatar) => {
|
||||
let { talent } = avatar
|
||||
let ds = avatar.getDetail()
|
||||
ds.aeq = talent?.a?.original + talent?.e?.original + talent?.q?.original || 3
|
||||
avatarRet.push(ds)
|
||||
|
||||
let profile = avatar.getProfile()
|
||||
if (!profile) {
|
||||
return true
|
||||
}
|
||||
if (profile) {
|
||||
if (profile.hasData) {
|
||||
let mark = profile.getArtisMark(false)
|
||||
avatar.artisMark = Data.getData(mark, 'mark,markClass,names')
|
||||
ds.artisMark = Data.getData(mark, 'mark,markClass,names')
|
||||
if (rank) {
|
||||
rank.getRank(profile)
|
||||
}
|
||||
@ -47,9 +58,6 @@ export async function profileStat (e) {
|
||||
avatarRet = lodash.orderBy(avatarRet, sortKey)
|
||||
avatarRet = avatarRet.reverse()
|
||||
let talentNotice = ''
|
||||
if (!avatars.isSelfCookie || avatarRet.length <= 8) {
|
||||
talentNotice = '未绑定CK,信息可能展示不完全。回复<span>#体力帮助</span>获取CK配置帮助'
|
||||
}
|
||||
|
||||
return await Common.render('character/profile-stat', {
|
||||
save_id: uid,
|
||||
|
29
apps/stat.js
29
apps/stat.js
@ -4,7 +4,7 @@
|
||||
* */
|
||||
import lodash from 'lodash'
|
||||
import { Cfg, Common, App, Data } from '../components/index.js'
|
||||
import { Abyss, AvatarList, Character, MysApi } from '../models/index.js'
|
||||
import { Abyss, Character, MysApi, Player } from '../models/index.js'
|
||||
import HutaoApi from './wiki/HutaoApi.js'
|
||||
|
||||
let app = App.init({
|
||||
@ -195,6 +195,9 @@ async function abyssTeam (e) {
|
||||
if (!mys || !mys.uid || !mys.isSelfCookie) {
|
||||
return true
|
||||
}
|
||||
let player = Player.create(e)
|
||||
await player.refreshMys()
|
||||
await player.refreshTalent()
|
||||
|
||||
let abyssData = await HutaoApi.getAbyssTeam()
|
||||
if (!abyssData || !abyssData.data) {
|
||||
@ -202,18 +205,7 @@ async function abyssTeam (e) {
|
||||
return true
|
||||
}
|
||||
abyssData = abyssData.data
|
||||
let avatars
|
||||
try {
|
||||
avatars = await AvatarList.getAll(e, mys)
|
||||
// resDetail = await mys.getCharacter()
|
||||
if (!avatars) {
|
||||
e.reply('角色信息获取失败')
|
||||
return true
|
||||
}
|
||||
} catch (err) {
|
||||
// console.log(err);
|
||||
}
|
||||
let avatarData = await avatars.getTalentData()
|
||||
let avatarData = player.getAvatarData()
|
||||
let avatarRet = {}
|
||||
let data = {}
|
||||
let noAvatar = {}
|
||||
@ -397,6 +389,7 @@ async function uploadData (e) {
|
||||
}
|
||||
let ret = {}
|
||||
let uid = mys.uid
|
||||
let player = Player.create(e)
|
||||
let resDetail, resAbyss
|
||||
try {
|
||||
resAbyss = await mys.getSpiralAbyss(1)
|
||||
@ -413,9 +406,6 @@ async function uploadData (e) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
if (resAbyss.floors.length > 0 && !await AvatarList.hasTalentCache(uid)) {
|
||||
e.reply('正在获取用户信息,请稍候...')
|
||||
}
|
||||
resDetail = await mys.getCharacter()
|
||||
if (!resDetail || !resAbyss || !resDetail.avatars || resDetail.avatars.length <= 3) {
|
||||
e.reply('角色信息获取失败')
|
||||
@ -431,6 +421,9 @@ async function uploadData (e) {
|
||||
} catch (err) {
|
||||
// console.log(err);
|
||||
}
|
||||
// 更新player信息
|
||||
player.setMysCharData(resDetail)
|
||||
|
||||
if (ret && ret.retcode === 0) {
|
||||
let stat = []
|
||||
if (ret.data) {
|
||||
@ -440,7 +433,6 @@ async function uploadData (e) {
|
||||
}
|
||||
let abyss = new Abyss(resAbyss)
|
||||
let abyssData = abyss.getData()
|
||||
let avatars = new AvatarList(uid, resDetail.avatars)
|
||||
let avatarIds = abyss.getAvatars()
|
||||
let overview = ret.info || (await HutaoApi.getOverview())?.data || {}
|
||||
let addMsg = function (title, ds) {
|
||||
@ -484,7 +476,8 @@ async function uploadData (e) {
|
||||
}
|
||||
addMsg('最强一击', ret.data?.damage || abyssData?.stat?.dmg || {})
|
||||
addMsg('最高承伤', ret.data?.takeDamage || abyssData?.stat.takeDmg || {})
|
||||
let avatarData = await avatars.getTalentData(avatarIds, mys)
|
||||
await player.refreshTalent(avatarIds)
|
||||
let avatarData = player.getAvatarData(avatarIds)
|
||||
return await Common.render('stat/abyss-summary', {
|
||||
abyss: abyssData,
|
||||
avatars: avatarData,
|
||||
|
@ -1,129 +0,0 @@
|
||||
import fs from 'fs'
|
||||
import lodash from 'lodash'
|
||||
import { Character, ProfileReq, ProfileData } from '../models/index.js'
|
||||
import Miao from './profile-data/miao.js'
|
||||
import Enka from './profile-data/enka.js'
|
||||
|
||||
const _path = process.cwd()
|
||||
const userPath = `${_path}/data/UserData/`
|
||||
if (!fs.existsSync(userPath)) {
|
||||
fs.mkdirSync(userPath)
|
||||
}
|
||||
|
||||
ProfileReq.regServ({ Miao, Enka })
|
||||
|
||||
let Profile = {
|
||||
async request (uid, e) {
|
||||
if (uid.toString().length !== 9) {
|
||||
return false
|
||||
}
|
||||
let req = new ProfileReq({ e, uid })
|
||||
let data
|
||||
try {
|
||||
data = await req.request()
|
||||
if (!data) {
|
||||
return false
|
||||
}
|
||||
return Profile.save(uid, data)
|
||||
} catch (err) {
|
||||
console.log(err)
|
||||
e.reply('请求失败')
|
||||
return false
|
||||
}
|
||||
},
|
||||
|
||||
save (uid, data) {
|
||||
let userData = {}
|
||||
const userFile = `${userPath}/${uid}.json`
|
||||
if (fs.existsSync(userFile)) {
|
||||
try {
|
||||
userData = JSON.parse(fs.readFileSync(userFile, 'utf8')) || {}
|
||||
} catch (e) {
|
||||
userData = {}
|
||||
}
|
||||
}
|
||||
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 data
|
||||
},
|
||||
|
||||
_get (uid, charId) {
|
||||
const userFile = `${userPath}/${uid}.json`
|
||||
let userData = {}
|
||||
if (fs.existsSync(userFile)) {
|
||||
try {
|
||||
userData = JSON.parse(fs.readFileSync(userFile, 'utf8')) || {}
|
||||
} catch (e) {
|
||||
}
|
||||
}
|
||||
if (userData && userData.chars) {
|
||||
let char = Character.get(charId)
|
||||
if (char.isTraveler) {
|
||||
let charData = userData.chars['10000005'] || userData.chars['10000007'] || false
|
||||
if (charData) {
|
||||
char.checkAvatars(charData, uid)
|
||||
}
|
||||
return charData
|
||||
} else {
|
||||
return userData.chars[charId]
|
||||
}
|
||||
}
|
||||
return false
|
||||
},
|
||||
|
||||
get (uid, charId, onlyHasData = false) {
|
||||
let data = Profile._get(uid, charId)
|
||||
if (data) {
|
||||
let profile = new ProfileData(data, uid)
|
||||
if (onlyHasData && !profile.hasData) {
|
||||
return false
|
||||
}
|
||||
return profile
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
},
|
||||
|
||||
getAll (uid) {
|
||||
const userFile = `${userPath}/${uid}.json`
|
||||
let userData = {}
|
||||
if (fs.existsSync(userFile)) {
|
||||
try {
|
||||
userData = JSON.parse(fs.readFileSync(userFile, 'utf8')) || {}
|
||||
} catch (e) {
|
||||
userData = {}
|
||||
}
|
||||
}
|
||||
if (userData && userData.chars) {
|
||||
let ret = {}
|
||||
lodash.forEach(userData.chars, (ds, id) => {
|
||||
let profile = new ProfileData(ds, uid)
|
||||
if (profile.hasData) {
|
||||
ret[id] = profile
|
||||
}
|
||||
})
|
||||
return ret
|
||||
}
|
||||
return false
|
||||
},
|
||||
|
||||
async forEach (uid, fn) {
|
||||
let profiles = Profile.getAll(uid)
|
||||
for (let id in profiles) {
|
||||
let ret = await fn(profiles[id], id)
|
||||
if (ret === false) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
getServName (uid) {
|
||||
let Serv = ProfileReq.getServ(uid)
|
||||
return Serv.name
|
||||
}
|
||||
}
|
||||
export default Profile
|
@ -3,7 +3,6 @@ import Format from './Format.js'
|
||||
import Common from './Common.js'
|
||||
import Cfg from './Cfg.js'
|
||||
import Version from './Version.js'
|
||||
import Profile from './Profile.js'
|
||||
import App from './App.js'
|
||||
|
||||
export { Data, Cfg, Format, Common, Version, Profile, App }
|
||||
export { Data, Cfg, Format, Common, Version, App }
|
||||
|
@ -1,48 +0,0 @@
|
||||
import { Data } from '../index.js'
|
||||
import lodash from 'lodash'
|
||||
|
||||
const _path = process.cwd()
|
||||
|
||||
export const artiIdx = {
|
||||
生之花: 1,
|
||||
死之羽: 2,
|
||||
时之沙: 3,
|
||||
空之杯: 4,
|
||||
理之冠: 5
|
||||
}
|
||||
|
||||
let relis = Data.readJSON('resources/meta/artifact/data.json')
|
||||
let setMap = {}
|
||||
|
||||
lodash.forEach(relis, (ds) => {
|
||||
if (ds.sets) {
|
||||
lodash.forEach(ds.sets, (tmp) => {
|
||||
if (tmp.name) {
|
||||
setMap[tmp.name] = ds.name
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
export const artiSetMap = setMap
|
||||
|
||||
export const attrMap = {
|
||||
HP: '小生命',
|
||||
HP_PERCENT: '大生命',
|
||||
ATTACK: '小攻击',
|
||||
ATTACK_PERCENT: '大攻击',
|
||||
DEFENSE: '小防御',
|
||||
DEFENSE_PERCENT: '大防御',
|
||||
FIRE_ADD_HURT: '火元素伤害加成',
|
||||
ICE_ADD_HURT: '冰元素伤害加成',
|
||||
ROCK_ADD_HURT: '岩元素伤害加成',
|
||||
ELEC_ADD_HURT: '雷元素伤害加成',
|
||||
WIND_ADD_HURT: '风元素伤害加成',
|
||||
WATER_ADD_HURT: '水元素伤害加成',
|
||||
PHYSICAL_ADD_HURT: '物理伤害加成',
|
||||
GRASS_ADD_HURT: '草元素伤害加成',
|
||||
HEAL_ADD: '治疗加成',
|
||||
ELEMENT_MASTERY: '元素精通',
|
||||
CRITICAL: '暴击率',
|
||||
CRITICAL_HURT: '暴击伤害',
|
||||
CHARGE_EFFICIENCY: '充能效率'
|
||||
}
|
@ -1,203 +0,0 @@
|
||||
import lodash from 'lodash'
|
||||
import Character from '../models/Character.js'
|
||||
|
||||
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 posIdx = {
|
||||
生之花: {
|
||||
idx: 1
|
||||
},
|
||||
死之羽: {
|
||||
idx: 2
|
||||
},
|
||||
时之沙: {
|
||||
idx: 3
|
||||
},
|
||||
空之杯: {
|
||||
idx: 4
|
||||
},
|
||||
理之冠: {
|
||||
idx: 5
|
||||
}
|
||||
}
|
||||
|
||||
let Data = {
|
||||
getData (uid, data) {
|
||||
let ret = {
|
||||
uid,
|
||||
chars: {}
|
||||
}
|
||||
|
||||
lodash.forEach({
|
||||
name: '角色名称',
|
||||
avatar: '头像ID',
|
||||
level: '冒险等阶'
|
||||
}, (title, key) => {
|
||||
ret[key] = data[title] || ''
|
||||
})
|
||||
|
||||
lodash.forEach(data.items, (ds) => {
|
||||
let char = Data.getAvatar(ds)
|
||||
ret.chars[char.id] = char
|
||||
})
|
||||
|
||||
return ret
|
||||
},
|
||||
getAvatar (data) {
|
||||
let char = Character.get(data['英雄Id'])
|
||||
return {
|
||||
id: data['英雄Id'],
|
||||
name: char ? char.name : '',
|
||||
level: 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)
|
||||
ret.phyBonus = (data['属性物理伤害加成'] * 100).toFixed(2)
|
||||
|
||||
return ret
|
||||
},
|
||||
getWeapon (data) {
|
||||
return {
|
||||
name: data['武器名称'],
|
||||
level: 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]; let 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
|
||||
}
|
||||
}
|
@ -4,8 +4,7 @@
|
||||
* */
|
||||
import Base from './Base.js'
|
||||
import lodash from 'lodash'
|
||||
import { Profile } from '../components/index.js'
|
||||
import { Artifact, Character, Weapon, ArtifactSet } from './index.js'
|
||||
import { Artifact, Character, Weapon, ArtifactSet, Player } from './index.js'
|
||||
import moment from 'moment'
|
||||
|
||||
const charKey = 'name,abbr,sName,star,imgs,face,side,gacha,weaponTypeName,elem'.split(',')
|
||||
@ -34,7 +33,7 @@ export default class Avatar extends Base {
|
||||
profile = pd
|
||||
} else if (/\d{9}/.test(pd)) {
|
||||
uid = pd
|
||||
profile = Profile.get(pd, char.id, true)
|
||||
profile = Player.getAvatar(pd, char.id, true)
|
||||
}
|
||||
}
|
||||
if (profile && profile.isProfile && profile.hasData) {
|
||||
|
257
models/AvatarArtis.js
Normal file
257
models/AvatarArtis.js
Normal file
@ -0,0 +1,257 @@
|
||||
/**
|
||||
* 面板圣遗物
|
||||
*/
|
||||
import lodash from 'lodash'
|
||||
import Base from './Base.js'
|
||||
import { Artifact, ArtifactSet } from './index.js'
|
||||
import { Format, Data } from '../components/index.js'
|
||||
import ArtisMark from './profile-lib/ArtisMark.js'
|
||||
|
||||
export default class AvatarArtis extends Base {
|
||||
constructor (charid = 0) {
|
||||
super()
|
||||
this.charid = charid
|
||||
this.artis = {}
|
||||
}
|
||||
|
||||
static isProfileArtis (ds) {
|
||||
let ret = true
|
||||
for (let idx = 1; idx <= 5; idx++) {
|
||||
if (ds[idx]) {
|
||||
if (!ds[idx].main || !ds[idx].attrs) {
|
||||
ret = false
|
||||
return ret
|
||||
}
|
||||
}
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
setArtisData (ds = {}, dataSource) {
|
||||
if (!this.hasArtis || AvatarArtis.isProfileArtis(ds) || !AvatarArtis.isProfileArtis(this.artis)) {
|
||||
for (let idx = 1; idx <= 5; idx++) {
|
||||
if (ds[idx]) {
|
||||
this.setArtis(idx, ds[idx] || {})
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
setArtis (idx = 1, ds = {}) {
|
||||
idx = idx.toString().replace('arti', '')
|
||||
let ret = {}
|
||||
ret.name = ds.name || ArtifactSet.getArtiNameBySet(ds.set, idx) || ''
|
||||
ret.set = ds.set || Artifact.getSetNameByArti(ret.name) || ''
|
||||
ret.level = ds.level || 1
|
||||
if (ds.main && ds.attrs) {
|
||||
ret.main = ArtisMark.formatAttr(ds.main || {})
|
||||
ret.attrs = []
|
||||
for (let attrIdx in ds.attrs || []) {
|
||||
if (ds.attrs[attrIdx]) {
|
||||
ret.attrs.push(ArtisMark.formatAttr(ds.attrs[attrIdx]))
|
||||
}
|
||||
}
|
||||
}
|
||||
this.artis[idx] = ret
|
||||
}
|
||||
|
||||
forEach (fn) {
|
||||
lodash.forEach(this.artis, (ds, idx) => {
|
||||
if (ds.name) {
|
||||
fn(ds, idx)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
_get (key) {
|
||||
let artis = this.artis
|
||||
switch (key) {
|
||||
case 'length':
|
||||
return lodash.keys(artis).length
|
||||
}
|
||||
if (artis[key]) {
|
||||
return artis[key]
|
||||
}
|
||||
}
|
||||
|
||||
toJSON () {
|
||||
let ret = {}
|
||||
for (let idx = 1; idx <= 5; idx++) {
|
||||
let ds = this.artis[idx]
|
||||
if (ds) {
|
||||
let tmp = {
|
||||
name: ds.name || '',
|
||||
level: ds.level || 1
|
||||
}
|
||||
if (ds.main && ds.attrs) {
|
||||
tmp.main = ds.main || null
|
||||
tmp.attrs = []
|
||||
for (let attrIdx in ds.attrs || []) {
|
||||
if (ds.attrs[attrIdx]) {
|
||||
tmp.attrs.push(ArtisMark.formatAttr(ds.attrs[attrIdx]))
|
||||
}
|
||||
}
|
||||
}
|
||||
ret[idx] = tmp
|
||||
}
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
getDetail () {
|
||||
let ret = {}
|
||||
for (let idx = 1; idx <= 5; idx++) {
|
||||
let ds = this.artis[idx]
|
||||
if (ds) {
|
||||
let artis = Artifact.get(ds.name)
|
||||
let tmp = {
|
||||
...artis?.getData('img,name,set'),
|
||||
level: ds.level || 1
|
||||
}
|
||||
if (ds.main && ds.attrs) {
|
||||
tmp.main = ds.main || null
|
||||
tmp.attrs = []
|
||||
for (let attrIdx in ds.attrs || []) {
|
||||
if (ds.attrs[attrIdx]) {
|
||||
tmp.attrs.push(ArtisMark.formatAttr(ds.attrs[attrIdx]))
|
||||
}
|
||||
}
|
||||
}
|
||||
ret[idx] = tmp
|
||||
}
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
get sets () {
|
||||
return this.getSetData().sets || {}
|
||||
}
|
||||
|
||||
get names () {
|
||||
return this.getSetData().names || []
|
||||
}
|
||||
|
||||
get hasArtis () {
|
||||
return !lodash.isEmpty(this.artis)
|
||||
}
|
||||
|
||||
mainAttr (idx = '') {
|
||||
if (!idx) {
|
||||
let ret = {}
|
||||
for (let i = 1; i <= 5; i++) {
|
||||
ret[i] = this.mainAttr(i)
|
||||
}
|
||||
return ret
|
||||
}
|
||||
let main = this.artis[idx]?.main
|
||||
if (!main) {
|
||||
return ''
|
||||
}
|
||||
return main.key || ''
|
||||
}
|
||||
|
||||
is (check, pos = '') {
|
||||
if (pos) {
|
||||
return this.isAttr(check, pos)
|
||||
}
|
||||
let sets = this.getSetData()?.abbrs || []
|
||||
let ret = false
|
||||
Data.eachStr(check, (s) => {
|
||||
if (sets.includes(s)) {
|
||||
ret = true
|
||||
return false
|
||||
}
|
||||
})
|
||||
return ret
|
||||
}
|
||||
|
||||
isAttr (attr, pos = '3,4,5') {
|
||||
let mainAttr = this.mainAttr()
|
||||
let check = true
|
||||
Data.eachStr(pos.toString(), (p) => {
|
||||
let attrs = attr.split(',')
|
||||
if (!attrs.includes(mainAttr[p]) && (p === '4' && !attrs.includes('dmg') && Format.isElem(mainAttr[p]))) {
|
||||
check = false
|
||||
return false
|
||||
}
|
||||
})
|
||||
return check
|
||||
}
|
||||
|
||||
// 获取圣遗物数据
|
||||
getArtisData () {
|
||||
let ret = {}
|
||||
this.forEach((ds, idx) => {
|
||||
let arti = Artifact.get(ds.name)
|
||||
ret[idx] = {
|
||||
...ds,
|
||||
name: arti.name,
|
||||
img: arti.img
|
||||
}
|
||||
})
|
||||
return ret
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取圣遗物套装数据
|
||||
* @returns {*|{imgs: *[], names: *[], sets: {}, abbrs: *[], sName: string, name: (string|*)}}
|
||||
* sets: 套装名:2/4
|
||||
* names: [套装名]
|
||||
* imgs: [img]
|
||||
* abbrs:[别名]
|
||||
* name: '组合名字', 若为4件套会使用套装完整名
|
||||
* sName: '简写名字',若为4件套也会使用简写
|
||||
*/
|
||||
geSetData () {
|
||||
let setCount = {}
|
||||
this.forEach((arti, idx) => {
|
||||
setCount[arti.set] = (setCount[arti.set] || 0) + 1
|
||||
})
|
||||
let sets = {}
|
||||
let names = []
|
||||
let imgs = []
|
||||
let abbrs = []
|
||||
let abbrs2 = []
|
||||
for (let set in setCount) {
|
||||
if (setCount[set] >= 2) {
|
||||
let count = setCount[set] >= 4 ? 4 : 2
|
||||
sets[set] = count
|
||||
let artiSet = ArtifactSet.get(set)
|
||||
names.push(artiSet.name)
|
||||
imgs.push(artiSet.img)
|
||||
abbrs.push(artiSet.abbr + count)
|
||||
abbrs2.push(artiSet.name + count)
|
||||
}
|
||||
}
|
||||
return {
|
||||
sets,
|
||||
names,
|
||||
imgs,
|
||||
abbrs: [...abbrs, ...abbrs2],
|
||||
name: (abbrs.length > 1 || abbrs2[0]?.length > 7) ? abbrs.join('+') : abbrs2[0],
|
||||
sName: abbrs.join('+')
|
||||
}
|
||||
}
|
||||
|
||||
static _eachArtisSet (sets, fn) {
|
||||
lodash.forEach(sets || [], (v, k) => {
|
||||
let artisSet = ArtifactSet.get(k)
|
||||
if (artisSet) {
|
||||
if (v >= 4) {
|
||||
fn(artisSet, 2)
|
||||
}
|
||||
fn(artisSet, v)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
eachArtisSet (fn) {
|
||||
AvatarArtis._eachArtisSet(this.sets, fn)
|
||||
}
|
||||
|
||||
static getArtisKeyTitle () {
|
||||
return ArtisMark.getKeyTitleMap()
|
||||
}
|
||||
}
|
244
models/AvatarData.js
Normal file
244
models/AvatarData.js
Normal file
@ -0,0 +1,244 @@
|
||||
import lodash from 'lodash'
|
||||
import Base from './Base.js'
|
||||
import moment from 'moment'
|
||||
import { Character, AvatarArtis, ProfileData, Weapon } from './index.js'
|
||||
import { Data } from '../components/index.js'
|
||||
import AttrCalc from './profile-lib/AttrCalc.js'
|
||||
|
||||
const charKey = 'name,abbr,sName,star,imgs,face,side,gacha,weaponTypeName'.split(',')
|
||||
|
||||
export default class AvatarData extends Base {
|
||||
constructor (ds = {}, dataSource) {
|
||||
super()
|
||||
let char = Character.get({ id: ds.id, elem: ds.elem })
|
||||
if (!char) {
|
||||
return false
|
||||
}
|
||||
this.id = char.id
|
||||
this.char = char
|
||||
this.artis = new AvatarArtis(this.id)
|
||||
this.setAvatar(ds, dataSource)
|
||||
}
|
||||
|
||||
static create (ds, dataSource) {
|
||||
let avatar = new AvatarData(ds)
|
||||
if (!avatar) {
|
||||
return false
|
||||
}
|
||||
return avatar
|
||||
}
|
||||
|
||||
_get (key) {
|
||||
if (charKey.includes(key)) {
|
||||
return this.char[key]
|
||||
}
|
||||
}
|
||||
|
||||
setAvatar (ds, source = '') {
|
||||
this._now = new Date() * 1
|
||||
this.setBasic(ds, source)
|
||||
ds.weapon && this.setWeapon(ds.weapon)
|
||||
ds.talent && this.setTalent(ds.talent, source)
|
||||
ds.artis && this.setArtis(ds)
|
||||
delete this._now
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置角色基础数据
|
||||
* @param ds
|
||||
* @param source
|
||||
*/
|
||||
setBasic (ds = {}, source = '') {
|
||||
const now = this._now || (new Date()) * 1
|
||||
this.level = ds.lv || ds.level || this.level || 1
|
||||
this.cons = ds.cons || this.cons || 0
|
||||
this.fetter = ds.fetter || this.fetter || 0
|
||||
this._costume = ds.costume || this._costume || 0
|
||||
this.elem = ds.elem || this.elem || this.char.elem || ''
|
||||
this.promote = lodash.isUndefined(ds.promote) ? (this.promote || AttrCalc.calcPromote(this.level)) : (ds.promote || 0)
|
||||
|
||||
this._source = ds._source || ds.dataSource || this._source || ''
|
||||
this._time = ds._time || this._time || now
|
||||
this._update = ds._update || this._update || ds._time || now
|
||||
this._talent = ds._talent || this._talent || ds._time || now
|
||||
// 存在数据源时更新时间
|
||||
if (source) {
|
||||
this._update = now
|
||||
if (source !== 'mys') {
|
||||
this._source = source
|
||||
this._time = now
|
||||
} else {
|
||||
this._source = this._source || source
|
||||
this._time = this._source !== 'mys' ? (this._time || now) : now
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
setWeapon (ds = {}) {
|
||||
let w = Weapon.get(ds.name) || {}
|
||||
this.weapon = {
|
||||
name: ds.name,
|
||||
level: ds.level || ds.lv || 1,
|
||||
promote: lodash.isUndefined(ds.promote) ? AttrCalc.calcPromote(ds.level || ds.lv || 1) : (ds.promote || 0),
|
||||
affix: ds.affix,
|
||||
...w?.getData('star,abbr,type,img')
|
||||
}
|
||||
if (this.weapon.level < 20) {
|
||||
this.weapon.promote = 0
|
||||
}
|
||||
}
|
||||
|
||||
setTalent (ds = {}, source = '', mode = 'original') {
|
||||
const now = this._now || (new Date()) * 1
|
||||
let ret = this.char.getAvatarTalent(ds, this.cons, mode)
|
||||
this.talent = ret || this.talent
|
||||
// 设置天赋更新时间
|
||||
this._talent = ds._talent || this._talent || ds._time || now
|
||||
if (source && ret) {
|
||||
this._talent = now
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 当前数据是否需要更新天赋
|
||||
* @returns {boolean}
|
||||
*/
|
||||
needRefreshTalent () {
|
||||
// 不存在天赋数据
|
||||
if (!this.hasTalent) {
|
||||
return true
|
||||
}
|
||||
// 超过2个小时的天赋数据进行请求
|
||||
return (new Date() * 1) - this._talent > 3600 * 2 * 1000
|
||||
}
|
||||
|
||||
async refreshTalent (mys) {
|
||||
if (mys && mys.isSelfCookie) {
|
||||
let char = this.char
|
||||
if (!char) {
|
||||
return false
|
||||
}
|
||||
let id = char.id
|
||||
let talent = {}
|
||||
let talentRes = await mys.getDetail(id)
|
||||
// { data: null, message: '请先登录', retcode: -100, api: 'detail' }
|
||||
if (talentRes && talentRes.skill_list) {
|
||||
let talentList = lodash.orderBy(talentRes.skill_list, ['id'], ['asc'])
|
||||
for (let val of talentList) {
|
||||
let { max_level: maxLv, level_current: lv } = val
|
||||
if (val.name.includes('普通攻击')) {
|
||||
talent.a = lv
|
||||
continue
|
||||
}
|
||||
if (maxLv >= 10 && !talent.e) {
|
||||
talent.e = lv
|
||||
continue
|
||||
}
|
||||
if (maxLv >= 10 && !talent.q) {
|
||||
talent.q = lv
|
||||
}
|
||||
}
|
||||
}
|
||||
let ret = char.getAvatarTalent(talent, this.cons, 'original')
|
||||
if (ret) {
|
||||
this.setTalent(ret, 'mys')
|
||||
}
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
setArtis (ds, source) {
|
||||
this.artis.setArtisData(ds.artis, source)
|
||||
}
|
||||
|
||||
get hasTalent () {
|
||||
return this.talent && !lodash.isEmpty(this.talent) && !!this._talent
|
||||
}
|
||||
|
||||
get name () {
|
||||
return this.char?.name || ''
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
get isProfile () {
|
||||
// 检查数据源
|
||||
if (!this._source || !['enka', 'change', 'miao'].includes(this._source)) {
|
||||
return false
|
||||
}
|
||||
// 检查属性
|
||||
if (!this.weapon || !this.talent || !this.artis) {
|
||||
return false
|
||||
}
|
||||
// 检查旅行者
|
||||
if (['空', '荧'].includes(this.name)) {
|
||||
return !!this.elem
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
getProfile () {
|
||||
if (!this.isProfile) {
|
||||
return false
|
||||
}
|
||||
return ProfileData.create(this)
|
||||
}
|
||||
|
||||
// 判断当前profileData是否具备有效圣遗物信息
|
||||
hasArtis () {
|
||||
return this.hasData && this.artis.length > 0
|
||||
}
|
||||
|
||||
get costume () {
|
||||
let costume = this._costume
|
||||
if (lodash.isArray(costume)) {
|
||||
costume = costume[0]
|
||||
}
|
||||
return costume
|
||||
}
|
||||
|
||||
get originalTalent () {
|
||||
return lodash.mapValues(this.talent, (ds) => ds.original)
|
||||
}
|
||||
|
||||
// toJSON 供保存使用
|
||||
toJSON () {
|
||||
return {
|
||||
...this.getData('name,id,elem,level,promote,fetter,costume,cons,talent:originalTalent'),
|
||||
weapon: Data.getData(this.weapon, 'name,level,promote,affix'),
|
||||
...this.getData('artis,_source,_time,_update,_talent')
|
||||
}
|
||||
}
|
||||
|
||||
getDetail (keys = '') {
|
||||
return this.getData(keys || 'id,name,level,star,cons,fetter,elem,face,side,gacha,abbr,weapon,talent,artisSet') || {}
|
||||
}
|
||||
|
||||
get updateTime () {
|
||||
let time = this._time
|
||||
if (!time) {
|
||||
return ''
|
||||
}
|
||||
if (lodash.isString(time)) {
|
||||
return moment(time).format('MM-DD HH:mm')
|
||||
}
|
||||
if (lodash.isNumber(time)) {
|
||||
return moment(new Date(time)).format('MM-DD HH:mm')
|
||||
}
|
||||
return ''
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取圣遗物套装属性
|
||||
* @returns {boolean|*|{imgs: *[], names: *[], sets: {}, abbrs: *[], sName: string, name: (string|*)}|{}}
|
||||
*/
|
||||
get artisSet () {
|
||||
return this.artis.geSetData()
|
||||
}
|
||||
|
||||
getArtisDetail () {
|
||||
return this.artis.getDetail()
|
||||
}
|
||||
}
|
@ -6,8 +6,8 @@
|
||||
* */
|
||||
import Base from './Base.js'
|
||||
import lodash from 'lodash'
|
||||
import { Data, Common, Profile } from '../components/index.js'
|
||||
import { Avatar, MysApi } from './index.js'
|
||||
import { Data, Common } from '../components/index.js'
|
||||
import { Avatar, MysApi, Player } from './index.js'
|
||||
|
||||
export default class AvatarList extends Base {
|
||||
constructor (uid, datas = [], withProfile = false) {
|
||||
@ -18,8 +18,9 @@ export default class AvatarList extends Base {
|
||||
this.uid = uid
|
||||
let avatars = {}
|
||||
let profiles = {}
|
||||
let player = Player.create(uid)
|
||||
if (withProfile) {
|
||||
profiles = Profile.getAll(uid)
|
||||
// TODO
|
||||
}
|
||||
lodash.forEach(datas, (ds) => {
|
||||
let avatar = new Avatar(ds, profiles[ds.id] || false)
|
||||
|
236
models/Player.js
Normal file
236
models/Player.js
Normal file
@ -0,0 +1,236 @@
|
||||
/**
|
||||
* 用户数据文件
|
||||
*/
|
||||
import Base from './Base.js'
|
||||
import { Data } from '../components/index.js'
|
||||
import fs from 'fs'
|
||||
import { ProfileReq, AvatarData } from './index.js'
|
||||
import Profile from './player-lib/profile.js'
|
||||
import lodash from 'lodash'
|
||||
|
||||
import MysAvatar from './player-lib/MysAvatar.js'
|
||||
|
||||
const _path = process.cwd()
|
||||
const userPath = `${_path}/data/UserData/`
|
||||
if (!fs.existsSync(userPath)) {
|
||||
fs.mkdirSync(userPath)
|
||||
}
|
||||
|
||||
export default class Player extends Base {
|
||||
constructor (uid) {
|
||||
super()
|
||||
if (!uid) {
|
||||
return false
|
||||
}
|
||||
let cacheObj = this._getCache(`player:${uid}`)
|
||||
if (cacheObj) {
|
||||
return cacheObj
|
||||
}
|
||||
this.uid = uid
|
||||
this.reload()
|
||||
return this._cache()
|
||||
}
|
||||
|
||||
static create (e) {
|
||||
if (e?._mys?.uid) {
|
||||
// 传入为e
|
||||
let player = new Player(e?._mys?.uid)
|
||||
player.e = e
|
||||
return player
|
||||
} else {
|
||||
return new Player(e)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 重新加载json文件
|
||||
*/
|
||||
reload () {
|
||||
let data
|
||||
data = Data.readJSON(`/data/UserData/${this.uid}.json`, 'root')
|
||||
this.setBasicData(data)
|
||||
if (data.chars) {
|
||||
this.setAvatars(data.chars)
|
||||
this._chars = data.chars
|
||||
}
|
||||
this.setAvatars(data.avatars || [])
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存json文件
|
||||
*/
|
||||
save () {
|
||||
let ret = Data.getData(this, 'uid,name,level,word,face,card,sign,_mys,_profile')
|
||||
ret.avatars = {}
|
||||
lodash.forEach(this._avatars, (ds) => {
|
||||
ret.avatars[ds.id] = ds.toJSON()
|
||||
})
|
||||
if (this._chars) {
|
||||
ret.chars = this._chars
|
||||
}
|
||||
Data.writeJSON(`/data/UserData/${this.uid}.json`, ret, '', 'root')
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置玩家基础数据
|
||||
* @param ds
|
||||
*/
|
||||
setBasicData (ds) {
|
||||
this.name = ds.name || this.name || ''
|
||||
this.level = ds.level || this.level || 1
|
||||
this.word = ds.word || this.word || 1
|
||||
this.face = ds.face || this.face || ''
|
||||
this.card = ds.card || this.card || ''
|
||||
this.sign = ds.sign || this.sign || ''
|
||||
this._avatars = this._avatars || {}
|
||||
this._profile = ds._profile || this._profile
|
||||
this._mys = ds._mys || this._mys
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置角色列表
|
||||
* @param ds
|
||||
*/
|
||||
setAvatars (ds) {
|
||||
lodash.forEach(ds, (avatar) => {
|
||||
this.setAvatar(avatar)
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置角色
|
||||
* @param ds
|
||||
* @param dataSource
|
||||
*/
|
||||
setAvatar (ds, source) {
|
||||
let avatar = this.getAvatar(ds.id)
|
||||
avatar.setAvatar(ds, source)
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取角色
|
||||
* @param id
|
||||
* @returns {*}
|
||||
*/
|
||||
getAvatar (id) {
|
||||
if (!this._avatars[id]) {
|
||||
this._avatars[id] = AvatarData.create({ id })
|
||||
}
|
||||
return this._avatars[id]
|
||||
}
|
||||
|
||||
/**
|
||||
* 循环角色
|
||||
* @param fn
|
||||
* @returns {Promise<boolean>}
|
||||
*/
|
||||
async forEachAvatarAsync (fn) {
|
||||
for (let id in this._avatars) {
|
||||
let ret = await fn(this._avatars[id], id)
|
||||
if (ret === false) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
forEachAvatar (fn) {
|
||||
for (let id in this._avatars) {
|
||||
let ret = fn(this._avatars[id], id)
|
||||
if (ret === false) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
getAvatarData (ids = '') {
|
||||
let ret = {}
|
||||
if (!ids) {
|
||||
this.forEachAvatar((avatar) => {
|
||||
ret[avatar.id] = avatar.getDetail()
|
||||
})
|
||||
} else {
|
||||
lodash.forEach(ids, (id) => {
|
||||
ret[id] = this.getAvatar(id)
|
||||
})
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前用户指定charid面板数据
|
||||
* @param id
|
||||
* @returns {*}
|
||||
*/
|
||||
getProfile (id) {
|
||||
let avatar = this.getAvatar(id)
|
||||
return avatar.getProfile()
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前用户所有面板数据
|
||||
* @returns {{}}
|
||||
*/
|
||||
getProfiles () {
|
||||
let ret = {}
|
||||
lodash.forEach(this._avatars, (avatar) => {
|
||||
let profile = avatar.getProfile()
|
||||
if (profile) {
|
||||
ret[profile.id] = profile
|
||||
}
|
||||
})
|
||||
return ret
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新面板
|
||||
* @param e
|
||||
* @returns {Promise<boolean|*|undefined>}
|
||||
*/
|
||||
async refreshProfile (e, force = true) {
|
||||
this._update = []
|
||||
let { uid } = this
|
||||
if (uid.toString().length !== 9) {
|
||||
return false
|
||||
}
|
||||
let req = new ProfileReq({ e, uid })
|
||||
try {
|
||||
await req.request(this)
|
||||
this._profile = new Date() * 1
|
||||
this.save()
|
||||
return this._update.length
|
||||
} catch (err) {
|
||||
console.log(err)
|
||||
e.reply('请求失败')
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// 更新米游社数据
|
||||
async refreshMys (force = false) {
|
||||
return MysAvatar.refreshMys(this, force)
|
||||
}
|
||||
|
||||
// 通过已有的Mys CharData更新
|
||||
setMysCharData (charData) {
|
||||
MysAvatar.setMysCharData(this, charData)
|
||||
}
|
||||
|
||||
// 使用MysApi刷新指定角色的天赋信息
|
||||
async refreshTalent (ids = '', force = false) {
|
||||
return await MysAvatar.refreshTalent(this, ids, force)
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取面板更新服务名
|
||||
* @param uid
|
||||
* @returns {*}
|
||||
*/
|
||||
static getProfileServName (uid) {
|
||||
let Serv = ProfileReq.getServ(uid)
|
||||
return Serv.name
|
||||
}
|
||||
|
||||
static getAvatar (uid, charId, onlyHasData = false) {
|
||||
return Profile.get(uid, charId, onlyHasData)
|
||||
}
|
||||
}
|
@ -1,30 +0,0 @@
|
||||
import Base from './Base.js'
|
||||
|
||||
export default class Profile extends Base {
|
||||
constructor (uid) {
|
||||
super()
|
||||
if (!uid) {
|
||||
return false
|
||||
}
|
||||
let cacheObj = this._getCache(`profile:${uid}`)
|
||||
if (cacheObj) {
|
||||
return cacheObj
|
||||
}
|
||||
this.uid = uid
|
||||
return this._cache()
|
||||
}
|
||||
|
||||
getProfileData () {
|
||||
|
||||
}
|
||||
|
||||
static create (uid) {
|
||||
let profile = new Profile(uid)
|
||||
return profile
|
||||
}
|
||||
|
||||
static get (uid, id) {
|
||||
let profile = Profile.create(uid)
|
||||
return profile.getProfileData(id)
|
||||
}
|
||||
}
|
@ -6,7 +6,7 @@ import { Character, ProfileArtis, ProfileDmg } from './index.js'
|
||||
import AttrCalc from './profile-lib/AttrCalc.js'
|
||||
|
||||
export default class ProfileData extends Base {
|
||||
constructor (ds = {}, uid, attrCalc = true) {
|
||||
constructor (ds = {}) {
|
||||
super()
|
||||
let char = Character.get({ id: ds.id, elem: ds.elem })
|
||||
if (!char) {
|
||||
@ -14,20 +14,16 @@ export default class ProfileData extends Base {
|
||||
}
|
||||
this.id = char.id
|
||||
this.char = char
|
||||
this.uid = uid || ''
|
||||
this.setBasic(ds)
|
||||
ds.attr && this.setAttr(ds.attr)
|
||||
ds.weapon && this.setWeapon(ds.weapon)
|
||||
ds.talent && this.setTalent(ds.talent)
|
||||
this.artis = new ProfileArtis(this.id, this.elem)
|
||||
ds.artis && this.setArtis(ds.artis)
|
||||
if (attrCalc && this.hasData) {
|
||||
this.calcAttr()
|
||||
}
|
||||
}
|
||||
|
||||
static create (ds, uid) {
|
||||
let profile = new ProfileData(ds, uid)
|
||||
static create (ds) {
|
||||
let profile = new ProfileData(ds)
|
||||
if (!profile) {
|
||||
return false
|
||||
}
|
||||
@ -50,16 +46,6 @@ export default class ProfileData extends Base {
|
||||
this._time = ds._time || ds.updateTime || new Date() * 1
|
||||
}
|
||||
|
||||
setAttr (ds) {
|
||||
this.attr = lodash.extend(Data.getData(ds, 'atk,atkBase,def,defBase,hp,hpBase,mastery,recharge'), {
|
||||
heal: ds.heal || ds.hInc || 0,
|
||||
cpct: ds.cpct || ds.cRate,
|
||||
cdmg: ds.cdmg || ds.cDmg,
|
||||
dmg: ds.dmg || ds.dmgBonus || 0,
|
||||
phy: ds.phy || ds.phyBonus || 0
|
||||
})
|
||||
}
|
||||
|
||||
setWeapon (ds = {}) {
|
||||
this.weapon = {
|
||||
name: ds.name,
|
||||
@ -75,7 +61,7 @@ export default class ProfileData extends Base {
|
||||
}
|
||||
|
||||
setArtis (ds = false) {
|
||||
this.artis.setProfile(this, ds)
|
||||
this.artis.setProfile(this, ds.artis || ds)
|
||||
}
|
||||
|
||||
setTalent (ds = {}, mode = 'original') {
|
||||
|
@ -51,16 +51,16 @@ export default class ProfileReq extends Base {
|
||||
this.e.reply(msg)
|
||||
}
|
||||
|
||||
async request () {
|
||||
async request (player) {
|
||||
let Serv = ProfileReq.getServ(this.uid)
|
||||
let reqParam = await Serv.getReqParam(this.uid)
|
||||
|
||||
let cdTime = await this.inCd()
|
||||
if (cdTime) {
|
||||
return this.err(`请求过快,请${cdTime}秒后重试..`)
|
||||
// return this.err(`请求过快,请${cdTime}秒后重试..`)
|
||||
}
|
||||
await this.setCd(20)
|
||||
this.msg(`开始获取uid:${this.uid}的数据,可能会需要一定时间~`)
|
||||
// this.msg(`开始获取uid:${this.uid}的数据,可能会需要一定时间~`)
|
||||
await sleep(100)
|
||||
// 发起请求
|
||||
let data = {}
|
||||
@ -92,16 +92,12 @@ export default class ProfileReq extends Base {
|
||||
if (data === false) {
|
||||
return false
|
||||
}
|
||||
let userData = Serv.getUserData(data)
|
||||
let profiles = Serv.getProfileData(data)
|
||||
Serv.updatePlayer(player, data)
|
||||
cdTime = Serv.getCdTime(data)
|
||||
if (cdTime) {
|
||||
await this.setCd(cdTime)
|
||||
}
|
||||
return lodash.extend({
|
||||
uid: this.uid,
|
||||
chars: profiles
|
||||
}, userData)
|
||||
return player
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -75,12 +75,8 @@ export default class ProfileServ extends Base {
|
||||
return Math.max(cdTime, this.execFn('cdTime', [data], 60))
|
||||
}
|
||||
|
||||
getUserData (data) {
|
||||
return this.execFn('userData', [data], {})
|
||||
}
|
||||
|
||||
getProfileData (data) {
|
||||
return this.execFn('profileData', [data], {})
|
||||
updatePlayer (player, data) {
|
||||
return this.execFn('updatePlayer', [player, data], {})
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3,8 +3,11 @@ import Character from './Character.js'
|
||||
import Artifact from './Artifact.js'
|
||||
import ArtifactSet from './ArtifactSet.js'
|
||||
import Avatar from './Avatar.js'
|
||||
import AvatarData from './AvatarData.js'
|
||||
import AvatarArtis from './AvatarArtis.js'
|
||||
import AvatarList from './AvatarList.js'
|
||||
import Abyss from './Abyss.js'
|
||||
import Player from './Player.js'
|
||||
import ProfileServ from './ProfileServ.js'
|
||||
import ProfileReq from './ProfileReq.js'
|
||||
import ProfileData from './ProfileData.js'
|
||||
@ -24,7 +27,9 @@ export {
|
||||
Artifact,
|
||||
ArtifactSet,
|
||||
Avatar,
|
||||
AvatarData,
|
||||
AvatarList,
|
||||
AvatarArtis,
|
||||
ProfileServ,
|
||||
ProfileReq,
|
||||
ProfileData,
|
||||
@ -35,5 +40,6 @@ export {
|
||||
Material,
|
||||
Weapon,
|
||||
User,
|
||||
MysApi
|
||||
MysApi,
|
||||
Player
|
||||
}
|
||||
|
123
models/player-lib/MysAvatar.js
Normal file
123
models/player-lib/MysAvatar.js
Normal file
@ -0,0 +1,123 @@
|
||||
import lodash from 'lodash'
|
||||
import { Common, Data } from '../../components/index.js'
|
||||
|
||||
const MysAvatar = {
|
||||
/**
|
||||
* 更新米游社角色信息
|
||||
* @param player
|
||||
* @param mys
|
||||
* @param force
|
||||
* @returns {Promise<boolean>}
|
||||
*/
|
||||
async refreshMys (player, force = false) {
|
||||
let mys = player?.e?._mys
|
||||
if (!mys) {
|
||||
return false
|
||||
}
|
||||
// 不必要更新
|
||||
if ((new Date() * 1 - player._mys < 10 * 60 * 1000) && !force) {
|
||||
return false
|
||||
}
|
||||
let charData = await mys.getCharacter()
|
||||
if (!charData || !charData.avatars) {
|
||||
return false
|
||||
}
|
||||
MysAvatar.setMysCharData(player, charData)
|
||||
},
|
||||
|
||||
/**
|
||||
* 根据已有Mys CharData更新player
|
||||
* @param player
|
||||
* @param charData
|
||||
*/
|
||||
setMysCharData (player, charData) {
|
||||
let role = charData.role
|
||||
player.setBasicData({
|
||||
level: role.level,
|
||||
name: role.nickname
|
||||
})
|
||||
lodash.forEach(charData.avatars, (ds) => {
|
||||
let avatar = Data.getData(ds, 'id,level,cons:actived_constellation_num,fetter')
|
||||
avatar.elem = ds.element.toLowerCase()
|
||||
// 处理实装数据
|
||||
let costume = (ds?.costumes || [])[0]
|
||||
if (costume && costume.id) {
|
||||
avatar.costume = costume.id
|
||||
}
|
||||
avatar.weapon = Data.getData(ds.weapon, 'name,star:rarity,level,promote:promote_level,affix:affix_level')
|
||||
// 处理圣遗物数据
|
||||
let artis = {}
|
||||
lodash.forEach(ds.reliquaries, (re) => {
|
||||
const posIdx = { 生之花: 1, 死之羽: 2, 时之沙: 3, 空之杯: 4, 理之冠: 5 }
|
||||
if (re && re.name && posIdx[re.pos_name]) {
|
||||
artis[posIdx[re.pos_name]] = {
|
||||
name: re.name,
|
||||
level: re.level
|
||||
}
|
||||
}
|
||||
})
|
||||
avatar.artis = artis
|
||||
player.setAvatar(avatar, 'mys')
|
||||
})
|
||||
player._mys = new Date() * 1
|
||||
player.save()
|
||||
},
|
||||
|
||||
/**
|
||||
* 获取当前角色需要更新天赋的角色ID
|
||||
* @param player
|
||||
* @param ids 角色列表,若传入则查询指定角色列表,不传入查询全部
|
||||
* @returns {*[]}
|
||||
*/
|
||||
getNeedRefreshIds (player, ids) {
|
||||
let ret = []
|
||||
if (!ids) {
|
||||
ids = lodash.keys(player._avatars)
|
||||
} else if (!lodash.isArray(ids)) {
|
||||
ids = [ids]
|
||||
}
|
||||
lodash.forEach(ids, (id) => {
|
||||
let avatar = player.getAvatar(id)
|
||||
if (avatar.needRefreshTalent()) {
|
||||
ret.push(avatar.id)
|
||||
}
|
||||
})
|
||||
return ret
|
||||
},
|
||||
|
||||
/**
|
||||
* 使用MysApi刷新指定角色的天赋信息
|
||||
* @param player
|
||||
* @param ids
|
||||
* @param force
|
||||
* @returns {Promise<boolean>}
|
||||
*/
|
||||
async refreshTalent (player, ids, force) {
|
||||
let e = player?.e
|
||||
let mys = e?._mys
|
||||
if (!e || !mys) {
|
||||
return false
|
||||
}
|
||||
let needReqIds = MysAvatar.getNeedRefreshIds(player, ids)
|
||||
if (needReqIds.length > 0) {
|
||||
if (needReqIds.length > 8) {
|
||||
e && e.reply('正在获取角色信息,请稍候...')
|
||||
}
|
||||
let num = 10
|
||||
let ms = 100
|
||||
let skillRet = []
|
||||
let avatarArr = lodash.chunk(needReqIds, num)
|
||||
for (let val of avatarArr) {
|
||||
for (let id of val) {
|
||||
let avatar = player.getAvatar(id)
|
||||
skillRet.push(await avatar.refreshTalent(mys))
|
||||
}
|
||||
skillRet = await Promise.all(skillRet)
|
||||
skillRet = skillRet.filter(item => item.id)
|
||||
await Common.sleep(ms)
|
||||
}
|
||||
}
|
||||
player.save()
|
||||
}
|
||||
}
|
||||
export default MysAvatar
|
@ -1,6 +1,6 @@
|
||||
import lodash from 'lodash'
|
||||
import enkaMeta from './enka-meta.js'
|
||||
import { Character, ArtifactSet, ProfileData } from '../../models/index.js'
|
||||
import { Character, ArtifactSet, ProfileData } from '../index.js'
|
||||
|
||||
const artiIdx = {
|
||||
EQUIP_BRACER: 1,
|
@ -1,6 +1,6 @@
|
||||
import lodash from 'lodash'
|
||||
import { Data } from '../index.js'
|
||||
import { ProfileServ } from '../../models/index.js'
|
||||
import { Data } from '../../components/index.js'
|
||||
import { ProfileServ } from '../index.js'
|
||||
import EnkaData from './enka-data.js'
|
||||
|
||||
let HttpsProxyAgent = ''
|
@ -1,6 +1,28 @@
|
||||
import { Character, ProfileData } from '../../models/index.js'
|
||||
import { Character, Artifact } from '../index.js'
|
||||
import lodash from 'lodash'
|
||||
import { artiIdx, artiSetMap, attrMap } from './miao-meta.js'
|
||||
|
||||
const attrMap = {
|
||||
HP: 'hpPlus',
|
||||
HP_PERCENT: 'hp',
|
||||
ATTACK: 'atkPlus',
|
||||
ATTACK_PERCENT: 'atk',
|
||||
DEFENSE: 'defPlus',
|
||||
DEFENSE_PERCENT: 'def',
|
||||
FIRE_ADD_HURT: '',
|
||||
ICE_ADD_HURT: 'cryo',
|
||||
ROCK_ADD_HURT: 'geo',
|
||||
ELEC_ADD_HURT: 'electro',
|
||||
WIND_ADD_HURT: 'anemo',
|
||||
WATER_ADD_HURT: 'hydro',
|
||||
PHYSICAL_ADD_HURT: 'phy',
|
||||
GRASS_ADD_HURT: 'dendro',
|
||||
HEAL_ADD: 'heal',
|
||||
ELEMENT_MASTERY: 'mastery',
|
||||
CRITICAL: 'cpct',
|
||||
CRITICAL_HURT: 'cdmg',
|
||||
CHARGE_EFFICIENCY: 'recharge'
|
||||
}
|
||||
|
||||
|
||||
let MiaoData = {
|
||||
key: 'miao',
|
||||
@ -27,70 +49,21 @@ let MiaoData = {
|
||||
level: ds.level
|
||||
}
|
||||
},
|
||||
getProfile (ds) {
|
||||
setAvatar (player, ds) {
|
||||
let char = Character.get(ds.id)
|
||||
let profile = new ProfileData({ id: char.id })
|
||||
profile.setBasic({
|
||||
let avatar = player.getAvatar(ds.id)
|
||||
let talentRet = MiaoData.getTalent(char.id, ds.skill)
|
||||
avatar.setAvatar({
|
||||
level: ds.level,
|
||||
cons: ds.constellationNum || 0,
|
||||
fetter: ds.fetterLevel,
|
||||
costume: char.checkCostume(ds.costumeID) ? ds.costumeID : 0,
|
||||
dataSource: 'miao'
|
||||
})
|
||||
profile.setAttr(MiaoData.getAttr(ds.combatValue))
|
||||
profile.setWeapon(MiaoData.getWeapon(ds.weapon))
|
||||
profile.setArtis(MiaoData.getArtifact(ds.reliquary))
|
||||
let talentRet = MiaoData.getTalent(char.id, ds.skill)
|
||||
profile.setTalent(talentRet.talent, 'level')
|
||||
if (talentRet.elem) {
|
||||
profile.elem = talentRet.elem
|
||||
}
|
||||
return profile
|
||||
},
|
||||
getAttr (data) {
|
||||
let ret = {}
|
||||
lodash.forEach({
|
||||
atk: 'attack',
|
||||
atkBase: 'baseATK',
|
||||
hp: 'health',
|
||||
hpBase: 'baseHP',
|
||||
def: 'defense',
|
||||
defBase: 'baseDEF',
|
||||
mastery: 'elementMastery',
|
||||
cpct: {
|
||||
src: 'critRate',
|
||||
pct: true
|
||||
},
|
||||
cdmg: {
|
||||
src: 'critDamage',
|
||||
pct: true
|
||||
},
|
||||
heal: {
|
||||
src: 'heal',
|
||||
pct: true
|
||||
},
|
||||
recharge: {
|
||||
src: 'recharge',
|
||||
pct: true
|
||||
}
|
||||
}, (cfg, key) => {
|
||||
if (!lodash.isObject(cfg)) {
|
||||
cfg = { src: cfg }
|
||||
}
|
||||
let val = data[cfg.src] || 0
|
||||
if (cfg.pct) {
|
||||
val = val * 100
|
||||
}
|
||||
ret[key] = val
|
||||
})
|
||||
let maxDmg = 0
|
||||
let hurt = data.addHurt || {}
|
||||
lodash.forEach('fire,elec,water,grass,wind,rock,ice'.split(','), (key) => {
|
||||
maxDmg = Math.max(hurt[key] * 100, maxDmg)
|
||||
})
|
||||
ret.dmg = maxDmg
|
||||
ret.phy = hurt.physical * 100
|
||||
return ret
|
||||
elem: talentRet.elem,
|
||||
weapon: MiaoData.getWeapon(ds.weapon),
|
||||
talent: talentRet.talent,
|
||||
artis: MiaoData.getArtifact(ds.reliquary)
|
||||
}, 'miao')
|
||||
return avatar
|
||||
},
|
||||
getWeapon (weapon) {
|
||||
return {
|
||||
@ -116,18 +89,23 @@ let MiaoData = {
|
||||
if (value && value < 1) {
|
||||
value = value * 100
|
||||
}
|
||||
return [attrMap[name], value]
|
||||
return { key: attrMap[name], value }
|
||||
}
|
||||
|
||||
lodash.forEach(data, (ds) => {
|
||||
let sub = ds.appendAffix || []
|
||||
let idx = artiIdx[ds.type]
|
||||
let idx = {
|
||||
生之花: 1,
|
||||
死之羽: 2,
|
||||
时之沙: 3,
|
||||
空之杯: 4,
|
||||
理之冠: 5
|
||||
}[ds.type]
|
||||
if (!idx) {
|
||||
return
|
||||
}
|
||||
ret[`arti${idx}`] = {
|
||||
ret[idx] = {
|
||||
name: ds.name,
|
||||
set: artiSetMap[ds.name] || '',
|
||||
set: Artifact.getSetNameByArti(ds.name) || '',
|
||||
level: ds.level,
|
||||
main: get(ds.mainAffix),
|
||||
attrs: [
|
||||
@ -162,7 +140,6 @@ let MiaoData = {
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
return {
|
||||
talent: ret,
|
||||
elem
|
@ -1,6 +1,6 @@
|
||||
import lodash from 'lodash'
|
||||
import { Data } from '../index.js'
|
||||
import { ProfileServ } from '../../models/index.js'
|
||||
import { Data } from '../../components/index.js'
|
||||
import { ProfileServ } from '../index.js'
|
||||
import MiaoData from './miao-data.js'
|
||||
|
||||
export default new ProfileServ({
|
||||
@ -18,19 +18,14 @@ export default new ProfileServ({
|
||||
return data
|
||||
},
|
||||
|
||||
userData (data) {
|
||||
return Data.getData(data, 'name:nickname,avatar:profilePicture.avatarID,level,signature')
|
||||
},
|
||||
|
||||
profileData (data) {
|
||||
let ret = {}
|
||||
updatePlayer (player, data) {
|
||||
player.setBasicData(Data.getData(data, 'name:nickname,face:profilePicture.avatarID,card:nameCardID,level,word:worldLevel,sign:signature'))
|
||||
lodash.forEach(data.showAvatarInfoList, (ds) => {
|
||||
let profile = MiaoData.getProfile(ds)
|
||||
if (profile && profile.id) {
|
||||
ret[profile.id] = profile
|
||||
let ret = MiaoData.setAvatar(player, ds)
|
||||
if (ret) {
|
||||
player._update.push(ret.id)
|
||||
}
|
||||
})
|
||||
return ret
|
||||
},
|
||||
|
||||
// 获取冷却时间
|
@ -103,7 +103,7 @@ class AttrCalc {
|
||||
* 计算武器属性
|
||||
*/
|
||||
setWeaponAttr () {
|
||||
let wData = this.profile?.weapon
|
||||
let wData = this.profile?.weapon || {}
|
||||
let weapon = Weapon.get(wData?.name)
|
||||
let level = wData.level
|
||||
let promote = lodash.isUndefined(wData.promote) ? -1 : wData.promote
|
||||
|
@ -1,38 +0,0 @@
|
||||
import fs from 'node:fs'
|
||||
import { Data } from '../../components/index.js'
|
||||
import lodash from 'lodash'
|
||||
|
||||
const _path = process.cwd()
|
||||
const userPath = `${_path}/data/UserData/`
|
||||
if (!fs.existsSync(userPath)) {
|
||||
fs.mkdirSync(userPath)
|
||||
}
|
||||
|
||||
let ProfileFile = {
|
||||
getData (uid) {
|
||||
let data = Data.readJSON('/data/UserData', 'root')
|
||||
if (data && data.chars) {
|
||||
return data
|
||||
} else {
|
||||
return {
|
||||
uid,
|
||||
chars: {}
|
||||
}
|
||||
}
|
||||
},
|
||||
saveData (profile) {
|
||||
let userData = {}
|
||||
const userFile = `${userPath}/${uid}.json`
|
||||
if (fs.existsSync(userFile)) {
|
||||
userData = JSON.parse(fs.readFileSync(userFile, 'utf8')) || {}
|
||||
}
|
||||
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 data
|
||||
}
|
||||
}
|
||||
export default ProfileFile
|
@ -78,7 +78,7 @@
|
||||
</div>
|
||||
|
||||
<div class="copyright data-source">
|
||||
数据源:{{data.dataSourceName}} {{data.updateTime}}
|
||||
数据源:{{ {miao:'喵喵API', 'enka':'Enka.Network', mys:'米游社'}[data.source]||data.source }} {{data.updateTime}}
|
||||
</div>
|
||||
{{else}}
|
||||
{{if custom}}
|
||||
|
@ -1,117 +0,0 @@
|
||||
import fs from 'fs'
|
||||
import { Profile } from '../components/index.js'
|
||||
import AttrCalc from '../models/profile-lib/AttrCalc.js'
|
||||
import lodash from 'lodash'
|
||||
|
||||
let _path = process.cwd()
|
||||
|
||||
function testCalcAttr (profile) {
|
||||
if (profile.hasData) {
|
||||
let attrCalc = AttrCalc.create(profile)
|
||||
let attr2 = attrCalc.calc()
|
||||
let char = profile.char
|
||||
let ret = {}
|
||||
lodash.forEach(profile.attr, (val, key) => {
|
||||
let diff = val - (attr2[key] || 0)
|
||||
if (Math.abs(diff / val) > 0.005 && Math.abs(diff) > 0.99) {
|
||||
ret[key] = [val, attr2[key]]
|
||||
}
|
||||
})
|
||||
if (!lodash.isEmpty(ret)) {
|
||||
let retKeys = lodash.keys(ret)
|
||||
let retKeyStr = lodash.keys(ret).join(',')
|
||||
let ret2 = lodash.extend({}, ret)
|
||||
if (retKeyStr === 'hp') {
|
||||
let [s, d] = ret.hp
|
||||
let hpBase = profile.attr?.hpBase
|
||||
let pct = Math.round((s - d) / hpBase * 100)
|
||||
if ([6, 12, 18, 30, 25, 31, 37, 43, 55].includes(pct)) {
|
||||
delete ret.hp
|
||||
}
|
||||
}
|
||||
if ((ret.atkBase) || (retKeys.length === 2 && ret.atkBase && ret.atk)) {
|
||||
|
||||
if ([1, 20, 40, 50, 60, 70, 80, 90].includes(profile.weapon.level)) {
|
||||
delete ret.atkBase
|
||||
delete ret.atk
|
||||
}
|
||||
}
|
||||
if (ret.def && ret.defBase && ret.hp && ret.hpBase) {
|
||||
let [s, d] = ret.defBase
|
||||
if (s > d && [1, 20, 40, 50, 60, 70, 80, 90].includes(profile.level)) {
|
||||
delete ret.def
|
||||
delete ret.defBase
|
||||
delete ret.hp
|
||||
delete ret.hpBase
|
||||
delete ret[char.detail?.attr?.keys[3]]
|
||||
}
|
||||
}
|
||||
if (retKeyStr === 'recharge') {
|
||||
if (char.isTraveler && char.isElem('风')) {
|
||||
delete ret.recharge
|
||||
}
|
||||
}
|
||||
if (retKeyStr === 'dmg') {
|
||||
let [s, d] = ret.dmg
|
||||
let dmg = Math.round(Math.abs(s - d - 46.6))
|
||||
console.log(dmg)
|
||||
if ([0, 15].includes(dmg) || char.name === '莫娜') {
|
||||
delete ret.dmg
|
||||
}
|
||||
}
|
||||
let cmd = `#${profile.name}面板${profile.uid}`
|
||||
if (lodash.isEmpty(ret)) {
|
||||
console.log(`Calc IGNORE: ${cmd}`)
|
||||
return true
|
||||
} else {
|
||||
console.log(`Calc Diff: ${cmd}`, ret2)
|
||||
}
|
||||
return false
|
||||
} else {
|
||||
console.log(`Calc OK:${profile.uid}:${profile.id}`)
|
||||
return true
|
||||
}
|
||||
} else {
|
||||
console.log('!has data')
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
async function test (ignore) {
|
||||
let files = fs.readdirSync(`${_path}/data/UserData`)
|
||||
let count = 0
|
||||
let total = 0
|
||||
for (let file of files) {
|
||||
if (count > 0) {
|
||||
break
|
||||
}
|
||||
let testRet = /(\d{9}).json/.exec(file)
|
||||
if (testRet && testRet[1]) {
|
||||
let uid = testRet[1]
|
||||
if (ignore.includes(uid * 1)) {
|
||||
continue
|
||||
}
|
||||
Profile.forEach(uid, (profile) => {
|
||||
if (count > 0) {
|
||||
return false
|
||||
}
|
||||
let cmd = `#${profile.name}面板${profile.uid}`
|
||||
if (ignore.includes(cmd)) {
|
||||
return true
|
||||
}
|
||||
console.log(profile.id)
|
||||
let ret = testCalcAttr(profile)
|
||||
if (ret === false) {
|
||||
count++
|
||||
}
|
||||
total++
|
||||
})
|
||||
}
|
||||
}
|
||||
console.log(`calc test done total:${total}`)
|
||||
return true
|
||||
}
|
||||
|
||||
const ignore = ['#荧面板100000023', '#班尼特面板100009630', '#荧面板100147429', '#八重神子面板100160080', '#纳西妲面板100181800', '#荧面板100211780',
|
||||
'#九条裟罗面板100248492', '#砂糖面板100270260']
|
||||
await test(ignore)
|
Loading…
Reference in New Issue
Block a user