class DizhuPlayerErdayiMatch(DizhuPlayer): def __init__(self, room, userId, isAI, matchUserInfo): super(DizhuPlayerErdayiMatch, self).__init__(room, userId) self.matchUserInfo = matchUserInfo self.rank = 0 self.isAI = isAI self.waitReason = WaitReason.UNKNOWN self.ai = None self._timer = None if self.isAI: self.ai = AIPlayer(self) def startTimer(self, delay, func, *args, **kw): assert(self.isAI) self.cancelTimer() self._timer = FTTimer(delay, functools.partial(func, *args, **kw)) def cancelTimer(self): if self._timer: self._timer.cancel() self._timer = None def doActiveOutCard(self): assert(self.isAI) return self.ai.doActiveOutCard() def doPassiveOutCard(self): assert(self.isAI) return self.ai.doPassiveOutCard()
class SeatBase(object): def __init__(self, table, seatIndex, seatId): # 属于哪个桌子 self._table = table # 座位index self._seatIndex = seatIndex # seatId self._seatId = seatId # 该座位的玩家 self._player = None # 下一个座位 self._next = None # 该座位定时器 self._timer = None @property def table(self): return self._table @property def tableId(self): return self._table.tableId @property def seatId(self): return self._seatId @property def seatIndex(self): return self._seatIndex @property def state(self): return self._state @property def player(self): return self._player @property def next(self): return self._next @property def userId(self): return self._player.userId if self._player else 0 def startTimer(self, delay, func, *args, **kw): self.cancelTimer() self._timer = FTTimer(delay, functools.partial(func, *args, **kw)) def cancelTimer(self): if self._timer: self._timer.cancel() self._timer = None
class RoomTimer(object): def __init__(self, room): self._fttimer = None # 计时器对象 self._interval = 0 # 倒计时时间,单位: 秒 self._room = room def _onTimeOut(self): msg = stackless.getcurrent()._fttask.run_argl[0] self._room.on_match_event(msg) def setup(self, interval, msg, cancelLastTimer=True): if self._fttimer and cancelLastTimer: self._fttimer.cancel() self._interval = interval self._fttimer = FTTimer(interval, self._onTimeOut, msg) def cancel(self): ''' 取消当前的计时器 ''' if self._fttimer : self._fttimer.cancel() self._fttimer = None self._interval = 0 def reset(self, interval): ''' 重置当前的计时器 ''' if self._fttimer: self._fttimer.reset(interval) self._interval = interval def getInterval(self): ''' 取得当前计时器的倒计时时间 ''' if self._fttimer: return self._interval else: return 0 def getTimeOut(self): ''' 取得当前计时器的剩余的倒计时时间, 若没有开始倒计时, 那么返回0 ''' if self._fttimer : self._fttimer.getTimeOut() return 0.0
class Notify(object): ''' 一条通知 ''' def __init__(self, argd): self.argd = argd self._alive = False if self.argd['ntimeId'] == NOTIFY_TIME_ATONCE_ID: self.startTimer = FTTimer(0, self.start) ftlog.hinfo('Notify.__init__ atonce', self.argd) else: ntime = [0, 1] if self.argd['ntimeId'] == NOTIFY_TIME_TIMER_ID: try: dtList = self.argd['ntime'].split('|') ntime = map(int, dtList[1].split(':')) except: ftlog.warn('Notify.__init__.NOTIFY_TIME_TIMER_ID error') ntime = map(int, '00:01'.split(':')) else: ntime = map(int, self.argd['ntime'].split(':')) hm = map(int, getNowTimeStr().split(':')) interval = (ntime[0] * 60 * 60 + ntime[1] * 60) - (hm[0] * 60 * 60 + hm[1] * 60) ftlog.hinfo('Notify.__init__ begin:', ntime, hm, interval, (ntime[0] * 60 * 60 + ntime[1] * 60), (hm[0] * 60 * 60 + hm[1] * 60)) if interval > 0: self.startTimer = FTTimer(interval, self.start) ftlog.hinfo('Notify.__init__ end:', interval, self.argd) def start(self): self.startTimer.cancel() if self.argd['rmTag'] == 1: ftlog.hinfo('Notify.start error because be removed', self.argd['uuid']) return self._alive = True self.endTimer = FTTimer(NOTIFY_TIMER_LIFE, self.end) ftlog.hinfo('Notify.start', NOTIFY_TIMER_LIFE, self.argd['uuid']) def end(self): self.endTimer.cancel() self._alive = False if self.argd['ntimeId'] == NOTIFY_TIME_TIMER_ID: daobase.executeRankCmd('HDEL', notify_timer_key % self.argd['hall'], self.uuid) ftlog.hinfo('HDEL.notify timer', self.argd) ftlog.hinfo('Notify.end', self.argd['uuid']) def pushNotify(self, userId, gameId, clientId, clientSys): try: if ftlog.is_debug(): ftlog.hinfo('Notify.pushNotify enter argd=', userId, gameId, clientId, clientSys, self.typeId, self.typeId == NOTIFY_TYPEID_ANNOUNCE, self.argd) if self.argd['rmTag'] == 1: ftlog.hinfo('Notify.pushNotify notify be removed', userId, gameId, clientId, clientSys) return if len(self.argd['userId']) >= len('10000') and str( userId) not in self.argd['userId'].split('|'): ftlog.hinfo('Notify.pushNotify userId not match', userId, gameId, clientId, clientSys) return package = self.argd['package'] if len(package) > 0: if clientId not in package.split('|'): ftlog.hinfo('Notify.pushNotify clientId not in package', userId, gameId, clientId, clientSys) return platform = self.argd['platform'] if platform == '1': if clientSys != CLIENT_SYS_IOS: ftlog.hinfo('Notify.pushNotify clientSys not is ios', userId, gameId, clientId, clientSys) return elif platform == '2': if clientSys != CLIENT_SYS_ANDROID: ftlog.hinfo('Notify.pushNotify clientSys not is android', userId, gameId, clientId, clientSys) return elif platform == '3': pass #任意平台都可以 else: ftlog.warn('Notify.pushNotify clientSys error platform') return if clientId.count(self.argd['hall']) == 0: ftlog.hinfo('Notify.pushNotify hall not match', userId, gameId, self.argd['hall'], clientId, clientSys) return else: plugin_gameid = self.argd['gameId'] if len(plugin_gameid) > 0: if plugin_gameid != str(gameId): ftlog.hinfo( 'Notify.pushNotify plugin_gameid not match', userId, gameId, self.argd['gameId'], clientId, clientSys) return if self.typeId == NOTIFY_TYPEID_ANNOUNCE: sendNotify_announce(gameId, userId, self.argd) elif self.typeId == NOTIFY_TYPEID_MESSAGE: sendNotify_message(gameId, userId, self.argd) except: ftlog.error('Notify.pushNotify before11', userId, gameId, clientId, clientSys, self.argd) def rmTag(self): self.argd['rmTag'] = 1 ftlog.hinfo('Notify.rmTag is 1', self.uuid) @property def alive(self): return self._alive @property def typeId(self): return self.argd['typeId'] @property def uuid(self): return self.argd['uuid'] def __str__(self): return dict(self.argd).__repr__() def __repr__(self): return self.__str__()
class TYTableTimer(object): ''' 桌子使用的专用的计时器, 当计时器触发时, 触发桌子的同步方法:doTableCall ''' def __init__(self, table): self._table = table # 桌子对象 self._fttimer = None # 计时器对象 self._interval = 0 # 倒计时时间,单位: 秒 def _onTimeOut(self): ''' 计时器到时, 触发table的doTableCall方法 ''' msg = stackless.getcurrent()._fttask.run_argl[0] seatId = msg.getParam('seatId') if seatId == None: seatId = 0 userId = msg.getParam('userId') if userId == None: userId = 0 assert (isinstance(userId, int)) assert (isinstance(seatId, int)) action = msg.getParam('action') clientId = runcmd.getClientId(msg) self._table.doTableCall(msg, userId, seatId, action, clientId) def setup(self, interval, action, msgPackParams, cancelLastTimer=True): ''' 启动计时器 interval 倒计时的时间, 单位: 秒 action table_call命令下(params中)的action值 msgPackParams 传递的其他的参数数据集合dict, 可以在doTableCall中的msg中使用msg.getParam(key)来取得其中的参数 ''' if self._fttimer and cancelLastTimer: self._fttimer.cancel() self._interval = interval userId = msgPackParams.get('userId', 0) clientId = msgPackParams.get('clientId', None) assert (isinstance(userId, int)) assert (isinstance(action, (unicode, str))) if clientId != None: assert (isinstance(clientId, (unicode, str))) msg = MsgPack() msg.updateParam(msgPackParams) msg.setCmdAction('table_call', action) msg.setParam('gameId', self._table.gameId) msg.setParam('roomId', self._table.roomId) msg.setParam('tableId', self._table.tableId) msg.setParam('userId', userId) msg.setParam('clientId', clientId) self._fttimer = FTTimer(interval, self._onTimeOut, msg) def cancel(self): ''' 取消当前的计时器 ''' if self._fttimer: self._fttimer.cancel() self._fttimer = None def reset(self, interval): ''' 重置当前的计时器 ''' self._interval = interval self._fttimer.reset(interval) def getInterval(self): ''' 取得当前计时器的倒计时时间 ''' return self._interval def getTimeOut(self): ''' 取得当前计时器的剩余的倒计时时间, 若没有开始倒计时, 那么返回0 ''' if self._fttimer: time = self._fttimer.getTimeOut() if time < 0 or time > 3600: time = 0 return time return 0
class Heartbeat(object): ST_IDLE = 0 ST_START = 1 ST_STOP = 2 def __init__(self, target, interval): self._target = target self._state = Heartbeat.ST_IDLE self._count = 0 self._postTaskList = [] self._timer = None self._interval = interval self._logger = Logger() self._init = False def start(self): assert (self._state == Heartbeat.ST_IDLE) self._state = Heartbeat.ST_START self._timer = FTTimer(0, self._onInit) def stop(self): if self._state != Heartbeat.ST_STOP: self._state = Heartbeat.ST_STOP if self._timer: self._timer.cancel() self._timer = None @property def count(self): return self._count def postCall(self, func, *args, **kwargs): self.postTask(functools.partial(func, *args, **kwargs)) def postTask(self, task): if self._state != Heartbeat.ST_STOP: self._postTaskList.append(task) if self._init and self._timer: self._timer.cancel() self._timer = FTTimer(0, self._onTimeout) def _onInit(self): try: self._timer = None interval = self._target.onInit() if interval: self._interval = interval self._scheduleTimer() except: self._logger.error('Heartbeat._onInit') def _onTimeout(self): try: self._timer = None self._count += 1 self._processPostTaskList() interval = self._target.onHeartbeat() if interval is not None: self._interval = interval except: self._interval = 1 self._logger.error('Heartbeat._onTimeout') self._scheduleTimer() def _scheduleTimer(self): if self._state == Heartbeat.ST_START: interval = 0 if self._postTaskList else self._interval self._timer = FTTimer(interval, self._onTimeout) def _processPostTaskList(self): taskList = self._postTaskList self._postTaskList = [] for task in taskList: try: task() except: self._logger.error('task=', task)
class TableBase(Observable): def __init__(self, room, tableId, dealer): super(TableBase, self).__init__() # 房间 self._room = room # 当前状态 self._state = dealer.sm.findStateByName('idle') # 桌子ID self._tableId = tableId # 玩法 self._dealer = dealer # 桌子定时器 self._timer = None # 所有座位 self._seats = [] # 锁 self.locker = FTLock(self.__class__.__name__ + "_%d" % id(self)) @property def sm(self): return self._dealer.sm @property def playMode(self): return self._dealer.playMode @property def state(self): return self._state @property def gameId(self): return self.room.gameId @property def room(self): return self._room @property def roomId(self): return self.room.roomId @property def bigRoomId(self): return self.room.bigRoomId @property def tableId(self): return self._tableId @property def dealer(self): return self._dealer @property def seats(self): return self._seats @property def seatCount(self): return len(self._seats) @property def idleSeatCount(self): count = 0 for seat in self._seats: if not seat.player: count += 1 return count @locked def processCommand(self, cmd): self._processCommand(cmd) def getSeat(self, seatId): if seatId > 0 and seatId <= len(self._seats): return self._seats[seatId - 1] return None def getSeatByUserId(self, userId): for seat in self._seats: if seat.userId == userId: return seat return None def getPlayers(self): ret = [] for seat in self._seats: if seat.player: ret.append(seat.player) return ret def getSeatUserIds(self): ret = [] for seat in self._seats: ret.append(seat.userId) return ret def findIdleSeat(self): for seat in self._seats: if seat.player is None: return seat return None def init(self): self._makeSeats(self.playMode.seatCount) self._initImpl() return self def fire(self, event): event.table = self super(TableBase, self).fire(event) def startTimer(self, delay, func, *args, **kw): self.cancelTimer() self._timer = FTTimer(delay, functools.partial(func, *args, **kw)) def cancelTimer(self): if self._timer: self._timer.cancel() self._timer = None def _processCommand(self, cmd): assert (isinstance(cmd, TableCommand)) cmd.table = self cmd.timestamp = time.time() self.state.processCommand(cmd) def _makeSeats(self, seatCount): for i in xrange(seatCount): seat = self._newSeat(i, i + 1) assert (seat.table == self) assert (seat.seatId == i + 1) self._seats.append(seat) def _newSeat(self, seatIndex, seatId): raise NotImplementedError def _initImpl(self): pass