def __init__(self, table):
        super(DizhuErdayiMatchSender, self).__init__(table)
        assert (table)

        self._logger = Logger()
        self._logger.add('roomId', self.table.roomId)
        self._logger.add('tableId', self.table.tableId)
Exemplo n.º 2
0
 def __init__(self, room, tableSeatCount):
     self._room = room
     self._tableSeatCount = tableSeatCount
     self._idleTables = []
     self._allTableMap = {}
     self._roomIds = set()
     self._logger = Logger()
     self._logger.add('roomId', self._room.roomId)
Exemplo n.º 3
0
 def __init__(self, roomdefine):
     super(TYErdayiMatchRoom, self).__init__(roomdefine)
     self.bigmatchId = self.bigRoomId
     self.matchPlugin = gdata.games()[self.gameId].getErdayiMatchPlugin()
     self.match = None
     self.matchMaster = None
     self._logger = Logger()
     self._logger.add('roomId', self.roomId)
     self._logger.add('bigmatchId', self.bigmatchId)
     serverType = gdata.serverType()
     if serverType == gdata.SRV_TYPE_ROOM:
         self.initMatch()  # 此处会给self.match赋值
Exemplo n.º 4
0
 def __init__(self, stageConf, group):
     self._group = group
     self._stageConf = stageConf
     self._stageId3 = None
     self._logger = Logger()
     self._logger.add('matchingId', self.matchingId)
     if self.matchingId3:
         self._stageId3 = '%s%02d%s' % (self.matchingId3[0:12],
                                        self.stageIndex + 1,
                                        self.matchingId3[12:])
         self._logger.add('matchingId3', self.matchingId3)
     self._logger.add('stageIndex', self.stageIndex)
Exemplo n.º 5
0
class TableControllerTest(TableController):
    def __init__(self, area):
        self.area = area
        self.busyTables = set()
        self._logger = Logger()

    def startTable(self, table):
        '''
        让桌子开始
        '''
        self.busyTables.add(table)
        self._logger.info('TableControllerTest.startTable tableId=',
                          table.tableId)

    def clearTable(self, table):
        '''
        清理桌子
        '''
        self.busyTables.discard(table)
        self._logger.info('TableControllerTest.clearTable tableId=',
                          table.tableId)

    def updateTableInfo(self, table):
        '''
        桌子信息变化
        '''
        self._logger.info('TableControllerTest.updateTableInfo tableId=',
                          table.tableId)

    def userReconnect(self, table, seat):
        '''
        用户坐下
        '''
        self._logger.info('TableControllerTest.userReconnect tableId=',
                          table.tableId)
Exemplo n.º 6
0
 def __init__(self, stageConf, group):
     self._group = group
     self._stageConf = stageConf
     self._stageId3 = None
     self._logger = Logger()
     self._logger.add('matchingId', self.matchingId)
     if self.matchingId3:
         self._stageId3 = '%s%02d%s' % (self.matchingId3[0:12], self.stageIndex + 1, self.matchingId3[12:])
         self._logger.add('matchingId3', self.matchingId3)
     self._logger.add('stageIndex', self.stageIndex)
Exemplo n.º 7
0
class MyStage(MatchStage):
    def __init__(self, stageConf):
        super(MyStage, self).__init__(stageConf)
        self._count = 0
        self._logger = Logger()
        self._logger.add('stageIndex', self.stageIndex)

    def start(self):
        self._logger.info('MatchStage.start')

    def kill(self, reason):
        self._logger.info('MatchStage.kill', 'reason=', reason)

    def finish(self, reason):
        self._logger.info('MatchStage.finish', 'reason=', reason)

    def processStage(self):
        self._logger.info('MatchStage.processStage', 'count=', self._count)
        self._count += 1
        if self._count >= 10:
            self.group.finishGroup(MatchFinishReason.FINISH)
Exemplo n.º 8
0
 def __init__(self, roomdefine):
     super(TYErdayiMatchRoom, self).__init__(roomdefine)
     self.bigmatchId = self.bigRoomId
     self.matchPlugin = gdata.games()[self.gameId].getErdayiMatchPlugin()
     self.match = None
     self.matchMaster = None
     self._logger = Logger()
     self._logger.add('roomId', self.roomId)
     self._logger.add('bigmatchId', self.bigmatchId)
     serverType = gdata.serverType()
     if serverType == gdata.SRV_TYPE_ROOM:
         self.initMatch()  # 此处会给self.match赋值
