From a5c236963401d7b5fa8f8695545aae65be796400 Mon Sep 17 00:00:00 2001 From: zhl Date: Fri, 22 Jan 2021 13:18:45 +0800 Subject: [PATCH 1/2] =?UTF-8?q?=E6=B8=B8=E6=88=8F=E7=BB=93=E6=9E=9C?= =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E8=8E=B7=E5=BE=97=E7=89=A9=E5=93=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/common/WebApi.ts | 22 ++++++++++++++++++++++ src/global.d.ts | 2 +- src/rooms/GeneralRoom.ts | 4 ++-- src/rooms/RankedLobbyRoom.ts | 3 ++- src/rooms/commands/GameResultCommand.ts | 8 +++++--- 5 files changed, 32 insertions(+), 7 deletions(-) diff --git a/src/common/WebApi.ts b/src/common/WebApi.ts index 7fa9b70..d6921f3 100644 --- a/src/common/WebApi.ts +++ b/src/common/WebApi.ts @@ -54,6 +54,28 @@ export async function reportGameResult(data: any) { return axios(reqConfig) } +/** + * 使用物品 + * @param {string} accountid + * @param {number} itemid + * @param {number} count + */ +export async function useItem(accountid: string, itemid: number, count: number) { + const data = {itemid, count} + let dataStr = JSON.stringify(data); + let reqConfig = { + method: 'post', + url: `${config.info_svr}/${accountid}/useitem`, + headers: { + 'Content-Type': 'application/json', + }, + data : dataStr + }; + + // @ts-ignore + return axios(reqConfig) +} + /** * 创建机器人 * @param data diff --git a/src/global.d.ts b/src/global.d.ts index c26ba9e..e483d76 100644 --- a/src/global.d.ts +++ b/src/global.d.ts @@ -31,7 +31,7 @@ declare module "colyseus" { dispatcher: Dispatcher; mainClock: Delayed; robotCount: number; - match: boolean; + match: string | undefined ; score: number; /** * 根据sessionId获取client diff --git a/src/rooms/GeneralRoom.ts b/src/rooms/GeneralRoom.ts index 6bf19b0..c70a3a4 100644 --- a/src/rooms/GeneralRoom.ts +++ b/src/rooms/GeneralRoom.ts @@ -31,7 +31,7 @@ export class GeneralRoom extends Room { gameClock: Map = new Map(); assistMap: Map = new Map(); - match = false; + match = ''; robotCount = 0; async onAuth (client:Client, options: any, request: IncomingMessage) { @@ -48,7 +48,7 @@ export class GeneralRoom extends Room { if (options.count) { this.robotCount = Math.min(Math.max(0, options.count), this.maxClients - 1); } - this.match = !!options.match || false; + this.match = options.match; if (options.score) { this.score = options.score; } diff --git a/src/rooms/RankedLobbyRoom.ts b/src/rooms/RankedLobbyRoom.ts index f859256..9064971 100644 --- a/src/rooms/RankedLobbyRoom.ts +++ b/src/rooms/RankedLobbyRoom.ts @@ -79,6 +79,7 @@ export class RankedLobbyRoom extends Room { rank_mpa = 0.2; fair_ir = 1.2; step_ir = 1.3; + matchid = '100001' onCreate(options: any) { const fc = global.$cfg.get(BaseConst.FORMULA); @@ -332,7 +333,7 @@ export class RankedLobbyRoom extends Room { * Create room instance in the server. */ const room = await matchMaker.createRoom(this.roomToCreate, { - match: true, + match: this.matchid, rank: group.averageRank, score: avaScore, count: this.numClientsToMatch - group.count diff --git a/src/rooms/commands/GameResultCommand.ts b/src/rooms/commands/GameResultCommand.ts index f9c7235..de5e7e5 100644 --- a/src/rooms/commands/GameResultCommand.ts +++ b/src/rooms/commands/GameResultCommand.ts @@ -193,13 +193,14 @@ export class GameResultCommand extends Command { } let time = new GameEnv().gameResultTime * 1000; this.room.beginSchedule(time, resultTimeOver, 'restart_schedule'); - let seasonData = (await self.reportGameResult(winner, mvp.id, results.get(mvp).mvpScore, results)).data.data; + let saveData = (await self.reportGameResult(winner, mvp.id, results.get(mvp).mvpScore, results)).data.data; let resultData: any = { winner: winner, mvp: mvp.id, results: [...results.values()], statics: statics, - seasonData + seasonData: saveData.seasonData, + items: saveData.itemData }; this.room.bGameResult(resultData); this.resetAllState(); @@ -253,7 +254,8 @@ export class GameResultCommand extends Command { roomid: this.room.roomId, round: this.state.round, winner: winner, - season: this.room.match ? 1: 0 + season: this.room.match ? 1: 0, + matchid: this.room.match } let players: any[] = []; let i = 0; From 2170e80fecfdea430705a446cd244e237d6586c6 Mon Sep 17 00:00:00 2001 From: zhl Date: Fri, 22 Jan 2021 14:08:45 +0800 Subject: [PATCH 2/2] =?UTF-8?q?=E5=BC=80=E5=A7=8B=E5=8C=B9=E9=85=8D?= =?UTF-8?q?=E5=89=8D=E6=A3=80=E6=9F=A5=E6=89=80=E9=9C=80=E7=89=A9=E5=93=81?= =?UTF-8?q?=E6=98=AF=E5=90=A6=E8=B6=B3=E5=A4=9F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/common/WebApi.ts | 119 +++++++++------ src/rooms/RankedLobbyRoom.ts | 280 ++++++++++++++++++----------------- 2 files changed, 222 insertions(+), 177 deletions(-) diff --git a/src/common/WebApi.ts b/src/common/WebApi.ts index d6921f3..2ffc56a 100644 --- a/src/common/WebApi.ts +++ b/src/common/WebApi.ts @@ -1,8 +1,8 @@ -import axios from "axios"; -import {Config} from "../cfg/Config"; -import {debugRoom, error} from "./Debug"; +import axios from 'axios' +import { Config } from '../cfg/Config' +import { debugRoom, error } from './Debug' -let config: Config = require('../../config/config.json'); +let config: Config = require('../../config/config.json') /** * 获取卡组详情 @@ -12,15 +12,15 @@ let config: Config = require('../../config/config.json'); * @return {Promise>} */ export function getCardGroup(accountid: string, heroid: number, cardgroup: string) { - return axios.get(`${config.info_svr}/${accountid}/group_info/${heroid}/${cardgroup}`, ) - .then(function (response) { - let res = response.data; - if (res.errcode) { - throw new Error(res.errmsg); - } else { - return res.data; - } - }) + return axios.get(`${ config.info_svr }/${ accountid }/group_info/${ heroid }/${ cardgroup }`) + .then(function (response) { + let res = response.data + if (res.errcode) { + throw new Error(res.errmsg) + } else { + return res.data + } + }) } /** @@ -30,8 +30,8 @@ export function getCardGroup(accountid: string, heroid: number, cardgroup: strin * @return {Promise>} */ export function requestUnlockHero(accountid: string, heroid: number | string) { - let data = {"type": 0}; - return axios.post(`${config.info_svr}/${accountid}/hero/unlock/${heroid}`, data); + let data = { 'type': 0 } + return axios.post(`${ config.info_svr }/${ accountid }/hero/unlock/${ heroid }`, data) } /** @@ -39,19 +39,19 @@ export function requestUnlockHero(accountid: string, heroid: number | string) { * @param data */ export async function reportGameResult(data: any) { - let dataStr = JSON.stringify(data); + let dataStr = JSON.stringify(data) - let reqConfig = { - method: 'post', - url: `${config.info_svr}/record/save`, - headers: { - 'Content-Type': 'application/json', - }, - data : dataStr - }; + let reqConfig = { + method: 'post', + url: `${ config.info_svr }/record/save`, + headers: { + 'Content-Type': 'application/json' + }, + data: dataStr + } - // @ts-ignore - return axios(reqConfig) + // @ts-ignore + return axios(reqConfig) } /** @@ -61,19 +61,48 @@ export async function reportGameResult(data: any) { * @param {number} count */ export async function useItem(accountid: string, itemid: number, count: number) { - const data = {itemid, count} - let dataStr = JSON.stringify(data); - let reqConfig = { - method: 'post', - url: `${config.info_svr}/${accountid}/useitem`, - headers: { - 'Content-Type': 'application/json', - }, - data : dataStr - }; + const data = { itemid, count } + let dataStr = JSON.stringify(data) + let reqConfig = { + method: 'post', + url: `${ config.info_svr }/${ accountid }/useitem`, + headers: { + 'Content-Type': 'application/json' + }, + data: dataStr + } - // @ts-ignore - return axios(reqConfig) + // @ts-ignore + return axios(reqConfig) +} + +/** + * 检查匹配所需的资源是否足够 + * @param {string} accountid + * @param {string} matchid + * @return {Promise} + */ +export async function checkMatchTicket(accountid: string, matchid: string) { + const data = { matchid } + const url = `${ config.info_svr }/${ accountid }/beginmatch` + let reqConfig = { + method: 'post', + url, + headers: { + 'Content-Type': 'application/json' + }, + data: JSON.stringify(data) + } + + // @ts-ignore + return axios(reqConfig).then(function (response) { + let res = response.data + if (res.errcode) { + throw new Error(res.errmsg) + } else { + return {} + } + }) } /** @@ -81,13 +110,13 @@ export async function useItem(accountid: string, itemid: number, count: number) * @param data */ export function createRobot(data: any) { - axios.get('http://127.0.0.1:2500/robot/create', { - params: data - }).then((res) => { - debugRoom(`caeate robot result: `,res.data); - }).catch((err) => { - error(err); - }) + axios.get('http://127.0.0.1:2500/robot/create', { + params: data + }).then((res) => { + debugRoom(`caeate robot result: `, res.data) + }).catch((err) => { + error(err) + }) } diff --git a/src/rooms/RankedLobbyRoom.ts b/src/rooms/RankedLobbyRoom.ts index 9064971..2ce20bd 100644 --- a/src/rooms/RankedLobbyRoom.ts +++ b/src/rooms/RankedLobbyRoom.ts @@ -1,5 +1,7 @@ -import {Client, generateId, matchMaker, Room} from "colyseus"; -import {BaseConst} from "../constants/BaseConst"; +import { Client, generateId, matchMaker, Room, ServerError } from 'colyseus' +import { BaseConst } from '../constants/BaseConst' +import { IncomingMessage } from 'http' +import { checkMatchTicket } from '../common/WebApi' interface MatchmakingGroup { averageRank: number; @@ -13,7 +15,7 @@ interface MatchmakingGroup { } interface ClientStat { - clients: Map; + clients: Map; waitingTime: number; options?: any; groupTag?: string; @@ -30,42 +32,42 @@ export class RankedLobbyRoom extends Room { * reached) will be matched together. Your room should fill the remaining * spots with "bots" on this case. */ - allowUnmatchedGroups: boolean = true; + allowUnmatchedGroups: boolean = true /** * Evaluate groups for each client at interval */ - evaluateGroupsInterval = 1000; + evaluateGroupsInterval = 1000 /** * Groups of players per iteration */ - groups: MatchmakingGroup[] = []; + groups: MatchmakingGroup[] = [] /** * name of the room to create */ - roomToCreate = "general_room"; + roomToCreate = 'general_room' /** * 最大匹配时间 */ - maxWaitingTime = 15 * 1000; + maxWaitingTime = 15 * 1000 /** * 超过该时间, 组队玩家可匹配单排玩家 * @type {number} */ - groupAddOneTime = 10 * 1000; + groupAddOneTime = 10 * 1000 /** * after this time, try to fit this client with a not-so-compatible group */ - maxWaitingTimeForPriority?: number = 10 * 1000; + maxWaitingTimeForPriority?: number = 10 * 1000 /** * number of players on each match */ - numClientsToMatch = 4; + numClientsToMatch = 4 // /** // * after a group is ready, clients have this amount of milliseconds to confirm @@ -75,46 +77,59 @@ export class RankedLobbyRoom extends Room { /** * rank and group cache per-player */ - stats: ClientStat[] = []; - rank_mpa = 0.2; - fair_ir = 1.2; - step_ir = 1.3; + stats: ClientStat[] = [] + rank_mpa = 0.2 + fair_ir = 1.2 + step_ir = 1.3 matchid = '100001' + async onAuth(client: Client, options: any, request: IncomingMessage) { + let { accountid } = options + if (!accountid) { + throw new ServerError(10, 'not enough params') + } + try { + await checkMatchTicket(accountid, this.matchid) + } catch (err) { + throw new ServerError(11, 'not enough ticket') + } + return true + } + onCreate(options: any) { - const fc = global.$cfg.get(BaseConst.FORMULA); - this.rank_mpa = fc.get(70028).number / 100; - this.fair_ir = fc.get(70029).number / 100 + 1; - this.step_ir = fc.get(70031).number / 100 + 1; - this.groupAddOneTime = fc.get(70023).number * 1000; - this.maxWaitingTime = (fc.get(70024).number + fc.get(70025).number) * 1000; + const fc = global.$cfg.get(BaseConst.FORMULA) + this.rank_mpa = fc.get(70028).number / 100 + this.fair_ir = fc.get(70029).number / 100 + 1 + this.step_ir = fc.get(70031).number / 100 + 1 + this.groupAddOneTime = fc.get(70023).number * 1000 + this.maxWaitingTime = (fc.get(70024).number + fc.get(70025).number) * 1000 if (options.maxWaitingTime) { - this.maxWaitingTime = options.maxWaitingTime; + this.maxWaitingTime = options.maxWaitingTime } if (options.numClientsToMatch) { - this.numClientsToMatch = options.numClientsToMatch; + this.numClientsToMatch = options.numClientsToMatch } - this.onMessage("bye", (client: Client, message: any) => { - const stat = this.stats.find(obj => obj.clients.has(client.sessionId)); + this.onMessage('bye', (client: Client, message: any) => { + const stat = this.stats.find(obj => obj.clients.has(client.sessionId)) - if (stat && stat.group && typeof (stat.group.confirmed) === "number") { - stat.confirmed = true; - stat.group.confirmed++; + if (stat && stat.group && typeof (stat.group.confirmed) === 'number') { + stat.confirmed = true + stat.group.confirmed++ //stat.clients.delete(client.sessionId); - client.leave(); + client.leave() } }) this.onMessage('gogogo', (client: Client, message: any) => { - const stat = this.stats.find(obj => obj.clients.has(client.sessionId)); - stat.priority = true; + const stat = this.stats.find(obj => obj.clients.has(client.sessionId)) + stat.priority = true }) /** * Redistribute clients into groups at every interval */ - this.setSimulationInterval(() => this.redistributeGroups(), this.evaluateGroupsInterval); + this.setSimulationInterval(() => this.redistributeGroups(), this.evaluateGroupsInterval) } onJoin(client: Client, options: any) { @@ -125,17 +140,17 @@ export class RankedLobbyRoom extends Room { * 如果找到的记录, clients是1, 则把当前client添加到该记录中, 同时更新rank */ if (options.group) { - let length = this.stats.length; - let groupData; + let length = this.stats.length + let groupData for (let i = 0; i < length; i++) { if (this.stats[i].groupTag == options.group) { - groupData = this.stats[i]; + groupData = this.stats[i] break } } if (!groupData) { - let clientMap = new Map(); - clientMap.set(client.sessionId, {client, options}); + let clientMap = new Map() + clientMap.set(client.sessionId, { client, options }) groupData = { clients: clientMap, rank: options.rank, @@ -143,112 +158,112 @@ export class RankedLobbyRoom extends Room { waitingTime: 0, options } - this.stats.push(groupData); + this.stats.push(groupData) } else { if (groupData.clients.size >= 2) { - let clientMap = new Map(); - options.group = generateId(); - clientMap.set(client.sessionId, {client, options}); + let clientMap = new Map() + options.group = generateId() + clientMap.set(client.sessionId, { client, options }) this.stats.push({ clients: clientMap, rank: options.rank, waitingTime: 0, options - }); + }) } else { - groupData.clients.set(client.sessionId, {client, options}); - groupData.rank = (groupData.rank + options.rank) / 2 * (1 + this.rank_mpa); + groupData.clients.set(client.sessionId, { client, options }) + groupData.rank = (groupData.rank + options.rank) / 2 * (1 + this.rank_mpa) } } - client.send("clients", groupData.clients.size); + client.send('clients', groupData.clients.size) } else { - let clientMap = new Map(); - clientMap.set(client.sessionId, {client, options}); + let clientMap = new Map() + clientMap.set(client.sessionId, { client, options }) this.stats.push({ clients: clientMap, rank: options.rank, waitingTime: 0, options - }); + }) } - client.send("clients", 1); + client.send('clients', 1) } createGroup() { - let group: MatchmakingGroup = {clients: [], averageRank: 0, count: 0}; - this.groups.push(group); - return group; + let group: MatchmakingGroup = { clients: [], averageRank: 0, count: 0 } + this.groups.push(group) + return group } redistributeGroups() { // re-set all groups - this.groups = []; + this.groups = [] - const stats = this.stats.sort((a, b) => a.rank - b.rank); + const stats = this.stats.sort((a, b) => a.rank - b.rank) - let currentGroup: MatchmakingGroup = this.createGroup(); - let totalRank = 0; + let currentGroup: MatchmakingGroup = this.createGroup() + let totalRank = 0 // 先过滤一边组队的情况 for (let i = 0, l = stats.length; i < l; i++) { if (stats[i].clients.size == 1) { - continue; + continue } - const stat = stats[i]; - stat.waitingTime += this.clock.deltaTime; + const stat = stats[i] + stat.waitingTime += this.clock.deltaTime if (stat.group && stat.group.ready) { - continue; + continue } if (currentGroup.averageRank > 0) { - const diff = Math.abs(stat.rank - currentGroup.averageRank); - const diffRatio = (diff / currentGroup.averageRank); + const diff = Math.abs(stat.rank - currentGroup.averageRank) + const diffRatio = (diff / currentGroup.averageRank) /** * figure out how to identify the diff ratio that makes sense */ if (diffRatio > this.step_ir) { - currentGroup = this.createGroup(); - totalRank = 0; + currentGroup = this.createGroup() + totalRank = 0 } } - stat.group = currentGroup; - currentGroup.clients.push(stat); - currentGroup.count += stat.clients.size; + stat.group = currentGroup + currentGroup.clients.push(stat) + currentGroup.count += stat.clients.size - totalRank += stat.rank; - currentGroup.averageRank = totalRank / currentGroup.clients.length; + totalRank += stat.rank + currentGroup.averageRank = totalRank / currentGroup.clients.length if (currentGroup.count === this.numClientsToMatch) { - currentGroup.ready = true; - currentGroup = this.createGroup(); - totalRank = 0; + currentGroup.ready = true + currentGroup = this.createGroup() + totalRank = 0 } } - totalRank = 0; - currentGroup = this.createGroup(); + totalRank = 0 + currentGroup = this.createGroup() for (let i = 0, l = stats.length; i < l; i++) { - const stat = stats[i]; + const stat = stats[i] if (stats[i].clients.size == 1) { - stat.waitingTime += this.clock.deltaTime; + stat.waitingTime += this.clock.deltaTime } else { if (stat.waitingTime < this.groupAddOneTime) { - continue; + continue } } /** * do not attempt to re-assign groups for clients inside "ready" groups */ if (stat.group && stat.group.ready) { - continue; + continue } if (currentGroup.count + stat.clients.size > this.maxClients) { - continue; + continue } if (stat.priority) { - currentGroup.priority = true; + currentGroup.priority = true } /** @@ -264,24 +279,24 @@ export class RankedLobbyRoom extends Room { currentGroup.averageRank > 0 && !currentGroup.priority ) { - const diff = Math.abs(stat.rank - currentGroup.averageRank); - const diffRatio = (diff / currentGroup.averageRank); + const diff = Math.abs(stat.rank - currentGroup.averageRank) + const diffRatio = (diff / currentGroup.averageRank) /** * figure out how to identify the diff ratio that makes sense */ if (diffRatio > this.fair_ir) { - currentGroup = this.createGroup(); - totalRank = 0; + currentGroup = this.createGroup() + totalRank = 0 } } - stat.group = currentGroup; - currentGroup.clients.push(stat); - currentGroup.count += stat.clients.size; + stat.group = currentGroup + currentGroup.clients.push(stat) + currentGroup.count += stat.clients.size - totalRank += stat.rank; - currentGroup.averageRank = totalRank / currentGroup.count; + totalRank += stat.rank + currentGroup.averageRank = totalRank / currentGroup.count if ( (currentGroup.count === this.numClientsToMatch) || @@ -293,42 +308,43 @@ export class RankedLobbyRoom extends Room { (stat.waitingTime >= this.maxWaitingTime && this.allowUnmatchedGroups) || stat.priority ) { - currentGroup.ready = true; - currentGroup = this.createGroup(); - totalRank = 0; + currentGroup.ready = true + currentGroup = this.createGroup() + totalRank = 0 } } - this.checkGroupsReady(); + this.checkGroupsReady() } generateSeat(index: number): number { switch (index) { case 0: - return 0; + return 0 case 1: - return 3; + return 3 case 2: - return 1; + return 1 case 3: - return 2; + return 2 } } + async checkGroupsReady() { await Promise.all( this.groups .map(async (group) => { if (group.ready) { - group.confirmed = 0; - let score = 0; - let count = 0; + group.confirmed = 0 + let score = 0 + let count = 0 group.clients.map(client => { - for (let [,data] of client.clients) { - score += (data.options?.score || 0); - count ++; + for (let [, data] of client.clients) { + score += (data.options?.score || 0) + count++ } }) - let avaScore = score / count; + let avaScore = score / count /** * Create room instance in the server. */ @@ -337,36 +353,36 @@ export class RankedLobbyRoom extends Room { rank: group.averageRank, score: avaScore, count: this.numClientsToMatch - group.count - }); + }) // 预处理数据, 确定座次 - let hasGroup = false; + let hasGroup = false for (let client of group.clients) { if (client.clients.size > 1) { - hasGroup = true; - break; + hasGroup = true + break } } - let seat = 0; + let seat = 0 if (hasGroup) { for (let client of group.clients) { if (client.clients.size > 1) { - for (let [,sub] of client.clients) { - sub.seat = this.generateSeat(seat ++); + for (let [, sub] of client.clients) { + sub.seat = this.generateSeat(seat++) } } } for (let client of group.clients) { if (client.clients.size == 1) { - for (let [,sub] of client.clients) { - sub.seat = this.generateSeat(seat ++); + for (let [, sub] of client.clients) { + sub.seat = this.generateSeat(seat++) } } } } else { - group.clients.sort((a, b) => a.rank - b.rank); + group.clients.sort((a, b) => a.rank - b.rank) for (let client of group.clients) { - for (let [,sub] of client.clients) { - sub.seat = seat ++; + for (let [, sub] of client.clients) { + sub.seat = seat++ } } } @@ -377,17 +393,17 @@ export class RankedLobbyRoom extends Room { /** * Send room data for new WebSocket connection! */ - for (let [,data] of client.clients) { + for (let [, data] of client.clients) { let matchOpt = { seat: data.seat } - Object.assign(matchOpt, data.options); - const matchData = await matchMaker.reserveSeatFor(room, matchOpt); - let options: any = {seat: data.seat, rank: data.options.rank}; - Object.assign(options, matchData); - data.client.send("match_success", options); + Object.assign(matchOpt, data.options) + const matchData = await matchMaker.reserveSeatFor(room, matchOpt) + let options: any = { seat: data.seat, rank: data.options.rank } + Object.assign(options, matchData) + data.client.send('match_success', options) } - })); + })) // /** // * Cancel & re-enqueue clients if some of them couldn't confirm connection. @@ -405,23 +421,23 @@ export class RankedLobbyRoom extends Room { * Notify all clients within the group on how many players are in the queue */ group.clients.forEach(client => { - for (let [,data] of client.clients) { - data.client.send("clients", group.count); + for (let [, data] of client.clients) { + data.client.send('clients', group.count) } - }); + }) } }) - ); + ) } onLeave(client: Client, consented: boolean) { - const stat = this.stats.find(obj => obj.clients.has(client.sessionId)); + const stat = this.stats.find(obj => obj.clients.has(client.sessionId)) if (stat.clients.size > 1) { - stat.clients.delete(client.sessionId); - let data = [...stat.clients.values()][0]; - stat.rank = data.options.rank; + stat.clients.delete(client.sessionId) + let data = [...stat.clients.values()][0] + stat.rank = data.options.rank } else { - this.stats.remove(stat); + this.stats.remove(stat) } }