Merge branch 'normalBattle'

This commit is contained in:
liangtongchuan
2020-09-14 22:24:44 +08:00
29 changed files with 9365 additions and 7 deletions

3
.gitignore vendored
View File

@@ -1,3 +1,6 @@
node_modules
game-server/dist
game-server/logs
*.DS_Store
.vscode/*
shared/**/*.js

1
game-server/app/resource Symbolic link
View File

@@ -0,0 +1 @@
../../shared/resource

View File

@@ -0,0 +1,181 @@
import { Application, BackendSession } from 'pinus';
import { BattleRecordModel } from '../../../db/BattleRecord';
import { getWarById, getGoodById } from '../../../util/gamedata';
import { CounterModel } from '../../../db/Counter';
import { HeroModel } from '../../../db/Hero';
import { EquipModel } from '../../../db/Equip';
import { genCode } from '../../../util/util';
export default function(app: Application) {
return new NormalBattleHandler(app);
}
export class NormalBattleHandler {
constructor(private app: Application) {
}
// 进入关卡前,记录信息,生成唯一标识
async checkBattle(msg: {battleId: number, heroes: Array<any> }, session: BackendSession) {
const { battleId, heroes } = msg;
let roleId = session.get('roleId');
let roleName = session.get('roleName');
let warInfo = getWarById(battleId);
if(!warInfo) {
return {
code: 202,
data: "缺少关卡信息"
}
}
const battleCode = genCode(8);
const BattleRecord = await BattleRecordModel.updateBattleRecordByCode(battleCode, {
$set: {
roleId,
roleName,
battleId,
status: 0,
warName: warInfo.gk_name,
warType: warInfo.war_type,
record: { heroes }
}
}, true);
let {status} = BattleRecord;
return {
code: 200,
data: {
battleId, battleCode, status
}
}
}
// 关卡结算,记录使用的武将,获得奖励
async battleEnd(msg: {battleCode: string, battleId: number, isSuccess: boolean, heroes: Array<any>, }, session: BackendSession) {
const { battleCode, battleId, isSuccess, heroes } = msg;
let roleId = session.get('roleId');
let roleName = session.get('roleName');
let warInfo = getWarById(battleId);
const BattleRecord = await BattleRecordModel.getBattleRecordByCode(battleCode, true);
if(!BattleRecord || BattleRecord.status != 0) {
return {
code: 202,
data: '关卡状态错误'
}
}
let flag = 1; // 对比hero信息
let { record: { heroes: dbHeroes } } = BattleRecord;
for(let hid of heroes) {
if(dbHeroes.indexOf(hid) == -1) flag = 0;
}
if(!flag) {
return {
code: 202,
data: '关卡信息不同'
}
}
let params = {}, reward: Array<any>;
if(isSuccess) { // 挑战胜利
params = {
$set: {
status: 1,
record: { heroes }
}
}
reward = await this.handleReward(roleId, roleName, warInfo.reward);
} else { // 挑战失败
params = {
$set: {
status: 2,
record: { heroes }
}
}
reward = [];
}
const updateResult = await BattleRecordModel.updateBattleRecordByCode(battleCode, params, true);
let { status } = updateResult;
return {
code: 200,
data: {
battleCode, battleId, status,
goods: reward
}
}
}
private async handleReward(roleId: string, roleName: string, rewardStr:string) {
let {weapons, armors, items, souls} = this.decodeReward(rewardStr);
let addWeapons = await this.rewardWeapons(roleId, roleName, weapons);
// 暂时只处理装备
// let addArmors = await this.rewardArmors(roleId, roleName, armors);
// let addItems = await this.rewardItems(roleId, roleName, items);
// let addSouls = await this.rewardSouls(roleId, roleName, souls);
let result = [].concat(addWeapons);
return result;
}
private async rewardWeapons (roleId: string, roleName:string, weapons: Array<{id:number,cnt:number, type: number}>) {
let weaponsData = [];
for (let weapon of weapons) {
let cnt = weapon.cnt;
let g = getGoodById(weapon.id);
while (cnt > 0) {
const seqId = await CounterModel.getNewCounter('eid');
const equipInfo = {
roleId,
roleName,
eid: weapon.id,
eName: g.name,
seqId,
type: weapon.type,
lv: g.lv
}
const equip = await EquipModel.createEquip(equipInfo);
cnt -= 1;
weaponsData.push(equip);
}
}
return weaponsData;
}
private decodeReward(rewardStr: string, multiple=1) {
let weapons = [];
let armors = [];
let items = [];
let souls = [];
rewardStr.split('|').forEach((rStr) => {
// r[0]: type, r[1]: id, r[2]: count
let r = rStr.split('&');
let type = parseInt(r[0] || '')||0;
let id = parseInt(r[1] || '') || 0;
let cnt = (parseInt(r[2] || '') || 0) * multiple;
if (id !== 0 && cnt !== 0) {
switch (r[0]) {
case '0':
items.push({id, cnt, type});
break;
case '1':
weapons.push({id, cnt, type});
break;
case '2':
armors.push({id, cnt, type});
break;
case '3':
souls.push({id, cnt, type});
break;
default:
break;
}
}
});
return {weapons, armors, items, souls};
}
}

