finish unlock hero
This commit is contained in:
parent
dd5c51c722
commit
c4c3ba8ac1
23
docs/api.md
23
docs/api.md
@ -244,8 +244,7 @@
|
|||||||
|
|
||||||
| 字段 | 说明 |
|
| 字段 | 说明 |
|
||||||
| -------- | -------------------------------------- |
|
| -------- | -------------------------------------- |
|
||||||
| moneyid |代币的item id |
|
| count |使用数量 |
|
||||||
| count |试用数量 |
|
|
||||||
|
|
||||||
3. Response: JSON
|
3. Response: JSON
|
||||||
|
|
||||||
@ -258,7 +257,25 @@
|
|||||||
```
|
```
|
||||||
|
|
||||||
### 11. 将专属英雄碎片转化成经验
|
### 11. 将专属英雄碎片转化成经验
|
||||||
|
1. Method: POST
|
||||||
|
2. URI: /api/:accountid/hero/toexp/:heroid
|
||||||
|
|
||||||
|
| 字段 | 说明 |
|
||||||
|
| -------- | -------------------------------------- |
|
||||||
|
| accountid | 帐号id |
|
||||||
|
| heroid | 英雄id |
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
3. Response: JSON
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
exp: 1022, // 当前经验值
|
||||||
|
exp_POST: 100, // 本次获得的经验
|
||||||
|
level: 1 // 当前等级
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
## 三. 服务端接口列表
|
## 三. 服务端接口列表
|
||||||
|
|
||||||
@ -277,3 +294,5 @@
|
|||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
```
|
@ -1,18 +1,15 @@
|
|||||||
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 {Account} from "../models/Account";
|
import {User} from "../models/User";
|
||||||
import {ZError} from "../common/ZError";
|
import {ZError} from "../common/ZError";
|
||||||
import {Hero} from "../models/subdoc/Hero";
|
|
||||||
import {Card} from "../models/subdoc/Card";
|
import {Card} from "../models/subdoc/Card";
|
||||||
import {CardGroup} from "../models/CardGroup";
|
|
||||||
import {MoneyTypeConst} from "../constants/MoneyTypeConst";
|
|
||||||
|
|
||||||
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} = req.params;
|
let {accountid} = req.params;
|
||||||
let account = (await Account.findOrCreate({_id: accountid})).doc;
|
let account = (await User.findOrCreate({_id: accountid})).doc;
|
||||||
let result: any = {accountid: account.id};
|
let result: any = {accountid: account.id};
|
||||||
if (account.locked) {
|
if (account.locked) {
|
||||||
throw new ZError(4, 'account locked');
|
throw new ZError(4, 'account locked');
|
||||||
@ -63,69 +60,5 @@ export default class AccountController extends BaseController {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@router('post /api/:accountid/heros')
|
|
||||||
async herolist(req: any) {
|
|
||||||
let account = req.user;
|
|
||||||
let heros: any[] = [];
|
|
||||||
for(let [key, hero] of account.heros) {
|
|
||||||
heros.push({
|
|
||||||
heroid: hero.heroid,
|
|
||||||
owned: true,
|
|
||||||
usetype: 0,
|
|
||||||
level: hero.level,
|
|
||||||
exp: hero.exp,
|
|
||||||
free: hero.free,
|
|
||||||
free_expire: 0
|
|
||||||
});
|
|
||||||
}
|
|
||||||
//TODO:: 添加限免英雄和免费英雄
|
|
||||||
return heros;
|
|
||||||
}
|
|
||||||
|
|
||||||
@router('post /api/:accountid/hero/unlock/:heroid')
|
|
||||||
async unlockHero(req: any) {
|
|
||||||
let account = req.user;
|
|
||||||
let {heroid, type} = req.params;
|
|
||||||
if (!heroid) {
|
|
||||||
throw new ZError(101, '未指定heroid');
|
|
||||||
}
|
|
||||||
if (account.heros.has(heroid + '')) {
|
|
||||||
if (!account.heros.get(heroid + '').free) {
|
|
||||||
throw new ZError(102, '你已经解锁了该英雄');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
let money0 = MoneyTypeConst.getHeroShard(heroid);
|
|
||||||
let money1 = MoneyTypeConst.HERO_SHARD;
|
|
||||||
let count0 = account.moneys.has(money0) ? account.moneys.get(money0) : 0;
|
|
||||||
let count1 = account.moneys.has(money1) ? account.moneys.get(money1) : 0;
|
|
||||||
// TODO:: 根据配置获取解锁英雄需要的碎片数量
|
|
||||||
let needCount = 30;
|
|
||||||
if (count0 + count1 < needCount) {
|
|
||||||
throw new ZError(102, '碎片数量不足');
|
|
||||||
}
|
|
||||||
if (count0 > 0) {
|
|
||||||
let rest = needCount - count0;
|
|
||||||
if (rest >= 0) {
|
|
||||||
needCount = rest;
|
|
||||||
account.moneys.set(money0, 0);
|
|
||||||
} else {
|
|
||||||
needCount = 0;
|
|
||||||
account.moneys.set(money0, Math.abs(rest));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// 上面已经过滤了 count0 + count1 > needcount, 所以这里不需要判断碎片是否足够
|
|
||||||
if (needCount > 0) {
|
|
||||||
count1 = count1 - needCount;
|
|
||||||
account.moneys.set(money1, count1);
|
|
||||||
}
|
|
||||||
let hero = new Hero();
|
|
||||||
hero.heroid = heroid;
|
|
||||||
hero.free = false;
|
|
||||||
hero.level = 1;
|
|
||||||
hero.exp = 0;
|
|
||||||
account.heros.set(heroid + '', hero);
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
70
src/controllers/HeroController.ts
Normal file
70
src/controllers/HeroController.ts
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
import BaseController from "../common/base.controller";
|
||||||
|
import {router} from "../decorators/router";
|
||||||
|
import {ZError} from "../common/ZError";
|
||||||
|
import {MoneyTypeConst} from "../constants/MoneyTypeConst";
|
||||||
|
import {Hero} from "../models/subdoc/Hero";
|
||||||
|
import {User} from "../models/User";
|
||||||
|
|
||||||
|
export default class HeroController extends BaseController {
|
||||||
|
@router('post /api/:accountid/heros')
|
||||||
|
async herolist(req: any) {
|
||||||
|
let account = req.user;
|
||||||
|
let heros: any[] = [];
|
||||||
|
for(let [key, hero] of account.heros) {
|
||||||
|
heros.push({
|
||||||
|
heroid: hero.heroid,
|
||||||
|
owned: true,
|
||||||
|
usetype: 0,
|
||||||
|
level: hero.level,
|
||||||
|
exp: hero.exp,
|
||||||
|
free: hero.free,
|
||||||
|
free_expire: 0
|
||||||
|
});
|
||||||
|
}
|
||||||
|
//TODO:: 添加限免英雄和免费英雄
|
||||||
|
return heros;
|
||||||
|
}
|
||||||
|
|
||||||
|
@router('post /api/:accountid/hero/unlock/:heroid')
|
||||||
|
async unlockHero(req: any) {
|
||||||
|
let account = req.user;
|
||||||
|
let {heroid, type} = req.params;
|
||||||
|
if (!heroid) {
|
||||||
|
throw new ZError(101, '未指定heroid');
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
if (!type) {
|
||||||
|
let hero = await account.unlockHero(heroid);
|
||||||
|
await account.save();
|
||||||
|
return hero;
|
||||||
|
} else {
|
||||||
|
let hero = await account.tryHero(heroid);
|
||||||
|
await account.save();
|
||||||
|
return hero;
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@router('post /api/:accountid/hero/update/:heroid')
|
||||||
|
async updateHero(req: any) {
|
||||||
|
let account = req.user;
|
||||||
|
let {heroid, count} = req.params;
|
||||||
|
if (!heroid) {
|
||||||
|
throw new ZError(101, '未指定heroid');
|
||||||
|
}
|
||||||
|
if (!account.heros.has(heroid + '')) {
|
||||||
|
throw new ZError(102, '你未解锁该英雄');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@router('post /api/:accountid/hero/toexp/:heroid')
|
||||||
|
async shardToExp(req: any) {
|
||||||
|
let account = req.user;
|
||||||
|
let {heroid} = req.params;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@ -1,91 +0,0 @@
|
|||||||
import {
|
|
||||||
prop,
|
|
||||||
getModelForClass,
|
|
||||||
modelOptions,
|
|
||||||
index,
|
|
||||||
plugin,
|
|
||||||
mongoose
|
|
||||||
} from '@typegoose/typegoose';
|
|
||||||
import {dbconn} from '../decorators/dbconn';
|
|
||||||
// @ts-ignore
|
|
||||||
import findOrCreate from 'mongoose-findorcreate';
|
|
||||||
import {
|
|
||||||
Base,
|
|
||||||
FindOrCreate,
|
|
||||||
TimeStamps
|
|
||||||
} from "@typegoose/typegoose/lib/defaultClasses";
|
|
||||||
import {Card} from "./subdoc/Card";
|
|
||||||
import {Hero} from "./subdoc/Hero";
|
|
||||||
|
|
||||||
interface AccountClass extends Base<string>, TimeStamps {}
|
|
||||||
@dbconn()
|
|
||||||
// @index({ _id: 1}, { unique: true })
|
|
||||||
@plugin(findOrCreate)
|
|
||||||
@modelOptions({schemaOptions:
|
|
||||||
{collection: "account", timestamps: true}
|
|
||||||
})
|
|
||||||
class AccountClass extends FindOrCreate{
|
|
||||||
@prop()
|
|
||||||
public _id: string;
|
|
||||||
|
|
||||||
@prop({default: false})
|
|
||||||
public locked: boolean;
|
|
||||||
@prop()
|
|
||||||
public lockedtime?: number;
|
|
||||||
|
|
||||||
@prop()
|
|
||||||
public comment?: string;
|
|
||||||
@prop()
|
|
||||||
public lastLogin?: Date;
|
|
||||||
/**
|
|
||||||
* 已获得卡牌信息
|
|
||||||
*/
|
|
||||||
@prop({ type: () => [Number] })
|
|
||||||
public cards: number[];
|
|
||||||
/**
|
|
||||||
* 已解锁英雄信息
|
|
||||||
*/
|
|
||||||
@prop({ type: Hero, default: new Map() })
|
|
||||||
public heros: Map<string, Hero>;
|
|
||||||
/**
|
|
||||||
* 货币信息
|
|
||||||
* coin: 金币
|
|
||||||
* diamond: 钻石
|
|
||||||
* hero_shard: 通用英雄碎片
|
|
||||||
* hero_exp: 通用英雄经验
|
|
||||||
* hero_shard_heroid: 英雄专用碎片
|
|
||||||
* hero_exp_heroid: 英雄专用经验
|
|
||||||
* card_scroll: 抽卡卷轴
|
|
||||||
*/
|
|
||||||
@prop({ type: Number, default: new Map() })
|
|
||||||
public moneys: Map<string, number>;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 匹配: 胜利场数, 失败场数, 平局场数, 掉线场数
|
|
||||||
*/
|
|
||||||
@prop({type: Number, default: [0,0,0,0]})
|
|
||||||
public normal_stat: number[];
|
|
||||||
/**
|
|
||||||
* 当前赛季: 胜利场数, 失败场数, 平局场数, 掉线场数
|
|
||||||
*/
|
|
||||||
@prop({type: Number, default: [0,0,0,0]})
|
|
||||||
public season_stat: number[];
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 所有未定义的信息, 供扩展
|
|
||||||
*/
|
|
||||||
@prop({type: mongoose.Schema.Types.Mixed})
|
|
||||||
public extinfo: any;
|
|
||||||
|
|
||||||
public toJson() {
|
|
||||||
return {
|
|
||||||
accountid: this._id,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
export const Account = getModelForClass(AccountClass,
|
|
||||||
// @ts-ignore
|
|
||||||
{existingConnection: AccountClass['db']});
|
|
146
src/models/User.ts
Normal file
146
src/models/User.ts
Normal file
@ -0,0 +1,146 @@
|
|||||||
|
import {
|
||||||
|
prop,
|
||||||
|
getModelForClass,
|
||||||
|
modelOptions,
|
||||||
|
index,
|
||||||
|
plugin,
|
||||||
|
mongoose
|
||||||
|
} from '@typegoose/typegoose';
|
||||||
|
import {dbconn} from '../decorators/dbconn';
|
||||||
|
// @ts-ignore
|
||||||
|
import findOrCreate from 'mongoose-findorcreate';
|
||||||
|
import {
|
||||||
|
Base,
|
||||||
|
FindOrCreate,
|
||||||
|
TimeStamps
|
||||||
|
} from "@typegoose/typegoose/lib/defaultClasses";
|
||||||
|
import {Card} from "./subdoc/Card";
|
||||||
|
import {Hero} from "./subdoc/Hero";
|
||||||
|
import {ZError} from "../common/ZError";
|
||||||
|
import {MoneyTypeConst} from "../constants/MoneyTypeConst";
|
||||||
|
|
||||||
|
interface AccountClass extends Base<string>, TimeStamps {}
|
||||||
|
@dbconn()
|
||||||
|
// @index({ _id: 1}, { unique: true })
|
||||||
|
@plugin(findOrCreate)
|
||||||
|
@modelOptions({schemaOptions:
|
||||||
|
{collection: "account", timestamps: true}
|
||||||
|
})
|
||||||
|
class UserClass extends FindOrCreate{
|
||||||
|
@prop()
|
||||||
|
public _id: string;
|
||||||
|
|
||||||
|
@prop({default: false})
|
||||||
|
public locked: boolean;
|
||||||
|
@prop()
|
||||||
|
public lockedtime?: number;
|
||||||
|
|
||||||
|
@prop()
|
||||||
|
public comment?: string;
|
||||||
|
@prop()
|
||||||
|
public lastLogin?: Date;
|
||||||
|
/**
|
||||||
|
* 已获得卡牌信息
|
||||||
|
*/
|
||||||
|
@prop({ type: () => [Number] })
|
||||||
|
public cards: number[];
|
||||||
|
/**
|
||||||
|
* 已解锁英雄信息
|
||||||
|
*/
|
||||||
|
@prop({ type: Hero, default: new Map() })
|
||||||
|
public heros: Map<string, Hero>;
|
||||||
|
/**
|
||||||
|
* 货币信息
|
||||||
|
* coin: 金币
|
||||||
|
* diamond: 钻石
|
||||||
|
* hero_shard: 通用英雄碎片
|
||||||
|
* hero_exp: 通用英雄经验
|
||||||
|
* hero_shard_heroid: 英雄专用碎片
|
||||||
|
* hero_exp_heroid: 英雄专用经验
|
||||||
|
* card_scroll: 抽卡卷轴
|
||||||
|
*/
|
||||||
|
@prop({ type: Number, default: new Map() })
|
||||||
|
public moneys: Map<string, number>;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 匹配: 胜利场数, 失败场数, 平局场数, 掉线场数
|
||||||
|
*/
|
||||||
|
@prop({type: Number, default: [0,0,0,0]})
|
||||||
|
public normal_stat: number[];
|
||||||
|
/**
|
||||||
|
* 当前赛季: 胜利场数, 失败场数, 平局场数, 掉线场数
|
||||||
|
*/
|
||||||
|
@prop({type: Number, default: [0,0,0,0]})
|
||||||
|
public season_stat: number[];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 所有未定义的信息, 供扩展
|
||||||
|
*/
|
||||||
|
@prop({type: mongoose.Schema.Types.Mixed})
|
||||||
|
public extinfo: any;
|
||||||
|
|
||||||
|
public toJson() {
|
||||||
|
return {
|
||||||
|
accountid: this._id,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async unlockHero(heroid: number) {
|
||||||
|
if (this.heros.has(heroid + '')) {
|
||||||
|
if (!this.heros.get(heroid + '').free) {
|
||||||
|
throw new ZError(102, '你已经解锁了该英雄');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let money0 = MoneyTypeConst.getHeroShard(heroid);
|
||||||
|
let money1 = MoneyTypeConst.HERO_SHARD;
|
||||||
|
let count0 = this.moneys.has(money0) ? this.moneys.get(money0) : 0;
|
||||||
|
let count1 = this.moneys.has(money1) ? this.moneys.get(money1) : 0;
|
||||||
|
// TODO:: 根据配置获取解锁英雄需要的碎片数量
|
||||||
|
let needCount = 30;
|
||||||
|
if (count0 + count1 < needCount) {
|
||||||
|
throw new ZError(102, '碎片数量不足');
|
||||||
|
}
|
||||||
|
if (count0 > 0) {
|
||||||
|
let rest = needCount - count0;
|
||||||
|
if (rest >= 0) {
|
||||||
|
needCount = rest;
|
||||||
|
this.moneys.set(money0, 0);
|
||||||
|
} else {
|
||||||
|
needCount = 0;
|
||||||
|
this.moneys.set(money0, Math.abs(rest));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 上面已经过滤了 count0 + count1 > needcount, 所以这里不需要判断碎片是否足够
|
||||||
|
if (needCount > 0) {
|
||||||
|
count1 = count1 - needCount;
|
||||||
|
this.moneys.set(money1, count1);
|
||||||
|
}
|
||||||
|
let hero = new Hero();
|
||||||
|
hero.heroid = heroid;
|
||||||
|
hero.free = false;
|
||||||
|
hero.level = 1;
|
||||||
|
hero.exp = 0;
|
||||||
|
this.heros.set(heroid + '', hero);
|
||||||
|
return hero;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async tryHero(heroid: number) {
|
||||||
|
if (this.heros.has(heroid + '')) {
|
||||||
|
throw new ZError(102, '你已经解锁了该英雄');
|
||||||
|
}
|
||||||
|
//TODO:: 根据配置查看该英雄是否可使用
|
||||||
|
let hero = new Hero();
|
||||||
|
hero.heroid = heroid;
|
||||||
|
hero.free = true;
|
||||||
|
hero.level = 1;
|
||||||
|
hero.exp = 0;
|
||||||
|
this.heros.set(heroid+'', hero);
|
||||||
|
return hero;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export const User = getModelForClass(UserClass,
|
||||||
|
// @ts-ignore
|
||||||
|
{existingConnection: UserClass['db']});
|
@ -4,7 +4,7 @@ import {
|
|||||||
FastifyRequest,
|
FastifyRequest,
|
||||||
} from 'fastify';
|
} from 'fastify';
|
||||||
import fastifyPlugin from 'fastify-plugin';
|
import fastifyPlugin from 'fastify-plugin';
|
||||||
import {Account} from '../models/Account';
|
import {User} from '../models/User';
|
||||||
import {ZError} from "../common/ZError";
|
import {ZError} from "../common/ZError";
|
||||||
|
|
||||||
declare module 'fastify' {
|
declare module 'fastify' {
|
||||||
@ -41,7 +41,7 @@ const apiAuthPlugin: FastifyPluginAsync = async function(
|
|||||||
// if (!data || !data.id) {
|
// if (!data || !data.id) {
|
||||||
// return reply.send({code: 10, msg: 'need login'});
|
// return reply.send({code: 10, msg: 'need login'});
|
||||||
// }
|
// }
|
||||||
let account = await Account.findById(accountid);
|
let account = await User.findById(accountid);
|
||||||
if (!account) {
|
if (!account) {
|
||||||
return reply.send({code: 5, msg: 'account not found'});
|
return reply.send({code: 5, msg: 'account not found'});
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user