Exemplo n.º 9
0
class MatchStatusDaoRedis(MatchStatusDao):
    def __init__(self, room):
        self._room = room
        self._logger = Logger()
        self._logger.add('roomId', self._room.roomId)

    def load(self, matchId):
        '''
        加载比赛信息
        @return: MatchStatus
        '''
        key = 'mstatus:%s' % (self._room.gameId)
        jstr = daobase.executeMixCmd('hget', key, matchId)
        if jstr:
            d = strutil.loads(jstr)
            return MatchStatus(matchId, d['seq'], d['startTime'])
        return None

    def save(self, status):
        '''
        保存比赛信息
        '''
        try:
            key = 'mstatus:%s' % (self._room.gameId)
            d = {'seq': status.sequence, 'startTime': status.startTime}
            jstr = strutil.dumps(d)
            daobase.executeMixCmd('hset', key, status.matchId, jstr)
        except:
            self._logger.error('MatchStatusDaoDizhu.save',
                               'matchId=', status.matchId,
                               'instId=', status.instId,
                               'startTime=', status.startTime)

    def getNextMatchingSequence(self, matchId):
        key = 'matchingId:%s' % (self._room.gameId)
        self._logger.hinfo('MatchStatusDaoDizhu.getNextMatchingSequence',
                           'matchId=', matchId,
                           'key=', key)
        return daobase.executeMixCmd('hincrby', key, matchId, 1)
Exemplo n.º 10
0
class MatchStage(object):
    def __init__(self, stageConf, group):
        self._group = group
        self._stageConf = stageConf
        self._stageId3 = None
        self._logger = Logger()
        self._logger.add('matchingId', self.matchingId)
        if self.matchingId3:
            self._stageId3 = '%s%02d%s' % (self.matchingId3[0:12], self.stageIndex + 1, self.matchingId3[12:])
            self._logger.add('matchingId3', self.matchingId3)
        self._logger.add('stageIndex', self.stageIndex)

    @property
    def matchConf(self):
        return self._group.matchConf

    @property
    def matchingId(self):
        return self._group.matchingId

    @property
    def matchingId3(self):
        return self._group.matchingId3

    @property
    def stageId3(self):
        return self._stageId3

    @property
    def stageConf(self):
        return self._stageConf

    @property
    def stageIndex(self):
        return self._stageConf.index

    @property
    def group(self):
        return self._group

    @property
    def area(self):
        return self.group.area

    def calcUncompleteTableCount(self, player):
        return 0

    def hasNextStage(self):
        return self.stageIndex + 1 < len(self.matchConf.stages)

    def start(self):
        raise NotImplementedError

    def kill(self, reason):
        raise NotImplementedError

    def finish(self, reason):
        raise NotImplementedError

    def isStageFinished(self):
        raise NotImplementedError

    def processStage(self):
        raise NotImplementedError
Exemplo n.º 11
0
class MatchStage(object):
    def __init__(self, stageConf, group):
        self._group = group
        self._stageConf = stageConf
        self._stageId3 = None
        self._logger = Logger()
        self._logger.add('matchingId', self.matchingId)
        if self.matchingId3:
            self._stageId3 = '%s%02d%s' % (self.matchingId3[0:12],
                                           self.stageIndex + 1,
                                           self.matchingId3[12:])
            self._logger.add('matchingId3', self.matchingId3)
        self._logger.add('stageIndex', self.stageIndex)

    @property
    def matchConf(self):
        return self._group.matchConf

    @property
    def matchingId(self):
        return self._group.matchingId

    @property
    def matchingId3(self):
        return self._group.matchingId3

    @property
    def stageId3(self):
        return self._stageId3

    @property
    def stageConf(self):
        return self._stageConf

    @property
    def stageIndex(self):
        return self._stageConf.index

    @property
    def group(self):
        return self._group

    @property
    def area(self):
        return self.group.area

    def calcUncompleteTableCount(self, player):
        return 0

    def hasNextStage(self):
        return self.stageIndex + 1 < len(self.matchConf.stages)

    def start(self):
        raise NotImplementedError

    def kill(self, reason):
        raise NotImplementedError

    def finish(self, reason):
        raise NotImplementedError

    def isStageFinished(self):
        raise NotImplementedError

    def processStage(self):
        raise NotImplementedError