View File

@@ -31,7 +31,8 @@ export class EntryHandler {
console.log('user token not found');
return {
code: 500,
error: true
error: true,
data: 'user token not found'
};
}

View File

@@ -0,0 +1,44 @@
const fs = require('fs');
const path = require('path');
var gamedata = {};
function initData () {
fs.readdirSync(__dirname + '/../resource')
.filter(function(file) {
return (file.indexOf(".") !== 0) && (file !== "index.js");
})
//筛选有文件名且不是index进行遍历
.forEach(function(file) {
var name = file.split('.')[0];
try {
gamedata[name] = JSON.parse(
fs.readFileSync(path.resolve(__dirname, "../resource/" + file))
);
} catch(e) {
console.error('【文件缺少】:' + file);
gamedata[name] = [];
}
});
}
initData();
export function getGamedata(key) {
return gamedata[key];
}
export function getWarById(warid) {
let warInfo = gamedata['dic_zyz_gk']||[];
return warInfo.find(cur => {
return cur.war_id == warid
});
}
export function getGoodById(gid) {
console.log(gid)
let goodsInfo = gamedata['goods']||[];
return goodsInfo.find(cur => {
return cur.good_id == gid
});
}

View File

@@ -0,0 +1,10 @@
export function genCode(len) {
const chars = '123456789ABCDEFGHJKLMNPQRSTWXYZabcdefghijklmnopqrstuvwxyz';
const charArr = chars.split('');
let code = '';
for (let i = 0; i < len; i++) {
code += charArr[Math.floor(Math.random() * charArr.length)];
}
return code;
}

View File

@@ -7,5 +7,8 @@ module.exports = [{
}, {
'type': 'gate',
'token': 'agarxhqb98rpajloaxn34ga8xrunpagkjwlaw3ruxnpaagl29w4rxn'
}, {
'type': 'battle',
'token': 'agarxhqb98rpajloaxn34ga8xrunpagkjwlaw3ruxnpaagl29w4rxn'
}
];

View File

