import { TexasCreateTableDataModel, TexasTable } from "../Table/TexasTable"; import * as _ from "underscore"; import { BlindModel, GBlindSer } from "../../../../Common/Service/BlindService"; import { GMatchSer, MatchModel } from "../../../../Common/Service/MatchService"; import { TexasServer } from "../TexasServer"; import { GLog, Timer } from "cgserver"; import { GExtUserSer } from "../../../../Common/Service/ExtUserService"; import { EErrorCode } from "../../Config/_error_"; import { CreateMatchInsInfo, EMatchState, GMatchInsSer, MatchInsModel, MatchPlayer } from "../../../../Common/Service/MatchInstanceService"; import { ns_texas } from "../../Config/_ini_"; import { TexasClientWebSocket } from "../../Net/TexasClientWebSocket"; import { GMonitorSer, MonitorModel } from "../../../../Common/Service/MonitorService"; import { ns_common } from "../../../../Common/Config/_ini_"; export class TexasMatch { protected _server:TexasServer=null protected _matchM:MatchModel=null get matchM() { return this._matchM } protected _matchInsM:MatchInsModel=null get matchInsM() { return this._matchInsM } get simpleInsM() { let mim = new MatchInsModel() mim.id=this._matchInsM.id mim.match_id=this._matchInsM.match_id mim.match=this._matchInsM.match mim.start_time=this._matchInsM.start_time mim.end_time=this._matchInsM.end_time mim.players={} mim.player_num=this._matchInsM.player_num mim.blind_index=this._matchInsM.blind_index mim.state=this._matchInsM.state return mim } protected _blindM:BlindModel=null protected _tables:{[table_id:number]:TexasTable}={} get playerLen() { return this._matchInsM.player_num } get matchId() { return this._matchM?.id } get matchInsId() { return this._matchInsM?.id } get leftNum() { let num=0 for(let key in this._matchInsM.players) { let pi = this._matchInsM.players[key] if(pi.point>0) { ++num } } return num } protected _timer=new Timer() protected _monitor_timer=new Timer() get deadline() { return this._timer.deadline } protected async _waitForBeginEnd() { while(this._isbegining) { await new Promise((resolve,reject)=> { setTimeout(()=> { resolve(null) },100) }) } return } onMonitor() { let m = new MonitorModel() m.id=this.matchInsId m.type="match" m.player_left_num=0 m.player_num=this._matchInsM.player_num m.table_num=0 for(let key in this._tables) { let tb = this._tables[key] m.player_left_num+=tb.user_num m.table_num+=1 m.tables[tb.id]=[tb.user_num,tb.state] } GMonitorSer.updateOne(m,{id:m.id},true) if(ns_common.GIsTest) { GLog.info(m,true) } } onLeave(user_id:number) { for(let key in this._tables) { let tb = this._tables[key] tb.onLeave(user_id) } } /** * 开赛后的报名必须调过来 */ async onSignup(user_id:number) { await this._waitForBeginEnd() let playerinfo = await GMatchInsSer.getPlayerInfo(this._matchInsM.id,user_id) if(playerinfo) { playerinfo.rank=-1 if(!this._matchInsM.players[user_id]) { ++this._matchInsM.player_num } this._matchInsM.players[user_id]=playerinfo if(this._matchInsM.state==EMatchState.Playing) { playerinfo.point=this._matchInsM.match.coin this._server.matchMgr.onLeave(user_id) for(let key in this._tables) { let tb = this._tables[key] let errcode = tb.onEnter(playerinfo) if(!errcode) { let model = {} model["players."+user_id]=playerinfo await GMatchInsSer.updateOne(model,{_id:this._matchInsM._id}) return } } let table = await this.createTable() table.ctdm.auto_start=true table.state=ns_texas.ETexasTableState.WaintingCombine table.onEnter(playerinfo) this._waittables.push(table) } } else { GLog.error("onsignup user_id:"+user_id+" not found!ins_id:"+this._matchInsM.id) } } /** * 取消比赛 */ async onCancel() { GLog.info(`match(${this._matchInsM.match_id}-${this._matchInsM.id}) has canceled!`,true) await GMatchInsSer.onCancel(this.matchInsId) this._timer.clear() this._monitor_timer.clear() GMonitorSer.deleteOne({id:this.matchInsId}) return true } async _initForException() { this._matchM=this._matchInsM.match if(!this._matchInsM.match) { GLog.error("restart exception match expetion:"+this._matchInsM.id) return true } this._blindM = await GBlindSer.getById(this._matchM.blind_id) if(!this._blindM) { GLog.error("restart blind "+this._matchM.blind_id+" init failed!") return false } this.onReBegin() GLog.warn("restart match ins_id:"+this._matchM.name+"-"+this._matchInsM.id) return false } async init(cmii:CreateMatchInsInfo,server:TexasServer) { this._server=server this._matchInsM = await GMatchInsSer.getById(cmii.id) //表示异常重开 if(this._matchInsM) { //重新开启 if(this._matchInsM.state==EMatchState.Playing) { this._initForException() return } //过期了就直接取消 else if(this._matchInsM.state==EMatchState.Waiting&&this._matchInsM.start_time0) { ++len } } let tbnum = Math.ceil(len/9) GLog.info(`match:${this._matchInsM.match.name}(${this._matchInsM.id}) begin...player:${this._matchInsM.player_num}...audience:${0}...table:${tbnum}`,true) let alltables:TexasTable[]=[] while(alltables.length{} let user = await GExtUserSer.getById(user_id) if(!user) { ret.errcode=EErrorCode.No_User_By_User_Id return ret } let table_id = -1 let player = this._matchInsM.players[user_id] if(!player) { //继续验证一次,因为很有可能异常导致,报名了还没通知过来,或者通知过来的时候比赛还没被实例化起, //总之很特殊的情况都会导致找不到,但实际上已经报名的情况 let playerinfo = await GMatchInsSer.getPlayerInfo(this._matchInsM.id,user_id) if(playerinfo) { this._matchInsM.players[user_id]=playerinfo } player = this._matchInsM.players[user_id] } let alltables:TexasTable[]=[] for(let key in this._tables) { let table=this._tables[key] alltables.push(table) } if(alltables.length==0) { ret.errcode=EErrorCode.Table_Not_Fond return ret } if(!player) { let i = _.random(alltables.length-1) table_id=alltables[i].id } else { table_id=player.table_id } let table = this._tables[table_id] as TexasTable if(!table) { //仍然有积分通告异常 if(player.point>0&&this._matchInsM.state==EMatchState.Playing) { ret.errcode=EErrorCode.Table_Not_Fond return ret } //重新分配个观看的桌子 let i = _.random(alltables.length-1) table_id=alltables[i].id table = this._tables[table_id] //分配失败 if(!table) { ret.errcode=EErrorCode.Table_Not_Fond return ret } } let mim = this.simpleInsM if(player) { mim.players=[player] let ws = this._server.getAnyWebSocket() as TexasClientWebSocket ws?.send_enter_match(player.id,mim) } if(player&&this._matchInsM.state==EMatchState.Playing&&player.point>0) { table.onEnter(player) ret.table=table } else { table.onEnterAsAudience(user) } ret.player=player return ret } protected _waittables:TexasTable[]=[] /** * 桌子人数少,需要合桌子 * @param table */ onCombieTable(table:TexasTable) { let tbs = _.toArray(this._tables) if(tbs.length==1) { return } tbs=tbs.sort((t1,t2)=> { return t2.user_num-t1.user_num }) if(tbs.length>2) { this._combieFor3OrMore(table,tbs) } else if(tbs.length==2) { this._combieFor2(tbs) } } protected _combieFor3OrMore(table:TexasTable,tbs:TexasTable[]) { //不要开启了 table.onPause() table.state=ns_texas.ETexasTableState.WaintingCombine let left = table.user_num //就这桌 let ids = table.user_id_list for(let i=0;i=0;--i) { let tb = tbs[i] if(tb.user_num==9) { break } while(tb.user_num!=9&&ids.length>0) { let id = ids.pop() let pi = this._matchInsM.players[id] let errcode = tb.onEnter(pi) if(!errcode) { tb.onStandUp(id) } else { GLog.error(errcode) } } if(ids.length==0) { let audience=table.audience for(let key in audience) { this.onEnter(audience[key].id) } table.clearAudience() return } } //还是有剩余 //继续 if(table.user_num>2) { table.state=ns_texas.ETexasTableState.Waiting table.onResume() } //等待任一桌结束,然后,两个桌子分拆或合并 else { this._waittables.push(table) table.broadcast("waitcombine_bc") } } protected _combieFor2(tbs:TexasTable[]) { let totalnum = tbs[0].user_num+tbs[1].user_num let dtnum = tbs[0].user_num-tbs[1].user_num //合道一桌就完事了 if(totalnum<=9) { let ids = tbs[1].user_id_list for(let i=0;i1) { let half = Math.floor(dtnum/2) let ids = tbs[0].user_id_list for(let i=0;itb.id==table.id) if(index<0) { return } this._waittables.splice(index,1) } /** * 一局结束 * @param table */ onTableOneEnd(table:TexasTable) { let table_num=0 for(let key in this._tables) { ++table_num } if(table.user_num<=1&&table_num<=1) { //比赛结束 this.onEnd() return } if(table_num<=1) { //只有一桌了,不管 return } //查看是否需要触发凑桌,合桌 if(table.user_num<=3||table_num==2) { this.onCombieTable(table) return } else if(this._waittables.length>0) { table.onPause() let all:number[] = [] for(let i=0;ievery) { let id = ids.pop() allids[id]=tb//准备踢出去 } while(tb.user_num3) { tb.state=ns_texas.ETexasTableState.Waiting tb.onResume() } else if(tb.user_num>0) { left_tbs.push(tb) } } this._waittables=left_tbs } } onTableEnd(table:TexasTable) { delete this._tables[table.id] } onPlayerEnd(playerinfo:MatchPlayer) { if(playerinfo.point>0) { return } playerinfo.rank=this.leftNum+1 let key = "players."+playerinfo.id let model = {} model[key]=playerinfo GMatchInsSer.updateOne(model,{_id:this._matchInsM._id}) let umodel={} umodel["matchinos."+this.matchInsId+".rank"]=playerinfo.rank GExtUserSer.updateOne(umodel,{id:playerinfo.id}) if(playerinfo.rank==2) { //比赛结束,已经出来了第二名了 this.onEnd() } } }