调整player更新逻辑

This commit is contained in:
Kokomi 2023-10-19 17:48:52 +08:00
parent 20709c437b
commit 119eff6f27
30 changed files with 268 additions and 242 deletions

View File

@ -1,5 +1,6 @@
import lodash from 'lodash'
import fs from 'fs'
import fs from 'node:fs'
import util from 'node:util'
const _path = process.cwd()
const getRoot = (root = '') => {
@ -243,9 +244,7 @@ let Data = {
if (lodash.isArray(data)) {
for (let idx = 0; idx < data.length; idx++) {
let ret = fn(data[idx], idx)
if (ret instanceof Promise) {
ret = await ret
}
ret = Data.isPromise(ret) ? await ret : ret
if (ret === false) {
break
}
@ -253,9 +252,7 @@ let Data = {
} else if (lodash.isPlainObject(data)) {
for (const idx in data) {
let ret = fn(data[idx], idx)
if (ret instanceof Promise) {
ret = await ret
}
ret = Data.isPromise(ret) ? await ret : ret
if (ret === false) {
break
}
@ -263,6 +260,10 @@ let Data = {
}
},
isPromise(data){
return util.types.isPromise(data)
},
// 循环字符串回调
eachStr: (arr, fn) => {
if (lodash.isString(arr)) {

View File

@ -1,11 +1,11 @@
import lodash from 'lodash'
import AvatarBase from './avatar/AvatarBase.js'
import { Data } from '#miao'
import { ProfileDmg } from './index.js'
import AvatarBase from './avatar/AvatarBase.js'
import Attr from './attr/Attr.js'
import CharImg from './character/CharImg.js'
import Artis from './artis/Artis.js'
import Profile from './player/Profile.js'
import ProfileAvatar from './avatar/ProfileAvatar.js'
import ArtisMark from './artis/ArtisMark.js'
export default class Avatar extends AvatarBase {
@ -16,12 +16,12 @@ export default class Avatar extends AvatarBase {
// 是否是合法面板数据
get isProfile () {
return Profile.isProfile(this)
return ProfileAvatar.isProfile(this)
}
// profile.hasData 别名
get hasData(){
return Profile.isProfile(this)
get hasData () {
return ProfileAvatar.isProfile(this)
}
get imgs () {
@ -29,7 +29,7 @@ export default class Avatar extends AvatarBase {
}
get costumeSplash () {
return CharImg.getCostumeSplash(this)
return ProfileAvatar.getCostumeSplash(this)
}
get hasDmg () {
@ -50,13 +50,16 @@ export default class Avatar extends AvatarBase {
setAvatar (ds, source = '') {
super.setAvatar(ds, source)
if (ds.artis) {
if (ds.artis && source !== 'mys') {
this._artis.setArtisData(ds.artis)
}
// this.calcAttr()
this.calcAttr()
}
calcAttr () {
if (!this.isProfile) {
return false
}
let attr = this._attr = this._attr || Attr.create(this)
this.attr = attr.calc()
this.base = attr.getBase()

View File

@ -9,8 +9,8 @@ import Base from './Base.js'
import { Data } from '#miao'
import { Avatar, ProfileRank, Character } from './index.js'
import MysAvatar from './player/MysAvatar.js'
import Profile from './player/Profile.js'
import MysAvatar from './avatar/MysAvatar.js'
import ProfileAvatar from './avatar/ProfileAvatar.js'
Data.createDir('/data/UserData', 'root')
Data.createDir('/data/PlayerData/gs', 'root')
@ -80,8 +80,7 @@ export default class Player extends Base {
// 获取面板更新服务名
static getProfileServName (uid, game = 'gs') {
let Serv = Profile.getServ(uid, game)
return Serv.name
return ProfileAvatar.getServ(uid, game)?.name
}
static delByUid (uid, game = 'gs') {
@ -199,11 +198,12 @@ export default class Player extends Base {
}
// 循环Avatar
forEachAvatar (fn) {
async forEachAvatar (fn) {
for (let id in this._avatars) {
let avatar = this._avatars[id]
if (avatar && avatar.hasData) {
let ret = fn(this._avatars[id])
let ret = fn(this._avatars[id], id)
ret = Data.isPromise(ret) ? await ret : ret
if (ret === false) {
return false
}
@ -232,17 +232,18 @@ export default class Player extends Base {
// 获取指定角色的面板数据
getProfile (id) {
let avatar = this.getAvatar(id)
avatar.calcAttr()
if (!avatar.isProfile) {
return false
}
return avatar
}
// 获取所有面板数据
getProfiles () {
let ret = {}
lodash.forEach(this._avatars, (avatar) => {
let profile = avatar.getProfile()
if (profile) {
ret[profile.id] = profile
this.forEachAvatar((avatar) => {
if (avatar.isProfile) {
ret[avatar.id] = avatar
}
})
return ret
@ -265,7 +266,7 @@ export default class Player extends Base {
// 更新面板
async refreshProfile (force = 2) {
return await Profile.refreshProfile(this, force)
return await ProfileAvatar.refreshProfile(this, force)
}
// 更新米游社数据

View File

@ -4,9 +4,9 @@ import Base from './Base.js'
import { Character } from './index.js'
import { attrMap as attrMapGS } from '../resources/meta/artifact/index.js'
import { attrMap as attrMapSR } from '../resources/meta-sr/artifact/index.js'
import DmgBuffs from './profile/DmgBuffs.js'
import DmgAttr from './profile/DmgAttr.js'
import DmgCalc from './profile/DmgCalc.js'
import DmgBuffs from './dmg/DmgBuffs.js'
import DmgAttr from './dmg/DmgAttr.js'
import DmgCalc from './dmg/DmgCalc.js'
import { Common, MiaoError } from '#miao'
export default class ProfileDmg extends Base {

View File

@ -4,7 +4,6 @@ import moment from 'moment'
import { Character, Avatar, Weapon } from '#miao.models'
import { Data, Format } from '#miao'
import Attr from '../attr/Attr.js'
import Profile from '../player/Profile.js'
import Artis from '../artis/Artis.js'
const charKey = 'name,abbr,sName,star,imgs,face,side,gacha,weaponTypeName'.split(',')
@ -113,7 +112,9 @@ export default class AvatarBase extends Base {
this.setBasic(ds, source)
ds.weapon && this.setWeapon(ds.weapon)
ds.talent && this.setTalent(ds.talent, 'original', source)
this._mysArtis.setArtisData(ds.mysArtis || ds.artis)
let artis = ds.mysArtis || ds.artis
// 只要具备圣遗物信息就更新mysArtis
this._mysArtis.setArtisData(artis)
delete this._now
}

View File

@ -0,0 +1,18 @@
const AvatarUtil = {
needRefresh (time, force = 0, forceMap = {}) {
if (!time || force === 2) {
return true
}
if (force === true) {
force = 0
}
let duration = (new Date() * 1 - time * 1) / 1000
if (isNaN(duration) || duration < 0) {
return true
}
let reqTime = forceMap[force] === 0 ? 0 : (forceMap[force] || 60)
return duration > reqTime * 60
}
}
export default AvatarUtil

View File

@ -2,24 +2,10 @@ import lodash from 'lodash'
import moment from 'moment'
import { Data } from '#miao'
import { chestInfo } from '../../resources/meta/info/index.js'
import AvatarUtil from './AvatarUtil.js'
const MysAvatar = {
needRefresh (time, force = 0, forceMap = {}) {
if (!time || force === 2) {
return true
}
if (force === true) {
force = 0
}
let duration = (new Date() * 1 - time * 1) / 1000
if (isNaN(duration) || duration < 0) {
return true
}
let reqTime = forceMap[force] === 0 ? 0 : (forceMap[force] || 60)
return duration > reqTime * 60
},
checkForce (player, force) {
let e = player?.e
let mys = e?._mys
@ -49,7 +35,7 @@ const MysAvatar = {
if (!mys) {
return false
}
if (!MysAvatar.needRefresh(player._mys, force, { 0: 60, 1: 2, 2: 0 })) {
if (!AvatarUtil.needRefresh(player._mys, force, { 0: 60, 1: 2, 2: 0 })) {
return false
}
let charData = await mys.getCharacter()
@ -67,7 +53,7 @@ const MysAvatar = {
if (!mys) {
return false
} // 不必要更新
if (!MysAvatar.needRefresh(player._info, force, { 0: 60, 1: 2, 2: 0 })) {
if (!AvatarUtil.needRefresh(player._info, force, { 0: 60, 1: 2, 2: 0 })) {
return false
}
let infoData = await mys.getIndex()
@ -114,7 +100,8 @@ const MysAvatar = {
player.setAvatar(avatar, 'mys')
charIds[avatar.id] = true
})
// 若角色数据>8检查缓存删除错误缓存的数据
// 若角色数据>8则说明为带ck更新
// 检查缓存,删除错误缓存的数据
if (lodash.keys(charIds).length > 8) {
player.forEachAvatar((avatar) => {
if (!charIds[avatar.id] && !avatar.isProfile) {
@ -193,7 +180,7 @@ const MysAvatar = {
return true
}
let needMap = { 0: avatar.hasTalent ? 60 * 48 : 60 * 3, 1: 60, 2: 0 }
if (MysAvatar.needRefresh(avatar._talent, force, needMap)) {
if (AvatarUtil.needRefresh(avatar._talent, force, needMap)) {
ret.push(avatar.id)
}
})

View File

@ -0,0 +1,91 @@
import AvatarUtil from './AvatarUtil.js'
import lodash from 'lodash'
import CharImg from '../character/CharImg.js'
import Serv from '../serv/Serv.js'
import { Cfg } from '#miao'
const ProfileAvatar = {
/**
* 更新面板数据
* @param player
* @param force
* @returns {Promise<boolean|number>}
*/
async refreshProfile (player, force = 2) {
if (!AvatarUtil.needRefresh(player._profile, force, { 0: 24, 1: 2, 2: 0 })) {
return false
}
let { uid, e } = player
if (uid.toString().length !== 9 || !e) {
return false
}
let ret = await Serv.req(e, player)
if (ret) {
player._profile = new Date() * 1
player.save()
return player._update.length
}
},
isProfile (avatar) {
if (avatar.isSr) {
return true
}
// 检查数据源
if (!avatar._source || !['enka', 'change', 'miao', 'mgg', 'hutao', 'homo'].includes(avatar._source)) {
return false
}
// 检查武器及天赋
if (!avatar.weapon || lodash.isUndefined(avatar.weapon.promote) || !avatar.talent) {
return false
}
// 检查圣遗物词条是否完备
if (!avatar.artis || !avatar.artis.hasAttr) {
return false
}
// 检查旅行者
if (['空', '荧'].includes(avatar.name)) {
return !!avatar.elem
}
return true
},
getCostumeSplash (profile) {
let { char, name } = profile
if (!Cfg.get('costumeSplash', true)) {
return char.getImgs(profile._costume).splash
}
let costume = profile._costume
costume = profile.char.checkCostume(costume) ? '2' : ''
if (!Cfg.get('costumeSplash', true)) {
return this.char.getImgs(profile._costume).splash
}
let nPath = `meta/character/${name}`
let isSuper = false
let talent = profile.talent ? lodash.map(profile.talent, (ds) => ds.original).join('') : ''
if (profile.cons === 6 || ['ACE', 'MAX'].includes(profile.artis?.markClass) || talent === '101010') {
isSuper = true
}
if (isSuper) {
return CharImg.getRandomImg(
[`profile/super-character/${name}`, `profile/normal-character/${name}`],
[`${nPath}/imgs/splash0.webp`, `${nPath}/imgs/splash${costume}.webp`, `/${nPath}/imgs/splash.webp`]
)
} else {
return CharImg.getRandomImg(
[`profile/normal-character/${name}`],
[`${nPath}/imgs/splash${costume}.webp`, `/${nPath}/imgs/splash.webp`]
)
}
},
getServ (uid, game = 'gs') {
return Serv.getServ(uid, game)
}
}
export default ProfileAvatar

View File

@ -96,7 +96,7 @@ const CharId = {
isSr (id) {
return gameMap[id] === 'sr'
},
getId (ds = '', gsCfg = null, game = 'gs') {
getId (ds = '', gsCfg = null, game = '') {
if (!ds) {
return false
}
@ -110,10 +110,12 @@ const CharId = {
if (!lodash.isObject(ds)) {
let original = lodash.trim(ds || '')
ds = original.toLowerCase()
// 尝试使用元素起始匹配
let em = Format.matchElem(ds, '', true)
if (em && aliasMap[em.name] && CharId.isTraveler(aliasMap[em.name])) {
return ret(aliasMap[em.name], em.elem)
if(game !== 'sr') {
// 尝试使用元素起始匹配
let em = Format.matchElem(ds, '', true)
if (em && aliasMap[em.name] && CharId.isTraveler(aliasMap[em.name])) {
return ret(aliasMap[em.name], em.elem)
}
}
// 直接匹配
if (aliasMap[ds]) {

View File

@ -147,37 +147,6 @@ const CharImg = {
imgs.cons3 = imgs[talentCons[3]]
imgs.cons5 = imgs[talentCons[5]]
return imgs
},
getCostumeSplash (profile) {
let {char, name} = profile
if (!Cfg.get('costumeSplash', true)) {
return char.getImgs(profile._costume).splash
}
let costume = profile._costume
costume = profile.char.checkCostume(costume) ? '2' : ''
if (!Cfg.get('costumeSplash', true)) {
return this.char.getImgs(profile._costume).splash
}
let nPath = `meta/character/${name}`
let isSuper = false
let talent = profile.talent ? lodash.map(profile.talent, (ds) => ds.original).join('') : ''
if (profile.cons === 6 || ['ACE', 'MAX'].includes(profile.artis?.markClass) || talent === '101010') {
isSuper = true
}
if (isSuper) {
return CharImg.getRandomImg(
[`profile/super-character/${name}`, `profile/normal-character/${name}`],
[`${nPath}/imgs/splash0.webp`, `${nPath}/imgs/splash${costume}.webp`, `/${nPath}/imgs/splash.webp`]
)
} else {
return CharImg.getRandomImg(
[`profile/normal-character/${name}`],
[`${nPath}/imgs/splash${costume}.webp`, `/${nPath}/imgs/splash.webp`]
)
}
}
}
export default CharImg

View File

@ -4,8 +4,6 @@ import Artifact from './Artifact.js'
import ArtifactSet from './ArtifactSet.js'
import Abyss from './Abyss.js'
import Player from './Player.js'
import ProfileServ from './ProfileServ.js'
import ProfileReq from './ProfileReq.js'
import Avatar from './Avatar.js'
import ProfileDmg from './ProfileDmg.js'
import ProfileRank from './ProfileRank.js'
@ -14,17 +12,12 @@ import Weapon from './Weapon.js'
import User from './User.js'
import MysApi from './MysApi.js'
export const ProfileData = Avatar
export const AvatarData = ProfileData
export {
Base,
Abyss,
Character,
Artifact,
ArtifactSet,
ProfileServ,
ProfileReq,
Avatar,
ProfileDmg,
ProfileRank,

View File

@ -1,137 +0,0 @@
import { ProfileReq, ProfileServ } from '../index.js'
import { Cfg, Data } from '#miao'
import MysAvatar from './MysAvatar.js'
import enkaApi from './EnkaApi.js'
import miaoApi from './MiaoApi.js'
import mggApi from './MggApi.js'
import hutaoApi from './HutaoApi.js'
import homoApi from './HomoApi.js'
import lodash from 'lodash'
import avocadoApi from './AvocadoApi.js'
import enkaHSRApi from './EnkaHSRApi.js'
let { diyCfg } = await Data.importCfg('profile')
const Profile = {
servs: {},
serv (key) {
if (!Profile.servs[key]) {
Profile.servs[key] = new ProfileServ({
miao: miaoApi,
mgg: mggApi,
enka: enkaApi,
hutao: hutaoApi,
homo: homoApi,
avocado: avocadoApi,
enkaHSR: enkaHSRApi
}[key])
}
return Profile.servs[key]
},
/**
* 根据UID分配请求服务器
* @param uid
* @param game
* @returns {ProfileServ}
*/
getServ (uid, game = 'gs') {
let token = diyCfg?.miaoApi?.token
let qq = diyCfg?.miaoApi?.qq
let hasToken = !!(qq && token && token.length === 32 && !/^test/.test(token))
let isGs = game === 'gs'
// 根据uid判断当前服务器类型。官服0 B服1 国际2
let servType = { 1: 0, 2: 0, 3: 0, 4: 0, 5: 1, 6: 2, 7: 2, 8: 2, 9: 2 }[uid[0]]
// 获取原神、星铁对应服务选择的配置
let servCfg = Cfg.get(isGs ? 'profileServer' : 'srProfileServer', '0').toString() || '0'
let servIdx = servCfg[servType] || servCfg[0] || '0'
// 设置为自动或1时如果具备token则使用miao
if ((servIdx === '0' || servIdx === '1') && hasToken) {
return Profile.serv('miao')
}
// 如果指定了序号则返回对应服务。0和1已前置判断
// 原神0自动1喵2Enka3Mgg, 4:Hutao
// 星铁0自动1喵2Mihomo3Avocado, 4EnkaHSR
let servKey = isGs ? {
2: 'enka',
3: 'mgg',
4: 'hutao'
} : {
2: 'homo',
3: 'avocado',
4: 'enkaHSR'
}
if (servKey[servIdx]) {
return Profile.serv(servKey[servIdx])
}
// 设置为0或无token使用返回默认的serv。官服0 B服1 国际2
let defServKey = isGs ? ['mgg', 'mgg', 'enka'] : ['homo', 'homo', 'homo']
return Profile.serv(defServKey[servType])
},
/**
* 更新面板数据
* @param player
* @param force
* @returns {Promise<boolean|number>}
*/
async refreshProfile (player, force = 2) {
if (!MysAvatar.needRefresh(player._profile, force, { 0: 24, 1: 2, 2: 0 })) {
return false
}
player._update = []
let { uid, e } = player
if (uid.toString().length !== 9 || !e) {
return false
}
let req = ProfileReq.create(e, player.game)
if (!req) {
return false
}
let serv = Profile.getServ(uid, player.game)
try {
await req.requestProfile(player, serv, player.game)
player._profile = new Date() * 1
player.save()
return player._update.length
} catch (err) {
if (!e._isReplyed) {
e.reply(`UID:${uid}更新面板失败,更新服务:${serv.name}`)
}
console.log(err)
return false
}
},
isProfile (avatar) {
if (avatar.isSr) {
return true
}
// 检查数据源
if (!avatar._source || !['enka', 'change', 'miao', 'mgg', 'hutao', 'homo'].includes(avatar._source)) {
return false
}
// 检查武器及天赋
if (!avatar.weapon || lodash.isUndefined(avatar.weapon.promote) || !avatar.talent) {
return false
}
// 检查圣遗物词条是否完备
if (!avatar.artis || !avatar.artis.hasAttr) {
return false
}
// 检查旅行者
if (['空', '荧'].includes(avatar.name)) {
return !!avatar.elem
}
return true
}
}
export default Profile

View File

@ -1,11 +1,11 @@
import Base from './Base.js'
import Base from '../Base.js'
import fetch from 'node-fetch'
export default class ProfileReq extends Base {
constructor (e, game = 'gs') {
super()
this.e = e
this.game = game
this.game = e.game || game
this.uid = e.uid
}
@ -17,7 +17,7 @@ export default class ProfileReq extends Base {
if (e.uid * 1 < 100000006) {
return false
}
return new ProfileReq(e, game)
return new ProfileReq(e, e.game || game)
}
async setCd (seconds = 60) {

View File

@ -1,10 +1,11 @@
import lodash from 'lodash'
import Base from './Base.js'
import { Data, Cfg } from '#miao'
import Base from '../Base.js'
import { Data } from '#miao'
let { sysCfg, diyCfg } = await Data.importCfg('profile')
export default class ProfileServ extends Base {
constructor (cfg) {
super()
this._name = cfg.name

99
models/serv/Serv.js Normal file
View File

@ -0,0 +1,99 @@
import { Cfg, Data } from '#miao'
let { diyCfg } = await Data.importCfg('profile')
import ProfileServ from './ProfileServ.js'
import ProfileReq from './ProfileReq.js'
import enkaApi from './api/EnkaApi.js'
import miaoApi from './api/MiaoApi.js'
import mggApi from './api/MggApi.js'
import hutaoApi from './api/HutaoApi.js'
import homoApi from './api/HomoApi.js'
import avocadoApi from './api/AvocadoApi.js'
import enkaHSRApi from './api/EnkaHSRApi.js'
const apis = {
miao: miaoApi,
mgg: mggApi,
enka: enkaApi,
hutao: hutaoApi,
homo: homoApi,
avocado: avocadoApi,
enkaHSR: enkaHSRApi
}
const servs = {}
const Serv = {
// 根据UID获取 ProfileServ
getServ (uid, game = 'gs') {
let token = diyCfg?.miaoApi?.token
let qq = diyCfg?.miaoApi?.qq
let hasToken = !!(qq && token && token.length === 32 && !/^test/.test(token))
let isGs = game === 'gs'
// 根据uid判断当前服务器类型。官服0 B服1 国际2
let servType = { 1: 0, 2: 0, 3: 0, 4: 0, 5: 1, 6: 2, 7: 2, 8: 2, 9: 2 }[uid[0]]
// 获取原神、星铁对应服务选择的配置
let servCfg = Cfg.get(isGs ? 'profileServer' : 'srProfileServer', '0').toString() || '0'
let servIdx = servCfg[servType] || servCfg[0] || '0'
// 设置为自动或1时如果具备token则使用miao
if ((servIdx === '0' || servIdx === '1') && hasToken) {
return Serv.serv('miao')
}
// 如果指定了序号则返回对应服务。0和1已前置判断
// 原神0自动1喵2Enka3Mgg, 4:Hutao
// 星铁0自动1喵2Mihomo3Avocado, 4EnkaHSR
let servKey = isGs ? {
2: 'enka',
3: 'mgg',
4: 'hutao'
} : {
2: 'homo',
3: 'avocado',
4: 'enkaHSR'
}
if (servKey[servIdx]) {
return Serv.serv(servKey[servIdx])
}
// 设置为0或无token使用返回默认的serv。官服0 B服1 国际2
let defServKey = isGs ? ['mgg', 'mgg', 'enka'] : ['homo', 'homo', 'homo']
return Serv.serv(defServKey[servType])
},
// 根据key获取ProfileServ
serv (key) {
if (!servs[key]) {
servs[key] = new ProfileServ(apis[key])
}
return servs[key]
},
// 发起请求
async req (e, player) {
let req = ProfileReq.create(e, player.game)
if (!req) {
return false
}
let serv = Serv.getServ(e.uid, player.game)
let { uid } = player
try {
player._update = []
await req.requestProfile(player, serv, player.game)
return player._update?.length || 0
} catch (err) {
if (!e._isReplyed) {
e.reply(`UID:${uid}更新面板失败,更新服务:${serv.name}`)
}
console.log(err)
return false
}
}
}
export default Serv

View File

@ -1,6 +1,6 @@
import lodash from 'lodash'
import { attrMap, idsMap, artisIdxMap } from './ProfileMeta.js'
import { Character, ArtifactSet, Weapon } from '../index.js'
import { Character, ArtifactSet, Weapon } from '#miao.models'
let EnkaData = {
setAvatar (player, data, dataSource = 'enka') {

View File

@ -1,6 +1,5 @@
import lodash from 'lodash'
import MiaoData from './MiaoData.js'
import { Data } from '#miao'
export default {
key: 'miao',

View File

@ -1,8 +1,6 @@
import { Character } from '../index.js'
import { Character } from '#miao.models'
import lodash from 'lodash'
import { attrMap, artisIdxMap } from './ProfileMeta.js'
let MiaoData = {
setAvatar (player, ds) {
let char = Character.get(ds.id)