@@ -7,6 +7,7 @@
],
"module": "commonjs", //指定生成哪个模块系统代码
"target": "es2017",
"resolveJsonModule": true,
"lib": [
"es2015",
"es2016",
@@ -24,6 +25,7 @@
"watch":false //在监视模式下运行编译器。会监视输出文件,在它们改变时重新编译。
},
"include":[
"./app/**/*.json",
"./app/**/*.ts",
"./config/**/*.ts",
"./app.ts",

View File

@@ -1,4 +1,5 @@
import { prop, pre } from '@typegoose/typegoose';
import { TimeStamps } from '@typegoose/typegoose/lib/defaultClasses';
/**
* BaseModel
@@ -12,7 +13,7 @@ import { prop, pre } from '@typegoose/typegoose';
next();
})
export default class BaseModel {
export default class BaseModel extends TimeStamps {
_id?: string

38
shared/db/BattleRecord.ts Normal file
View File

@@ -0,0 +1,38 @@
import BaseModel from './BaseModel';
import { index, getModelForClass, prop } from '@typegoose/typegoose';
@index({ roleId: 1, hid: 1, eid: 1 })
@index({ seqId: 1 })
export default class BattleRecord extends BaseModel {
@prop({ required: true })
roleId: string; // 角色 id
@prop({ required: true })
roleName: string; // 角色名称
@prop({ required: true })
battleCode: string; // 关卡记录唯一标识
@prop({ required: true })
battleId: number; // 关卡 id
@prop({ required: true })
status: number; // 关卡状态 0-挑战中 1-挑战成功 2-挑战失败
@prop({ required: true })
record: { // 使用的武将等记录
heroes: Array <number>; // 武将id
};
public static async getBattleRecordByCode(battleCode: string, lean = true) {
const result = await BattleRecordModel.findOne({ battleCode }).lean(lean);
return result;
}
public static async updateBattleRecordByCode( battleCode: string, params: object, lean = true) {
const result = await BattleRecordModel.findOneAndUpdate({ battleCode }, params, {new: true, upsert: true}).lean(lean);
return result;
}
}
export const BattleRecordModel = getModelForClass(BattleRecord);

File diff suppressed because it is too large Load Diff

6602
shared/resource/goods.json Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -5,4 +5,11 @@ export default class HomeController extends Controller {
const { ctx } = this;
ctx.body = await ctx.service.test.sayHi('egg');
}
public async dev() {
const { ctx } = this;
await ctx.render('index',{
title: 'xxx'
});
}
}

View File

@@ -19,6 +19,10 @@ function aesDecrypt(data, key, iv) {
module.exports = options => {
return async function parmsDecode(ctx: Context, next) {
if(ctx.request.url == '/dev') {
await next();
return;
}
if (options.threshold && ctx.length < options.threshold) return;
const reqBody = ctx.request.body;

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,69 @@
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>
chatofpinus
</title>
<link rel="stylesheet" href="bootstrap.min.css" type="text/css" />
<link rel="stylesheet" href="style.css" type="text/css" />
<script src="js/lib/jquery-1.8.0.min.js" type="text/javascript">
</script>
<script src="js/lib/build/build.js" type="text/javascript">
</script>
<script type="text/javascript">
require('boot');
</script>
<script src="js/client.js">
</script>
</head>
<body>
<div id="app" class="container">
<div class="page-header"><h1>调试</h1></div>
<div class="row">
<div id="loginError"></div>
<div class="col-sm-6">
<form id="form">
<div class="form-group">
<label for="uid">uid (chat)</label>
<input type="text" class="form-control" id="uid" name="uid" placeholder="uid" value="asd">
</div>
<div class="form-group">
<label for="rid">rid (chat)</label>
<input type="text" class="form-control" id="rid" name="rid" placeholder="rid" value="123">
</div>
<div class="form-group">
<label for="route">接口</label>
<input type="text" class="form-control" id="route" name="route" placeholder="接口">
</div>
<div class="form-group">
<label for="route">token</label>
<input type="text" class="form-control" id="token" name="token" placeholder="token">
</div>
<div class="form-group">
<label for="route">serverId</label>
<input type="text" class="form-control" id="serverId" name="serverId" placeholder="serverId">
</div>
<div class="form-group">
<label for="params">参数</label>
<textarea class="form-control" name="params" id="params" cols="30" rows="10"></textarea>
</div>
<div class="text-right" aria-label="...">
<button type="button" id="add" class="btn btn-default btn-l">加入</button>
<button type="button" id="remove" class="btn btn-default btn-l" style="display: none;">离开</button>
<button type="button" id="send" class="btn btn-primary btn-l">发送</button>
</div>
</form>
</div>
<div class="col-sm-6" id="content"></div>
</div>
</div>
</body>
</html>

View File

@@ -0,0 +1,6 @@
{
"name": "pomelo-client",
"description": "pomelo-client",
"local": [ "boot" ],
"paths": [ "local"]
}

View File

@@ -0,0 +1,14 @@
{
"name": "pomelo-protocol",
"description": "pomelo-protocol",
"keywords": [
"pomelo",
"protocol"
],
"version": "0.1.3",
"main": "lib/protocol.js",
"scripts": [
"lib/protocol.js"
],
"repo": "https://github.com/NetEase/pomelo-protocol"
}

View File

@@ -0,0 +1,14 @@
{
"name": "emitter",
"repo": "component/emitter",
"description": "Event emitter",
"keywords": [
"emitter",
"events"
],
"version": "1.1.2",
"scripts": [
"index.js"
],
"license": "MIT"
}

View File

@@ -0,0 +1,15 @@
{
"name": "pomelo-jsclient-websocket",
"description": "pomelo-jsclient-websocket",
"keywords": [
"pomelo",
"jsclient",
"websocket"
],
"version": "0.0.1",
"main": "lib/pomelo-client.js",
"scripts": [
"lib/pomelo-client.js"
],
"repo": "https://github.com/pomelonode/pomelo-jsclient-websocket"
}

View File

@@ -0,0 +1,14 @@
{
"name": "pomelo-protobuf",
"description": "pomelo-protobuf",
"keywords": [
"pomelo",
"protobuf"
],
"version": "0.2.0",
"main": "lib/client/protobuf.js",
"scripts": [
"lib/client/protobuf.js"
],
"repo": "https://github.com/pomelonode/pomelo-protobuf"
}

View File

@@ -0,0 +1,11 @@
{
"name": "boot",
"description": "Main app boot component",
"dependencies": {
"component/emitter":"master",
"NetEase/pomelo-protocol": "master",
"pomelonode/pomelo-protobuf": "master",
"pomelonode/pomelo-jsclient-websocket": "master"
},
"scripts": ["index.js"]
}

View File

@@ -0,0 +1,183 @@
body {
padding: 0;
margin: 0;
}
body, #entry {
color: #000000;
}
body, table {
font-family: DejaVu Sans Mono, fixed;
font-size: 14pt;
line-height: 150%;
}
#loginView {
width: 100%;
font-size: 13pt;
overflow: hidden;
}
#loginTitle {
width: 100%;
margin-top: 150px;
font-size: 50pt;
text-align: center;
}
#loginView input[type = "text"] {
height: 30px;
width: 270px;
font-size: inherit;
margin-left: 15px;
}
#loginView input[type = "button"] {
height: 30px;
width: 90px;
font-size: inherit;
}
#loginView table {
width: 100%;
height: 100%;
margin-top: 10%;
}
#loginView table tr {
text-align: center;
height: 50%;
}
#loginView table tr td {
padding-top: 25px;
}
#loginError {
text-align: center;
font-size: 16pt;
color: #ff0000;
margin-top: 15px;
}
#chatHistory {
padding-bottom: 5.1em;
}
#toolbar {
position: fixed;
width: 100%;
bottom: 0;
background: #007077;
}
#toolbar ul {
margin: 0;
padding: 5px 0 0 6px;
height: 35px;
list-style: none;
}
#toolbar li {
display: block;
float: left;
margin: 0 2em 0 0;
}
#toolbar select {
width: 100px;
height: 30px;
font-size: inherit;
}
#entry {
width: 100%;
font-size: inherit;
padding: 1em;
margin: 0;
border-width: 0;
outline-width: 0;
clear: both;
}
.message {
margin: 0.1em 0;
}
.message td {
vertical-align: top;
}
.nick {
font-weight: bold;
padding: 0 1em 0 0.5em;
}
#pop {
display: none;
background: #fff;
width: 260px;
height: 152px;
border: 1px solid #e0e0e0;
font-size: 12px;
font-family: DejaVu Sans Mono, fixed;
position: fixed;
right: 10px;
bottom: 10px;
}
#popHead {
line-height: 40px;
background: #E74C65;
border-bottom: 1px solid #e0e0e0;
position: relative;
font-size: 12px;
padding: 0 0 0 10px;
}
#popHead h2 {
font-size: 14px;
color: #666;
line-height: 40px;
height: 32px;
margin-top: -12px;
}
#popHead #popClose {
position: absolute;
right: 10px;
top: 1px;
}
#popHead a#popClose:hover {
color: #f00;
cursor: pointer;
}
#popContent {
padding: 20px 10px;
}
#popIntro {
text-align: center;
line-height: 160%;
margin: 5px 0;
color: #000;
font-size: 12pt;
}
#popMore {
text-align: right;
border-top: 1px solid #ccc;
line-height: 24px;
padding-top: 5px;
}
#popMore:hover {
color: #f00;
cursor: pointer;
}
.btn-l {
width: 100px;
}

View File

@@ -3,6 +3,7 @@ import { Application } from 'egg';
export default (app: Application) => {
const { controller, router } = app;
const tokenParser = app.middleware.tokenParser();
router.get('/dev', controller.home.dev);
router.get('/', controller.home.index);
router.post('/user/getsms', controller.account.getSms);
router.post('/user/smslogin', controller.account.smsLogin);

View File

@@ -1,4 +1,5 @@
import { EggAppConfig, EggAppInfo, PowerPartial } from 'egg';
const path = require('path');
export default (appInfo: EggAppInfo) => {
const config = {} as PowerPartial<EggAppConfig>;
@@ -31,6 +32,20 @@ export default (appInfo: EggAppInfo) => {
packages: [ '/root/zyz/web-server/package.json' ],
};
config.view = {
root: path.join(appInfo.baseDir, '/app/public'),
defaultViewEngine: 'nunjucks',
mapping: {
'.html': 'nunjucks' //左边写成.html后缀会自动渲染.html文件
},
};
config.static = {
prefix: '/',
dir: path.join(appInfo.baseDir, '/app/public'),
};
// add your special config in here
const bizConfig = {
sourceUrl: `https://github.com/eggjs/examples/tree/master/${appInfo.name}`,

View File

@@ -2,11 +2,11 @@ import { EggPlugin } from 'egg';
import 'tsconfig-paths/register';
const plugin: EggPlugin = {
// static: true,
// nunjucks: {
// enable: true,
// package: 'egg-view-nunjucks',
// },
static: true,
nunjucks: {
enable: true,
package: 'egg-view-nunjucks',
},
cors: {
enable: true,
package: 'egg-cors',

View File

@@ -3972,6 +3972,14 @@
"mz": "^2.7.0"
}
},
"egg-view-nunjucks": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/egg-view-nunjucks/-/egg-view-nunjucks-2.2.0.tgz",
"integrity": "sha512-csuqQSFRpR1G+nu8OxDgHDba1v8RVJ8i4fadX66o73mnclKN6EXPdX9c9igegPeXXucUdDAPAHfJo6nZMJaghw==",
"requires": {
"nunjucks": "^3.1.2"
}
},
"egg-watcher": {
"version": "3.1.1",
"resolved": "https://registry.npm.taobao.org/egg-watcher/download/egg-watcher-3.1.1.tgz",

View File

@@ -27,6 +27,7 @@
"egg-alinode": "^2.0.1",
"egg-cors": "^2.2.3",
"egg-scripts": "^2.6.0",
"egg-view-nunjucks": "^2.2.0",
"reflect-metadata": "^0.1.13",
"underscore": "^1.10.2"
},

View File

@@ -14,6 +14,7 @@ import 'egg-schedule';
import 'egg-static';
import 'egg-jsonp';
import 'egg-view';
import 'egg-view-nunjucks';
import 'egg-cors';
import 'egg-alinode';
import { EggPluginItem } from 'egg';
@@ -31,6 +32,7 @@ declare module 'egg' {
static?: EggPluginItem;
jsonp?: EggPluginItem;
view?: EggPluginItem;
nunjucks?: EggPluginItem;
cors?: EggPluginItem;
alinode?: EggPluginItem;
}