Exemplo n.º 12
0
 def __init__(self, area):
     self.area = area
     self.busyTables = set()
     self._logger = Logger()
Exemplo n.º 13
0
class SigninRecordDaoRedis(SigninRecordDao):
    def __init__(self, gameId):
        self._gameId = gameId
        self._logger = Logger()

    def buildKey(self, matchId, instId, ctrlRoomId):
        return 'msignin4:%s:%s:%s' % (self._gameId, instId, ctrlRoomId)

    @classmethod
    def decodeRecord(cls, userId, jstr):
        d = strutil.loads(jstr)
        record = SigninRecord(userId)
        record.signinTime = d['st']
        fee = d.get('fee')
        if fee:
            record.fee = TYContentItem.decodeFromDict(fee)
        return record

    @classmethod
    def encodeRecord(cls, record):
        d = {'st': record.signinTime}
        if record.fee:
            d['fee'] = record.fee.toDict()
        return strutil.dumps(d)

    def loadAll(self, matchId, instId, ctrlRoomId):
        ret = []
        key = self.buildKey(matchId, instId, ctrlRoomId)
        datas = daobase.executeMixCmd('hgetall', key)
        if datas:
            i = 0
            while (i + 1 < len(datas)):
                try:
                    userId = int(datas[i])
                    record = self.decodeRecord(userId, datas[i + 1])
                    ret.append(record)
                except:
                    self._logger.error('SigninRecordDaoRedis.loadAll',
                                       'matchId=', matchId,
                                       'instId=', instId,
                                       'ctrlRoomId=', ctrlRoomId,
                                       'Bad SigninRecord data: [%s, %s]' % (datas[i], datas[i + 1]))
                i += 2
        return ret

    def add(self, matchId, instId, ctrlRoomId, record):
        key = self.buildKey(matchId, instId, ctrlRoomId)
        if self._logger.isDebug():
            self._logger.debug('SigninRecordDaoRedis.add',
                               'matchId=', matchId,
                               'instId=', instId,
                               'ctrlRoomId=', ctrlRoomId,
                               'key=', key,
                               'record=', self.encodeRecord(record))
        return daobase.executeMixCmd('hsetnx', key, record.userId, self.encodeRecord(record)) == 1

    def remove(self, matchId, instId, ctrlRoomId, userId):
        key = self.buildKey(matchId, instId, ctrlRoomId)
        if self._logger.isDebug():
            self._logger.debug('SigninRecordDaoRedis.remove',
                               'matchId=', matchId,
                               'instId=', instId,
                               'ctrlRoomId=', ctrlRoomId,
                               'userId=', userId,
                               'key=', key)
        daobase.executeMixCmd('hdel', key, userId)

    def removeAll(self, matchId, instId, ctrlRoomId):
        key = self.buildKey(matchId, instId, ctrlRoomId)
        if self._logger.isDebug():
            self._logger.debug('SigninRecordDaoRedis.removeAll',
                               'matchId=', matchId,
                               'instId=', instId,
                               'ctrlRoomId=', ctrlRoomId,
                               'key=', key)
        daobase.executeMixCmd('del', key)
