开始匹配前检查所需物品是否足够

This commit is contained in:
zhl 2021-01-22 14:08:45 +08:00
parent a5c2369634
commit 2170e80fec
2 changed files with 222 additions and 177 deletions

View File

@ -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<AxiosResponse<any>>}
*/
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<AxiosResponse<any>>}
*/
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<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 {}
}
})
}
/**
@ -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)
})
}

View File

@ -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<string, {client: Client, options: any, seat?: number}>;
clients: Map<string, { client: Client, options: any, seat?: number }>;
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)
}
}