将机器人的信息存入account表, 增加服务端获取机器人信息的接口

This commit is contained in:
zhl 2021-01-28 21:57:57 +08:00
parent 8dcac22067
commit 483af1973c
12 changed files with 197 additions and 61 deletions

View File

@ -666,15 +666,24 @@
{
nickname: '阿三', // 英雄id
avatar: true, // 头像
accountid: ''
score: 1000
}
```
### 5. 随机获取一个机器人信息
1. Method: GET
1. Method: POST
2. URI: /svr/randomrobot
> POST参数
| 字段 | 说明 |
| -------- | -------------------------------------- |
| min |最小天梯分 |
| max |最高天梯分 |
| accounts |需要过滤的accountid数组 |
3. Response: JSON
@ -683,6 +692,8 @@
{
nickname: '阿三', // 英雄id
avatar: true, // 头像
accountid: ''
score: 1000
}
```

5
package-lock.json generated
View File

@ -909,6 +909,11 @@
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
},
"nanoid": {
"version": "3.1.20",
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.1.20.tgz",
"integrity": "sha512-a1cQNyczgKbLX9jwbS/+d7W8fX/RfgYR7lVWwWOGIPNgK2m0MWvrGF6/m4kk6U3QcFMnZf3RIhL0v2Jgh/0Uxw=="
},
"once": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",

View File

@ -28,6 +28,7 @@
"mime-types": "^2.1.28",
"mongoose": "5.10.3",
"mongoose-findorcreate": "^3.0.0",
"nanoid": "^3.1.20",
"redis": "^2.8.0",
"tracer": "^1.1.4",
"urlencode": "^1.1.0"

View File

@ -81,4 +81,20 @@ export class BaseConst {
*/
public static readonly ROBOT_INFO_SEP = '|||'
public static readonly RANK_SCORE = 'rank_score'
/**
* id前缀
*/
public static readonly ROBOT_PREFIX = '1000_3200_'
/**
*
*/
public static readonly DEFAULT_ROBOT_NAME = '匿名玩家'
/**
*
*/
public static readonly DEFAULT_ROBOT_AVATAR = 'https://resource.kingsome.cn/matchvs_cdn/1.0.0.1/avatar/21_1.jpg'
}

View File