Exemplo n.º 14
0
class TableManager(object):
    def __init__(self, room, tableSeatCount):
        self._room = room
        self._tableSeatCount = tableSeatCount
        self._idleTables = []
        self._allTableMap = {}
        self._roomIds = set()
        self._logger = Logger()
        self._logger.add('roomId', self._room.roomId)

    @property
    def tableSeatCount(self):
        return self._tableSeatCount

    @property
    def roomCount(self):
        return len(self._roomIds)

    @property
    def gameId(self):
        return self._room.gameId

    @property
    def allTableCount(self):
        return len(self._allTableMap)

    @property
    def idleTableCount(self):
        return len(self._idleTables)

    @property
    def busyTableCount(self):
        return max(0, self.allTableCount - self.idleTableCount())

    def getTableCountPerRoom(self):
        return len(self._allTableMap) / max(1, self.roomCount)

    def addTable(self, table):
        assert (not table.tableId in self._allTableMap)
        assert (table.seatCount == self.tableSeatCount)
        self._idleTables.append(table)
        self._allTableMap[table.tableId] = table

    def addTables(self, roomId, baseId, count):
        if count > 0:
            self._roomIds.add(roomId)
        for i in xrange(count):
            tableId = baseId + i + 1  # 新框架里tableId 从 1开始计数, 0表示队列。
            table = Table(self.gameId, roomId, tableId, self._tableSeatCount)
            self._idleTables.append(table)
            self._allTableMap[tableId] = table

    def borrowTables(self, count):
        assert (self.idleTableCount >= count)
        ret = self._idleTables[0:count]
        self._idleTables = self._idleTables[count:]
        self._logger.info('TableManager.borrowTables',
                          'count=', count,
                          'idleTableCount=', self.idleTableCount,
                          'allTableCount=', self.allTableCount)
        return ret

    def returnTables(self, tables):
        for table in tables:
            assert (self._allTableMap.get(table.tableId, None) == table)
            assert (not table.getPlayerList())
            self._idleTables.append(table)
        self._logger.info('TableManager.returnTables',
                          'count=', len(tables),
                          'idleTableCount=', self.idleTableCount,
                          'allTableCount=', self.allTableCount)

    def findTable(self, roomId, tableId):
        return self._allTableMap.get(tableId, None)
Exemplo n.º 15
0
 def __init__(self, gameId):
     self._gameId = gameId
     self._logger = Logger()
Exemplo n.º 16
0
class TYErdayiMatchRoom(TYRoom):
    def __init__(self, roomdefine):
        super(TYErdayiMatchRoom, self).__init__(roomdefine)
        self.bigmatchId = self.bigRoomId
        self.matchPlugin = gdata.games()[self.gameId].getErdayiMatchPlugin()
        self.match = None
        self.matchMaster = None
        self._logger = Logger()
        self._logger.add('roomId', self.roomId)
        self._logger.add('bigmatchId', self.bigmatchId)
        serverType = gdata.serverType()
        if serverType == gdata.SRV_TYPE_ROOM:
            self.initMatch()  # 此处会给self.match赋值

    def initMatch(self):
        assert (self.matchPlugin.getMatch(self.roomId) is None)
        self._logger.info('TYErdayiMatchRoom.initMatch ...')
        conf = MatchConfig.parse(self.gameId, self.roomId, self.bigmatchId,
                                 self.roomConf['name'], self.matchConf)
        conf.tableId = self.roomId * 10000  # 用来表示玩家在房间队列的特殊tableId
        conf.seatId = 1

        tableManager = TableManager(self, conf.tableSeatCount)
        shadowRoomIds = self.roomDefine.shadowRoomIds

        self._logger.info('TYErdayiMatchRoom.initMatch', 'shadowRoomIds=',
                          list(shadowRoomIds))

        for roomId in shadowRoomIds:
            count = self.roomDefine.configure['gameTableCount']
            baseid = roomId * 10000
            self._logger.info('TYErdayiMatchRoom.initMatch addTables',
                              'shadowRoomId=', roomId, 'tableCount=', count,
                              'baseid=', baseid)
            tableManager.addTables(roomId, baseid, count)
        random.shuffle(tableManager._idleTables)
        match, master = self.matchPlugin.buildMatch(conf, self)
        match.tableManager = tableManager

        if gdata.mode() == gdata.RUN_MODE_ONLINE:
            playerCapacity = int(tableManager.allTableCount *
                                 tableManager.tableSeatCount * 0.9)
            if playerCapacity <= conf.start.userMaxCountPerMatch:
                self._logger.error(
                    'TYErdayiMatchRoom.initMatch', 'allTableCount=',
                    tableManager.allTableCount, 'tableSeatCount=',
                    tableManager.tableSeatCount, 'playerCapacity=',
                    playerCapacity, 'userMaxCount=', conf.start.userMaxCount,
                    'confUserMaxCountPerMatch=',
                    conf.start.userMaxCountPerMatch, 'err=', 'NotEnoughTable')
            assert (playerCapacity > conf.start.userMaxCountPerMatch)

        self.match = match
        self.matchMaster = master
        self.matchPlugin.setMatch(self.roomId, match)
        if master:
            master.startHeart()

    def doEnter(self, userId):
        if self._logger.isDebug():
            self._logger.debug('TYErdayiMatchRoom.doEnter', 'userId=', userId)
        mo = MsgPack()
        mo.setCmd('m_enter')
        mo.setResult('gameId', self.gameId)
        mo.setResult('roomId', self.roomId)
        mo.setResult('userId', userId)

        try:
            self.match.enter(userId)
        except MatchException, e:
            self.matchPlugin.handleMatchException(self, e, userId, mo)
        router.sendToUser(mo, userId)
