def enterOneTable(self, userId, shadowRoomId, tableId): '''指定桌子坐下 Returns False: 重试超过次数 ''' if ftlog.is_debug(): ftlog.debug("<< |userId, roomId, shadowRoomId, tableId", userId, self.roomId, shadowRoomId, tableId, caller=self) if tyconfig.getRoomDefine(shadowRoomId).tableCount == 1: return tableId for _ in xrange(5): # 这张桌子有可能正在分配座位,如果取桌子失败,需要休眠后重试 result = roomdao.DaoTableScore.removeTableScore( shadowRoomId, tableId) if ftlog.is_debug(): ftlog.debug("after ZREM tableId", "|userId, shadowRoomId, tableId, result:", userId, shadowRoomId, tableId, result, caller=self) if result == 1: return tableId ftcore.sleep(1) return 0
def onSitOk(self, userId, idleSeatId, result): '''坐下条件成功后的处理 Return: player:新空座位上的player ''' ftlog.hinfo('onSitOk << |userId, tableId, seatId:', userId, self.tableId, idleSeatId, "|observers:", self.observers, caller=self) # 设置玩家坐在座位上, 为了支持并发坐下,此设置需要在异步操作前完成!!! seat = self.table.seats[idleSeatId - 1] seat.userId = userId seat.setWaitingState() if ftlog.is_debug(): ftlog.debug("|seats:", self.table.seats, caller=self) if userId in self.table.observers: del self.table.observers[userId] pluginCross.onlinedata.removeOnLineLoc(userId, self.roomId, self.tableId) # 设置玩家的在线状态 if ftlog.is_debug(): ftlog.debug("before addOnlineLoc. |tableId, onlineSeatId:", self.tableId, pluginCross.onlinedata.getOnLineLocSeatId( userId, self.roomId, self.tableId), caller=self) pluginCross.onlinedata.addOnLineLoc(userId, self.roomId, self.tableId, idleSeatId) if ftlog.is_debug(): ftlog.debug("after addOnlineLoc. |tableId, onlineSeatId:", self.tableId, pluginCross.onlinedata.getOnLineLocSeatId( userId, self.roomId, self.tableId), caller=self) # 记录当前座位的userId, 以便对玩家的金币做恢复处理 self.table.recordSeatUserId(idleSeatId, userId) result["seatId"] = idleSeatId result["reason"] = TYRoom.ENTER_ROOM_REASON_OK ftlog.hinfo('onSitOk >> |userId, tableId, seatId:', userId, self.tableId, idleSeatId, "|observers:", self.observers, caller=self)
def doReloadConf(self, roomDefine): if ftlog.is_debug(): ftlog.info('<<', "|roomDefine.configure:", roomDefine.configure) super(TYRoom, self).doReloadConf(roomDefine) for table in self.maptable.values(): table.doReloadConf(self.tableConf) if ftlog.is_debug(): ftlog.debug('>>', "|roomId:", self.roomId) from majiang2.poker2.entity.game import quick_start quick_start._CANDIDATE_ROOM_IDS = {}
def doSit(self, msg, userId, seatId, clientId): ''' 桌子同步安全操作方法 玩家操作, 尝试再当前的某个座位上坐下 若 seatId为0, 那么需要桌子自动未玩家挑选一个座位 通常此方法由客户端发送quick_start进行快速开始触发: AppClient->ConnServer->UtilServer->RoomServer->ThisTableServer 或: AppClient->ConnServer->RoomServer->ThisTableServer 若 seatId为有效的座位号, 那么桌子需要保证玩家能够正常的坐下 通常此方法由客户端发送quick_start进行断线重连触发: AppClient->ConnServer->ThisTableServer 实例桌子可以覆盖 _doSit 方法来进行自己的业务逻辑处理 无论sit是否成功,都需要调用room.updateTableScore ''' if ftlog.is_debug(): ftlog.debug("<< |params:", userId, seatId, clientId, msg, caller=self) try: return self._doSit(msg, userId, seatId, clientId) except: ftlog.exception() return { "isOK": False, "reason": TYRoom.ENTER_ROOM_REASON_INNER_ERROR } finally: self.room.updateTableScore(self.getTableScore(), self.tableId, force=True)
def uploadVideo(uploadUrl, token, uploadPath, videoData): try: filename = os.path.basename(uploadPath) formItems = [] formItems.append(MultipartForm.FormItemData('token', token)) formItems.append(MultipartForm.FormItemData('key', uploadPath)) formItems.append( MultipartForm.FormItemFile('file', videoData, filename)) #formItems.append(FormItemFile('fileBinaryData', videoData, filename)) headers, uploadData = MultipartForm.encodeFormItems(formItems) retrydata = {'max': 3} code, res = fthttp.queryHttp(method='POST', url=uploadUrl, header=headers, body=uploadData, connect_timeout=5, retrydata=retrydata) if ftlog.is_debug(): ftlog.debug('uploader.uploadVideo uploadUrl=', uploadUrl, 'uploadPath=', uploadPath, 'token=', token, 'ret=', (code, res)) if code == 200 or code == 406: # 406 文件已经存在 return 0, '上传成功' ftlog.info('uploader.uploadVideo Res uploadUrl=', uploadUrl, 'uploadPath=', uploadPath, 'token=', token, 'ret=', code) return -1, '上传失败' except: return -2, '上传失败'
def onStandUpOk(self, userId, seatId): '''坐下条件成功后的处理 note: 站起后没有自动进入旁观列表 ''' if ftlog.is_debug(): ftlog.debug('<< |userId, tableId, seatId:', userId, self.tableId, seatId, caller=self) # 清理在线信息 pluginCross.onlinedata.removeOnLineLoc(userId, self.roomId, self.tableId) # 清理当前座位的userId self.recordSeatUserId(seatId, 0) seat = self.table.seats[seatId - 1] seat.userId = 0 # 更新当前桌子的快速开始积分, 如果此时桌子正在分配玩家,刷新将失败 # self.room.updateTableScore(self.getTableScore(), self.tableId) ftlog.hinfo('onStandUpOk >> |userId, tableId, seatId:', userId, self.tableId, seatId, "|observers:", self.observers, caller=self)
def saveRecord(cls, gameId, userId, matchId, record, mixId=None): if ftlog.is_debug(): ftlog.debug('MatchRecord.saveRecord gameId=', gameId, 'userId=', userId, 'matchId=', matchId, 'record=', json.dumps(record.toDict()), 'mixId=', mixId)
def callLaterFunc(self, interval, func, userId=0, timer=None, msgPackParams=None): '''延时调用table对象的一个函数 原理:延时调用table.doTableCall命令,通过此命令调用table对象的一个函数 意义:table.doTableCall函数会锁定table对象,保证数据操作的同步性 ''' if msgPackParams == None: msgPackParams = {} msgPackParams["userId"] = userId clientId = tysessiondata.getClientId(userId) if userId > 0 else None msgPackParams["clientId"] = clientId msgPackParams["func"] = func action = "CL_FUNC" if timer == None: timer = TYTableTimer(self) timer.setup(interval, action, msgPackParams, cancelLastTimer=False) funcName = func.func.func_name if ftlog.is_debug(): ftlog.debug(">> |clientId, userId, tableId:", clientId, userId, self.tableId, "|action, func, interval:", action, funcName, interval, caller=self)
def doShutDown(self): ''' 桌子同步安全操作方法 桌子关闭, 此方法由安全进程结束的方法调用 ''' if ftlog.is_debug(): ftlog.debug("<< doShutDown Table !!", caller=self) self._doShutDown()
def _canQuickEnterRoom(cls, userId, gameId, roomId, isOnly): try: chip = hallrpcutil.getChip(userId) if ftlog.is_debug(): ftlog.debug(tyconfig.getRoomDefine(roomId).configure) roomConfig = tyconfig.getRoomDefine(roomId).configure if ftlog.is_debug(): ftlog.debug('userId =', userId, 'minCoin =', roomConfig.get('minCoin'), 'maxCoin =', roomConfig.get('maxCoin'), 'minCoinQS =', roomConfig.get('minCoinQS'), 'maxCoinQS =', roomConfig.get('maxCoinQS'), 'chip =', chip, 'isOnly =', isOnly) if isOnly: minCoinQs = roomConfig['minCoin'] maxCoinQs = roomConfig['maxCoin'] else: minCoinQs = roomConfig['minCoinQS'] maxCoinQs = roomConfig['maxCoinQS'] ismatch = roomConfig.get('ismatch') if ismatch or minCoinQs <= 0: return TYRoom.ENTER_ROOM_REASON_NOT_QUALIFIED if ftlog.is_debug(): ftlog.debug('roomId =', roomId, 'minCoinQs =', minCoinQs, 'maxCoinQs =', maxCoinQs, 'chip =', chip, caller=cls) if chip < minCoinQs: return TYRoom.ENTER_ROOM_REASON_LESS_MIN if maxCoinQs > 0 and chip >= maxCoinQs: return TYRoom.ENTER_ROOM_REASON_GREATER_MAX return TYRoom.ENTER_ROOM_REASON_OK except Exception as e: ftlog.error(e) return TYRoom.ENTER_ROOM_REASON_INNER_ERROR
def _leave(self, userId, reason, needSendRes): if ftlog.is_debug(): ftlog.debug("<< |roomId, userId:", self.roomId, userId, caller=self) if not self._remoteTableLeave(userId, reason): return False return True
def _chooseRoom(cls, userId, gameId, playMode): '''服务端为玩家选择房间''' candidateRoomIds = cls._getCandidateRoomIds(gameId, playMode) if ftlog.is_debug(): ftlog.debug("<<|candidateRoomIds:", candidateRoomIds, 'playMode=', playMode, caller=cls) for roomId in candidateRoomIds: ret = cls._canQuickEnterRoom(userId, gameId, roomId, 0) if ftlog.is_debug(): ftlog.debug("|roomId, ret:", roomId, ret, caller=cls) if ret == TYRoom.ENTER_ROOM_REASON_OK: return roomId, TYRoom.ENTER_ROOM_REASON_OK return 0, TYRoom.ENTER_ROOM_REASON_LESS_MIN
def __init__(self, table): self.table = table self._initField() self.transitToStateWait() if ftlog.is_debug(): ftlog.info("__init__ >>", self.getBasicAttrsLog())
def sendRobotNotifyShutDown(self, params): hasrobot = self.table.runConfig["hasrobot"] if ftlog.is_debug(): ftlog.debug("|hasrobot, params", hasrobot, params, caller=self) if hasrobot: ucount, uids = self.getSeatUserIds() gameRpcRoomOne.srvrobot.doRobotShutDown(self.table.roomId, self.table.tableId, ucount, uids, params, 0)
def _baseLogStr(self, des="", userId=None): if ftlog.is_debug(): baseTableInfo = '%s |tableId, playersNum: %d, %d' % ( des, self.tableId, self.playersNum) else: baseTableInfo = '%s |tableId: %d' % (des, self.tableId) baseUserInfo = '' if not userId else ' |userId: %d' % (userId) return self.__class__.__name__ + " " + baseTableInfo + baseUserInfo
def doLeave(self, msg, userId, clientId): ''' 桌子同步安全操作方法 玩家操作, 尝试离开当前的桌子 实例桌子可以覆盖 _doLeave 方法来进行自己的业务逻辑处理 ''' if ftlog.is_debug(): ftlog.debug("<< |params:", userId, clientId, msg, caller=self) self._doLeave(msg, userId, clientId)
def doActionGameEnd(self): if ftlog.is_debug(): ftlog.info("doActionGameEnd <<", self.getBasicAttrsLog(), caller=self) if self.__state != self.GAME_PLAY_STATE_FINAL: ftlog.warn("state error!", self.getBasicAttrsLog(), caller=self) return self.transitToStateWait()
def doTableCall(self, msg, userId, seatId, action, clientId): ''' 桌子同步安全操作方法 桌子内部处理所有的table_call命令 实例桌子可以覆盖 _doTableCall 方法来进行自己的业务逻辑处理 子类需要自行判定userId和seatId是否吻合 ''' if ftlog.is_debug(): ftlog.debug("<< |params:", userId, seatId, action, clientId, msg, caller=self) self._doTableCall(msg, userId, seatId, action, clientId)
def doStandUp(self, msg, userId, seatId, reason, clientId): ''' 桌子同步安全操作方法 玩家操作, 尝试离开当前的座位 实例桌子可以覆盖 _standUp 方法来进行自己的业务逻辑处理 此处不调用room.updateTableScore,由各游戏确认standup成功后调用。 ''' if ftlog.is_debug(): ftlog.debug("<< |params:", userId, seatId, reason, clientId, msg, caller=self) self._doStandUp(msg, userId, seatId, reason, clientId)
def doTableManage(self, msg, action): ''' 桌子同步安全操作方法 桌子内部处理所有的table_manage命令 实例桌子可以覆盖 _doTableManage 方法来进行自己的业务逻辑处理 ''' if ftlog.is_debug(): ftlog.debug("<< |params:", action, msg, caller=self) try: return self._doTableManage(msg, action) except: ftlog.exception() return {"isOK":False, "reason":TYRoom.ENTER_ROOM_REASON_INNER_ERROR}
def _buildTableClearMessage(table): msg = MsgPack() msg.setCmd('table_manage') msg.setParam('action', 'm_table_clear') msg.setParam('gameId', table.gameId) msg.setParam('roomId', table.roomId) msg.setParam('tableId', table.tableId) msg.setParam('ccrc', table.ccrc) if table.group: msg.setParam('matchId', table.group.area.matchId) if ftlog.is_debug(): ftlog.debug('_buildTableClearMessage', 'msg=', msg) return msg
def notifyMatchUpdate(self, userId): """ 通知比赛更新. 比赛前,报名人数更新 比赛中,参数人数更新 """ try: if ftlog.is_debug(): ftlog.debug('PokerMatchPlayerNotifier.notifyMatchUpdate', 'userId=', userId) self._notifyMatchUpdate(userId) except: ftlog.error('PokerMatchPlayerNotifier.notifyMatchUpdate', 'userId=', userId)
def loadHistory(cls, gameId, userId, matchId): try: # jstr = gamedata.getGameAttr(userId, gameId, cls.__buildField(matchId,"histories")) jstr = "" if ftlog.is_debug(): ftlog.debug('MatchRecord.loadRecord gameId=', gameId, 'userId=', userId, 'matchId=', matchId, 'data=', jstr, caller=cls) if jstr: return json.loads(jstr) else: return [] except: ftlog.exception() return None
def notifyMatchRank(self, player): """ 通知比赛排行榜 """ try: if ftlog.is_debug(): ftlog.debug('PokerMatchPlayerNotifier.notifyMatchRank', 'userId=', player.userId, 'isQuit=', player.isQuit, 'groupId=', player.group.groupId, 'clientId=', player.clientId) if player.isQuit: return self._notifyMatchRank(player) except: ftlog.error('PokerMatchPlayerNotifier.notifyMatchRank', 'userId=', player.userId, 'groupId=', player.group.groupId, 'clientId=', player.clientId)
def loadRecord(cls, gameId, userId, matchId, mixId=None): try: # jstr = gamedata.getGameAttr(userId, gameId, cls.__buildField(matchId, mixId)) # TODO histories # pluginCross.halldata.getUpdateToVersion511flag(userId) jstr ="" if ftlog.is_debug(): ftlog.debug('MatchRecord.loadRecord gameId=', gameId, 'userId=', userId, 'matchId=', matchId, 'data=', jstr, caller=cls) if jstr: return MatchRecordDaoRedis.Record.fromDict(json.loads(jstr)) except: ftlog.exception() return None
def _saveUserMatchHistory(cls,gameId, userId, matchId, rank, desc): """ 比赛详情上历史成绩 """ hisories = cls.loadHistory(gameId, userId, matchId) if hisories is None: hisories = [] hisories.append({"rank":rank,"time":int(time.time()),"desc":desc}) # 保留5条记录 if len(hisories) > 10 : hisories=hisories[-10:] if ftlog.is_debug(): ftlog.debug('MatchRecord.addHistory gameId=', gameId, 'userId=', userId, 'matchId=', matchId, 'rank=', rank, 'desc=', desc) # gamedata.setGameAttr(userId, gameId, cls.__buildField(matchId, "histories"), json.dumps(hisories))
def getRankRewards(self, player): """ 获取奖励配置 """ rankRewardsList = player.group.stageConf.rankRewardsList if player.group.isGrouping else player.group.matchConf.rankRewardsList rank = player.lastRank if player.isQuit else player.rank if ftlog.is_debug(): ftlog.debug('MatchRankRewardsIFStage.getRankRewards', 'userId=', player.userId, 'rank=', rank, 'rankRewardsList=', rankRewardsList, 'stageConf.rankRewards=', player.group.stageConf.rankRewardsList) if rankRewardsList: for rankRewards in rankRewardsList: if ((rankRewards.rankRange[0] == -1 or rank >= rankRewards.rankRange[0]) and (rankRewards.rankRange[1] == -1 or rank <= rankRewards.rankRange[1])): return rankRewards return None
def addPlayerToGroup(serverId, roomId, masterRoomId, groupId, playerList): startTime = time.time() _area, group = findGroup(roomId, groupId) if not group: ftlog.error('stage_match_remote.addPlayerToGroup serverId=', serverId, 'roomId=', roomId, 'masterRoomId=', masterRoomId, 'groupId=', groupId, 'playerCount=', len(playerList), 'err=', 'NotFoundGroup') return playerList = decodePlayerList(playerList) for player in playerList: group.addPlayer(player) if ftlog.is_debug(): ftlog.info('stage_match_remote.addPlayerToGroup serverId=', serverId, 'roomId=', roomId, 'masterRoomId=', masterRoomId, 'groupId=', groupId, 'userIds=', [p.userId for p in playerList]) ftlog.info('group_match_remote.addPlayerToGroup OK serverId=', serverId, 'roomId=', roomId, 'masterRoomId=', masterRoomId, 'groupId=', groupId, 'playerCount=', len(playerList), 'usedTime=', time.time() - startTime)
def __init__(self, room, tableId): ''' Args: room : 牌桌所属的房间对象 tableId : 系统分配的唯一桌子ID ''' if ftlog.is_debug(): ftlog.debug("<<", "|roomId:", room.roomId, "|talbeId:", tableId, "|tableConf", room.tableConf, caller=self) self.__gameId = room.gameId # 当前桌子的GAMEID self.__tableId = tableId # 当前桌子的唯一ID self.__room = room # 当前桌子隶属的房间 self.__config_changed = 1 # 标记当前桌子的配置是否发生变换, 缺省为发生变化,需要载入配置 self.__config = room.tableConf # 当前桌子的原始基本配置 # 运行数据, 初始化时算出来,从而可以通过redis恢复牌桌当前状态 self.__players = TYPlayerList(self) # 玩家的数据控制 # 动态数据, 需要redis化 self._inRedis = False # 牌桌数据是否全部存入redis self.__state = TYTableState(self) # TODO 需要redis化 self.__seats = TYSeatList(self) # TODO 需要redis化 self.__observers = TYObservers(self) # TODO 需要redis化 self.room.updateTableScore(self.getTableScore(), self.tableId, force=True)
def sendToAllTableUser(self, mo, exclude=None): if ftlog.is_debug(): ftlog.debug('<< |tableId:', self.tableId, '|len players=', self.table.playersNum, 'len observers=', self.table.observers, 'exclude=', exclude, '|mo:', mo, caller=self) if isinstance(mo, MsgPack): mo = mo.pack() if exclude == None: exclude = [] for p in self.table.players: if p.userId > 0 and not p.userId in exclude: tyrpcconn.sendToUser(p.userId, mo) for userId in self.table.observers: tyrpcconn.sendToUser(userId, mo)