Merge branch 'second' of http://git.kingsome.cn/node/card_svr into second

This commit is contained in:
yuexin 2021-01-22 14:43:22 +08:00
commit 996274b288
5 changed files with 242 additions and 172 deletions

View File

@ -1,8 +1,8 @@
import axios from "axios"; import axios from 'axios'
import {Config} from "../cfg/Config"; import { Config } from '../cfg/Config'
import {debugRoom, error} from "./Debug"; 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<AxiosResponse<any>>} * @return {Promise<AxiosResponse<any>>}
*/ */
export function getCardGroup(accountid: string, heroid: number, cardgroup: string) { export function getCardGroup(accountid: string, heroid: number, cardgroup: string) {
return axios.get(`${config.info_svr}/${accountid}/group_info/${heroid}/${cardgroup}`, ) return axios.get(`${ config.info_svr }/${ accountid }/group_info/${ heroid }/${ cardgroup }`)
.then(function (response) { .then(function (response) {
let res = response.data; let res = response.data
if (res.errcode) { if (res.errcode) {
throw new Error(res.errmsg); throw new Error(res.errmsg)
} else { } else {
return res.data; return res.data
} }
}) })
} }
/** /**
@ -30,8 +30,8 @@ export function getCardGroup(accountid: string, heroid: number, cardgroup: strin
* @return {Promise<AxiosResponse<any>>} * @return {Promise<AxiosResponse<any>>}
*/ */
export function requestUnlockHero(accountid: string, heroid: number | string) { export function requestUnlockHero(accountid: string, heroid: number | string) {
let data = {"type": 0}; let data = { 'type': 0 }
return axios.post(`${config.info_svr}/${accountid}/hero/unlock/${heroid}`, data); return axios.post(`${ config.info_svr }/${ accountid }/hero/unlock/${ heroid }`, data)
} }
/** /**
@ -39,19 +39,70 @@ export function requestUnlockHero(accountid: string, heroid: number | string) {
* @param data * @param data
*/ */
export async function reportGameResult(data: any) { export async function reportGameResult(data: any) {
let dataStr = JSON.stringify(data); let dataStr = JSON.stringify(data)
let reqConfig = { let reqConfig = {
method: 'post', method: 'post',
url: `${config.info_svr}/record/save`, url: `${ config.info_svr }/record/save`,
headers: { headers: {
'Content-Type': 'application/json', 'Content-Type': 'application/json'
}, },
data : dataStr data: dataStr
}; }
// @ts-ignore // @ts-ignore
return axios(reqConfig) 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 {string} accountid
* @param {string} matchid
* @return {Promise<any>}
*/
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 {}
}
})
} }
/** /**
@ -59,13 +110,13 @@ export async function reportGameResult(data: any) {
* @param data * @param data
*/ */
export function createRobot(data: any) { export function createRobot(data: any) {
axios.get('http://127.0.0.1:2500/robot/create', { axios.get('http://127.0.0.1:2500/robot/create', {
params: data params: data
}).then((res) => { }).then((res) => {
debugRoom(`caeate robot result: `,res.data); debugRoom(`caeate robot result: `, res.data)
}).catch((err) => { }).catch((err) => {
error(err); error(err)
}) })
} }

2
src/global.d.ts vendored
View File