Exemplo n.º 17
0
class TYErdayiMatchRoom(TYRoom):
    def __init__(self, roomdefine):
        super(TYErdayiMatchRoom, self).__init__(roomdefine)
        self.bigmatchId = self.bigRoomId
        self.matchPlugin = gdata.games()[self.gameId].getErdayiMatchPlugin()
        self.match = None
        self.matchMaster = None
        self._logger = Logger()
        self._logger.add('roomId', self.roomId)
        self._logger.add('bigmatchId', self.bigmatchId)
        serverType = gdata.serverType()
        if serverType == gdata.SRV_TYPE_ROOM:
            self.initMatch()  # 此处会给self.match赋值

    def initMatch(self):
        assert (self.matchPlugin.getMatch(self.roomId) is None)
        self._logger.info('TYErdayiMatchRoom.initMatch ...')
        conf = MatchConfig.parse(self.gameId, self.roomId, self.bigmatchId,
                                 self.roomConf['name'],
                                 self.matchConf)
        conf.tableId = self.roomId * 10000  # 用来表示玩家在房间队列的特殊tableId
        conf.seatId = 1

        tableManager = TableManager(self, conf.tableSeatCount)
        shadowRoomIds = self.roomDefine.shadowRoomIds

        self._logger.info('TYErdayiMatchRoom.initMatch',
                          'shadowRoomIds=', list(shadowRoomIds))

        for roomId in shadowRoomIds:
            count = self.roomDefine.configure['gameTableCount']
            baseid = roomId * 10000
            self._logger.info('TYErdayiMatchRoom.initMatch addTables',
                              'shadowRoomId=', roomId,
                              'tableCount=', count,
                              'baseid=', baseid)
            tableManager.addTables(roomId, baseid, count)
        random.shuffle(tableManager._idleTables)
        match, master = self.matchPlugin.buildMatch(conf, self)
        match.tableManager = tableManager

        if gdata.mode() == gdata.RUN_MODE_ONLINE:
            playerCapacity = int(tableManager.allTableCount * tableManager.tableSeatCount * 0.9)
            if playerCapacity <= conf.start.userMaxCountPerMatch:
                self._logger.error('TYErdayiMatchRoom.initMatch',
                                   'allTableCount=', tableManager.allTableCount,
                                   'tableSeatCount=', tableManager.tableSeatCount,
                                   'playerCapacity=', playerCapacity,
                                   'userMaxCount=', conf.start.userMaxCount,
                                   'confUserMaxCountPerMatch=', conf.start.userMaxCountPerMatch,
                                   'err=', 'NotEnoughTable')
            assert (playerCapacity > conf.start.userMaxCountPerMatch)

        self.match = match
        self.matchMaster = master
        self.matchPlugin.setMatch(self.roomId, match)
        if master:
            master.startHeart()

    def doEnter(self, userId):
        if self._logger.isDebug():
            self._logger.debug('TYErdayiMatchRoom.doEnter',
                               'userId=', userId)
        mo = MsgPack()
        mo.setCmd('m_enter')
        mo.setResult('gameId', self.gameId)
        mo.setResult('roomId', self.roomId)
        mo.setResult('userId', userId)

        try:
            self.match.enter(userId)
        except MatchException, e:
            self.matchPlugin.handleMatchException(self, e, userId, mo)
        router.sendToUser(mo, userId)
