Merge branch 'second' of http://git.kingsome.cn/node/card_svr into second
This commit is contained in:
commit
14f3cc5628
2
src/global.d.ts
vendored
2
src/global.d.ts
vendored
@ -30,6 +30,8 @@ declare module "colyseus" {
|
||||
battleMan: BattleHandler;
|
||||
dispatcher: Dispatcher;
|
||||
mainClock: Delayed;
|
||||
robotCount: number;
|
||||
match: boolean;
|
||||
/**
|
||||
* 根据sessionId获取client
|
||||
* @param player 玩家id或者玩家的对象
|
||||
|
18
src/index.ts
18
src/index.ts
@ -1,15 +1,14 @@
|
||||
import http from "http";
|
||||
import express from "express";
|
||||
import cors from "cors";
|
||||
import {RedisPresence, Server} from "colyseus";
|
||||
import { monitor } from "@colyseus/monitor";
|
||||
import {Server} from "colyseus";
|
||||
import {monitor} from "@colyseus/monitor";
|
||||
import rateLimit from "express-rate-limit";
|
||||
// import socialRoutes from "@colyseus/social/express"
|
||||
|
||||
import { GeneralRoom } from "./rooms/GeneralRoom";
|
||||
import {MongooseDriver} from "colyseus/lib/matchmaker/drivers/MongooseDriver";
|
||||
import {GeneralRoom} from "./rooms/GeneralRoom";
|
||||
import {initData} from "./common/GConfig";
|
||||
import {Config} from "./cfg/Config";
|
||||
import {RankedLobbyRoom} from "./rooms/RankedLobbyRoom";
|
||||
|
||||
require('./rooms/MSender');
|
||||
require('./rooms/RoomExtMethod');
|
||||
@ -34,7 +33,9 @@ const gameServer = new Server({
|
||||
|
||||
// register your room handlers
|
||||
gameServer.define('general_room', GeneralRoom);
|
||||
|
||||
gameServer
|
||||
.define('match_room', RankedLobbyRoom)
|
||||
.filterBy(['numClientsToMatch']);
|
||||
/**
|
||||
* Register @colyseus/social routes
|
||||
*
|
||||
@ -61,5 +62,6 @@ gameServer.onShutdown(function () {
|
||||
console.log("master process is being shut down!");
|
||||
//TODO:: 保存所有数据至db, 重启时恢复
|
||||
});
|
||||
gameServer.listen(port).then(()=>{});
|
||||
console.log(`Listening on ws://localhost:${ port }`)
|
||||
gameServer.listen(port).then(() => {
|
||||
});
|
||||
console.log(`Listening on ws://localhost:${port}`)
|
||||
|
@ -30,6 +30,8 @@ export class GeneralRoom extends Room {
|
||||
gameClock: Map<string, Delayed> = new Map();
|
||||
|
||||
assistMap: Map<String, RobotClient> = new Map();
|
||||
match = false;
|
||||
robotCount = 0;
|
||||
|
||||
async onAuth (client:Client, options: any, request: IncomingMessage) {
|
||||
debugRoom(options);
|
||||
@ -40,8 +42,14 @@ export class GeneralRoom extends Room {
|
||||
}
|
||||
onCreate (options: any) {
|
||||
let cs = new CardGameState();
|
||||
this.setMetadata({rank: 2});
|
||||
this.setState(cs);
|
||||
this.setPrivate(true);
|
||||
if (options.count) {
|
||||
this.robotCount = Math.min(Math.max(0, options.count), this.maxClients - 1);
|
||||
}
|
||||
if (options.match) {
|
||||
this.match = options.match;
|
||||
}
|
||||
this.battleMan.init(cs, this);
|
||||
this.clock.start();
|
||||
this.state.gameState = GameStateConst.STATE_WAIT_JOIN;
|
||||
@ -105,6 +113,7 @@ export class GeneralRoom extends Room {
|
||||
let data = {
|
||||
client: client,
|
||||
accountId: options.accountid,
|
||||
seat: options.seat
|
||||
};
|
||||
this.dispatcher.dispatch(new OnJoinCommand(), data);
|
||||
}
|
||||
|
393
src/rooms/RankedLobbyRoom.ts
Normal file
393
src/rooms/RankedLobbyRoom.ts
Normal file
@ -0,0 +1,393 @@
|
||||
import {Client, generateId, matchMaker, Room} from "colyseus";
|
||||
|
||||
interface MatchmakingGroup {
|
||||
averageRank: number;
|
||||
clients: ClientStat[],
|
||||
priority?: boolean;
|
||||
|
||||
ready?: boolean;
|
||||
confirmed?: number;
|
||||
count: number;
|
||||
// cancelConfirmationTimeout?: Delayed;
|
||||
}
|
||||
|
||||
interface ClientStat {
|
||||
clients: Map<string, {client: Client, options: any, seat?: number}>;
|
||||
waitingTime: number;
|
||||
options?: any;
|
||||
groupTag?: string;
|
||||
group?: MatchmakingGroup;
|
||||
rank: number;
|
||||
confirmed?: boolean;
|
||||
}
|
||||
|
||||
export class RankedLobbyRoom extends Room {
|
||||
/**
|
||||
* If `allowUnmatchedGroups` is true, players inside an unmatched group (that
|
||||
* did not reached `numClientsToMatch`, and `maxWaitingTime` has been
|
||||
* reached) will be matched together. Your room should fill the remaining
|
||||
* spots with "bots" on this case.
|
||||
*/
|
||||
allowUnmatchedGroups: boolean = true;
|
||||
|
||||
/**
|
||||
* Evaluate groups for each client at interval
|
||||
*/
|
||||
evaluateGroupsInterval = 1000;
|
||||
|
||||
/**
|
||||
* Groups of players per iteration
|
||||
*/
|
||||
groups: MatchmakingGroup[] = [];
|
||||
|
||||
/**
|
||||
* name of the room to create
|
||||
*/
|
||||
roomToCreate = "general_room";
|
||||
|
||||
/**
|
||||
* 最大匹配时间
|
||||
*/
|
||||
maxWaitingTime = 15 * 1000;
|
||||
/**
|
||||
* 超过该时间, 组队玩家可匹配单排玩家
|
||||
* @type {number}
|
||||
*/
|
||||
groupAddOneTime = 10 * 1000;
|
||||
|
||||
/**
|
||||
* after this time, try to fit this client with a not-so-compatible group
|
||||
*/
|
||||
maxWaitingTimeForPriority?: number = 10 * 1000;
|
||||
|
||||
/**
|
||||
* number of players on each match
|
||||
*/
|
||||
numClientsToMatch = 4;
|
||||
|
||||
// /**
|
||||
// * after a group is ready, clients have this amount of milliseconds to confirm
|
||||
// * connection to the created room
|
||||
// */
|
||||
// cancelConfirmationAfter = 5000;
|
||||
maxDiffRatio = 1.2;
|
||||
/**
|
||||
* rank and group cache per-player
|
||||
*/
|
||||
stats: ClientStat[] = [];
|
||||
|
||||
onCreate(options: any) {
|
||||
if (options.maxWaitingTime) {
|
||||
this.maxWaitingTime = options.maxWaitingTime;
|
||||
}
|
||||
|
||||
if (options.numClientsToMatch) {
|
||||
this.numClientsToMatch = options.numClientsToMatch;
|
||||
}
|
||||
|
||||
this.onMessage("bye", (client: Client, message: any) => {
|
||||
const stat = this.stats.find(stat => stat.clients.has(client.sessionId));
|
||||
|
||||
if (stat && stat.group && typeof (stat.group.confirmed) === "number") {
|
||||
stat.confirmed = true;
|
||||
stat.group.confirmed++;
|
||||
stat.clients.delete(client.sessionId);
|
||||
client.leave();
|
||||
}
|
||||
})
|
||||
|
||||
/**
|
||||
* Redistribute clients into groups at every interval
|
||||
*/
|
||||
this.setSimulationInterval(() => this.redistributeGroups(), this.evaluateGroupsInterval);
|
||||
}
|
||||
|
||||
onJoin(client: Client, options: any) {
|
||||
/**
|
||||
* 如果请求带有group, 那么查找当前队列中group相同的记录
|
||||
* 如果没有, 就插一条记录
|
||||
* 如果找到的记录, clients已经查过2条, 则也插入一条记录
|
||||
* 如果找到的记录, clients是1, 则把当前client添加到该记录中, 同时更新rank
|
||||
*/
|
||||
if (options.group) {
|
||||
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];
|
||||
break
|
||||
}
|
||||
}
|
||||
if (!groupData) {
|
||||
let clientMap = new Map();
|
||||
clientMap.set(client.sessionId, {client, options});
|
||||
groupData = {
|
||||
clients: clientMap,
|
||||
rank: options.rank,
|
||||
groupTag: options.group,
|
||||
waitingTime: 0,
|
||||
options
|
||||
}
|
||||
this.stats.push(groupData);
|
||||
} else {
|
||||
if (groupData.clients.size >= 2) {
|
||||
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
|
||||
}
|
||||
}
|
||||
client.send("clients", groupData.clients.size);
|
||||
} else {
|
||||
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);
|
||||
}
|
||||
|
||||
createGroup() {
|
||||
let group: MatchmakingGroup = {clients: [], averageRank: 0, count: 0};
|
||||
this.groups.push(group);
|
||||
return group;
|
||||
}
|
||||
|
||||
redistributeGroups() {
|
||||
// re-set all groups
|
||||
this.groups = [];
|
||||
|
||||
const stats = this.stats.sort((a, b) => a.rank - b.rank);
|
||||
|
||||
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;
|
||||
}
|
||||
const stat = stats[i];
|
||||
stat.waitingTime += this.clock.deltaTime;
|
||||
if (stat.group && stat.group.ready) {
|
||||
continue;
|
||||
}
|
||||
if (currentGroup.averageRank > 0) {
|
||||
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.maxDiffRatio) {
|
||||
currentGroup = this.createGroup();
|
||||
totalRank = 0;
|
||||
}
|
||||
}
|
||||
|
||||
stat.group = currentGroup;
|
||||
currentGroup.clients.push(stat);
|
||||
currentGroup.count += stat.clients.size;
|
||||
|
||||
totalRank += stat.rank;
|
||||
currentGroup.averageRank = totalRank / currentGroup.clients.length;
|
||||
if (currentGroup.count === this.numClientsToMatch) {
|
||||
currentGroup.ready = true;
|
||||
currentGroup = this.createGroup();
|
||||
totalRank = 0;
|
||||
}
|
||||
}
|
||||
totalRank = 0;
|
||||
currentGroup = this.createGroup();
|
||||
for (let i = 0, l = stats.length; i < l; i++) {
|
||||
|
||||
const stat = stats[i];
|
||||
|
||||
if (stats[i].clients.size == 1) {
|
||||
stat.waitingTime += this.clock.deltaTime;
|
||||
} else {
|
||||
if (stat.waitingTime < this.groupAddOneTime) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* do not attempt to re-assign groups for clients inside "ready" groups
|
||||
*/
|
||||
if (stat.group && stat.group.ready) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Force this client to join a group, even if rank is incompatible
|
||||
*/
|
||||
// if (
|
||||
// this.maxWaitingTimeForPriority !== undefined &&
|
||||
// stat.waitingTime >= this.maxWaitingTimeForPriority
|
||||
// ) {
|
||||
// currentGroup.priority = true;
|
||||
// }
|
||||
|
||||
if (
|
||||
currentGroup.averageRank > 0 &&
|
||||
!currentGroup.priority
|
||||
) {
|
||||
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.maxDiffRatio) {
|
||||
currentGroup = this.createGroup();
|
||||
totalRank = 0;
|
||||
}
|
||||
}
|
||||
|
||||
stat.group = currentGroup;
|
||||
currentGroup.clients.push(stat);
|
||||
currentGroup.count += stat.clients.size;
|
||||
|
||||
totalRank += stat.rank;
|
||||
currentGroup.averageRank = totalRank / currentGroup.count;
|
||||
|
||||
if (
|
||||
(currentGroup.count === this.numClientsToMatch) ||
|
||||
|
||||
/**
|
||||
* Match long-waiting clients with bots
|
||||
* FIXME: peers of this group may be entered short ago
|
||||
*/
|
||||
(stat.waitingTime >= this.maxWaitingTime && this.allowUnmatchedGroups)
|
||||
) {
|
||||
currentGroup.ready = true;
|
||||
currentGroup = this.createGroup();
|
||||
totalRank = 0;
|
||||
}
|
||||
}
|
||||
|
||||
this.checkGroupsReady();
|
||||
}
|
||||
|
||||
generateSeat(index: number): number {
|
||||
switch (index) {
|
||||
case 0:
|
||||
return 0;
|
||||
case 1:
|
||||
return 4;
|
||||
case 2:
|
||||
return 1;
|
||||
case 3:
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
async checkGroupsReady() {
|
||||
await Promise.all(
|
||||
this.groups
|
||||
.map(async (group) => {
|
||||
if (group.ready) {
|
||||
group.confirmed = 0;
|
||||
|
||||
/**
|
||||
* Create room instance in the server.
|
||||
*/
|
||||
const room = await matchMaker.createRoom(this.roomToCreate, {rank: true, count: this.numClientsToMatch - group.count});
|
||||
// TODO: 预处理数据, 确定座次
|
||||
let hasGroup = false;
|
||||
for (let client of group.clients) {
|
||||
if (client.clients.size > 1) {
|
||||
hasGroup = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
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 client of group.clients) {
|
||||
if (client.clients.size == 1) {
|
||||
for (let [,sub] of client.clients) {
|
||||
sub.seat = this.generateSeat(seat ++);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
group.clients.sort((a, b) => a.rank - b.rank);
|
||||
for (let client of group.clients) {
|
||||
for (let [,sub] of client.clients) {
|
||||
sub.seat = seat ++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
await Promise.all(group.clients.map(async (client) => {
|
||||
const matchData = await matchMaker.reserveSeatFor(room, client.options);
|
||||
|
||||
/**
|
||||
* Send room data for new WebSocket connection!
|
||||
*/
|
||||
for (let [,data] of client.clients) {
|
||||
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.
|
||||
// */
|
||||
// group.cancelConfirmationTimeout = this.clock.setTimeout(() => {
|
||||
// group.clients.forEach(stat => {
|
||||
// this.send(stat.client, 0);
|
||||
// stat.group = undefined;
|
||||
// stat.waitingTime = 0;
|
||||
// });
|
||||
// }, this.cancelConfirmationAfter);
|
||||
|
||||
} else {
|
||||
/**
|
||||
* 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);
|
||||
}
|
||||
});
|
||||
}
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
onLeave(client: Client, consented: boolean) {
|
||||
const stat = this.stats.find(stat => stat.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;
|
||||
} else {
|
||||
this.stats.remove(stat);
|
||||
}
|
||||
}
|
||||
|
||||
onDispose() {
|
||||
}
|
||||
|
||||
}
|
@ -12,42 +12,42 @@ import {GameEnv} from "../../cfg/GameEnv";
|
||||
*/
|
||||
export class NextTurnCommand extends Command<CardGameState, {}> {
|
||||
|
||||
async execute(){
|
||||
this.state.updateGameState(GameStateConst.STATE_BEGIN_DRAW);
|
||||
const players = [...this.state.players.values()];
|
||||
players.sort((a, b) => a.idx - b.idx);
|
||||
const sessionIds = players.map(p => p.id);
|
||||
if (!this.state.currentTurn) {
|
||||
this.state.round = 0;
|
||||
}
|
||||
// 如果上一轮是最后一个玩家, 则round + 1;
|
||||
if (this.state.currentTurn
|
||||
&& sessionIds.indexOf(this.state.currentTurn) == (sessionIds.length - 1)) {
|
||||
this.state.round += 1;
|
||||
// 所有玩家根据配置, 增加5点灵活值
|
||||
if (this.state.round > 0) {
|
||||
let moreRoundTime = new GameEnv().roundExtTime * 1000;
|
||||
let maxTime = new GameEnv().maxExtTime * 1000;
|
||||
for (let [, p] of this.state.players) {
|
||||
p.extraTime = Math.min(p.extraTime + moreRoundTime, maxTime);
|
||||
}
|
||||
}
|
||||
}
|
||||
this.state.updateGameTurn((this.state.currentTurn)
|
||||
? sessionIds[(sessionIds.indexOf(this.state.currentTurn) + 1) % sessionIds.length]
|
||||
: sessionIds[0]);
|
||||
let player = this.state.players.get(this.state.currentTurn);
|
||||
player.cardQueue.clear();
|
||||
if (!player) {
|
||||
error('未找到玩家');
|
||||
}
|
||||
let time = this.room.battleMan.onPlayerRoundStart(player);
|
||||
await this.delay(time);
|
||||
if (player.state == PlayerStateConst.PLAYER_DEAD) {
|
||||
return [new TurnEndCommand()];
|
||||
} else {
|
||||
return [new DrawCommand()]
|
||||
}
|
||||
async execute() {
|
||||
this.state.updateGameState(GameStateConst.STATE_BEGIN_DRAW);
|
||||
const players = [...this.state.players.values()];
|
||||
players.sort((a, b) => a.idx - b.idx);
|
||||
const sessionIds = players.map(p => p.id);
|
||||
if (!this.state.currentTurn) {
|
||||
this.state.round = 0;
|
||||
}
|
||||
// 如果上一轮是最后一个玩家, 则round + 1;
|
||||
if (this.state.currentTurn
|
||||
&& sessionIds.indexOf(this.state.currentTurn) == (sessionIds.length - 1)) {
|
||||
this.state.round += 1;
|
||||
// 所有玩家根据配置, 增加5点灵活值
|
||||
if (this.state.round > 0) {
|
||||
let moreRoundTime = new GameEnv().roundExtTime * 1000;
|
||||
let maxTime = new GameEnv().maxExtTime * 1000;
|
||||
for (let [, p] of this.state.players) {
|
||||
p.extraTime = Math.min(p.extraTime + moreRoundTime, maxTime);
|
||||
}
|
||||
}
|
||||
}
|
||||
this.state.updateGameTurn((this.state.currentTurn)
|
||||
? sessionIds[(sessionIds.indexOf(this.state.currentTurn) + 1) % sessionIds.length]
|
||||
: sessionIds[0]);
|
||||
let player = this.state.players.get(this.state.currentTurn);
|
||||
player.cardQueue.clear();
|
||||
if (!player) {
|
||||
error('未找到玩家');
|
||||
}
|
||||
let time = this.room.battleMan.onPlayerRoundStart(player);
|
||||
await this.delay(time);
|
||||
if (player.state == PlayerStateConst.PLAYER_DEAD) {
|
||||
return [new TurnEndCommand()];
|
||||
} else {
|
||||
return [new DrawCommand()]
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -9,43 +9,60 @@ import {GameEnv} from "../../cfg/GameEnv";
|
||||
* 玩家成功加入房间
|
||||
*/
|
||||
export class OnJoinCommand extends Command<CardGameState, {
|
||||
client: Client,
|
||||
accountId: string
|
||||
client: Client,
|
||||
accountId: string,
|
||||
seat?: number,
|
||||
}> {
|
||||
execute({client, accountId} = this.payload) {
|
||||
let count = this.state.players.size;
|
||||
let team = (count == 1 || count == 2)? 1 : 0;
|
||||
let player = new Player(client.sessionId, count, team);
|
||||
if (accountId && accountId == 'robot') {
|
||||
accountId = `robot_${client.sessionId}`;
|
||||
} else if (!accountId) {
|
||||
accountId = `player_${client.sessionId}`;
|
||||
execute({client, accountId, seat} = this.payload) {
|
||||
let count = this.state.players.size;
|
||||
if (count >= this.room.maxClients) {
|
||||
return;
|
||||
}
|
||||
if (accountId && accountId == 'robot') {
|
||||
accountId = `robot_${client.sessionId}`;
|
||||
} else if (!accountId) {
|
||||
accountId = `player_${client.sessionId}`;
|
||||
}
|
||||
let team = 0;
|
||||
let idx = count;
|
||||
if (seat != undefined) {
|
||||
idx = +seat;
|
||||
} else {
|
||||
team = (count == 1 || count == 2) ? 1 : 0;
|
||||
}
|
||||
let player = new Player(client.sessionId, idx, team);
|
||||
player.accountId = accountId;
|
||||
this.state.players.set(client.sessionId, player);
|
||||
this.room.addAssistClient(client.sessionId);
|
||||
let self = this;
|
||||
if (this.room.clientCount() == 1) {
|
||||
// 正常的匹配逻辑进入的第一个玩家, 开启定时, 超过设定时间人没齐的话, 添加机器人
|
||||
let timeOutWaitingPlayer = function () {
|
||||
let count = self.room.maxClients - self.room.clientCount();
|
||||
if (count > 0) {
|
||||
for (let i = 0; i < count; i++) {
|
||||
self.room.addRobot();
|
||||
}
|
||||
}
|
||||
player.accountId = accountId;
|
||||
this.state.players.set(client.sessionId, player);
|
||||
this.room.addAssistClient(client.sessionId);
|
||||
let self = this;
|
||||
if (this.room.clientCount() == 1) {
|
||||
// 正常的匹配逻辑进入的第一个玩家, 开启定时, 超过设定时间人没齐的话, 添加机器人
|
||||
let timeOutWaitingPlayer = function () {
|
||||
let count = self.room.maxClients - self.room.clientCount();
|
||||
if (count > 0) {
|
||||
for (let i = 0; i < count; i++) {
|
||||
self.room.addRobot();
|
||||
}
|
||||
}
|
||||
}
|
||||
let time = new GameEnv().waitingPlayerTime * 1000;
|
||||
self.room.beginSchedule(time, timeOutWaitingPlayer, 'waiting_player');
|
||||
} else if (this.room.clientCount() > 1 && this.room.clientCount() < this.room.maxClients) {
|
||||
let moreTime = new GameEnv().waitingPlayerOnePlus * 1000;
|
||||
self.room.addScheduleTime(moreTime, 'play_join', 'waiting_player')
|
||||
}
|
||||
if (this.state.players.size >= this.room.maxClients) {
|
||||
this.room.lock().then(() => {});
|
||||
this.state.updateGameState(GameStateConst.STATE_WAIT_PREPARE);
|
||||
}
|
||||
this.room.bUserJoin(`${client.sessionId}`, {except: client});
|
||||
}
|
||||
let time = new GameEnv().waitingPlayerTime * 1000;
|
||||
self.room.beginSchedule(time, timeOutWaitingPlayer, 'waiting_player');
|
||||
} else if (this.room.clientCount() > 1 && this.room.clientCount() < this.room.maxClients) {
|
||||
let moreTime = new GameEnv().waitingPlayerOnePlus * 1000;
|
||||
self.room.addScheduleTime(moreTime, 'play_join', 'waiting_player')
|
||||
}
|
||||
if (this.state.players.size >= this.room.maxClients) {
|
||||
this.room.lock().then(() => {
|
||||
});
|
||||
this.state.updateGameState(GameStateConst.STATE_WAIT_PREPARE);
|
||||
} else if (this.state.players.size < this.room.maxClients
|
||||
&& this.state.players.size >= this.room.maxClients - this.room.robotCount) {
|
||||
for (let i = 0; i < this.room.robotCount; i++) {
|
||||
self.room.addRobot();
|
||||
}
|
||||
}
|
||||
|
||||
this.room.bUserJoin(`${client.sessionId}`, {except: client});
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,4 +1,11 @@
|
||||
import {ArraySchema, filter, MapSchema, Schema, SetSchema, type} from "@colyseus/schema";
|
||||
import {
|
||||
ArraySchema,
|
||||
filter,
|
||||
MapSchema,
|
||||
Schema,
|
||||
SetSchema,
|
||||
type
|
||||
} from "@colyseus/schema";
|
||||
import {Pet} from "./Pet";
|
||||
import {Card} from "./Card";
|
||||
import {GameEnv} from "../../cfg/GameEnv";
|
||||
@ -7,107 +14,112 @@ import {StateTypeEnum} from "../enums/StateTypeEnum";
|
||||
|
||||
|
||||
export class Player extends Schema {
|
||||
@type("string")
|
||||
id: string;
|
||||
@type("string")
|
||||
id: string;
|
||||
|
||||
accountId: string;
|
||||
accountId: string;
|
||||
/**
|
||||
* 用于组队匹配时候队伍的标记
|
||||
* @type {string}
|
||||
*/
|
||||
group?: string;
|
||||
|
||||
@type("number")
|
||||
heroId: number;
|
||||
/**
|
||||
* 手牌
|
||||
*/
|
||||
@filter(function(this: Player, client, value, root) {
|
||||
return (client.sessionId == this.id);
|
||||
})
|
||||
@type({ map: Card })
|
||||
cards = new MapSchema<Card>();
|
||||
@type("number")
|
||||
heroId: number;
|
||||
/**
|
||||
* 手牌
|
||||
*/
|
||||
@filter(function (this: Player, client, value, root) {
|
||||
return (client.sessionId == this.id);
|
||||
})
|
||||
@type({map: Card})
|
||||
cards = new MapSchema<Card>();
|
||||
|
||||
@type({ set: "string" })
|
||||
cardSet = new SetSchema<string>();
|
||||
@type({set: "string"})
|
||||
cardSet = new SetSchema<string>();
|
||||
|
||||
/**
|
||||
* 玩家出的牌
|
||||
*/
|
||||
@type([Card])
|
||||
cardQueue = new ArraySchema<Card>();
|
||||
/**
|
||||
* 当前hp
|
||||
*/
|
||||
@type("number")
|
||||
hp: number;
|
||||
/**
|
||||
* 玩家出的牌
|
||||
*/
|
||||
@type([Card])
|
||||
cardQueue = new ArraySchema<Card>();
|
||||
/**
|
||||
* 当前hp
|
||||
*/
|
||||
@type("number")
|
||||
hp: number;
|
||||
|
||||
/**
|
||||
* 状态
|
||||
* 0: 正常状态
|
||||
* 1: 已准备好
|
||||
* 2: 死亡
|
||||
* 3: 已换完牌
|
||||
* 4: 玩家已选择英雄
|
||||
* 9: 掉线
|
||||
*/
|
||||
@type("number")
|
||||
state: number;
|
||||
/**
|
||||
* 随从
|
||||
*/
|
||||
@type({ map: Pet })
|
||||
pets = new MapSchema<Pet>();
|
||||
/**
|
||||
* 状态
|
||||
* 0: 正常状态
|
||||
* 1: 已准备好
|
||||
* 2: 死亡
|
||||
* 3: 已换完牌
|
||||
* 4: 玩家已选择英雄
|
||||
* 9: 掉线
|
||||
*/
|
||||
@type("number")
|
||||
state: number;
|
||||
/**
|
||||
* 随从
|
||||
*/
|
||||
@type({map: Pet})
|
||||
pets = new MapSchema<Pet>();
|
||||
|
||||
/**
|
||||
* 队伍
|
||||
*/
|
||||
@type("number")
|
||||
team: number;
|
||||
/**
|
||||
* 队伍
|
||||
*/
|
||||
@type("number")
|
||||
team: number;
|
||||
|
||||
@type("number")
|
||||
idx: number;
|
||||
/**
|
||||
* 玩家灵活时限, 客户端每次显示倒计时的时候, 需读取该时间
|
||||
*/
|
||||
@type("number")
|
||||
extraTime: number;
|
||||
/**
|
||||
* 当前游戏总抽卡数量
|
||||
*/
|
||||
countTotal: number;
|
||||
/**
|
||||
* 当前累计抽卡
|
||||
*/
|
||||
countPresent: number;
|
||||
/**
|
||||
* 记录当前局内统计数字
|
||||
*/
|
||||
statData: Map<StateTypeEnum, number> = new Map();
|
||||
/**
|
||||
* 用于记录pet值, 用于统计伤害
|
||||
*/
|
||||
petData: Map<number, number> = new Map();
|
||||
@type("number")
|
||||
idx: number;
|
||||
/**
|
||||
* 玩家灵活时限, 客户端每次显示倒计时的时候, 需读取该时间
|
||||
*/
|
||||
@type("number")
|
||||
extraTime: number;
|
||||
/**
|
||||
* 当前游戏总抽卡数量
|
||||
*/
|
||||
countTotal: number;
|
||||
/**
|
||||
* 当前累计抽卡
|
||||
*/
|
||||
countPresent: number;
|
||||
/**
|
||||
* 记录当前局内统计数字
|
||||
*/
|
||||
statData: Map<StateTypeEnum, number> = new Map();
|
||||
/**
|
||||
* 用于记录pet值, 用于统计伤害
|
||||
*/
|
||||
petData: Map<number, number> = new Map();
|
||||
|
||||
/**
|
||||
* 英雄绑定的卡组, 选好英雄后, 从默认配置或玩家卡组(待实现)中获取
|
||||
* key = 效果卡id
|
||||
* val = weight
|
||||
*/
|
||||
@type({ map: "number" })
|
||||
unitCfgs = new MapSchema<number>();
|
||||
/**
|
||||
* 英雄绑定的卡组, 选好英雄后, 从默认配置或玩家卡组(待实现)中获取
|
||||
* key = 效果卡id
|
||||
* val = weight
|
||||
*/
|
||||
@type({map: "number"})
|
||||
unitCfgs = new MapSchema<number>();
|
||||
|
||||
constructor(id: string, idx: number, team: number) {
|
||||
super();
|
||||
this.id = id;
|
||||
this.state = PlayerStateConst.PLAYER_NORMAL;
|
||||
this.hp = 0;
|
||||
this.idx = idx;
|
||||
this.heroId = 0;
|
||||
this.team = team;
|
||||
this.countTotal = 0;
|
||||
this.countPresent = 0;
|
||||
for (let i = 0; i < new GameEnv().maxPlayerPetCount + 1; i++) {
|
||||
let pet = new Pet(i);
|
||||
pet.state = 0;
|
||||
pet.isHero = i === 0;
|
||||
this.pets.set(i+'', pet);
|
||||
constructor(id: string, idx: number, team: number) {
|
||||
super();
|
||||
this.id = id;
|
||||
this.state = PlayerStateConst.PLAYER_NORMAL;
|
||||
this.hp = 0;
|
||||
this.idx = idx;
|
||||
this.heroId = 0;
|
||||
this.team = team;
|
||||
this.countTotal = 0;
|
||||
this.countPresent = 0;
|
||||
for (let i = 0; i < new GameEnv().maxPlayerPetCount + 1; i++) {
|
||||
let pet = new Pet(i);
|
||||
pet.state = 0;
|
||||
pet.isHero = i === 0;
|
||||
this.pets.set(i + '', pet);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user