@ -1,64 +1,23 @@
import BaseController from '../common/base.controller'
import { role, router } from '../decorators/router'
import { User } from '../models/User'
import { ZError } from '../common/ZError'
import { Card } from '../models/subdoc/Card'
import { BaseConst } from '../constants/BaseConst'
import { Hero } from '../models/subdoc/Hero'
import { BagItem, ItemType } from '../models/BagItem'
import { addHeroDefaultCardGroup } from '../dao/CardGroupDao'
import { RedisClient } from '../redis/RedisClient'
import { checkGameing, setGameing, usersByScore } from '../service/rank'
import { fetchAccount } from '../dao/AccountDao'
import { generateId } from '../utils/security.util'
import { getRandom } from '../utils/number.util'
export default class AccountController extends BaseController {
@role('anon')
@router('post /api/:accountid/uinfo')
async info(req: any) {
let { accountid, nickname, avatar } = req.params
let account = (await User.findOrCreate({ _id: accountid })).doc
const account = await fetchAccount({accountid, nickname, avatar})
account.isnew = 0
await account.save()
let result: any = { accountid: account.id }
if (account.locked) {
throw new ZError(4, 'account locked')
}
const formulaCfg = global.$cfg.get(BaseConst.FORMULA)
if (account.season_score == -1) {
account.season_score = formulaCfg.get(70003).number
}
if (nickname) {
account.nickname = nickname
}
if (avatar) {
account.avatar = avatar
}
let cardMap = account.cardMap
for (let [, cfg] of global.$cfg.get(BaseConst.EFFECTCARD)) {
if (cfg.org_gift == 1 && cfg.type_id == 1 && !cardMap.has(cfg.id + '')) {
const card = new Card()
card.cardid = cfg.id
card.owned = true
card.ban = false
card.usetype = 0
card.free = true
card.free_expire = 0
card.time = Date.now()
cardMap.set(card.cardid + '', card)
}
}
for (let [, cfg] of global.$cfg.get(BaseConst.HERO)) {
if (cfg.org_gift == 1) {
let hero = new Hero()
hero.heroid = cfg.id
hero.free = true
hero.trial = false
hero.level = 1
hero.slot = 1
hero.time = Date.now()
hero.exp = 0
if (!account.heros.has(cfg.id + '')) {
account.heros.set(cfg.id + '', hero)
await addHeroDefaultCardGroup(accountid, hero.heroid, cardMap)
}
}
}
result.cards = [...account.cardMap.values()].map(o => o.toJson())
let heros: any[] = []
for (let [key, hero] of account.heros) {
@ -66,7 +25,6 @@ export default class AccountController extends BaseController {
}
result.heros = heros
await account.save()
const moneyList = await BagItem.find({accountid, itemtype: ItemType.MONEY})
result.moneys = moneyList.map(o => o.toJson())
result.normal_stat = account.normal_stat
@ -80,6 +38,7 @@ export default class AccountController extends BaseController {
async simpleInfo(req: any) {
let account = req.user
return {
accountid: account._id,
nickname: account.nickname,
avatar: account.avatar,
score: account.season_score
@ -88,15 +47,46 @@ export default class AccountController extends BaseController {
@router('post /svr/randomrobot')
async randomRobot(req: any) {
let { min, max } = req.params
// @ts-ignore
let str: string = await new RedisClient().srandmember(BaseConst.ROBOT_INFO)
let arr = ['default', 'https://resource.kingsome.cn/matchvs_cdn/1.0.0.1/avatar/21_1.jpg']
if (str)
arr = str.split(BaseConst.ROBOT_INFO_SEP)
let { min, max, accounts } = req.params
let accountSet = new Set(accounts)
let datas: any = await usersByScore(min, max)
let accountid, targetScore
if (datas.length > 0) {
for (let i = 0; i < datas.length; i += 2) {
let gameing = await checkGameing(datas[i])
if (gameing) {
continue
}
if (!accountSet.has(datas[i]) ) {
accountid = datas[i]
targetScore = datas[i + 1] | 0
break
}
}
}
if (!accountid) {
accountid = BaseConst.ROBOT_PREFIX + generateId()
targetScore = getRandom(min, max) | 0
}
let account = await fetchAccount({accountid, robot: true})
if (account.isnew) {
// @ts-ignore
let str: string = await new RedisClient().srandmember(BaseConst.ROBOT_INFO)
let arr = [BaseConst.DEFAULT_ROBOT_NAME, BaseConst.DEFAULT_ROBOT_AVATAR]
if (str)
arr = str.split(BaseConst.ROBOT_INFO_SEP)
account.nickname = arr[0]
account.avatar = arr[1]
account.season_score = targetScore
account.isnew = 0
await account.save()
}
await setGameing(accountid)
return {
nickname: arr[0],
avatar: arr[1]
accounid: account._id,
nickname: account.nickname,
avatar: account.avatar,
score: account.season_score
}
}

View File

@ -9,6 +9,7 @@ import { MatchCfg } from '../cfg/parsers/MatchCfg'
import ItemCtrl from '../logic/ItemCtrl'
import { ItemInfo } from '../logic/ItemDef'
import { BagItem } from '../models/BagItem'
import { updateRank } from '../service/rank'
export default class RecordController extends BaseController {
@role('anon')
@ -56,7 +57,8 @@ export default class RecordController extends BaseController {
continue
}
user.season_score = Math.max(user.season_score + player.scoreChange, fc.get(70002).number)
user.season_score = Math.max((user.season_score + player.scoreChange) | 0, fc.get(70002).number)
await updateRank(user._id, user.season_score)
if (!user.season_data) {
user.season_data = new Map()
}

62
src/dao/AccountDao.ts Normal file
View File

@ -0,0 +1,62 @@
import { User } from '../models/User'
import { ZError } from '../common/ZError'
import { BaseConst } from '../constants/BaseConst'
import { updateRank } from '../service/rank'
import { Card } from '../models/subdoc/Card'
import { Hero } from '../models/subdoc/Hero'
import { addHeroDefaultCardGroup } from './CardGroupDao'
export async function fetchAccount({ accountid, nickname, avatar, robot = false }
: { accountid: string, nickname?: string, avatar?: string, robot?: boolean }) {
let account = (await User.findOrCreate({ _id: accountid })).doc
if (account.locked) {
throw new ZError(4, 'account locked')
}
const formulaCfg = global.$cfg.get(BaseConst.FORMULA)
if (account.season_score == -1) {
account.season_score = formulaCfg.get(70003).number
await updateRank(accountid, account.season_score)
}
if (robot) {
account.robot = 1
}
if (nickname) {
account.nickname = nickname
}
if (avatar) {
account.avatar = avatar
}
let cardMap = account.cardMap
for (let [, cfg] of global.$cfg.get(BaseConst.EFFECTCARD)) {
if (cfg.org_gift == 1 && cfg.type_id == 1 && !cardMap.has(cfg.id + '')) {
const card = new Card()
card.cardid = cfg.id
card.owned = true
card.ban = false
card.usetype = 0
card.free = true
card.free_expire = 0
card.time = Date.now()
cardMap.set(card.cardid + '', card)
}
}
for (let [, cfg] of global.$cfg.get(BaseConst.HERO)) {
if (cfg.org_gift == 1) {
let hero = new Hero()
hero.heroid = cfg.id
hero.free = true
hero.trial = false
hero.level = 1
hero.slot = 1
hero.time = Date.now()
hero.exp = 0
if (!account.heros.has(cfg.id + '')) {
account.heros.set(cfg.id + '', hero)
await addHeroDefaultCardGroup(accountid, hero.heroid, cardMap)
}
}
}
await account.save()
return account
}

View File

@ -63,6 +63,9 @@ class UserClass extends FindOrCreate {
@prop({default: 0})
public robot: number
@prop({default: 1})
public isnew: number
/**
*
*/

View File

@ -156,6 +156,20 @@ export class RedisClient {
});
}
public async zadd(key: string, value: any, member: string) {
return new Promise((resolve) => {
this.pub.zadd(key, value, member, resolve);
});
}
public async zrangebyscore(key: string, min: number, max: number) {
return new Promise((resolve, reject) => {
this.pub.zrangebyscore(key, min, max, 'withscores', (err, data) => {
if (err) { return reject(err); }
resolve(data);
});
});
}
public async hset(key: string, field: string, value: string) {
return new Promise((resolve) => {
this.pub.hset(key, field, value, resolve);

View File

@ -1,4 +1,22 @@
import { RedisClient } from '../redis/RedisClient'
import { BaseConst } from '../constants/BaseConst'
export function updateRank(accountid: string, score: number) {
const MAX_TIME = 5000000000000
export async function updateRank(accountid: string, score: number) {
let scoreL = parseFloat(`${score | 0}.${MAX_TIME - Date.now()}`)
await new RedisClient().zadd(BaseConst.RANK_SCORE, scoreL, accountid)
}
export async function usersByScore(min: number, max: number) {
return await new RedisClient().zrangebyscore(BaseConst.RANK_SCORE, min, max)
}
export async function setGameing(accountid: string) {
await new RedisClient().setex('gameing_' + accountid, (Date.now() / 1000 | 0) + '', 30)
}
export async function checkGameing(accountid: string) {
return await new RedisClient().get('gameing_' + accountid)
}

10
src/utils/number.util.ts Normal file
View File

@ -0,0 +1,10 @@
/**
*
* @param {number} max
* @param {number} min
* @return {number}
*/
export function getRandom(max: number, min: number): number {
min = min || 0;
return Math.floor(Math.random()*(max-min)+min);
}

View File

@ -1,5 +1,5 @@
import crypto from 'crypto'
import { nanoid } from 'nanoid'
// 生成签名字段
// paramStr 为key1=val1&key2=val2, key1, key2按字母升序
@ -8,3 +8,7 @@ export function createSign(secretKey: string, paramStr: string, timestamp: numbe
paramStr = `${paramStr}:${timestamp}${secretKey}`;
return crypto.createHash('md5').update(paramStr, 'utf8').digest('hex');
}
export function generateId(length: number = 21) {
return nanoid(length);
}