Exemplo n.º 18
0
 def __init__(self, room):
     self._room = room
     self._logger = Logger()
     self._logger.add('roomId', self._room.roomId)
Exemplo n.º 19
0
 def __init__(self, stageConf):
     super(MyStage, self).__init__(stageConf)
     self._count = 0
     self._logger = Logger()
     self._logger.add('stageIndex', self.stageIndex)
Exemplo n.º 20
0
class DizhuErdayiMatchSender(DizhuSender):
    def __init__(self, table):
        super(DizhuErdayiMatchSender, self).__init__(table)
        assert (table)

        self._logger = Logger()
        self._logger.add('roomId', self.table.roomId)
        self._logger.add('tableId', self.table.tableId)

    def sendJiabeiRes(self, seatId, jiabei):
        mo = self.createMsgPackRes('table_call', 'jiabei')
        mo.setResult('jiabei', jiabei)
        mo.setResult('seatId', seatId)
        mo.setResult('userId', self.table.seats[seatId - 1].userId)
        self.sendToAllTableUser(mo)

    def sendWaitJiabei(self, optime):
        if self.table.status.state == DizhuState.TABLE_STATE_NM_DOUBLE:
            mo = self.createMsgPackRes('table_call', 'wait_nm_jiabei')
        else:
            mo = self.createMsgPackRes('table_call', 'wait_dz_jiabei')
        mo.setResult('optime', optime)
        self.sendToAllTableUser(mo)

    def sendToAllTableUser(self, mo):
        for p in self.table.players:
            if not p.isAI:
                router.sendToUser(mo, p.userId)

    def sendChuPaiNextRes(self, seatId, opTime):
        if self._logger.isDebug():
            self._logger.debug('DizhuGroupMatchSender.sendChuPaiNextRes',
                               'seatId=', seatId, 'opTime=', opTime)
        mo = self.createMsgPackRes('table_call', 'next')
        mo.setResult('next', seatId)
        mo.setResult('seatId', seatId)
        mo.setResult('stat', self.table.status.toInfoDict())
        mo.setResult('opTime', opTime)
        self.sendToAllTableUser(mo)

        # 收到next命令cancel所有的seatOpTimer
        self.table.cancelAllSeatOpTimers()

        # 机器人出牌,延时2秒
        player = self.table.players[seatId - 1]
        if player.isAI:
            params = {
                'seatId': seatId,
                'userId': player.userId,
                'ccrc': self.table.status.cardCrc
            }
            self.table.seatOpTimers[seatId - 1].setup(2, 'AI_OUTCARD_TIMEUP',
                                                      params)

    def sendTableInfoRes(self, userId, clientId, isrobot):
        if self._logger.isDebug():
            self._logger.debug('DizhuGroupMatchSender.sendTableInfoRes',
                               'userId=', userId, 'clientId=', clientId,
                               'isrobot=', isrobot)
        tableInfo = self.table._match_table_info
        if not tableInfo:
            self._logger.error(
                'DizhuGroupMatchSender.sendTableInfoRes NoMatchTableInfo',
                'userId=', userId, 'clientId=', clientId, 'isrobot=', isrobot)
            return

        player = self.table.getPlayer(userId)

        if not player:
            self._logger.error(
                'DizhuGroupMatchSender.sendTableInfoRes NoPlayer', 'userId=',
                userId, 'clientId=', clientId, 'isrobot=', isrobot)
            return

        baseinfo = self.table.buildBasicInfo(False, userId, clientId)
        _, clientVer, _ = strutil.parseClientId(clientId)
        mo = self.createMsgPackRes('table_info')
        playMode = self.table.gamePlay.getPlayMode()
        if clientVer <= 3.7:
            if playMode == dizhuconf.PLAYMODE_HAPPY or playMode == dizhuconf.PLAYMODE_123:
                playMode = 'normal'  # FIX, 客户端happy和123都是normal, grab=1就是欢乐
        isMatch = self.table.isMatch
        mo.setResult('isrobot', isrobot)
        mo.setResult('playMode', playMode)

        roomLevel = gdata.roomIdDefineMap()[self.table.roomId].configure.get(
            'roomLevel', 1)
        mo.setResult('roomLevel', roomLevel)
        roomName = self.table.room.roomConf['name'] if self.table.room else ''
        mo.setResult('roomName', roomName)
        mo.setResult('isMatch', isMatch)
        mo.setResult('info', baseinfo['info'])
        mo.setResult('config', baseinfo['config'])
        mo.setResult('stat', self.buildStatusInfoDict(player))
        mo.setResult('myCardNote', self.buildCardNote(player.seatIndex))
        if self.table.gameRound:
            mo.setResult('roundId', self.table.gameRound.roundId)

        if self.table._complain_open:
            clientIdVer = sessiondata.getClientIdVer(userId)
            clientIdLimit = dizhuconf.getAllComplainInfo().get(
                'clientIdLimit', 3.72)
            if clientIdVer >= clientIdLimit:
                mo.setResult('complain', self.table._complain)

        if self._logger.isDebug():
            self._logger.debug(
                'DizhuGroupMatchSender.sendTableInfoRes before getMatchTableInfo',
                'mo=', mo)
        self.getMatchTableInfo(userId, tableInfo, mo)
        if self._logger.isDebug():
            self._logger.debug(
                'DizhuGroupMatchSender.sendTableInfoRes after getMatchTableInfo',
                'mo=', mo)

        for i in xrange(len(self.table.seats)):
            seat = self.table.seats[i]
            oseat = self.buildSeatInfo(player, seat)
            seatuid = seat.userId
            if seatuid:
                seatPlayer = self.table.players[i]
                oseat.update(seatPlayer.datas)
                oseat['cardNote'] = seatPlayer.getCardNoteCount()
                seatPlayer.cleanDataAfterFirstUserInfo()
                self.getMatchUserInfo(seatPlayer.userId, tableInfo, oseat)
            else:
                oseat['uid'] = 0
            mo.setResult('seat' + str(i + 1), oseat)

        tmpobsr = []
        for _, obuser in self.table.observers.items():
            if obuser:
                tmpobsr.append((obuser.userId, obuser.name))
        mo.setResult('obsr', tmpobsr)

        mo.setResult('betpoolClose', 1)

        if player and player.getCardNoteCount() < 1:
            tableConf = self.table.room.roomConf.get(
                'tableConf') if self.table.room else None
            cardNoteChip = tableConf.get('cardNoteChip', 0)
            cardNoteDiamod = tableConf.get('cardNoteDiamond', 0)
            cardNote = dizhuconf.getCardNoteTips(userId,
                                                 player.datas.get('chip',
                                                                  0), clientId,
                                                 cardNoteChip, cardNoteDiamod)
            if cardNote:
                mo.setResult('cardNote', cardNote)

        # 发送消息至客户端
        router.sendToUser(mo, userId)

    def getMatchTableInfo(self, userId, tableInfo, mo):
        mo.setResult(
            'step', {
                'name':
                tableInfo['step']['name'],
                'des':
                '%s人参赛,%s人晋级' % (tableInfo['step']['playerCount'],
                                 tableInfo['step']['riseCount']),
                'playerCount':
                tableInfo['step']['playerCount'],
                'note':
                self.table._buildNote(userId, tableInfo),
                'basescore':
                tableInfo['step']['basescore']
            })

    def getMatchUserInfo(self, userId, tableInfo, oseat):
        from dizhu.erdayimatch.match import ErdayiMatch
        oseat['mscore'] = 0
        oseat['mrank'] = 0
        try:
            for userInfo in tableInfo['seats']:
                if userInfo['userId'] == userId:
                    oseat['mscore'] = ErdayiMatch.fmtScore(userInfo['score'])
                    oseat['mrank'] = userInfo['rank']

                    matchId = tableInfo.get('recordId', tableInfo['matchId'])
                    record = MatchRecord.loadRecord(self.table.gameId, userId,
                                                    matchId)
                    if record:
                        oseat['mrecord'] = {
                            'bestRank': record.bestRank,
                            'crownCount': record.crownCount,
                            'playCount': record.playCount
                        }
        except:
            self._logger.error('DizhuGroupMatchSender.getMatchUserInfo',
                               'userId=', userId, 'tableInfo=', tableInfo,
                               'oseat=', oseat)