将机器人的信息存入account表, 增加服务端获取机器人信息的接口
This commit is contained in:
parent
8dcac22067
commit
483af1973c
13
docs/api.md
13
docs/api.md
@ -666,15 +666,24 @@
|
|||||||
{
|
{
|
||||||
nickname: '阿三', // 英雄id
|
nickname: '阿三', // 英雄id
|
||||||
avatar: true, // 头像
|
avatar: true, // 头像
|
||||||
|
accountid: ''
|
||||||
|
score: 1000
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### 5. 随机获取一个机器人信息
|
### 5. 随机获取一个机器人信息
|
||||||
1. Method: GET
|
1. Method: POST
|
||||||
2. URI: /svr/randomrobot
|
2. URI: /svr/randomrobot
|
||||||
|
|
||||||
|
> POST参数
|
||||||
|
|
||||||
|
|
||||||
|
| 字段 | 说明 |
|
||||||
|
| -------- | -------------------------------------- |
|
||||||
|
| min |最小天梯分 |
|
||||||
|
| max |最高天梯分 |
|
||||||
|
| accounts |需要过滤的accountid数组 |
|
||||||
|
|
||||||
|
|
||||||
3. Response: JSON
|
3. Response: JSON
|
||||||
|
|
||||||
@ -683,6 +692,8 @@
|
|||||||
{
|
{
|
||||||
nickname: '阿三', // 英雄id
|
nickname: '阿三', // 英雄id
|
||||||
avatar: true, // 头像
|
avatar: true, // 头像
|
||||||
|
accountid: ''
|
||||||
|
score: 1000
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
5
package-lock.json
generated
5
package-lock.json
generated
@ -909,6 +909,11 @@
|
|||||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
|
||||||
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
|
"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": {
|
"once": {
|
||||||
"version": "1.4.0",
|
"version": "1.4.0",
|
||||||
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
|
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
|
||||||
|
@ -28,6 +28,7 @@
|
|||||||
"mime-types": "^2.1.28",
|
"mime-types": "^2.1.28",
|
||||||
"mongoose": "5.10.3",
|
"mongoose": "5.10.3",
|
||||||
"mongoose-findorcreate": "^3.0.0",
|
"mongoose-findorcreate": "^3.0.0",
|
||||||
|
"nanoid": "^3.1.20",
|
||||||
"redis": "^2.8.0",
|
"redis": "^2.8.0",
|
||||||
"tracer": "^1.1.4",
|
"tracer": "^1.1.4",
|
||||||
"urlencode": "^1.1.0"
|
"urlencode": "^1.1.0"
|
||||||
|
@ -81,4 +81,20 @@ export class BaseConst {
|
|||||||
*/
|
*/
|
||||||
public static readonly ROBOT_INFO_SEP = '|||'
|
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'
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,64 +1,23 @@
|
|||||||
import BaseController from '../common/base.controller'
|
import BaseController from '../common/base.controller'
|
||||||
import { role, router } from '../decorators/router'
|
import { role, router } from '../decorators/router'
|
||||||
import { User } from '../models/User'
|
|
||||||
import { ZError } from '../common/ZError'
|
|
||||||
import { Card } from '../models/subdoc/Card'
|
import { Card } from '../models/subdoc/Card'
|
||||||
import { BaseConst } from '../constants/BaseConst'
|
import { BaseConst } from '../constants/BaseConst'
|
||||||
import { Hero } from '../models/subdoc/Hero'
|
|
||||||
import { BagItem, ItemType } from '../models/BagItem'
|
import { BagItem, ItemType } from '../models/BagItem'
|
||||||
import { addHeroDefaultCardGroup } from '../dao/CardGroupDao'
|
|
||||||
import { RedisClient } from '../redis/RedisClient'
|
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 {
|
export default class AccountController extends BaseController {
|
||||||
@role('anon')
|
@role('anon')
|
||||||
@router('post /api/:accountid/uinfo')
|
@router('post /api/:accountid/uinfo')
|
||||||
async info(req: any) {
|
async info(req: any) {
|
||||||
let { accountid, nickname, avatar } = req.params
|
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 }
|
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())
|
result.cards = [...account.cardMap.values()].map(o => o.toJson())
|
||||||
let heros: any[] = []
|
let heros: any[] = []
|
||||||
for (let [key, hero] of account.heros) {
|
for (let [key, hero] of account.heros) {
|
||||||
@ -66,7 +25,6 @@ export default class AccountController extends BaseController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
result.heros = heros
|
result.heros = heros
|
||||||
await account.save()
|
|
||||||
const moneyList = await BagItem.find({accountid, itemtype: ItemType.MONEY})
|
const moneyList = await BagItem.find({accountid, itemtype: ItemType.MONEY})
|
||||||
result.moneys = moneyList.map(o => o.toJson())
|
result.moneys = moneyList.map(o => o.toJson())
|
||||||
result.normal_stat = account.normal_stat
|
result.normal_stat = account.normal_stat
|
||||||
@ -80,6 +38,7 @@ export default class AccountController extends BaseController {
|
|||||||
async simpleInfo(req: any) {
|
async simpleInfo(req: any) {
|
||||||
let account = req.user
|
let account = req.user
|
||||||
return {
|
return {
|
||||||
|
accountid: account._id,
|
||||||
nickname: account.nickname,
|
nickname: account.nickname,
|
||||||
avatar: account.avatar,
|
avatar: account.avatar,
|
||||||
score: account.season_score
|
score: account.season_score
|
||||||
@ -88,15 +47,46 @@ export default class AccountController extends BaseController {
|
|||||||
|
|
||||||
@router('post /svr/randomrobot')
|
@router('post /svr/randomrobot')
|
||||||
async randomRobot(req: any) {
|
async randomRobot(req: any) {
|
||||||
let { min, max } = req.params
|
let { min, max, accounts } = req.params
|
||||||
// @ts-ignore
|
let accountSet = new Set(accounts)
|
||||||
let str: string = await new RedisClient().srandmember(BaseConst.ROBOT_INFO)
|
let datas: any = await usersByScore(min, max)
|
||||||
let arr = ['default', 'https://resource.kingsome.cn/matchvs_cdn/1.0.0.1/avatar/21_1.jpg']
|
let accountid, targetScore
|
||||||
if (str)
|
if (datas.length > 0) {
|
||||||
arr = str.split(BaseConst.ROBOT_INFO_SEP)
|
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 {
|
return {
|
||||||
nickname: arr[0],
|
accounid: account._id,
|
||||||
avatar: arr[1]
|
nickname: account.nickname,
|
||||||
|
avatar: account.avatar,
|
||||||
|
score: account.season_score
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -9,6 +9,7 @@ import { MatchCfg } from '../cfg/parsers/MatchCfg'
|
|||||||
import ItemCtrl from '../logic/ItemCtrl'
|
import ItemCtrl from '../logic/ItemCtrl'
|
||||||
import { ItemInfo } from '../logic/ItemDef'
|
import { ItemInfo } from '../logic/ItemDef'
|
||||||
import { BagItem } from '../models/BagItem'
|
import { BagItem } from '../models/BagItem'
|
||||||
|
import { updateRank } from '../service/rank'
|
||||||
|
|
||||||
export default class RecordController extends BaseController {
|
export default class RecordController extends BaseController {
|
||||||
@role('anon')
|
@role('anon')
|
||||||
@ -56,7 +57,8 @@ export default class RecordController extends BaseController {
|
|||||||
continue
|
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) {
|
if (!user.season_data) {
|
||||||
user.season_data = new Map()
|
user.season_data = new Map()
|
||||||
}
|
}
|
||||||
|
62
src/dao/AccountDao.ts
Normal file
62
src/dao/AccountDao.ts
Normal 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
|
||||||
|
}
|
@ -63,6 +63,9 @@ class UserClass extends FindOrCreate {
|
|||||||
|
|
||||||
@prop({default: 0})
|
@prop({default: 0})
|
||||||
public robot: number
|
public robot: number
|
||||||
|
|
||||||
|
@prop({default: 1})
|
||||||
|
public isnew: number
|
||||||
/**
|
/**
|
||||||
* 已获得卡牌信息
|
* 已获得卡牌信息
|
||||||
*/
|
*/
|
||||||
|
@ -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) {
|
public async hset(key: string, field: string, value: string) {
|
||||||
return new Promise((resolve) => {
|
return new Promise((resolve) => {
|
||||||
this.pub.hset(key, field, value, resolve);
|
this.pub.hset(key, field, value, resolve);
|
||||||
|
@ -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
10
src/utils/number.util.ts
Normal 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);
|
||||||
|
}
|
@ -1,5 +1,5 @@
|
|||||||
|
|
||||||
import crypto from 'crypto'
|
import crypto from 'crypto'
|
||||||
|
import { nanoid } from 'nanoid'
|
||||||
|
|
||||||
// 生成签名字段
|
// 生成签名字段
|
||||||
// paramStr 为key1=val1&key2=val2, key1, key2按字母升序
|
// paramStr 为key1=val1&key2=val2, key1, key2按字母升序
|
||||||
@ -8,3 +8,7 @@ export function createSign(secretKey: string, paramStr: string, timestamp: numbe
|
|||||||
paramStr = `${paramStr}:${timestamp}${secretKey}`;
|
paramStr = `${paramStr}:${timestamp}${secretKey}`;
|
||||||
return crypto.createHash('md5').update(paramStr, 'utf8').digest('hex');
|
return crypto.createHash('md5').update(paramStr, 'utf8').digest('hex');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function generateId(length: number = 21) {
|
||||||
|
return nanoid(length);
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user