From 6d0f821f047c367899c0016bbaef4936cd508481 Mon Sep 17 00:00:00 2001 From: zhl Date: Thu, 29 Apr 2021 20:49:35 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E9=A2=98=E7=9B=AE=E5=8F=91?= =?UTF-8?q?=E9=80=81,=E5=92=8C=E7=A7=AF=E5=88=86=E6=9B=B4=E6=96=B0?= =?UTF-8?q?=E6=9C=BA=E5=88=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/api/controllers/puzzle.controller.ts | 53 ++++++++--------- src/api/controllers/server.controller.ts | 1 + src/constants/BaseConst.ts | 2 + src/models/match/PuzzleSession.ts | 23 ++++++-- src/services/GameLogic.ts | 74 ++++++++++++++++++++++++ src/services/WsSvr.ts | 45 ++++++++++++++ 6 files changed, 168 insertions(+), 30 deletions(-) create mode 100644 src/services/GameLogic.ts diff --git a/src/api/controllers/puzzle.controller.ts b/src/api/controllers/puzzle.controller.ts index 841582a..fc97710 100644 --- a/src/api/controllers/puzzle.controller.ts +++ b/src/api/controllers/puzzle.controller.ts @@ -8,30 +8,23 @@ import { import { ZError } from '../../common/ZError' import { BaseConst } from '../../constants/BaseConst' import { mission_vo } from '../../config/parsers/mission_vo' -import { beginGame, createRoom } from '../../services/WsSvr' +import { + beginGame, + broadcast, + createRoom, + sendQuestion, updateScore +} from '../../services/WsSvr' import { RoomState } from '../../services/RoomState' import { retry } from '../../utils/promise.util' import { RoomLockErr } from '../../common/RoomLockErr' import { Schedule } from '../../clock/Schedule' -import { createDeflateRaw } from 'zlib' +import { + checkSubFinish, sendOneQuestion, + startGame, + transformRecord +} from '../../services/GameLogic' + -const transformRecord = function (records: any[]) { - return records.map(o => { - let answers = [] - for (let i = 1; i <= 4; i++) { - if (o[`a${ i }`]) { - answers.push(o[`a${ i }`]) - } - } - answers.randomSort() - return { - id: o._id, - title: o.question, - answers, - type: 1 - } - }) -} class PuzzleController extends BaseController { @role('anon') @@ -59,7 +52,8 @@ class PuzzleController extends BaseController { @role('anon') @router('post /api/:accountid/puzzle/answer') async report(req, res) { - let { id, answer, type, session, accountid } = req.params + let { id, answer, type, session, accountid, mode } = req.params + mode = mode || 0 if (!id || !session) { throw new ZError(11, 'param mismatch') } @@ -79,7 +73,7 @@ class PuzzleController extends BaseController { throw new ZError(16, 'current question not in current match') } let statMap = history.members.get(accountid) - if (statMap.questions.find(o => o == id)) { + if (statMap.answer.has(id)) { throw new ZError(15, 'current question already answered') } let record = await Puzzle.findById(id) @@ -90,8 +84,7 @@ class PuzzleController extends BaseController { if (type == 1) { result = 0 } - statMap.answer.push(result) - statMap.questions.push(id) + statMap.answer.set(id, result) if (result == 1) { statMap.rightCount++ statMap.comboCount++ @@ -103,6 +96,13 @@ class PuzzleController extends BaseController { history.status = 1 history.markModified('members') await history.save() + if (mode == 1) { + let score = result ? 3 : -1 + await updateScore(history.room, [{accountid, score }]) + if (checkSubFinish(history, id)) { + await sendOneQuestion(history) + } + } return { result, answer: record.a1, stats: history.members } } @@ -132,6 +132,8 @@ class PuzzleController extends BaseController { if (history && !history.hasExpired()) { new RoomState().unlock(shop) beginTime = history.begin + history.members.set(accountid, new PuzzleStatusClass()) + await history.save() return roomId = history.room } else { let rsp = await createRoom(data) @@ -145,15 +147,14 @@ class PuzzleController extends BaseController { history.room = roomId //TODO: 根据配置赋值 const beginSecond = 20 * 1000 + history.total = 10 history.begin = Date.now() + beginSecond beginTime = history.begin history.expire = history.begin + (100 || 90) * 1000 history.type = 1 await history.save() new Schedule().beginSchedule(beginSecond, async function () { - await beginGame(roomId, {}) - history.status = 1 - await history.save() + await startGame(roomId, history) }, shop) new RoomState().unlock(shop) return roomId diff --git a/src/api/controllers/server.controller.ts b/src/api/controllers/server.controller.ts index 46c474c..035c52d 100644 --- a/src/api/controllers/server.controller.ts +++ b/src/api/controllers/server.controller.ts @@ -1,4 +1,5 @@ import BaseController from '../../common/base.controller' +import { role, router } from '../../decorators/router' class ServerController extends BaseController { diff --git a/src/constants/BaseConst.ts b/src/constants/BaseConst.ts index 4ee7af9..b3be77d 100644 --- a/src/constants/BaseConst.ts +++ b/src/constants/BaseConst.ts @@ -2,4 +2,6 @@ export class BaseConst{ public static readonly COMPOUND = 'compound' public static readonly MISSION = 'mission' public static readonly RANK_SCORE = 'rank_score' + // 多人答题时间 + public static readonly MATCH_ANSWER_TIME = 10000 } diff --git a/src/models/match/PuzzleSession.ts b/src/models/match/PuzzleSession.ts index aa969b3..b1b943f 100644 --- a/src/models/match/PuzzleSession.ts +++ b/src/models/match/PuzzleSession.ts @@ -10,11 +10,9 @@ import { Base, TimeStamps } from '@typegoose/typegoose/lib/defaultClasses' }) export class PuzzleStatusClass { - @prop({default: []}) - answer: number[] + @prop({ type: Number, default: new Map() }) + answer: Map - @prop({ type: () => [String], default: [] }) - questions: string[] /** * 打对数量 * @type {number} @@ -71,6 +69,19 @@ export class PuzzleSessionClass extends BaseModule { @prop({default: 0}) public type: number + /** + * 当前的问题 + * @type {number} + */ + @prop({default: 0}) + public current: number + /** + * 一共多少问题 + * @type {number} + */ + @prop() + public total: number + /** * 比赛状态 * 0: 未开始答题 @@ -93,6 +104,10 @@ export class PuzzleSessionClass extends BaseModule { public hasExpired(): boolean { return this.expire < Date.now() } + + public get scheduleKey() { + return this.room + this._id + } } export const PuzzleSession = getModelForClass(PuzzleSessionClass, { existingConnection: PuzzleSessionClass.db }) diff --git a/src/services/GameLogic.ts b/src/services/GameLogic.ts new file mode 100644 index 0000000..7fc8697 --- /dev/null +++ b/src/services/GameLogic.ts @@ -0,0 +1,74 @@ +import { beginGame, endGame, sendQuestion, updateScore } from './WsSvr' +import { Puzzle } from '../models/content/Puzzle' +import { Schedule } from '../clock/Schedule' +import { BaseConst } from '../constants/BaseConst' + + +export function transformRecord(records: any[]) { + return records.map(o => { + let answers = [] + for (let i = 1; i <= 4; i++) { + if (o[`a${ i }`]) { + answers.push(o[`a${ i }`]) + } + } + answers.randomSort() + return { + id: o._id, + title: o.question, + answers, + type: 1 + } + }) +} + +export function checkSubFinish(history: any, qid: string) { + let count = 0 + for (let [key, val] of history.members) { + if (val.has(qid)) { + count ++ + } + } + return count >= history.questions.length; +} +/** + * 开始游戏 + * @param {string} roomId + * @param history + * @return {Promise} + */ +export async function startGame(roomId: string, history: any) { + await beginGame(roomId, {}) + let records = await Puzzle.randomQuestions({}, history.total) + history.questions = records.map(o => o._id) + await history.save() + await sendOneQuestion(history) +} + +export async function sendOneQuestion(history: any) { + const roomId = history.room + new Schedule().stopSchedule(history.scheduleKey) + if (history.current >= history.questions.length) { + console.log('match over') + await endGame(roomId, {}) + return + } + + let qid = history.questions[history.current] + let record = await Puzzle.findById(qid) + let qdata: any = transformRecord([record])[0] + qdata.no = history.current + await sendQuestion(roomId, qdata) + history.current ++ + await history.save() + new Schedule().beginSchedule(BaseConst.MATCH_ANSWER_TIME, async function (){ + let datas = [] + for (let [accountid, data] of history.members) { + if (!data.answer.has(qid)) { + datas.push({accountid, score: -1}) + } + } + await updateScore(history.room, datas) + await sendOneQuestion(history) + }, history.scheduleKey) +} diff --git a/src/services/WsSvr.ts b/src/services/WsSvr.ts index 33c1c3d..972b1f3 100644 --- a/src/services/WsSvr.ts +++ b/src/services/WsSvr.ts @@ -85,8 +85,53 @@ export async function beginGame(roomId, params) { }) } +export async function endGame(roomId, params) { + console.log(`end game: ${roomId}, ${params}`) + const url = `${apiBase}/room/call` + const args = [params] + const data = { + roomId, + method: 'endGame', + args: JSON.stringify(args) + } + return axios.post(url, data) + .then(res => { + return res.data + }) +} + +/** + * 创建房间 + * @param data + * @return {Promise>} + */ export async function createRoom(data) { const url = `${apiBase}/matchmake/joinOrCreate/puzzle_room` return axios.post(url, data) } +/** + * 发送一条问题 + * @param {string} roomId + * @param data + * @return {Promise>} + */ +export async function sendQuestion(roomId: string, data: any) { + console.log(`sendOneQuestion to ${roomId}, ${JSON.stringify(data)}`) + return broadcast(roomId, 'question', data) +} + +export async function updateScore(roomId: string, data: any) { + console.log(`updateScore: ${roomId}, ${JSON.stringify(data)}`) + const url = `${apiBase}/room/call` + const args = [data] + const params = { + roomId, + method: 'updateScore', + args: JSON.stringify(args) + } + return axios.post(url, params) + .then(res => { + return res.data + }) +}