增加服务端机器人
This commit is contained in:
parent
fa949dd70c
commit
c7c8ee38c0
@ -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');
|
||||
|
2
src/global.d.ts
vendored
2
src/global.d.ts
vendored
@ -206,6 +206,8 @@ declare module "colyseus" {
|
||||
*/
|
||||
addScheduleTime(millisecond: number, reason?: string): void;
|
||||
|
||||
addRobot():void;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
135
src/robot/RobotClient.ts
Normal file
135
src/robot/RobotClient.ts
Normal file
@ -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<String, Card>;
|
||||
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<number>, options?: ISendOptions): void {
|
||||
// log('enqueueRaw:' + data.length);
|
||||
}
|
||||
|
||||
error(code: number, message?: string): void {
|
||||
}
|
||||
|
||||
leave(code?: number, data?: string): void {
|
||||
}
|
||||
|
||||
raw(data: ArrayLike<number>, 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
|
||||
});
|
||||
}
|
||||
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -18,7 +18,7 @@ export class BeginGameCommand extends Command<CardGameState, {}> {
|
||||
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);
|
||||
|
@ -54,7 +54,7 @@ export class ChangeCardCommand extends Command<CardGameState, { client: Client,
|
||||
if (finishCount >= this.room.maxClients) {
|
||||
// TODO:: 根据 this.state.firstPlayer确定先手
|
||||
// 正式开始游戏, 第一个玩家出牌
|
||||
this.state.gameState = GameStateConst.STATE_BEGIN_DRAW;
|
||||
this.state.updateGameState(GameStateConst.STATE_BEGIN_DRAW);
|
||||
return [new NextTurnCommand()];
|
||||
|
||||
}
|
||||
|
@ -75,7 +75,7 @@ export class DiscardCommand extends Command<CardGameState, { client: Client, car
|
||||
} else {
|
||||
let cardArr: Card[] = [...this.state.cards.values()];
|
||||
this.room.battleMan.onCardLinkOver(player, cardArr);
|
||||
this.state.gameState = GameStateConst.STATE_PICK_PET;
|
||||
this.state.updateGameState(GameStateConst.STATE_PICK_PET);
|
||||
let self = this;
|
||||
let time = singleton(GameEnv).playerActTime * 1000 + player.extraTime;
|
||||
// 开启选随从计时, 计时结束后结束当前轮
|
||||
|
@ -76,7 +76,7 @@ export class EatConfirmCommand extends Command<CardGameState, { timeUp: boolean
|
||||
player.cardSet.delete(id + '');
|
||||
}
|
||||
let cardArr: Card[] = [...this.state.cards.values()];
|
||||
this.state.gameState = GameStateConst.STATE_PICK_PET;
|
||||
this.state.updateGameState(GameStateConst.STATE_PICK_PET);
|
||||
let time = singleton(GameEnv).playerActTime * 1000 + player.extraTime;
|
||||
let self = this;
|
||||
|
||||
|
@ -22,6 +22,9 @@ export class GMCommand extends Command<CardGameState, {client: Client, message:
|
||||
case 'herohp':
|
||||
this.updateHeroHp(arr[1]);
|
||||
break;
|
||||
case 'addrobot':
|
||||
this.addRobot(arr[1]);
|
||||
break;
|
||||
case 'help':
|
||||
this.sendHelp(client, arr[1]);
|
||||
break;
|
||||
@ -40,6 +43,18 @@ export class GMCommand extends Command<CardGameState, {client: Client, message:
|
||||
str += '更新英雄血量: herohp:玩家index|血量 例: herohp:0|500 \n';
|
||||
client.send('notice_msg', str);
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加服务端机器人
|
||||
* addrobot:1
|
||||
* @param msg
|
||||
*/
|
||||
addRobot(msg:string) {
|
||||
let count = msg ? parseInt(msg) : 1;
|
||||
for (let i = 0; i< count; i++) {
|
||||
this.room.addRobot();
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 将一个玩家的手牌全变成指定的效果卡
|
||||
* changeeffect:玩家index|效果卡id
|
||||
|
@ -14,7 +14,7 @@ export class GameResultCommand extends Command<CardGameState, {}> {
|
||||
|
||||
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;
|
||||
|
@ -13,7 +13,7 @@ import {PlayerStateConst} from "../../constants/PlayerStateConst";
|
||||
export class NextSubCommand extends Command<CardGameState, {}> {
|
||||
|
||||
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) {
|
||||
|
@ -14,7 +14,7 @@ import {GameEnv} from "../../cfg/GameEnv";
|
||||
export class NextTurnCommand extends Command<CardGameState, {}> {
|
||||
|
||||
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;
|
||||
|
@ -17,7 +17,7 @@ export class OnJoinCommand extends Command<CardGameState, {
|
||||
this.state.players.set(client.sessionId, player);
|
||||
if (this.state.players.size >= 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});
|
||||
}
|
||||
|
@ -91,7 +91,7 @@ const comparePlayer = function (room: Room, p0: Player, p1: Player): CompareResu
|
||||
export class PartResultCommand extends Command<CardGameState, {}> {
|
||||
|
||||
execute() : Array<Command> | void {
|
||||
this.state.gameState = GameStateConst.STATE_ROUND_RESULT;
|
||||
this.state.updateGameState(GameStateConst.STATE_ROUND_RESULT);
|
||||
const time = singleton(GameEnv).resultShowTime || 1;
|
||||
|
||||
let t0 = [];
|
||||
|
@ -29,7 +29,7 @@ export class PlayReadyCommand extends Command<CardGameState, {
|
||||
player.team = (i ++ / 2) | 0;
|
||||
}
|
||||
await this.room.setPrivate(true);
|
||||
this.room.state.gameState = GameStateConst.CHANGE_HERO;
|
||||
this.room.state.updateGameState(GameStateConst.CHANGE_HERO);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -9,7 +9,7 @@ import {BeginGameCommand} from "./BeginGameCommand";
|
||||
export class PrepareCommand extends Command<CardGameState, {}> {
|
||||
|
||||
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) {
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user