@ -31,7 +31,7 @@ declare module "colyseus" {
dispatcher: Dispatcher; dispatcher: Dispatcher;
mainClock: Delayed; mainClock: Delayed;
robotCount: number; robotCount: number;
match: boolean; match: string | undefined ;
score: number; score: number;
/** /**
* sessionId获取client * sessionId获取client

View File

@ -31,7 +31,7 @@ export class GeneralRoom extends Room {
gameClock: Map<string, Delayed> = new Map(); gameClock: Map<string, Delayed> = new Map();
assistMap: Map<String, RobotClient> = new Map(); assistMap: Map<String, RobotClient> = new Map();
match = false; match = '';
robotCount = 0; robotCount = 0;
async onAuth (client:Client, options: any, request: IncomingMessage) { async onAuth (client:Client, options: any, request: IncomingMessage) {
@ -48,7 +48,7 @@ export class GeneralRoom extends Room {
if (options.count) { if (options.count) {
this.robotCount = Math.min(Math.max(0, options.count), this.maxClients - 1); this.robotCount = Math.min(Math.max(0, options.count), this.maxClients - 1);
} }
this.match = !!options.match || false; this.match = options.match;
if (options.score) { if (options.score) {
this.score = options.score; this.score = options.score;
} }

View File

@ -1,5 +1,7 @@
import {Client, generateId, matchMaker, Room} from "colyseus"; import { Client, generateId, matchMaker, Room, ServerError } from 'colyseus'
import {BaseConst} from "../constants/BaseConst"; import { BaseConst } from '../constants/BaseConst'
import { IncomingMessage } from 'http'
import { checkMatchTicket } from '../common/WebApi'
interface MatchmakingGroup { interface MatchmakingGroup {
averageRank: number; averageRank: number;
@ -13,7 +15,7 @@ interface MatchmakingGroup {
} }
interface ClientStat { interface ClientStat {
clients: Map<string, {client: Client, options: any, seat?: number}>; clients: Map<string, { client: Client, options: any, seat?: number }>;
waitingTime: number; waitingTime: number;
options?: any; options?: any;
groupTag?: string; groupTag?: string;
@ -30,42 +32,42 @@ export class RankedLobbyRoom extends Room {
* reached) will be matched together. Your room should fill the remaining * reached) will be matched together. Your room should fill the remaining
* spots with "bots" on this case. * spots with "bots" on this case.
*/ */
allowUnmatchedGroups: boolean = true; allowUnmatchedGroups: boolean = true
/** /**
* Evaluate groups for each client at interval * Evaluate groups for each client at interval
*/ */
evaluateGroupsInterval = 1000; evaluateGroupsInterval = 1000
/** /**
* Groups of players per iteration * Groups of players per iteration
*/ */
groups: MatchmakingGroup[] = []; groups: MatchmakingGroup[] = []
/** /**
* name of the room to create * name of the room to create
*/ */
roomToCreate = "general_room"; roomToCreate = 'general_room'
/** /**
* *
*/ */
maxWaitingTime = 15 * 1000; maxWaitingTime = 15 * 1000
/** /**
* , * ,
* @type {number} * @type {number}
*/ */
groupAddOneTime = 10 * 1000; groupAddOneTime = 10 * 1000
/** /**
* after this time, try to fit this client with a not-so-compatible group * 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 * number of players on each match
*/ */
numClientsToMatch = 4; numClientsToMatch = 4
// /** // /**
// * after a group is ready, clients have this amount of milliseconds to confirm // * after a group is ready, clients have this amount of milliseconds to confirm
@ -75,45 +77,59 @@ export class RankedLobbyRoom extends Room {
/** /**
* rank and group cache per-player * rank and group cache per-player
*/ */
stats: ClientStat[] = []; stats: ClientStat[] = []
rank_mpa = 0.2; rank_mpa = 0.2
fair_ir = 1.2; fair_ir = 1.2
step_ir = 1.3; 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) { onCreate(options: any) {
const fc = global.$cfg.get(BaseConst.FORMULA); const fc = global.$cfg.get(BaseConst.FORMULA)
this.rank_mpa = fc.get(70028).number / 100; this.rank_mpa = fc.get(70028).number / 100
this.fair_ir = fc.get(70029).number / 100 + 1; this.fair_ir = fc.get(70029).number / 100 + 1
this.step_ir = fc.get(70031).number / 100 + 1; this.step_ir = fc.get(70031).number / 100 + 1
this.groupAddOneTime = fc.get(70023).number * 1000; this.groupAddOneTime = fc.get(70023).number * 1000
this.maxWaitingTime = (fc.get(70024).number + fc.get(70025).number) * 1000; this.maxWaitingTime = (fc.get(70024).number + fc.get(70025).number) * 1000
if (options.maxWaitingTime) { if (options.maxWaitingTime) {
this.maxWaitingTime = options.maxWaitingTime; this.maxWaitingTime = options.maxWaitingTime
} }
if (options.numClientsToMatch) { if (options.numClientsToMatch) {
this.numClientsToMatch = options.numClientsToMatch; this.numClientsToMatch = options.numClientsToMatch
} }
this.onMessage("bye", (client: Client, message: any) => { this.onMessage('bye', (client: Client, message: any) => {
const stat = this.stats.find(obj => obj.clients.has(client.sessionId)); const stat = this.stats.find(obj => obj.clients.has(client.sessionId))
if (stat && stat.group && typeof (stat.group.confirmed) === "number") { if (stat && stat.group && typeof (stat.group.confirmed) === 'number') {
stat.confirmed = true; stat.confirmed = true
stat.group.confirmed++; stat.group.confirmed++
//stat.clients.delete(client.sessionId); //stat.clients.delete(client.sessionId);
client.leave(); client.leave()
} }
}) })
this.onMessage('gogogo', (client: Client, message: any) => { this.onMessage('gogogo', (client: Client, message: any) => {
const stat = this.stats.find(obj => obj.clients.has(client.sessionId)); const stat = this.stats.find(obj => obj.clients.has(client.sessionId))
stat.priority = true; stat.priority = true
}) })
/** /**
* Redistribute clients into groups at every interval * Redistribute clients into groups at every interval
*/ */
this.setSimulationInterval(() => this.redistributeGroups(), this.evaluateGroupsInterval); this.setSimulationInterval(() => this.redistributeGroups(), this.evaluateGroupsInterval)
} }
onJoin(client: Client, options: any) { onJoin(client: Client, options: any) {
@ -124,17 +140,17 @@ export class RankedLobbyRoom extends Room {
* , clients是1, client添加到该记录中, rank * , clients是1, client添加到该记录中, rank
*/ */
if (options.group) { if (options.group) {
let length = this.stats.length; let length = this.stats.length
let groupData; let groupData
for (let i = 0; i < length; i++) { for (let i = 0; i < length; i++) {
if (this.stats[i].groupTag == options.group) { if (this.stats[i].groupTag == options.group) {
groupData = this.stats[i]; groupData = this.stats[i]
break break
} }
} }
if (!groupData) { if (!groupData) {
let clientMap = new Map(); let clientMap = new Map()
clientMap.set(client.sessionId, {client, options}); clientMap.set(client.sessionId, { client, options })
groupData = { groupData = {
clients: clientMap, clients: clientMap,
rank: options.rank, rank: options.rank,
@ -142,112 +158,112 @@ export class RankedLobbyRoom extends Room {
waitingTime: 0, waitingTime: 0,
options options
} }
this.stats.push(groupData); this.stats.push(groupData)
} else { } else {
if (groupData.clients.size >= 2) { if (groupData.clients.size >= 2) {
let clientMap = new Map(); let clientMap = new Map()
options.group = generateId(); options.group = generateId()
clientMap.set(client.sessionId, {client, options}); clientMap.set(client.sessionId, { client, options })
this.stats.push({ this.stats.push({
clients: clientMap, clients: clientMap,
rank: options.rank, rank: options.rank,
waitingTime: 0, waitingTime: 0,
options options
}); })
} else { } else {
groupData.clients.set(client.sessionId, {client, options}); groupData.clients.set(client.sessionId, { client, options })
groupData.rank = (groupData.rank + options.rank) / 2 * (1 + this.rank_mpa); groupData.rank = (groupData.rank + options.rank) / 2 * (1 + this.rank_mpa)
} }
} }
client.send("clients", groupData.clients.size); client.send('clients', groupData.clients.size)
} else { } else {
let clientMap = new Map(); let clientMap = new Map()
clientMap.set(client.sessionId, {client, options}); clientMap.set(client.sessionId, { client, options })
this.stats.push({ this.stats.push({
clients: clientMap, clients: clientMap,
rank: options.rank, rank: options.rank,
waitingTime: 0, waitingTime: 0,
options options
}); })
} }
client.send("clients", 1); client.send('clients', 1)
} }
createGroup() { createGroup() {
let group: MatchmakingGroup = {clients: [], averageRank: 0, count: 0}; let group: MatchmakingGroup = { clients: [], averageRank: 0, count: 0 }
this.groups.push(group); this.groups.push(group)
return group; return group
} }
redistributeGroups() { redistributeGroups() {
// re-set all groups // 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 currentGroup: MatchmakingGroup = this.createGroup()
let totalRank = 0; let totalRank = 0
// 先过滤一边组队的情况 // 先过滤一边组队的情况
for (let i = 0, l = stats.length; i < l; i++) { for (let i = 0, l = stats.length; i < l; i++) {
if (stats[i].clients.size == 1) { if (stats[i].clients.size == 1) {
continue; continue
} }
const stat = stats[i]; const stat = stats[i]
stat.waitingTime += this.clock.deltaTime; stat.waitingTime += this.clock.deltaTime
if (stat.group && stat.group.ready) { if (stat.group && stat.group.ready) {
continue; continue
} }
if (currentGroup.averageRank > 0) { if (currentGroup.averageRank > 0) {
const diff = Math.abs(stat.rank - currentGroup.averageRank); const diff = Math.abs(stat.rank - currentGroup.averageRank)
const diffRatio = (diff / currentGroup.averageRank); const diffRatio = (diff / currentGroup.averageRank)
/** /**
* figure out how to identify the diff ratio that makes sense * figure out how to identify the diff ratio that makes sense
*/ */
if (diffRatio > this.step_ir) { if (diffRatio > this.step_ir) {
currentGroup = this.createGroup(); currentGroup = this.createGroup()
totalRank = 0; totalRank = 0
} }
} }
stat.group = currentGroup; stat.group = currentGroup
currentGroup.clients.push(stat); currentGroup.clients.push(stat)
currentGroup.count += stat.clients.size; currentGroup.count += stat.clients.size
totalRank += stat.rank; totalRank += stat.rank
currentGroup.averageRank = totalRank / currentGroup.clients.length; currentGroup.averageRank = totalRank / currentGroup.clients.length
if (currentGroup.count === this.numClientsToMatch) { if (currentGroup.count === this.numClientsToMatch) {
currentGroup.ready = true; currentGroup.ready = true
currentGroup = this.createGroup(); currentGroup = this.createGroup()
totalRank = 0; totalRank = 0
} }
} }
totalRank = 0; totalRank = 0
currentGroup = this.createGroup(); currentGroup = this.createGroup()
for (let i = 0, l = stats.length; i < l; i++) { for (let i = 0, l = stats.length; i < l; i++) {
const stat = stats[i]; const stat = stats[i]
if (stats[i].clients.size == 1) { if (stats[i].clients.size == 1) {
stat.waitingTime += this.clock.deltaTime; stat.waitingTime += this.clock.deltaTime
} else { } else {
if (stat.waitingTime < this.groupAddOneTime) { if (stat.waitingTime < this.groupAddOneTime) {
continue; continue
} }
} }
/** /**
* do not attempt to re-assign groups for clients inside "ready" groups * do not attempt to re-assign groups for clients inside "ready" groups
*/ */
if (stat.group && stat.group.ready) { if (stat.group && stat.group.ready) {
continue; continue
} }
if (currentGroup.count + stat.clients.size > this.maxClients) { if (currentGroup.count + stat.clients.size > this.maxClients) {
continue; continue
} }
if (stat.priority) { if (stat.priority) {
currentGroup.priority = true; currentGroup.priority = true
} }
/** /**
@ -263,24 +279,24 @@ export class RankedLobbyRoom extends Room {
currentGroup.averageRank > 0 && currentGroup.averageRank > 0 &&
!currentGroup.priority !currentGroup.priority
) { ) {
const diff = Math.abs(stat.rank - currentGroup.averageRank); const diff = Math.abs(stat.rank - currentGroup.averageRank)
const diffRatio = (diff / currentGroup.averageRank); const diffRatio = (diff / currentGroup.averageRank)
/** /**
* figure out how to identify the diff ratio that makes sense * figure out how to identify the diff ratio that makes sense
*/ */
if (diffRatio > this.fair_ir) { if (diffRatio > this.fair_ir) {
currentGroup = this.createGroup(); currentGroup = this.createGroup()
totalRank = 0; totalRank = 0
} }
} }
stat.group = currentGroup; stat.group = currentGroup
currentGroup.clients.push(stat); currentGroup.clients.push(stat)
currentGroup.count += stat.clients.size; currentGroup.count += stat.clients.size
totalRank += stat.rank; totalRank += stat.rank
currentGroup.averageRank = totalRank / currentGroup.count; currentGroup.averageRank = totalRank / currentGroup.count
if ( if (
(currentGroup.count === this.numClientsToMatch) || (currentGroup.count === this.numClientsToMatch) ||
@ -292,80 +308,81 @@ export class RankedLobbyRoom extends Room {
(stat.waitingTime >= this.maxWaitingTime && this.allowUnmatchedGroups) || (stat.waitingTime >= this.maxWaitingTime && this.allowUnmatchedGroups) ||
stat.priority stat.priority
) { ) {
currentGroup.ready = true; currentGroup.ready = true
currentGroup = this.createGroup(); currentGroup = this.createGroup()
totalRank = 0; totalRank = 0
} }
} }
this.checkGroupsReady(); this.checkGroupsReady()
} }
generateSeat(index: number): number { generateSeat(index: number): number {
switch (index) { switch (index) {
case 0: case 0:
return 0; return 0
case 1: case 1:
return 3; return 3
case 2: case 2:
return 1; return 1
case 3: case 3:
return 2; return 2
} }
} }
async checkGroupsReady() { async checkGroupsReady() {
await Promise.all( await Promise.all(
this.groups this.groups
.map(async (group) => { .map(async (group) => {
if (group.ready) { if (group.ready) {
group.confirmed = 0; group.confirmed = 0
let score = 0; let score = 0
let count = 0; let count = 0
group.clients.map(client => { group.clients.map(client => {
for (let [,data] of client.clients) { for (let [, data] of client.clients) {
score += (data.options?.score || 0); score += (data.options?.score || 0)
count ++; count++
} }
}) })
let avaScore = score / count; let avaScore = score / count
/** /**
* Create room instance in the server. * Create room instance in the server.
*/ */
const room = await matchMaker.createRoom(this.roomToCreate, { const room = await matchMaker.createRoom(this.roomToCreate, {
match: true, match: this.matchid,
rank: group.averageRank, rank: group.averageRank,
score: avaScore, score: avaScore,
count: this.numClientsToMatch - group.count count: this.numClientsToMatch - group.count
}); })
// 预处理数据, 确定座次 // 预处理数据, 确定座次
let hasGroup = false; let hasGroup = false
for (let client of group.clients) { for (let client of group.clients) {
if (client.clients.size > 1) { if (client.clients.size > 1) {
hasGroup = true; hasGroup = true
break; break
} }
} }
let seat = 0; let seat = 0
if (hasGroup) { if (hasGroup) {
for (let client of group.clients) { for (let client of group.clients) {
if (client.clients.size > 1) { if (client.clients.size > 1) {
for (let [,sub] of client.clients) { for (let [, sub] of client.clients) {
sub.seat = this.generateSeat(seat ++); sub.seat = this.generateSeat(seat++)
} }
} }
} }
for (let client of group.clients) { for (let client of group.clients) {
if (client.clients.size == 1) { if (client.clients.size == 1) {
for (let [,sub] of client.clients) { for (let [, sub] of client.clients) {
sub.seat = this.generateSeat(seat ++); sub.seat = this.generateSeat(seat++)
} }
} }
} }
} else { } 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 client of group.clients) {
for (let [,sub] of client.clients) { for (let [, sub] of client.clients) {
sub.seat = seat ++; sub.seat = seat++
} }
} }
} }
@ -376,17 +393,17 @@ export class RankedLobbyRoom extends Room {
/** /**
* Send room data for new WebSocket connection! * Send room data for new WebSocket connection!
*/ */
for (let [,data] of client.clients) { for (let [, data] of client.clients) {
let matchOpt = { let matchOpt = {
seat: data.seat seat: data.seat
} }
Object.assign(matchOpt, data.options); Object.assign(matchOpt, data.options)
const matchData = await matchMaker.reserveSeatFor(room, matchOpt); const matchData = await matchMaker.reserveSeatFor(room, matchOpt)
let options: any = {seat: data.seat, rank: data.options.rank}; let options: any = { seat: data.seat, rank: data.options.rank }
Object.assign(options, matchData); Object.assign(options, matchData)
data.client.send("match_success", options); data.client.send('match_success', options)
} }
})); }))
// /** // /**
// * Cancel & re-enqueue clients if some of them couldn't confirm connection. // * Cancel & re-enqueue clients if some of them couldn't confirm connection.
@ -404,23 +421,23 @@ export class RankedLobbyRoom extends Room {
* Notify all clients within the group on how many players are in the queue * Notify all clients within the group on how many players are in the queue
*/ */
group.clients.forEach(client => { group.clients.forEach(client => {
for (let [,data] of client.clients) { for (let [, data] of client.clients) {
data.client.send("clients", group.count); data.client.send('clients', group.count)
} }
}); })
} }
}) })
); )
} }
onLeave(client: Client, consented: boolean) { 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) { if (stat.clients.size > 1) {
stat.clients.delete(client.sessionId); stat.clients.delete(client.sessionId)
let data = [...stat.clients.values()][0]; let data = [...stat.clients.values()][0]
stat.rank = data.options.rank; stat.rank = data.options.rank
} else { } else {
this.stats.remove(stat); this.stats.remove(stat)
} }
} }

View File

@ -193,13 +193,14 @@ export class GameResultCommand extends Command<CardGameState, {}> {
} }
let time = new GameEnv().gameResultTime * 1000; let time = new GameEnv().gameResultTime * 1000;
this.room.beginSchedule(time, resultTimeOver, 'restart_schedule'); 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 = { let resultData: any = {
winner: winner, winner: winner,
mvp: mvp.id, mvp: mvp.id,
results: [...results.values()], results: [...results.values()],
statics: statics, statics: statics,
seasonData seasonData: saveData.seasonData,
items: saveData.itemData
}; };
this.room.bGameResult(resultData); this.room.bGameResult(resultData);
this.resetAllState(); this.resetAllState();
@ -253,7 +254,8 @@ export class GameResultCommand extends Command<CardGameState, {}> {
roomid: this.room.roomId, roomid: this.room.roomId,
round: this.state.round, round: this.state.round,
winner: winner, winner: winner,
season: this.room.match ? 1: 0 season: this.room.match ? 1: 0,
matchid: this.room.match
} }
let players: any[] = []; let players: any[] = [];
let i = 0; let i = 0;