From c7c8ee38c028efb08b043126f09075642abba33e Mon Sep 17 00:00:00 2001 From: zhl Date: Fri, 11 Dec 2020 16:58:12 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E6=9C=8D=E5=8A=A1=E7=AB=AF?= =?UTF-8?q?=E6=9C=BA=E5=99=A8=E4=BA=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/common/Debug.ts | 2 + src/global.d.ts | 2 + src/index.ts | 2 +- src/robot/RobotClient.ts | 135 ++++++++++++++++++++++++ src/rooms/GeneralRoom.ts | 27 ++++- src/rooms/commands/BeginGameCommand.ts | 2 +- src/rooms/commands/ChangeCardCommand.ts | 2 +- src/rooms/commands/DiscardCommand.ts | 2 +- src/rooms/commands/EatConfirmCommand.ts | 2 +- src/rooms/commands/GMCommand.ts | 15 +++ src/rooms/commands/GameResultCommand.ts | 2 +- src/rooms/commands/NextSubCommand.ts | 2 +- src/rooms/commands/NextTurnCommand.ts | 2 +- src/rooms/commands/OnJoinCommand.ts | 2 +- src/rooms/commands/PartResultCommand.ts | 2 +- src/rooms/commands/PlayReadyCommand.ts | 2 +- src/rooms/commands/PrepareCommand.ts | 2 +- src/rooms/schema/CardGameState.ts | 11 ++ 18 files changed, 203 insertions(+), 13 deletions(-) create mode 100644 src/robot/RobotClient.ts diff --git a/src/common/Debug.ts b/src/common/Debug.ts index cdbcc4a..1132649 100644 --- a/src/common/Debug.ts +++ b/src/common/Debug.ts @@ -5,3 +5,5 @@ export const debugRoom = debug('jc:room'); export const error = debug('jc:error'); export const msgLog = debug('jc:msg'); + +export const robotLog = debug('jc:robot'); diff --git a/src/global.d.ts b/src/global.d.ts index ec5e7bd..bb36731 100644 --- a/src/global.d.ts +++ b/src/global.d.ts @@ -206,6 +206,8 @@ declare module "colyseus" { */ addScheduleTime(millisecond: number, reason?: string): void; + addRobot():void; + } } diff --git a/src/index.ts b/src/index.ts index 4fc5072..fef3163 100644 --- a/src/index.ts +++ b/src/index.ts @@ -23,7 +23,7 @@ const server = http.createServer(app); const gameServer = new Server({ server, // driver: new MongooseDriver('mongodb://127.0.0.1/card-development'), - driver: new MongooseDriver('mongodb://192.168.100.24/card-development'), + driver: new MongooseDriver('mongodb://192.168.100.24/card-development-z'), }); // register your room handlers diff --git a/src/robot/RobotClient.ts b/src/robot/RobotClient.ts new file mode 100644 index 0000000..e9df88a --- /dev/null +++ b/src/robot/RobotClient.ts @@ -0,0 +1,135 @@ +import {Client, Room} from "colyseus"; +import {ClientState, ISendOptions} from "colyseus/lib/transport/Transport"; +import { EventEmitter } from 'events'; +import {robotLog as log} from '../common/Debug'; +import {CardGameState} from "../rooms/schema/CardGameState"; +import Clock from "@gamestdio/timer"; +import {GameStateConst} from "../constants/GameStateConst"; +import {Card} from "../rooms/schema/Card"; + +export class RobotClient implements Client { + id: string; + readyState: number; + ref: EventEmitter; + sessionId: string; + state: ClientState; + svrstate: CardGameState; + room: Room; + clock: Clock; + myTurn: boolean = false; + cards: Map; + onMessageHandlers: {[id: string]: (client: Client, message: any) => void} = {}; + + constructor(sessionId: string, state: CardGameState, clock: Clock, onMessageHandlers: {[id: string]: (client: Client, message: any) => void}) { + this.sessionId = sessionId; + this.svrstate = state; + this.clock = clock; + this.onMessageHandlers = onMessageHandlers; + let self = this; + let time = Math.random() * 2500 | 0; + this.clock.setTimeout(function (){ + self.reply('play_ready_c2s', ''); + }, time); + this.addListeners(); + + log(`new robot with session: ${sessionId}`); + } + addListeners() { + let self = this; + this.svrstate.listen('gameState', function (currentValue, previousValue) { + log(`server game state change: ${currentValue}, pre value: ${previousValue}`); + switch (currentValue) { + case GameStateConst.CHANGE_HERO: + self.selectHero(); + break; + case GameStateConst.STATE_CHANGE_CARD: + self.changeCard([]); + break; + case GameStateConst.STATE_BEGIN_EAT: + if (!self.myTurn) { + setTimeout(self.giveup.bind(self), 1000); + } + break; + case GameStateConst.STATE_ROUND_RESULT: + break; + } + }); + this.svrstate.listen('currentTurn', function (currentValue, previousValue) { + log(`server turn change: ${currentValue}, pre value: ${previousValue}`); + self.myTurn = currentValue === self.sessionId; + if (self.myTurn) { + self.discard(); + } + }) + } + close(code?: number, data?: string): void { + + } + + enqueueRaw(data: ArrayLike, options?: ISendOptions): void { + // log('enqueueRaw:' + data.length); + } + + error(code: number, message?: string): void { + } + + leave(code?: number, data?: string): void { + } + + raw(data: ArrayLike, options?: ISendOptions): void { + } + + public send(messageOrType: any, messageOrOptions?: any | ISendOptions, options?: ISendOptions) { + log(`receive server msg: ${messageOrType}, ${messageOrOptions}`); + switch (messageOrType) { + case 'draw_card_s2c': + break; + case 'player_ready_s2c': + break; + case 'steal_card_s2c': + + break; + } + } + + private reply(messageType: string, message: any) { + if (this.onMessageHandlers[messageType]) { + this.onMessageHandlers[messageType](this, message); + } else if (this.onMessageHandlers['*']) { + (this.onMessageHandlers['*'] as any)(this, messageType, message); + } + } + + + // >>>>>>>>>>>>>>>>>> begin + + private discard() { + let card; + for (let [key, d] of this.cards) { + card = d; + break; + } + if (!card) { + return; + } + this.reply('discard_card_c2s', { + cards: [card.id] + }); + } + + private giveup () { + this.reply('give_up_eat_c2s', {}); + } + private selectHero() { + this.cards = this.svrstate.players.get(this.sessionId).cards; + this.reply('select_hero_c2s', { + heroId: 30011 + }); + } + private changeCard(cardIds: number[]) { + this.reply('change_card_c2s', { + cards: cardIds + }); + } + +} diff --git a/src/rooms/GeneralRoom.ts b/src/rooms/GeneralRoom.ts index 94b6319..d8ab665 100644 --- a/src/rooms/GeneralRoom.ts +++ b/src/rooms/GeneralRoom.ts @@ -1,4 +1,4 @@ -import {Client, Room} from "colyseus"; +import {Client, generateId, Room} from "colyseus"; import {CardGameState} from "./schema/CardGameState"; import {OnJoinCommand} from "./commands/OnJoinCommand"; import {PlayReadyCommand} from "./commands/PlayReadyCommand"; @@ -18,6 +18,7 @@ import {Player} from "./schema/Player"; import {GMCommand} from "./commands/GMCommand"; import {GameStateConst} from "../constants/GameStateConst"; import {GameRestartCommand} from "./commands/GameRestartCommand"; +import {RobotClient} from "../robot/RobotClient"; export class GeneralRoom extends Room { @@ -176,4 +177,28 @@ export class GeneralRoom extends Room { } } + addRobot() { + const sessionId = generateId(); + let client = new RobotClient(sessionId, this.state, this.clock, this['onMessageHandlers']); + if (this.reservedSeatTimeouts[sessionId]) { + clearTimeout(this.reservedSeatTimeouts[sessionId]); + delete this.reservedSeatTimeouts[sessionId]; + } + // get seat reservation options and clear it + const options = this.reservedSeats[sessionId]; + delete this.reservedSeats[sessionId]; + this.clients.push(client); + // client.ref.on('message', this.onMessage.bind(this, client)); + const reconnection = this.reconnections[sessionId]; + if (reconnection) { + reconnection.resolve(client); + } + else { + if (this.onJoin) { + this.onJoin(client, options); + } + delete this.reservedSeats[sessionId]; + } + this._events.emit('join', client); + } } diff --git a/src/rooms/commands/BeginGameCommand.ts b/src/rooms/commands/BeginGameCommand.ts index ad9f886..8a7f935 100644 --- a/src/rooms/commands/BeginGameCommand.ts +++ b/src/rooms/commands/BeginGameCommand.ts @@ -18,7 +18,7 @@ export class BeginGameCommand extends Command { for (let client of this.room.clients) { this.room.addCard(client.sessionId, singleton(GameEnv).initCardNum, 0); } - this.state.gameState = GameStateConst.STATE_CHANGE_CARD; + this.state.updateGameState(GameStateConst.STATE_CHANGE_CARD); // 超时后结束换卡, 进入下一轮 const cardChangeTime = singleton(GameEnv).cardChangeTime; await this.delay(cardChangeTime*1000); diff --git a/src/rooms/commands/ChangeCardCommand.ts b/src/rooms/commands/ChangeCardCommand.ts index 160b166..710a894 100644 --- a/src/rooms/commands/ChangeCardCommand.ts +++ b/src/rooms/commands/ChangeCardCommand.ts @@ -54,7 +54,7 @@ export class ChangeCardCommand extends Command= this.room.maxClients) { // TODO:: 根据 this.state.firstPlayer确定先手 // 正式开始游戏, 第一个玩家出牌 - this.state.gameState = GameStateConst.STATE_BEGIN_DRAW; + this.state.updateGameState(GameStateConst.STATE_BEGIN_DRAW); return [new NextTurnCommand()]; } diff --git a/src/rooms/commands/DiscardCommand.ts b/src/rooms/commands/DiscardCommand.ts index cfe1ed4..44187a8 100644 --- a/src/rooms/commands/DiscardCommand.ts +++ b/src/rooms/commands/DiscardCommand.ts @@ -75,7 +75,7 @@ export class DiscardCommand extends Command { async execute() { this.room.bGameResult({}); - this.state.gameState = GameStateConst.STATE_GAME_OVER; + this.state.updateGameState(GameStateConst.STATE_GAME_OVER); this.resetAllState(); //TODO: 启动定时, 时间到后, 踢出没离开且没点重玩的玩家, 并将房间设为非private let self = this; diff --git a/src/rooms/commands/NextSubCommand.ts b/src/rooms/commands/NextSubCommand.ts index a1539e5..b59dad0 100644 --- a/src/rooms/commands/NextSubCommand.ts +++ b/src/rooms/commands/NextSubCommand.ts @@ -13,7 +13,7 @@ import {PlayerStateConst} from "../../constants/PlayerStateConst"; export class NextSubCommand extends Command { async execute() { - this.state.gameState = GameStateConst.STATE_BEGIN_EAT; + this.state.updateGameState(GameStateConst.STATE_BEGIN_EAT); this.state.tmpActionMap.clear(); // 先过滤已死亡玩家, 直接置为已放弃 for (let [key, player] of this.state.players) { diff --git a/src/rooms/commands/NextTurnCommand.ts b/src/rooms/commands/NextTurnCommand.ts index ec6c109..e52960c 100644 --- a/src/rooms/commands/NextTurnCommand.ts +++ b/src/rooms/commands/NextTurnCommand.ts @@ -14,7 +14,7 @@ import {GameEnv} from "../../cfg/GameEnv"; export class NextTurnCommand extends Command { async execute(){ - this.state.gameState = GameStateConst.STATE_BEGIN_DRAW; + this.state.updateGameState(GameStateConst.STATE_BEGIN_DRAW); const sessionIds = [...this.state.players.keys()]; if (!this.state.currentTurn) { this.state.round = 0; diff --git a/src/rooms/commands/OnJoinCommand.ts b/src/rooms/commands/OnJoinCommand.ts index 9dccf0d..4c3c89d 100644 --- a/src/rooms/commands/OnJoinCommand.ts +++ b/src/rooms/commands/OnJoinCommand.ts @@ -17,7 +17,7 @@ export class OnJoinCommand extends Command= this.room.maxClients) { this.room.lock().then(() => {}); - this.state.gameState = GameStateConst.STATE_WAIT_PREPARE; + this.state.updateGameState(GameStateConst.STATE_WAIT_PREPARE); } this.room.bUserJoin(`${client.sessionId}`, {except: client}); } diff --git a/src/rooms/commands/PartResultCommand.ts b/src/rooms/commands/PartResultCommand.ts index fd678ee..a65eaa5 100644 --- a/src/rooms/commands/PartResultCommand.ts +++ b/src/rooms/commands/PartResultCommand.ts @@ -91,7 +91,7 @@ const comparePlayer = function (room: Room, p0: Player, p1: Player): CompareResu export class PartResultCommand extends Command { execute() : Array | void { - this.state.gameState = GameStateConst.STATE_ROUND_RESULT; + this.state.updateGameState(GameStateConst.STATE_ROUND_RESULT); const time = singleton(GameEnv).resultShowTime || 1; let t0 = []; diff --git a/src/rooms/commands/PlayReadyCommand.ts b/src/rooms/commands/PlayReadyCommand.ts index 422820d..1e54b78 100644 --- a/src/rooms/commands/PlayReadyCommand.ts +++ b/src/rooms/commands/PlayReadyCommand.ts @@ -29,7 +29,7 @@ export class PlayReadyCommand extends Command { execute() { - this.state.gameState = GameStateConst.DETERMINE_TURN; + this.state.updateGameState(GameStateConst.DETERMINE_TURN); let time = 3000; //TODO:: 每人发2张牌, 并比较大小, 确定先手 for (let client of this.room.clients) { diff --git a/src/rooms/schema/CardGameState.ts b/src/rooms/schema/CardGameState.ts index d4a483d..6a29140 100644 --- a/src/rooms/schema/CardGameState.ts +++ b/src/rooms/schema/CardGameState.ts @@ -57,4 +57,15 @@ export class CardGameState extends Schema { */ restartCount = 0; + updateGameState(val: number) { + let preVal = this.gameState; + this.gameState = val; + this.$listeners.gameState.invoke(val, preVal); + } + + updateGameTurn(val: string) { + let preVal = this.currentTurn; + this.currentTurn = val; + this.$listeners.currentTurn.invoke(val, preVal); + } }