Example #1
0
 def __init__(self):
     setattr(Game, self._rpc_name_, self)
     self.max_players = config.max_players
     self.logic_players = config.logic_players
     self._users = {}
     self._players = {}
     self._sub_mgrs = {}
     self.mgr2addrs = {}
     self.logons = TimeMemCache(size=10000,
                                default_timeout=2,
                                name='rpc_player_mgr.logons')
     #        self.names = TimeMemCache(size=10000, default_timeout=1*30) #缓存保证不重名
     self.name2pids = {}
     self.pid2names = {}
     self._name_lock = RLock()
     self._new_player_lock = RLock()
     self.names4ad = {}
     self.overload_time = 0
     self._debug_ips = None
     self._debug_status = False
     self._area_url = None
     self._area_legal = None
     import app
     from game.base import msg_define
     app.sub(msg_define.MSG_START, self.start)
Example #2
0
 def __init__(self, game):
     BaseGameMgr.__init__(self, game)
     self._svr = None
     self._keys = TimeMemCache(size=1000, default_timeout=5*60, name='player_mgr._keys')
     self.users = {}
     self.players = {}
     self.others = TimeMemCache(size=1000, default_timeout=(self._SAVE_TIME_-1), name='player_mgr.others')
     self._game.reg_obj(self)
     self._loop_task = None
Example #3
0
 def __init__(self, game):
     BaseGameMgr.__init__(self, game)
     self._svr = None
     self._keys = TimeMemCache(size=1000,
                               default_timeout=5 * 60,
                               name='player_mgr._keys')
     self.users = {}
     self.players = {}
     self.others = TimeMemCache(size=1000,
                                default_timeout=(self._SAVE_TIME_ - 1),
                                name='player_mgr.others')
     self._game.reg_obj(self)
     self._loop_task = None
Example #4
0
    def __init__(self):
        setattr(Game, self._rpc_name_, self)
        self.cache = TimeMemCache(default_timeout=600, name='rank_mgr.cache')
        #[[ret1,ret2...],{pid:ret索引},{con:rank}]
        self.player_level_data = None
        self.player_cbe_data = None

        #当天第一次的排名时间
        self.first_time = None

        #深渊排名数据的保存
        #{层数:[pid1,pid2]...} 此数据保存数据库
        self.deep_floor_pids = {}
        #{pid1:层数,...}
        self.deep_pid_floor = {}

        #世界boss排名
        #[{排名:1, 名字:xx, 等级:22, 总伤害血量}...}
        self.boss_rank_datas = []
        #{pid1:(rank1, hurts),...} 此数据由世界boss广播而来 保存数据库
        self.boss_pid_data = {}

        #是否将当天排名数据保存到log_rank(当前只有深渊是每天零点更新)
        self.is_save_rank = False

        import app
        app.sub(MSG_START, self.start)
Example #5
0
    def __init__(self):
        self.arenas = TimeMemCache(
            size=CACHE_SIZE,
            default_timeout=CACHE_TIME)  #玩家信息 {pid:PlayerArena}
        self.rivals = TimeMemCache(
            size=CACHE_SIZE, default_timeout=CACHE_TIME)  # {pid:[name, rid]}
        self.rewards = HitMemCache(size=CACHE_SIZE)
        self.bots = {}

        self._lock = RLock()
        self.stoped = True
        self._reward_task = None
        self._auto_start_task = None
        self.clear()
        app.sub(MSG_START, self.start)
        self._active_mul = 1

        self.sorts = {}  #数据库中保存,方便修改 {sort:id}
Example #6
0
    def __init__(self):
        setattr(Game, self._rpc_name_, self)
        self.max_players = config.max_players
        self.logic_players = config.logic_players
        self._users = {}
        self._players = {}
        self._sub_mgrs = {}
        self.mgr2addrs = {}
        self.logons = TimeMemCache(size=10000, default_timeout=2, name='rpc_player_mgr.logons')
#        self.names = TimeMemCache(size=10000, default_timeout=1*30) #缓存保证不重名
        self.name2pids = {}
        self.pid2names = {}
        self._name_lock = RLock()
        self._new_player_lock = RLock()
        self.names4ad = {}
        self.overload_time = 0
        self._debug_ips = None
        self._debug_status = False
        self._area_url = None
        self._area_legal = None
        import app
        from game.base import msg_define
        app.sub(msg_define.MSG_START, self.start)
Example #7
0
class SubPlayerMgr(BaseGameMgr, DictExport):
    """ 逻辑进程使用的角色管理类 """
    _rpc_name_ = 'player_mgr'
    #定时保存时间 5分钟
    _SAVE_TIME_ = 60 * 5
    def __init__(self, game):
        BaseGameMgr.__init__(self, game)
        self._svr = None
        self._keys = TimeMemCache(size=1000, default_timeout=5*60, name='player_mgr._keys')
        self.users = {}
        self.players = {}
        self.others = TimeMemCache(size=1000, default_timeout=(self._SAVE_TIME_-1), name='player_mgr.others')
        self._game.reg_obj(self)
        self._loop_task = None

    def _rpc_mgr_init(self, rpc_mgr):
        if not self._game:
            return
        self.key = rpc_mgr.reg_sub_mgr(self, self._game.name,
                self._game.get_addr(), _proxy=True)

    def start(self):
        self._svr = new_stream_server_by_ports('0.0.0.0',
                                               config.player_ports,
                                               self._on_client_accept)
        self.address = config.inet_ip, self._svr.address[1]
        self.key = Game.rpc_player_mgr.reg_sub_mgr(self, self._game.name,
            self._game.get_addr(), _proxy=True)
        Game.sub_rpc_mgr_init(Game.rpc_player_mgr, self._rpc_mgr_init)
        self._loop_task = spawn(self._loop)

    def stop(self):
        if not BaseGameMgr.stop(self):
            return
        if self._svr:
            self._svr.stop()
            self._svr = None
        if self._loop_task:
            self._loop_task.kill(block=False)
            self._loop_task= None
        spawns(lambda u: u.logout(),
               [(u,) for u in self.users.itervalues()])
        if not Game.parent_stoped:
            Game.rpc_player_mgr.unreg_sub_mgr(self.key, _no_result=True)

    def _on_client_accept(self, sock, addr):
        log.debug(u'client发起连接(%s)', addr)
        user = User()
        user.start(self, sock, addr)
        user.wait_for_init()

    def _loop(self):
        """ 定时保存等处理 """
        stime = 30
        while 1:
            sleep(stime)
            try:
                for pid in self.players.keys():
                    p = self.players.get(pid)
                    if p is None or not p.logined:
                        continue
                    #是否需要定时保存
                    if p.save_time + self._SAVE_TIME_ <= time.time():
                        p.save()
            except:
                log.log_except()


    @property
    def global_count(self):
        """ 全服在线玩家总数 """
        return Game.rpc_player_mgr.get_count()

    @property
    def count(self):
        return len(self.users)

    @classmethod
    def cls_get_player_proxy(cls, pid, addr=None, local=1):
        if addr is None:
            addr = Game.get_addr()
        if local:
            proxy = DictItemProxy(cls._rpc_name_, dict_name='players',
                    key=pid, addr=addr)
        else:
            proxy = get_proxy_by_addr(addr, cls._rpc_name_, DictItemProxy)
            proxy.dict_name = 'players'
            proxy.key = pid
        return proxy

    def get_player_proxy(self, pid, check=True):
        if check and pid not in self.players:
            raise ValueError('player id(%d) not in player_mgr' % pid)
        return self.cls_get_player_proxy(pid)

    def logon(self, user_name, uid, key, sns_type):
        """ logon服务器发来的用户登录请求 """
        if self._game.stoped:
            return False, ''
        #log.debug('subPlayerMgr.logon:%s, %s, %s', user_name, uid, key)
        self._keys.set(uid, (uid, key, sns_type))
        return True, self.address

    def check_logon(self, uid, key):
        """ 检查角色登录情况,
        返回: 成功(uid, sns_type)
            失败(False, 0)
        """
        v = self._keys.delete(uid)
        #log.debug('subPlayerMgr.check_logon:%s, %s', user_name, v)
        if v is not None and v[1] == key:
            return v[0], v[2]
        return False, 0

    def add_user(self, user):
        self.users[user.data.id] = user

    def del_user(self, user):
        return self.users.pop(user.data.id, None)

    def del_user_by_id(self, uid):
        """ 全局管理器调用,强制玩家退出 """
        user = self.users.get(uid)
        if not user:
            return
        user.logout()

    def add_player(self, player):
        """ 玩家进入游戏 """
        pid = player.data.id
        rs = Game.rpc_player_mgr.add(self.key, pid, player.data.name, player.data.rid, player.data.uid)
        if not rs:
            return False
        self.players[pid] = player
        log.debug('sub_player_mgr.add_player:%s', pid)
        return True

    def logon_player(self, player):
        self.safe_pub(MSG_LOGON, player)

    def logoned_player(self, player):
        """ 已经发送初始化数据给前端,触发已登陆消息,其他模块可以正常发消息给前端 """
        self.safe_pub(MSG_LOGONED, player)

    def del_player(self, player):
        """ 玩家退出 """
        pid = player.data.id
        if pid not in self.players:
            return
        log.debug('sub_player_mgr.del_player:%s', pid)
        assert self.players[pid] == player, 'player != p'
        self.players.pop(pid)
        Game.rpc_player_mgr.delete(self.key, pid, player.data.uid)
        self.safe_pub(MSG_LOGOUT, player)

    def del_player_by_id(self, pid):
        """ 玩家退出,由全局管理器调用 """
        player = self.players.get(pid)
        if player is None:
            return
        player.user.logout()

    def get_player(self, pid):
        return self.players.get(pid)

    def send_msg_to_all(self, msg):
        data = prepare_send(msg)
        for user in self.users.itervalues():
            user.send_msg(data)

    def iter_players(self, pids):
        if pids is None:
            pids = self.players.keys()
        for pid in pids:
            p = self.players.get(pid)
            if p is None:
                continue
            yield pid, p

    def player_mails(self, pids, mids):
        """ 玩家接受邮件 """
        for pid, p in self.iter_players(pids):
            mid = mids.get(pid)
            if not mid:
                continue
            try:
                p.mail.recv_mails(mid)
            except:
                log.log_except()

    def get_partpids_by_level(self, level, start_chapter=False):
        """ 获取大于等于指定等级的所有玩家 start_chapter 是否包括初章"""
        pids = []
        for pid, player in self.iter_players(None):
            if player.data.level >= level:
                if start_chapter and player.data.chapter == constant.CHATER_START:
                    continue
                pids.append(pid)
        return pids

    def player_send_msg(self, pids, msg):
        data = prepare_send(msg)
        for pid, p in self.iter_players(pids):
            p.send_msg(data)

    def exec_players_func(self, pids, func, _pickle=True):
        """ 在玩家所在的逻辑进程执行方法,用于一般的玩家操作 """
        rs = {}
        for pid, p in self.iter_players(pids):
            try:
                rs[pid] = func(p)
            except Exception:
                log.log_except()
        return rs

    def look(self, pid):
        """ 查看其它玩家信息 """
        return self._get_other(pid)

    def _get_other(self, pid, cache=1):
        """ 获取其它玩家信息 """
        if cache:
            v = self.others.get(pid)
            if v is not None:
                return v
        p = self.get_player(pid)
        if not p:
            p = self._game.rpc_player_mgr.get_rpc_player(pid)
        if not p:#不在线
            p = Player.load_player(pid)
#            p = OtherPlayer.new(pid)
        if not p:
            v = 0, errcode.EC_NOFOUND
        else:
            #先计算出战斗力
            p.init()
            v = 1, p.look()
        self.others.set(pid, v)
        return v
Example #8
0
class GPlayerMgr(object):
    """ 联合进程使用的总角色管理类 """
    _rpc_name_ = 'rpc_player_mgr'
    _rpc_attr_pre = 'rc_'
    TIME_OUT = 0.1
    def __init__(self):
        setattr(Game, self._rpc_name_, self)
        self.max_players = config.max_players
        self.logic_players = config.logic_players
        self._users = {}
        self._players = {}
        self._sub_mgrs = {}
        self.mgr2addrs = {}
        self.logons = TimeMemCache(size=10000, default_timeout=2, name='rpc_player_mgr.logons')
#        self.names = TimeMemCache(size=10000, default_timeout=1*30) #缓存保证不重名
        self.name2pids = {}
        self.pid2names = {}
        self._name_lock = RLock()
        self._new_player_lock = RLock()
        self.names4ad = {}
        self.overload_time = 0
        self._debug_ips = None
        self._debug_status = False
        self._area_url = None
        self._area_legal = None
        import app
        from game.base import msg_define
        app.sub(msg_define.MSG_START, self.start)

    def start(self):
        self._svr = new_stream_server(config.player_addr,
                                      self._on_client_accept)
        self.sns_client = SNSClient(*config.logon_url)
        from game.base.msg_define import MSG_RES_RELOAD
        Game.res_mgr.sub(MSG_RES_RELOAD, self.load)
        Game.mail_mgr.start_expire_mail()
        self.load()

    def load(self):
        self._area_url = None
        self._area_legal = None
        op_lis = Game.rpc_status_mgr.get_config(GF_AREA_URLS)
        if not op_lis:
            return
        self._area_url = tuple(op_lis[:3])
        self._area_legal = op_lis[-1]

        data = Game.rpc_status_mgr.get(constant.STATUS_DEBUG_FT)
        if data:
            self._debug_ips = data['ip'].split(",")
            self._debug_status = bool(data['status'])

    def _on_client_accept(self, sock, addr):
        """ 处理玩家登陆请求 """
        log.debug(u'client发起连接(%s)', addr)
        _rpc = ClientRpc(sock, addr, self)
        _rpc.call_link_rpc = True
        _rpc.start()
        sleep(120)
        _rpc.stop()#该链接只用于登录接口,之后断开

    def on_close(self, rpcobj):
        pass

    def reg_sub_mgr(self, rpc_sub_mgr, sub_name, addr, _proxy=True):
        log.info('reg_player_mgr:%s', sub_name)
        self._sub_mgrs[sub_name] = [rpc_sub_mgr, set()]
        self.mgr2addrs[sub_name] = addr
        return sub_name

    def unreg_sub_mgr(self, sub_mgr_id, _no_result=True):
        log.info('unreg_player_mgr:%s', sub_mgr_id)
        self._sub_mgrs.pop(sub_mgr_id, None)
        self.mgr2addrs.pop(sub_mgr_id, None)

    def get_sub_mgr(self, pid):
        """ 获取玩家所在进程的player_mgr对象 """
        mid = self._players.get(pid)
        if not mid:
            return 0, None
        sub_mgr_ids = self._sub_mgrs.get(mid)
        if not sub_mgr_ids:
            return 0, None
        return mid, sub_mgr_ids[0]

    @wrap_pickle_result
    def get_sub_game(self, pid):
        """ 获取玩家所在进程的game对象 """
        mid, sub_mgr = self.get_sub_mgr(pid)
        if not mid:
            return
        addr = self.mgr2addrs.get(mid)
        return get_obj(addr, 'game')


    @grpc_monitor
    def pre_add(self, pid, uid):
        """ 玩家预备登陆,为防止重复,先踢在线的玩家 """
        old_mid, sub_mgr = self.get_sub_mgr(pid)
        if sub_mgr:
            sub_mgr.del_player_by_id(pid)
            self.delete(old_mid, pid, uid)
            return 1
        if not uid in self._users:
            return 1
        mid, _ = self._users[uid]
        sub_mgr = self._sub_mgrs[mid]
        sub_mgr[0].del_user_by_id(uid)
        return 1

    @grpc_monitor
    def add(self, mid, pid, name, rid, uid):
        """ 玩家登陆,防止在短时间内重复登录 """
        self._add_name_id(pid, name, rid)
        if self.logons.get(pid):
            log.info(u'禁止玩家(%s-%s)短时登录', pid, name)
            return False
        self.logons.set(pid, 1)
        self._users[uid] = mid, pid
        self._players[pid] = mid
        self._sub_mgrs[mid][1].add(pid)
        self.safe_pub(MSG_LOGON, pid)
        return True

    @grpc_monitor
    def delete(self, mid, pid, uid):
        """ sub_mgr调用,通知玩家退出 """
        self._users.pop(uid, None)
        self._players.pop(pid, None)
        if mid in self._sub_mgrs:
            pids = self._sub_mgrs[mid][1]
            if pid in pids:
                pids.remove(pid)
        self.safe_pub(MSG_LOGOUT, pid)

    @property
    def count(self):
        return len(self._players)

    def get_count(self):
        return self.count

    def have(self, pid):
        return pid in self._players

    def _add_name_id(self, pid, name, rid):
        if pid in self.pid2names:
            return
        self.name2pids[name] = pid
        self.pid2names[pid] = (name, rid)

    def change_name(self, pid, name, rid):
        """
        改名
        """
        if pid not in self.pid2names:
            return False, errcode.EC_VALUE
        self.del_player(pid)
        self.name2pids[name] = pid
        self.pid2names[pid] = (name, rid)
        return True, None

#    def valid_name(self, name):
#        """ 检查角色名是否没重复,可以用来新建角色 """
#        with self._name_lock:
#            pid = self.names.get(name)
#            if pid is not None:
#                return False
#            rs = Game.rpc_store.values(TN_PLAYER, ['name'], dict(name=name))
#            if rs:
#                pid = rs[0]['id']
#                self.names.set(name, pid)
#                return False
#            self.names.set(name, 0)
#            return True

    def get_id_by_name(self, name):
        """ 根据名称获取对应玩家id """
        try:
            return self.name2pids[name]
        except KeyError:
            pid_rid = PlayerData.name_to_id(name)
            if pid_rid is None:
                return
            self._add_name_id(pid_rid[0], name, pid_rid[1])
            return pid_rid[0]

    def get_name_by_id(self, pid, rid=0):
        """ 查询pid,
        rid: 1 一起查询主配将id
        return:
           name,
           name, rid
        """
        try:
            if rid:
                return self.pid2names[pid]
            return self.pid2names[pid][0]
        except KeyError:
            name_rid = PlayerData.id_to_name(pid)
            if name_rid is None:
                return
            self._add_name_id(pid, name_rid[0], name_rid[1])
            if rid:
                return name_rid
            return name_rid[0]

    def get_names(self, ids):
        """ 获取玩家名列表 """
        rs = {}
        for i in ids:
            n = self.get_name_by_id(i)
            if n is None:
                continue
            rs[i] = n
        return rs

    def get_name_rids(self, ids):
        """ 获取玩家名rid列表 """
        rs = {}
        for i in ids:
            n = self.get_name_by_id(i, rid=1)
            if n is None:
                continue
            rs[i] = n
        return rs

    def get_player_infos(self, pids, CBE=0):
        """ 获取玩家信息
        返回: onlines, {pid:(name, rid, level, CBE)}
        """
        onlines = self.get_online_ids(pids)
        rs = {}
        #等级
        if CBE:
            levels = self.exec_players_func(onlines, _get_level_CBE, has_result=1, _pickle=True)
        else:
            levels = self.exec_players_func(onlines, _get_level, has_result=1, _pickle=True)
        off_ids = set(pids).difference(levels.keys())
        if off_ids:
            off_lvs = PlayerData.get_players_levels(off_ids, CBE=CBE)
            if off_lvs:
                levels.update(off_lvs)

        for pid in pids:
            n_rid = self.get_name_by_id(pid, rid=1)
            if not n_rid:
                continue
            if CBE:
                lv, cbe = levels.get(pid, (1, 0))
                rs[pid] = (n_rid[0], n_rid[1], lv, cbe)
            else:
                rs[pid] = (n_rid[0], n_rid[1], levels.get(pid, 1))
        return onlines, rs

    def get_pids_by_level(self, level, start_chapter=False):
        """ 获取大于等于指定等级的所有在线pid """
        all_pids = []
        for sub_mgr in self._sub_mgrs.itervalues():
            player_mgr = sub_mgr[0]
            pids = player_mgr.get_partpids_by_level(level, start_chapter)
            all_pids.extend(pids)
        return all_pids

    def get_player_detail(self, pids, cols):
        """ 返回玩家详细信息 """
        return PlayerData.get_players_values(pids, cols)

    def get_user_detail_by_playername(self, name, *argv, **kw):
        """ 返回玩家详细信息 """
        return PlayerData.userinfo_from_name(name, *argv, **kw)



    @grpc_monitor
    def get_onlines(self, start, end, name=0, rid=0):
        """ 返回在线玩家列表,
        返回 根据传入的参数:
            默认: [pid, ....]
            name=1: [(pid, name), ....]
            rid=1: [(pid, name, rid), ...]
            level=1: [(pid, name, rid, level), ...]
        """
        rs = []
        for index, pid in enumerate(self._players.iterkeys()):
            if index < start:
                continue
            if index >= end:
                break
            if name or rid:
                n_rid = self.get_name_by_id(pid, rid=1)
            if rid:
                rs.append((pid, n_rid[0], n_rid[1]))
            elif name:
                rs.append((pid, n_rid[0]))
            else:
                rs.append(pid)
        return rs

    @grpc_monitor
    def get_online_ids(self, pids=None, random_num=None):
        """ 返回在线的玩家id列表,
        pids: 查询的玩家列表,返回在线的ids
        random:整形, 随机选择random个pid返回
        """
        if random_num is not None:
            if len(self._players) <= random_num:
                return self._players.keys()
            return random.sample(self._players, random_num)
        if not pids:
            return self._players.keys()
        return [pid for pid in pids if pid in self._players]

    @grpc_monitor
    def new_player(self, uid, name, rid):
        """ 创建玩家对象,防止重名 """
        with self._new_player_lock:
            if self.get_id_by_name(name) is not None:
                return
            pid, data = PlayerData.new_player(uid, name, rid)
            self._add_name_id(pid, name, rid)
            return data

    def del_player(self, pid):
        name = self.pid2names.pop(pid, None)
        self.name2pids.pop(name, None)

    def _new_user(self, t, user, pwd, UDID, DT, MAC, DEV, VER):
        u = dict(sns=t, name=user, pwd=pwd, UDID=UDID, DT=DT,
                MAC=MAC, DEV=DEV, VER=VER,
                tNew=int(time.time()))
        u = User(adict=u)
        u.save(Game.rpc_store)
        return u

    def _get_login_params(self, user, uid, sns_type=0):
        """ 选择一个逻辑进程,返回登录用参数 """
        if uid in self._users:#重复登陆
            mid, pid = self._users.get(uid)
            self.pre_add(pid, uid)
            self._users.pop(uid, None)

        key = uuid()
        rs, address = self._login_sub(user, uid, key, sns_type)
        return dict(uid=uid, key=key, time=int(time.time()),
            ip=address[0], port=address[1])

    @wrap_wait4init
    @grpc_monitor
    def rc_login(self, user, pwd, UDID, DT, MAC='', DEV='', VER='', **kw):
        """ 用户登录请求 """
        log.debug(u'收到用户登录请求:%s, %s, %s, %s, %s, %s, %s, %s',
                user, pwd, UDID, DT, MAC, DEV, VER, kw)
        resp_f = 'login'
        if self.count >= self.max_players:
            return pack_msg(resp_f, 0, err=language.STR_PLAYER_3)

        if not user:#游客登录
            u = Game.rpc_store.query_loads(TN_USER, dict(UDID=UDID, name=''))
        else:
            #检查user,pwd是否正确,返回uid
            u = Game.rpc_store.query_loads(TN_USER, dict(name=user))
        if not u:
            #不存在自动增加
            u = self._new_user(SNS_NONE, user, pwd, UDID, DT,
                    MAC, DEV, VER)
        else:
            u = u[0]
            u = User(adict=u)
        if u.data.pwd != pwd:
            return pack_msg(resp_f, 0, err=language.LOGIN_PWD_ERROR)
        params = self._get_login_params(user, u.data.id)
        return pack_msg(resp_f, 1, data=params)

    def bindSNS(self, uid, t, sid, session):
        """ 绑定平台账号 """
        rs, data = self.sns_client.login(t, sid, session)
        if not rs:
            return 0, data
        u = Game.rpc_store.load(TN_USER, uid)
        if not u:
            return 0, errcode.EC_NOFOUND
        Game.rpc_store.update(TN_USER, uid, dict(name=sid))
        return 1, None

    def area_legal(self):
        """登陆时区域是不是合法"""
        if not self._area_url or not self._area_legal:
            #未配置则所有人合法登陆
            return True
        rpc = client_rpc.get_cur_rpc()
        data = urllib.urlencode({'ip':rpc.addr[0], 'check':str(0)})
        host, port, url = self._area_url
        try:
            area = tools.http_post_ex(host, port, url, params=data, timeout=GPlayerMgr.TIME_OUT)
            area = json.loads(area)
            country = area['country']
            log.debug('area_legal:%s in %s', rpc.addr[0], country)
            return not country or country in self._area_legal
        except BaseException as e:
            log.warn("area_legal error:%s", e)
            return True

    def is_debug_time(self):
        """
        测试期间只允许特定IP登陆
        """
        if not self._debug_status or not self._debug_ips:
            return True
        rpc = client_rpc.get_cur_rpc()
        ip = rpc.addr[0]
        if ip in self._debug_ips:
            return True
        log.info('during debug time in_ip:%s forbid :%s', self._debug_ips, ip)
        return False

    @wrap_wait4init
    @grpc_monitor
    def rc_loginSNS(self, t, sid, session, UDID, DT,
            MAC='', DEV='', VER='', **kw):
        """ 平台登录接口 """
        resp_f = 'loginSNS'
        if not self.area_legal():
            return pack_msg(resp_f, 0, err=errcode.EC_LOGIN_AREA_ERR)
        if not self.is_debug_time():
            return pack_msg(resp_f, 0, err=errcode.EC_LOGIN_DEBUG_TIME)

        log.debug(u'平台(%s)用户登录请求:%s, %s, %s, %s, %s, %s, %s, %s',
                t, sid, session, UDID, DT, MAC, DEV, VER, kw)
        if self.count >= self.max_players:
            return pack_msg(resp_f, 0, err=errcode.EC_TEAM_ROLE_FULL)

        if not sid and t not in SNS_LOGINS:#游客登录
            return pack_msg(resp_f, 0, err=errcode.EC_VALUE)
            #u = Game.rpc_store.query_loads(TN_USER, dict(UDID=UDID, name=''))
        else:
            rs, data = self.sns_client.login(t, sid, session)
            if not rs:
                return pack_msg(resp_f, 0, err=data)
            if data:#login返回sid
                sid = data
            u = UserData.user_by_sns(t, sid)
        if not u:
            #不存在自动增加
            u = self._new_user(t, sid, '', UDID, DT, MAC, DEV, VER)
        else:
            u = u[0]
            u = User(adict=u)
            #如果mac地址不同,记录
            if u.data.UDID != UDID or u.data.DT != DT or \
                u.data.DEV != DEV or \
                u.data.MAC != MAC or u.data.VER != VER:
                def _log_mac():
                    if 1: #强制保存更新信息, not u.data.MAC:
                        u.data.UDID = UDID
                        u.data.DT = DT
                        u.data.MAC = MAC
                        u.data.DEV = DEV
                        u.data.VER = VER
                        u.save(Game.rpc_store)
                    else:
                        self.glog(PM_MAC, u=u.data.id,
                                UDID=UDID, MAC=MAC, DEV=DEV, VER=VER)
                spawn(_log_mac)

        params = self._get_login_params(sid, u.data.id, t)
        log.debug(u'loginSNS finish:%s', params)
        return pack_msg(resp_f, 1, data=params)


    def glog(self, type, **kw):
        kw['t'] = type
        Game.glog.log(kw)


    def _login_sub(self, user_name, uid, key, sns_type):
        """ 选取subgame """
        sub_ids = None
        while not sub_ids:
            sub_ids = self._sub_mgrs.keys()
            if sub_ids:
                break
            log.info('_login_sub wait game init')
            sleep(1)

        sub_ids.sort()
        for sub_mgr_id in sub_ids:
            mgr, pids = self._sub_mgrs[sub_mgr_id]
            if len(pids) < self.logic_players:
                rs, address = mgr.logon(user_name, uid, key, sns_type)
                return rs, address
        #如果全部都满人,随机选择
        sub_id = random.choice(sub_ids)
        mgr, count = self._sub_mgrs[sub_id]
        rs, address = mgr.logon(user_name, uid, key, sns_type)
        return rs, address

    @grpc_monitor
    def distribute(self, func_name, pids, *args, **kw):
        """ 分发方法调用到各个自进程:
         func_name: SubPlayerMgr中的方法名
         pids: 玩家id列表, pids=None广播所有玩家
        """
        if pids is not None:
            pids = set(pids)
        for mid, (mgr, mids) in self._sub_mgrs.items():
            if not mids:
                continue
            if pids is None:
                mpids = None
            else:
                mpids = list(pids.intersection(mids))
            func = getattr(mgr, func_name)
            try:
                func(mpids, *args, **kw)
            except Exception as err:
                log.log_except('distribute error:%s(%s, %s)', func_name, args, kw)

    @wrap_distribute
    def player_mails(self, pids, mids, _no_result=True):
        """ 玩家收到新的邮件 """

    @wrap_distribute
    def player_send_msg(self, pids, msg, _no_result=True):
        """
        广播消息给玩家
        pids:None 时广播所有在线玩家
       """

    @wrap_pickle_result
    def get_rpc_player(self, pid):
        mid, sub_mgr = self.get_sub_mgr(pid)
        if not mid:
            return
        addr = self.mgr2addrs.get(mid)
        proxy = SubPlayerMgr.cls_get_player_proxy(pid, addr=addr, local=0)
        return proxy

    @wrap_pickle_result
    @grpc_monitor
    def get_rpc_players(self, pids):
        """ 获取rpc_player列表,用于少量玩家操作 """
        rs = []
        for pid in pids:
            proxy = self.get_rpc_player(pid)
            if proxy:
                rs.append(proxy)
        return rs

    @grpc_monitor
    def exec_players_func(self, pids, func, has_result=False, _pickle=True):
        """ 在玩家所在的逻辑进程执行方法,用于一般的玩家操作
        func: 定义: def func(player)
        """
        pids = set(pids)
        rs = {}
        for mid, (mgr, mids) in self._sub_mgrs.iteritems():
            mpids = pids.intersection(mids)
            if not mpids:
                continue
            mpids = tuple(mpids)
            if has_result:
                sub_rs = mgr.exec_players_func(mpids, func, _pickle=True)
                rs.update(sub_rs)
            else:
                mgr.exec_players_func(mpids, func, _pickle=True, _no_result=True)
        return rs

    def overload(self, m):
        """ 启动压力测试m分钟 """
        self.overload_time = time.time() + m * 60
        log.warn('overload start to %s',
                datetime.datetime.fromtimestamp(self.overload_time))

    def is_overload(self):
        """ 是否处于压力测试状态 """
        return time.time() < self.overload_time


    def set_debug_data(self, ips, status):
        """
        设置测试的数据
        """
        self._debug_ips = ips
        self._debug_status = bool(status)
        self._players.keys()
        #状态开启了
        if not self._debug_status:
            return
        pids = self.get_online_ids()
        for pid in pids:
            rpc = self.get_rpc_player(pid)
            if rpc and rpc.get_ip() not in self._debug_ips:
                rpc.debug_kick()
Example #9
0
    def init(self):
        #定时器
        from corelib.common import TimerSet
        self.timer_set = TimerSet(self)
        self.stop_mgrs.append(self.timer_set)
        #缓存,缓存数量待优化
        self.caches = TimeMemCache(size=500, name='game.caches')

        self.init_snss()
        self.init_res_mgr()
        self.init_gm_mgr()
        self.init_player_mgr()
        self.init_scene_mgr()
        self.init_task_mgr()
        self.init_mining_mgr()

        from game.mgr.deep import DeepMgr
        self.deep_mgr = DeepMgr(self)
        self.stop_mgrs.append(self.deep_mgr)

        from game.mgr.fish import FishMgr
        self.fish_mgr = FishMgr(self)
        self.stop_mgrs.append(self.fish_mgr)

        from game.mgr.coinstree import CTreeMgr
        self.ctree_mgr = CTreeMgr(self)
        self.stop_mgrs.append(self.ctree_mgr)

        from game.mgr.tbox import TboxMgr
        self.tbox_mgr = TboxMgr(self)
        self.stop_mgrs.append(self.tbox_mgr)

        from game.mgr.hfate import HitFateMgr
        self.hfate_mgr = HitFateMgr(self)
        self.stop_mgrs.append(self.hfate_mgr)

        from game.mgr.bftask import BfTaskMgr
        self.bftask_mgr = BfTaskMgr(self)
        self.stop_mgrs.append(self.bftask_mgr)

        from game.mgr.fete import FeteMgr
        self.fete_mgr = FeteMgr(self)
        self.stop_mgrs.append(self.fete_mgr)

        #'神秘商人'
        from game.mgr.shop import ShopMgr
        self.shop_mgr = ShopMgr(self)
        self.stop_mgrs.append(self.shop_mgr)

        from game.mgr.social import SocialMgr
        self.social_mgr = SocialMgr(self)
        self.stop_mgrs.append(self.social_mgr)

        from game.achievement.achi_mgr import AchievementMgr
        self.achi_mgr = AchievementMgr(self)
        self.stop_mgrs.append(self.achi_mgr)

        from game.mgr.gem import GemMgr
        self.gem_mgr = GemMgr(self)
        self.stop_mgrs.append(self.gem_mgr)

        from game.mgr.day_lucky import DayLuckyMgr
        self.day_lucky_mgr = DayLuckyMgr(self)
        self.stop_mgrs.append(self.day_lucky_mgr)

        from game.mgr.day_sign import DaySignMgr
        self.day_sign_mgr = DaySignMgr(self)
        self.stop_mgrs.append(self.day_sign_mgr)

        #玩家vip属性管理
        from game.mgr.vipattr import PlayerVipAttrMgr
        self.vip_attr_mgr = PlayerVipAttrMgr(self)
        self.stop_mgrs.append(self.vip_attr_mgr)

        #奖励奖励管理
        from game.mgr.reward import RewardMgr
        self.reward_mgr2 = RewardMgr(self)
        self.stop_mgrs.append(self.reward_mgr2)
Example #10
0
class Game(object):
    instance = None
    inited = False
    if 0:
        #跨进程对象
        instance = Game()
        from player.player_mgr import GPlayerMgr
        rpc_player_mgr = GPlayerMgr()
        from client import GameClient
        rpc_client = GameClient()
        from game.scene.scene_mgr import GSceneMgr
        rpc_scene_mgr = GSceneMgr()
        from game.store import GameStore, ResStore, PayStore
        rpc_store = GameStore()
        rpc_res_store = ResStore()
        rpc_pay_store = PayStore()
        from game.glog.logger import LoggerServer
        rpc_logger_svr = LoggerServer()
        from game.mgr.status import StatusMgr
        rpc_status_mgr = StatusMgr()
        from game.mgr.report import ReportMgr
        rpc_report_mgr = ReportMgr()
        from ally.ally_mgr import AllyMgr
        rpc_ally_mgr = AllyMgr()
        from game.mgr.arena import ArenaMgr
        rpc_arena_mgr = ArenaMgr()
        from game.mgr.boss import BossMgr
        rpc_boss_mgr = BossMgr()
        from game.player.vip import GVipMgr
        rpc_vip_mgr = GVipMgr()
        from game.mgr.rewardcode import ExchangeCodeMgr
        rpc_ex_code_mgr = ExchangeCodeMgr()
        from game.mgr.tbox import GTboxNewsMgr
        rpc_tboxnews_mgr = GTboxNewsMgr()
        from game.mgr.horn import HornMgr
        rpc_horn_mgr = HornMgr()
        from game.team.team_mgr import TeamMgr
        rpc_team_mgr = TeamMgr()
        from game.mgr.reward import RpcRewardMgr
        rpc_reward_mgr = RpcRewardMgr()
        from .mgr.chat import MyNotifyServer
        rpc_notify_svr = MyNotifyServer()
        from .mgr.rank import RankMgr
        rpc_rank_mgr = RankMgr()

        #本地全局对象
        from game.res.res_mgr import ResMgr
        res_mgr = ResMgr()
        from game.glog.logger import GameLogger
        glog = GameLogger()
        from .base.setting import SettingMgr
        setting_mgr = SettingMgr()
        from game.item.item_mgr import ItemMgr
        item_mgr = ItemMgr()
        from game.item.reward import RewardMgr
        reward_mgr = RewardMgr()
        from game.mgr import chat
        chat_mgr = chat.ChatMgr()
        from game.player import mail, vip
        mail_mgr = mail.MailMgr()
        vip_mgr = vip.VipMgr()
        from game.achievement import achi_mgr
        achi_mgr = achi_mgr.AchievementMgr()
        from game.mgr import gem
        gem_mgr = gem.GemMgr()

    main_app = None
    app = None
    name = ''
    parent_stoped = False
    rpc_names = set()
    games = {}  #其它逻辑进程中的game对象, {addr:(game, pid)}
    rpc_init_funcs = {}
    #缓存,缓存数量待优化
    gcaches = TimeMemCache(size=1000, name='game.gcaches')
    lock_count = 9999

    def __init__(self):
        Game.instance = self
        self.stoping = False
        self.stoped = True
        self.big_area = None  #大区名
        self.area = None  #小区名
        self.stop_lock = Semaphore(self.lock_count)
        self.stop_mgrs = []

    @classmethod
    def _rpc_on_close(cls, proxy):
        """ 功能服关闭,等待重新链接 """
        name = proxy._rpc_name
        addr, key = proxy.get_proxy_id()
        if os.environ.get('PARENT_STOPED', None):
            return
        if Game.app.stoped:
            return
        log.info('reconnect rpc(%s):%s', name, addr)
        while 1:
            new = get_obj(addr, key)
            if new is None or not new.valid():
                sleep(0.1)
                continue
            cls.add_rpc_mgr(name, new)
            funcs = cls.rpc_init_funcs.get(name, [])
            for f in funcs:
                spawn(f, new)
            break

    @classmethod
    def iter_games(cls):
        addrs = Game.games.keys()
        for key in addrs:
            g = Game.games.get(key, None)
            if not g:
                continue
            yield g[0]

    @classmethod
    def one_game(cls):
        return Game.games.itervalues().next()[0]

    @classmethod
    def valid_games(cls):
        """ 返回有效的逻辑进程game对象 """
        import psutil
        return [
            game for game, pid in Game.games.values() if psutil.pid_exists(pid)
        ]

    @classmethod
    def reg_other_game(cls,
                       rpc_game,
                       process_id,
                       _pickle=True,
                       _no_result=True):
        """ 注册其它进程的game对象 """
        log.debug('reg_other_game(%s)', rpc_game.get_addr())
        Game.games[rpc_game.get_addr()] = (rpc_game, process_id)

    @classmethod
    def unreg_other_game(cls, game_addr, _no_result=True):
        """ 反注册其它进程的game对象 """
        log.debug('unreg_other_game(%s)', game_addr)
        if isinstance(game_addr, list):
            game_addr = tuple(game_addr)
        Game.games.pop(game_addr, None)

    @classmethod
    def init_snss(cls,
                  get_config=None,
                  web_app=None,
                  api_url=None,
                  res_store=None):
        """ 初始化sns模块 """
        from game.store import get_sns_params
        from webapi import init_snss, SNSClient
        if res_store is None:
            res_store = Game.rpc_res_store
        SNSClient.res_store = res_store

        if get_config is None:
            get_config = Game.rpc_res_store.get_config
        params = get_sns_params(get_config)
        return init_snss(params, web_app=web_app, api_url=api_url)

    @classmethod
    def sub_rpc_mgr_init(cls, rpc_mgr, func):
        funcs = Game.rpc_init_funcs.setdefault(rpc_mgr._rpc_name, set())
        funcs.add(func)

    @classmethod
    def add_rpc_mgr(cls, name, mgr):
        if hasattr(mgr, 'sub_close'):
            #log.info('rpc_mgr sub_close:(%s, %s)', name, mgr)
            mgr.sub_close(cls._rpc_on_close)
        cls.rpc_names.add(name)
        mgr._rpc_name = name
        setattr(cls, name, mgr)

    @classmethod
    def init_res_mgr(cls):
        if getattr(cls, 'res_mgr', None):
            return
        from game.res.res_mgr import ResMgr
        Game.res_mgr = ResMgr()
        Game.res_mgr.load()

    @classmethod
    def init_logger(cls):
        if getattr(cls, 'glog', None):
            return
        from game.glog.logger import GameLogger
        Game.glog = GameLogger()

    @classmethod
    def init_mail_mgr(cls):
        if getattr(cls, 'mail_mgr', None):
            return
        from game.player.mail import MailMgr
        Game.mail_mgr = MailMgr()

    @classmethod
    def init_setting_mgr(cls):
        from .base.setting import SettingMgr
        Game.setting_mgr = SettingMgr()
        Game.setting_mgr.start()

    @classmethod
    def init_chat_mgr(cls):
        from game.mgr.chat import ChatMgr
        Game.chat_mgr = ChatMgr()
        Game.chat_mgr.start()

    @classmethod
    def init_item_mgr(cls):
        from .item.item_mgr import ItemMgr
        Game.item_mgr = ItemMgr()

    @classmethod
    def init_reward_mgr(cls):
        from .item.reward import RewardMgr
        Game.reward_mgr = RewardMgr()
        Game.reward_mgr.start()

    @classmethod
    def init_vip_mgr(cls):
        from .player.vip import VipMgr
        Game.vip_mgr = VipMgr()
        Game.vip_mgr.start()

    @classmethod
    def init_cls(cls):
        cls.init_res_mgr()
        cls.init_logger()
        cls.init_mail_mgr()
        cls.init_setting_mgr()
        cls.init_chat_mgr()
        cls.init_item_mgr()
        cls.init_reward_mgr()
        cls.init_vip_mgr()

    @classmethod
    def get_addr(cls):
        return Game.app.get_addr()

    def init_player_mgr(self):
        from player.player_mgr import SubPlayerMgr
        self.player_mgr = SubPlayerMgr(self)
        self.stop_mgrs.append(self.player_mgr)

    def init_scene_mgr(self):
        from scene.scene_mgr import SubSceneMgr
        self.scene_mgr = SubSceneMgr(self)
        self.stop_mgrs.append(self.scene_mgr)

    def init_task_mgr(self):
        """ 初始化任务管理器 """
        from task.task_mgr import TaskMgr
        self.task_mgr = TaskMgr(self)

    def init_gm_mgr(self):
        from game.gm import GameMasterMgr
        self.gm_mgr = GameMasterMgr(self)

    def init_mining_mgr(self):
        from .mgr.mining import MiningMgr
        self.mining_mgr = MiningMgr(self)
        self.stop_mgrs.append(self.mining_mgr)

    def init(self):
        #定时器
        from corelib.common import TimerSet
        self.timer_set = TimerSet(self)
        self.stop_mgrs.append(self.timer_set)
        #缓存,缓存数量待优化
        self.caches = TimeMemCache(size=500, name='game.caches')

        self.init_snss()
        self.init_res_mgr()
        self.init_gm_mgr()
        self.init_player_mgr()
        self.init_scene_mgr()
        self.init_task_mgr()
        self.init_mining_mgr()

        from game.mgr.deep import DeepMgr
        self.deep_mgr = DeepMgr(self)
        self.stop_mgrs.append(self.deep_mgr)

        from game.mgr.fish import FishMgr
        self.fish_mgr = FishMgr(self)
        self.stop_mgrs.append(self.fish_mgr)

        from game.mgr.coinstree import CTreeMgr
        self.ctree_mgr = CTreeMgr(self)
        self.stop_mgrs.append(self.ctree_mgr)

        from game.mgr.tbox import TboxMgr
        self.tbox_mgr = TboxMgr(self)
        self.stop_mgrs.append(self.tbox_mgr)

        from game.mgr.hfate import HitFateMgr
        self.hfate_mgr = HitFateMgr(self)
        self.stop_mgrs.append(self.hfate_mgr)

        from game.mgr.bftask import BfTaskMgr
        self.bftask_mgr = BfTaskMgr(self)
        self.stop_mgrs.append(self.bftask_mgr)

        from game.mgr.fete import FeteMgr
        self.fete_mgr = FeteMgr(self)
        self.stop_mgrs.append(self.fete_mgr)

        #'神秘商人'
        from game.mgr.shop import ShopMgr
        self.shop_mgr = ShopMgr(self)
        self.stop_mgrs.append(self.shop_mgr)

        from game.mgr.social import SocialMgr
        self.social_mgr = SocialMgr(self)
        self.stop_mgrs.append(self.social_mgr)

        from game.achievement.achi_mgr import AchievementMgr
        self.achi_mgr = AchievementMgr(self)
        self.stop_mgrs.append(self.achi_mgr)

        from game.mgr.gem import GemMgr
        self.gem_mgr = GemMgr(self)
        self.stop_mgrs.append(self.gem_mgr)

        from game.mgr.day_lucky import DayLuckyMgr
        self.day_lucky_mgr = DayLuckyMgr(self)
        self.stop_mgrs.append(self.day_lucky_mgr)

        from game.mgr.day_sign import DaySignMgr
        self.day_sign_mgr = DaySignMgr(self)
        self.stop_mgrs.append(self.day_sign_mgr)

        #玩家vip属性管理
        from game.mgr.vipattr import PlayerVipAttrMgr
        self.vip_attr_mgr = PlayerVipAttrMgr(self)
        self.stop_mgrs.append(self.vip_attr_mgr)

        #奖励奖励管理
        from game.mgr.reward import RewardMgr
        self.reward_mgr2 = RewardMgr(self)
        self.stop_mgrs.append(self.reward_mgr2)

    def start(self):
        if not self.stoped:
            return
        self.stoped = False
        self.timer_set.start()
        #每天定时清理
        self.cron_clean_data_zero(inited=True)  #0点
        for mgr in self.stop_mgrs:
            try:
                if not hasattr(mgr, 'start'):
                    continue
                mgr.start()
            except StandardError as e:
                log.log_except('stop mgr(%s) error:%s', mgr, e)

    def _stop(self):
        pass

    def stop(self):
        """ 进程退出 """
        if self.stoping:
            return
        self.stoping = True
        log.info(u'game模块停止')
        Game.parent_stoped = bool(os.environ.get('PARENT_STOPED', False))

        def _stop_func():
            try:
                self._stop()
            except StandardError:
                log.log_except()

            for mgr in self.stop_mgrs:
                try:
                    mgr.stop()
                except StandardError as e:
                    log.log_except('stop mgr(%s) error:%s', mgr, e)
            sleep(0.5)  #允许其它线程切换
            #等待其它完成
            while self.stop_lock.wait() < self.lock_count:
                sleep(0.1)

        try:
            #保证在30分钟内处理完
            with Timeout.start_new(60 * 30):
                _stop_func()
        except:
            log.log_except()
        self.stoped = True

    def cron_clean_data_zero(self, inited=False):
        """
        定在每天凌晨0点初始化的处理
        """
        now = datetime.datetime.now()
        refresh_time = custom_today(hour=0, minute=0)
        refresh_time += ONE_DAY_DELTA
        sleep_times = (refresh_time - now).seconds + 5
        self.timer_set.call_later(sleep_times, self.cron_clean_data_zero)
        #执行游戏逻辑刷新
        if not inited:
            log.info(u"每日0点定时刷新开始")
            spawn(self.on_cron_clean_data_zero)


#            for player in self.scene_mgr.players.itervalues():
#                spawn(self.on_player_cron_clean_data_zero, player)

    def on_cron_clean_data_zero(self):
        """ channel,battle都需要的0点清理 """
        pass

    def on_player_cron_clean_data_zero(self, player):
        """ channel,battle都需要的0点角色清理 """
        pass

    def is_gm(self, uid):
        """ 根据用户名,检查是否gm """
        from game.player.player import UserData
        return UserData.is_gm(uid)

    def sync_exec(self, func, args, _pickle=True):
        """ 由该进程执行func, func内独立使用各自的lock,保证同步执行 """
        try:
            if args:
                return func(*args)
            return func()
        except:
            log.log_except()
            raise
Example #11
0
class SubPlayerMgr(BaseGameMgr, DictExport):
    """ 逻辑进程使用的角色管理类 """
    _rpc_name_ = 'player_mgr'
    #定时保存时间 5分钟
    _SAVE_TIME_ = 60 * 5

    def __init__(self, game):
        BaseGameMgr.__init__(self, game)
        self._svr = None
        self._keys = TimeMemCache(size=1000,
                                  default_timeout=5 * 60,
                                  name='player_mgr._keys')
        self.users = {}
        self.players = {}
        self.others = TimeMemCache(size=1000,
                                   default_timeout=(self._SAVE_TIME_ - 1),
                                   name='player_mgr.others')
        self._game.reg_obj(self)
        self._loop_task = None

    def _rpc_mgr_init(self, rpc_mgr):
        if not self._game:
            return
        self.key = rpc_mgr.reg_sub_mgr(self,
                                       self._game.name,
                                       self._game.get_addr(),
                                       _proxy=True)

    def start(self):
        self._svr = new_stream_server_by_ports('0.0.0.0', config.player_ports,
                                               self._on_client_accept)
        self.address = config.inet_ip, self._svr.address[1]
        self.key = Game.rpc_player_mgr.reg_sub_mgr(self,
                                                   self._game.name,
                                                   self._game.get_addr(),
                                                   _proxy=True)
        Game.sub_rpc_mgr_init(Game.rpc_player_mgr, self._rpc_mgr_init)
        self._loop_task = spawn(self._loop)

    def stop(self):
        if not BaseGameMgr.stop(self):
            return
        if self._svr:
            self._svr.stop()
            self._svr = None
        if self._loop_task:
            self._loop_task.kill(block=False)
            self._loop_task = None
        spawns(lambda u: u.logout(), [(u, ) for u in self.users.itervalues()])
        if not Game.parent_stoped:
            Game.rpc_player_mgr.unreg_sub_mgr(self.key, _no_result=True)

    def _on_client_accept(self, sock, addr):
        log.debug(u'client发起连接(%s)', addr)
        user = User()
        user.start(self, sock, addr)
        user.wait_for_init()

    def _loop(self):
        """ 定时保存等处理 """
        stime = 30
        while 1:
            sleep(stime)
            try:
                for pid in self.players.keys():
                    p = self.players.get(pid)
                    if p is None or not p.logined:
                        continue
                    #是否需要定时保存
                    if p.save_time + self._SAVE_TIME_ <= time.time():
                        p.save()
            except:
                log.log_except()

    @property
    def global_count(self):
        """ 全服在线玩家总数 """
        return Game.rpc_player_mgr.get_count()

    @property
    def count(self):
        return len(self.users)

    @classmethod
    def cls_get_player_proxy(cls, pid, addr=None, local=1):
        if addr is None:
            addr = Game.get_addr()
        if local:
            proxy = DictItemProxy(cls._rpc_name_,
                                  dict_name='players',
                                  key=pid,
                                  addr=addr)
        else:
            proxy = get_proxy_by_addr(addr, cls._rpc_name_, DictItemProxy)
            proxy.dict_name = 'players'
            proxy.key = pid
        return proxy

    def get_player_proxy(self, pid, check=True):
        if check and pid not in self.players:
            raise ValueError('player id(%d) not in player_mgr' % pid)
        return self.cls_get_player_proxy(pid)

    def logon(self, user_name, uid, key, sns_type):
        """ logon服务器发来的用户登录请求 """
        if self._game.stoped:
            return False, ''
        #log.debug('subPlayerMgr.logon:%s, %s, %s', user_name, uid, key)
        self._keys.set(uid, (uid, key, sns_type))
        return True, self.address

    def check_logon(self, uid, key):
        """ 检查角色登录情况,
        返回: 成功(uid, sns_type)
            失败(False, 0)
        """
        v = self._keys.delete(uid)
        #log.debug('subPlayerMgr.check_logon:%s, %s', user_name, v)
        if v is not None and v[1] == key:
            return v[0], v[2]
        return False, 0

    def add_user(self, user):
        self.users[user.data.id] = user

    def del_user(self, user):
        return self.users.pop(user.data.id, None)

    def del_user_by_id(self, uid):
        """ 全局管理器调用,强制玩家退出 """
        user = self.users.get(uid)
        if not user:
            return
        user.logout()

    def add_player(self, player):
        """ 玩家进入游戏 """
        pid = player.data.id
        rs = Game.rpc_player_mgr.add(self.key, pid, player.data.name,
                                     player.data.rid, player.data.uid)
        if not rs:
            return False
        self.players[pid] = player
        log.debug('sub_player_mgr.add_player:%s', pid)
        return True

    def logon_player(self, player):
        self.safe_pub(MSG_LOGON, player)

    def logoned_player(self, player):
        """ 已经发送初始化数据给前端,触发已登陆消息,其他模块可以正常发消息给前端 """
        self.safe_pub(MSG_LOGONED, player)

    def del_player(self, player):
        """ 玩家退出 """
        pid = player.data.id
        if pid not in self.players:
            return
        log.debug('sub_player_mgr.del_player:%s', pid)
        assert self.players[pid] == player, 'player != p'
        self.players.pop(pid)
        Game.rpc_player_mgr.delete(self.key, pid, player.data.uid)
        self.safe_pub(MSG_LOGOUT, player)

    def del_player_by_id(self, pid):
        """ 玩家退出,由全局管理器调用 """
        player = self.players.get(pid)
        if player is None:
            return
        player.user.logout()

    def get_player(self, pid):
        return self.players.get(pid)

    def send_msg_to_all(self, msg):
        data = prepare_send(msg)
        for user in self.users.itervalues():
            user.send_msg(data)

    def iter_players(self, pids):
        if pids is None:
            pids = self.players.keys()
        for pid in pids:
            p = self.players.get(pid)
            if p is None:
                continue
            yield pid, p

    def player_mails(self, pids, mids):
        """ 玩家接受邮件 """
        for pid, p in self.iter_players(pids):
            mid = mids.get(pid)
            if not mid:
                continue
            try:
                p.mail.recv_mails(mid)
            except:
                log.log_except()

    def get_partpids_by_level(self, level, start_chapter=False):
        """ 获取大于等于指定等级的所有玩家 start_chapter 是否包括初章"""
        pids = []
        for pid, player in self.iter_players(None):
            if player.data.level >= level:
                if start_chapter and player.data.chapter == constant.CHATER_START:
                    continue
                pids.append(pid)
        return pids

    def player_send_msg(self, pids, msg):
        data = prepare_send(msg)
        for pid, p in self.iter_players(pids):
            p.send_msg(data)

    def exec_players_func(self, pids, func, _pickle=True):
        """ 在玩家所在的逻辑进程执行方法,用于一般的玩家操作 """
        rs = {}
        for pid, p in self.iter_players(pids):
            try:
                rs[pid] = func(p)
            except Exception:
                log.log_except()
        return rs

    def look(self, pid):
        """ 查看其它玩家信息 """
        return self._get_other(pid)

    def _get_other(self, pid, cache=1):
        """ 获取其它玩家信息 """
        if cache:
            v = self.others.get(pid)
            if v is not None:
                return v
        p = self.get_player(pid)
        if not p:
            p = self._game.rpc_player_mgr.get_rpc_player(pid)
        if not p:  #不在线
            p = Player.load_player(pid)
#            p = OtherPlayer.new(pid)
        if not p:
            v = 0, errcode.EC_NOFOUND
        else:
            #先计算出战斗力
            p.init()
            v = 1, p.look()
        self.others.set(pid, v)
        return v
Example #12
0
 def __init__(self):
     setattr(Game, self._rpc_name_, self)
     self.cache = TimeMemCache(default_timeout=10, name='status_mgr.cache')
     self._slock = RLock()
Example #13
0
 def __init__(self):
     self.server_time = 0
     self.servers = None
     self.rpc_caches = TimeMemCache(default_timeout=60)
Example #14
0
class GameServers(object):
    """ 游戏服组管理类 """
    TIMEOUT = 30
    def __init__(self):
        self.server_time = 0
        self.servers = None
        self.rpc_caches = TimeMemCache(default_timeout=60)

    def _init_servers(self):
        """ 初始化游戏服数据 """
        if self.servers and (time.time() - self.server_time < self.TIMEOUT):
            return
        self.server_time = time.time()
        servers = model.logon_store.get_servers(all=1)
        self.servers = dict([(s.sid, s) for s in servers
                if s.status in s.OPEN_STATUSES])

    def get_servers(self):
        self._init_servers()
        return self.servers

    def iter_servers(self, sids=None):
        self._init_servers()
        if sids is None:
            sids = self.servers.keys()
        for sid in sids:
            if sid not in self.servers:
                continue
            s = self.servers.get(sid)
            host, port = s.host, s.port
            log.debug('iter_servers, host:%s, port:%s', host, port)
            rpc_client = with_timeout(3, grpc.get_proxy_by_addr,
                (host, port-1), 'rpc_client',
                timeout_value=None)
            if not rpc_client:
                continue
            #缓存代理类,保持连接一段时间
            self.rpc_caches.set(sid, rpc_client)
            yield sid, rpc_client


    def get_players(self, sns, sns_id, sids=None):
        """ 获取账号在对应服务器上的角色列表 """
        rs = {}
        def _players(rpc_client):
            try:
                return with_timeout(3, rpc_client.user_players,
                    sns, sns_id,
                    timeout_value=None)
            except:
                return None

        for sid, rpc_client in self.iter_servers(sids):
            log.debug('get_players, sid:%s', sid)
            if not rpc_client:
                continue
            players = _players(rpc_client)
            log.debug('get_players, sid:%s, players:%s', sid, players)
            if not players:
                continue
            rs[str(sid)] = players
        return rs
Example #15
0
class StatusMgr(object):
    """ 单服状态管理类 """
    _rpc_name_ = 'rpc_status_mgr'
    def __init__(self):
        setattr(Game, self._rpc_name_, self)
        self.cache = TimeMemCache(default_timeout=10, name='status_mgr.cache')
        self._slock = RLock()

    def _get(self, key):
        querys = dict(key=key)
        values = Game.rpc_store.query_loads(TN_STATUS, querys)
        if values:
            return values[0]['id'], values[0]['value']
        return None, None

    def get(self, key, default=None):
        """ 获取服状态 """
        _id, v = self.cache.get(key, (None, None))
        if v is not None:
            return v
        with self._slock:
            _id, v = self._get(key)
            if _id is None:
                return default
            self.cache.set(key, (_id, v))
        return v

    def _set(self, id, key, value):
        if id is None:
            id = Game.rpc_store.insert(TN_STATUS, dict(key=key, value=value))
            self.cache.set(key, (id, value))
        else:
            self.cache.set(key, (id, value))
            Game.rpc_store.save(TN_STATUS, dict(id=id, key=key, value=value))
        return id

    def set(self, key, value, orig_value=None):
        """ 设置服状态,
        orig_value=None 强制覆盖
        失败返回False """
        with self._slock:
            _id, v = self.cache.get(key, (None, None))
            if v is not None and orig_value is not None and orig_value != v:
                return False
            if v is None or _id is None:
                _id, v = self._get(key)
            if v is not None and orig_value is not None and v != orig_value:
                return False
            self._set(_id, key, value)
            return True

    def update_dict(self, key, adict):
        """更新 值 是字典类型的数据"""
        with self._slock:
            _id, v = self._get(key)
            if v is None:
                v = adict
            else:
                v.update(adict)
            self._set(_id, key, v)

    def _add(self, key, num=None):
        """ num=None时,清零 """
        with self._slock:
            _id, v = self.cache.get(key, (None, None))
            if _id is not None:
                v += num if num is not None else -v
                self.cache.set(key, (_id, v))
            else:
                _id, v = self._get(key)
                if v is None:
                    v = 0
                v += num if num is not None else -v
            self._set(_id, key, v)

    def inc(self, key, num=1):
        """ key对应的值+1 """
        spawn(self._add, key, num)

    def dec(self, key, num=-1):
        spawn(self._add, key, num)
    
    def zero(self, key):
        """ 清零 """
        spawn(self._add, key)

    def get_config(self, key, default=None):
        """ 获取gconfig全局配置 """
        return Game.rpc_res_store.get_config(key, default=default)
Example #16
0
class ArenaMgr(object):
    """ 竞技场管理类 """
    _rpc_name_ = 'rpc_arena_mgr'
    PLAYER_TIMEOUT = 60 * 0.1
    BOT_RANK = 1000  #机器人预留排名数

    def __init__(self):
        self.arenas = TimeMemCache(
            size=CACHE_SIZE,
            default_timeout=CACHE_TIME)  #玩家信息 {pid:PlayerArena}
        self.rivals = TimeMemCache(
            size=CACHE_SIZE, default_timeout=CACHE_TIME)  # {pid:[name, rid]}
        self.rewards = HitMemCache(size=CACHE_SIZE)
        self.bots = {}

        self._lock = RLock()
        self.stoped = True
        self._reward_task = None
        self._auto_start_task = None
        self.clear()
        app.sub(MSG_START, self.start)
        self._active_mul = 1

        self.sorts = {}  #数据库中保存,方便修改 {sort:id}

    def _get_status(self):
        status = Game.rpc_status_mgr.get(ARENA_STATUS)
        if status is None:
            self.arena_status = DEFAULT_STATUS
            return DEFAULT_STATUS
        return status

    def _set_status(self, value):
        Game.rpc_status_mgr.set(ARENA_STATUS, value)

    arena_status = property(_get_status, _set_status)

    def _get_is_start(self):
        """ 竞技场是否开启 """
        return self.arena_status['status']

    def _set_is_start(self, value):
        arena_status = self.arena_status
        arena_status['status'] = int(bool(value))
        self.arena_status = arena_status

    #竞技场是否处于启动状态
    is_start = property(_get_is_start, _set_is_start)

    def _get_reward_time(self):
        """ 获取上一次奖励时间 """
        return self.arena_status['rt']

    def _set_reward_time(self, value):
        arena_status = self.arena_status
        arena_status['rt'] = int(value)
        self.arena_status = arena_status

    reward_time = property(_get_reward_time, _set_reward_time)

    def clear(self):
        self.ranks = []  #排行榜 [pid, ...]
        self.pid2ranks = {}  # {pid:rk}

    def reload(self):
        """ 重新加载资源数据 """
        self.rewards.clear()
        init_setting()

    def start(self, init=False):
        if not self.stoped:
            return
        init_setting()
        if not self.is_start:  #开启自动启动线程
            if self._auto_start_task is None:
                self._auto_start_task = spawn_later(0, self._auto_start)
            return
        log.debug(u'arena_mgr start!')
        spawn(self.lood_save)
        Game.setting_mgr.sub(MSG_RES_RELOAD, self.reload)
        if init:
            self.init()
        else:
            self.load()
        self.arena_reward()
        Game.chat_mgr.sys_send(language.ARENA_START)
        self.stoped = False

    def stop(self):
        if self.stoped:
            return
        self.stoped = True
        self.save()
        if self._reward_task:
            self._reward_task.kill(block=False)
            self._reward_task = None

    def _auto_start(self):
        global arena_auto_start, arena_level
        sleep_times = 60 * 5
        log.info('arena auto_start(%s) running', arena_auto_start)
        while 1:
            sleep(sleep_times)
            c = PlayerData.count({FN_PLAYER_LEVEL: {FOP_GTE: arena_level}})
            if c >= arena_auto_start:
                log.info('arena auto start:%d', c)
                self.init()
                self.is_start = True
                self.start()
                self._auto_start_task = None
                return

    def lood_save(self):
        """ 保存 """
        while 1:
            #保存排名
            sleep(SAVE_RANK_TIME)
            self.save()

    def save(self):
        """ 保存 """
        #保存排名
        log.debug('------arena-rank-save---------')
        if not self.ranks:
            return
        num = len(self.ranks) / SAVE_PER_LEN + 1
        for i in xrange(num):
            start = i * SAVE_PER_LEN
            end = start + SAVE_PER_LEN
            pids = self.ranks[start:end]
            sort = i + 1
            if sort in self.sorts:
                dic = dict(id=self.sorts[sort], sort=sort, pids=pids)
                Game.rpc_store.save(TN_ARENA_RANKS, dic)
            else:
                dic = dict(id=sort, sort=sort, pids=pids)
                insert_id = Game.rpc_store.insert(TN_ARENA_RANKS, dic)
                self.sorts[sort] = insert_id
        log.debug('-----arena-rank-save--ok-----')

    @wrap_lock
    def init(self):
        """ 初始化竞技场数据:根据30级以上的玩家战斗力排名,得到竞技场排名 """
        log.warn(u"初始化竞技场")
        self.clear()
        #删除记录
        Game.rpc_store.deletes(TN_ARENA_RANKS)
        Game.rpc_store.deletes(TN_P_ARENA)
        #Game.rpc_store.insert(TN_ARENA_RANK, {FN_ID:0, FN_NEXT:END})
        #根据30级以上玩家战斗力排名
        CBEs = [(i[FN_P_ATTR_PID], i.get(FN_P_ATTR_CBE, index))
                for index, i in enumerate(PlayerAttr.get_CBE_ranks())]
        levels = PlayerData.get_players_levels(None)
        #插入机器人
        for i in xrange(self.BOT_RANK):
            self.update_rank(END, END - (i + 1))

        #真实玩家
        for pid, CBE in CBEs:
            if pid not in levels or levels[pid] < arena_level:
                continue
            self.update_rank(END, pid)

    @wrap_lock
    def load(self):
        """ 使用新方法的加载 """
        self.clear()
        ranks = Game.rpc_store.load_all(TN_ARENA_RANKS)
        if ranks is None:
            return
        rank_sort = sorted(ranks, key=lambda dic: dic[KEY_SORT])
        for rank in rank_sort:
            self.ranks.extend(rank[KEY_PIDS])
        for index, pid in enumerate(self.ranks):
            rk = index + 1
            self.pid2ranks[pid] = rk

    def get_rank(self, pid):
        return self.pid2ranks.get(pid)

    def get_pid(self, rank):
        if rank < 1 or rank > len(self.ranks):
            return 0
        return self.ranks[rank - 1]

    def update_rank(self, rank, pid):
        """ 更新排名 """
        orank = self.pid2ranks.get(pid, END)
        assert rank <= orank, ValueError('update_rank error:%s <= %s' %
                                         (rank, orank))
        #内存数据修改, rank 必须 <= orank
        if rank == END:
            self.ranks.append(pid)
            self.pid2ranks[pid] = len(self.ranks)
        else:
            self.ranks.pop(orank - 1)
            self.ranks.insert(rank - 1, pid)
            for index, pid in enumerate(self.ranks[rank - 1:orank]):
                self.pid2ranks[pid] = rank + index

    def init_player(self, pid):
        """ 加载并返回玩家信息 """
        parena = self.arenas.get(pid, add_time=CACHE_TIME)
        if parena is None:
            parena = PlayerArena(pid)
            self.arenas.set(pid, parena)
            data = Game.rpc_store.load(TN_P_ARENA, pid)
            if data is not None:
                parena.update(data)
                parena.pass_day()
            else:
                parena.modify()
            if pid not in self.pid2ranks:
                with self._lock:
                    self.update_rank(END, pid)
        return parena

    def _get_rivals(self, pids):
        """ 批量获取对手信息 """
        rs = {}
        ids = []
        for i in pids:
            rival = self.rivals.get(i)
            if rival:
                rs[i] = rival
            elif is_bot(i):
                bot = self.get_bot(i)
                rs[i] = bot._bot_rival
            else:
                ids.append(i)
        if ids:
            onlines, nids = Game.rpc_player_mgr.get_player_infos(ids, CBE=1)
            #nids = Game.rpc_player_mgr.get_name_rids(ids)
            self.rivals.update(nids)
            rs.update(nids)
        return rs

    get_rival_infos = _get_rivals

    def get_name(self, pid):
        rival = self.rivals.get(pid)
        if rival:
            return rival[0]
        else:
            rs = self._get_rivals([pid])
            return rs[pid][0]

    def get_rivals(self, parena):
        """ 获取对手列表 """
        base_rk = parena.rank
        base_pid = parena.data.id
        ranks = arena_ranks(base_rk)
        ids = []
        rks = []
        for r in ranks[1:]:
            if ranks[0] == RANK_PREV_R:
                rk = base_rk - int(r)
            elif ranks[0] == RANK_PREV_EQ:
                rk = int(r)
            else:
                raise ValueError('ARENA_RANK error:%s' % ranks)
            rks.append(rk)
            pid = self.get_pid(rk)
            if pid:
                ids.append(pid)
        if base_pid not in ids:
            rks.append(base_rk)
            ids.append(base_pid)
        rivals = self._get_rivals(ids)
        rs = []
        for index, i in enumerate(ids):
            rival = rivals.get(i)
            if not rival:
                continue
            CBE = 0 if rival[IPI_IDX_CBE] is None else rival[IPI_IDX_CBE]
            rs.append(
                dict(rk=rks[index],
                     pid=i,
                     n=rival[IPI_IDX_NAME],
                     rid=rival[IPI_IDX_RID],
                     level=rival[IPI_IDX_LEVEL],
                     CBE=CBE))
        return rs

    def get_bot(self, bid):
        assert is_bot(bid), ValueError('bid(%s) is not bot' % bid)
        try:
            return self.bots[bid]
        except KeyError:
            #从数据库中随机选择某等级区间的玩家作为基础数据
            key = 'arena_bot_pids'
            pids = Game.gcaches.get(key)
            if not pids:
                pids = PlayerData.get_level_pids(arena_level, arena_level + 10)
                Game.gcaches.set(key, pids, timeout=60 * 5)
            pid = random.choice(pids)
            bot = Player.load_player(pid)
            data = bot.data
            data.id = bid
            data.name = Game.res_mgr.get_random_name()
            bot._bot_rival = (data.name, data.rid, data.level,
                              bot.play_attr.CBE)
            self.bots[bid] = bot
            return bot

    def look_bot(self, bid):
        """ 获取机器人信息
        result:rs, info
        """
        bot = self.get_bot(bid)
        try:
            return 1, bot._bot_look
        except AttributeError:
            bot._bot_look = bot.look()
            return 1, bot._bot_look

    @grpc_monitor
    @wrap_arena
    def enter(self, pid, vip, parena=None):
        """ 玩家进入竞技场获取相关信息 """
        msg_dict = parena.enter(vip, self._active_mul)
        msg_dict['rk'] = self.get_rank(pid)
        msg_dict['rivals'] = self.get_rivals(parena)
        return 1, msg_dict

    @grpc_monitor
    @wrap_arena
    def start_arena(self, pid, rival_id, parena=None):
        """ 开始挑战排位,获取被挑战者数据, rk:挑战的玩家id """
        return parena.start_arena(rival_id)

    @grpc_monitor
    @wrap_arena
    def buy_arena(self, pid, c, coin2, parena=None):
        """ 购买次数 """
        cost = c * arena_coin
        if cost > coin2:
            return 0, errcode.EC_COST_ERR
        c = parena.buy(c)
        return 1, (c, cost)

    @grpc_monitor
    @wrap_arena_rival
    @wrap_lock
    def end_arena(self,
                  pid,
                  rid,
                  is_ok,
                  fp_id,
                  vip,
                  parena=None,
                  rival=None,
                  gm=False):
        """ 结束挑战,更新信息
        """
        if not gm and (not rid or rid != parena.rival_id):
            return 0, errcode.EC_VALUE
        if not gm and not parena.cost_arena():
            return 0, errcode.EC_COST_ERR
        parena.rival_id = None
        return self._end_arena(is_ok, parena, rival, fp_id, vip)

    def _end_arena(self, is_ok, parena, rival, fp_id, vip):
        """ 挑战胜利
        挑战类型: 1=挑战胜利, 2=挑战失败, 3=被挑战胜利, 4=被挑战失败
        """
        pid, rpid = parena.data.id, rival.data.id
        pname, rname = self.get_name(pid), self.get_name(rpid)
        parena_rank = self.get_rank(pid)
        rival_rank = self.get_rank(rpid)
        if is_ok:
            if rival_rank < parena_rank:  #排位调整
                self.update_rank(rival_rank, pid)
                parena_rank, rival_rank = rival_rank, rival_rank + 1
                #竞技场第一名广播事件
                if parena_rank == RANK_FIRST:
                    self.safe_pub(MSG_AREA_RANKFIRST, pid, pname, rpid, rname)
            #奖励
            coin, train = arena_rw_succ
            coin, train = parena.reward(vip, coin, train, self._active_mul)
            lt_p, lt_r = LT_SUCC, LT_B_FAIL
        else:
            #奖励
            coin, train = arena_rw_fail
            coin, train = parena.reward(vip, coin, train, self._active_mul)
            lt_p, lt_r = LT_FAIL, LT_B_SUCC
        #战报
        parena.add_log(lt_p, rpid, rname, parena_rank, fp_id)
        rival.add_log(lt_r, pid, pname, rival_rank, fp_id)
        return 1, (coin, train)

    def set_active_reward(self, mul):
        """活动奖励的设置"""
        self._active_mul = mul

    #@property
    #def next_reward_times(self):
    #    """ 到下一次奖励的秒数
    #    :rtype : int
    #    """
    #    reward_time = self.reward_time
    #    zero_time = zero_day_time()
    #    for index, weekday in enumerate(arena_rw_weekdays):
    #        t = week_time(weekday, zero=1)
    #        delay_time = t - zero_time
    #        if delay_time < -60:#前几天
    #            continue
    #        if delay_time < 60:
    #            if not is_pass_day(reward_time):#今天刚奖励完
    #                continue
    #            return 1
    #        return int(t - time.time())+2     #计算可用23:59:59发送奖励必须往后移一点否则一秒会执行多次
    #    #返回下周奖励时间
    #    return int(week_time(arena_rw_weekdays[0], zero=1, delta=1) - time.time())
    #    #raise ValueError('next_reward_times:%s' % str(arena_rw_weekdays))

    @property
    def next_reward_time(self):
        """ 到下一次奖励的具体时间
        :rtype : int
        """
        reward_time = self.reward_time
        zero_time = zero_day_time()
        for index, weekday in enumerate(arena_rw_weekdays):
            t = week_time(weekday, zero=1)
            delay_time = t - zero_time
            if delay_time < 0:  #前几天
                continue
            if delay_time == 0:
                if reward_time == t:  #今天刚奖励完
                    continue
            return t
            #返回下周奖励时间
        return week_time(arena_rw_weekdays[0], zero=1, delta=1)

    def arena_reward(self):
        """ 定时发放奖励 """
        #安装定时器
        #t = self.next_reward_times
        next_time = self.next_reward_time
        times = next_time - time.time() if next_time > time.time() else 0
        times += 10
        log.info('arena_reward after %s times', times)
        self._reward_task = spawn_later(times, self._reward_nomal, next_time)

    def _reward_nomal(self, r_t):
        """
        正常的发放奖励
        """
        global arena_rewards
        self.reward_time = r_t
        #下一个定时发放
        if not self.stoped:
            self.arena_reward()
        self._reward()

    def reward_active(self):
        """
        活动的发放奖励
        """
        if not self.stoped:
            self._reward()
            return
        log.error('%s is stop _reward_active is not send', self)

    def _reward(self):
        """ 发放奖励 """
        log.info(u'竞技场排名:%s', self.ranks[:500])
        #log.info('arena_ranks:%s', self.pid2ranks)

        mail_mgr = Game.mail_mgr
        rw_mail = Game.res_mgr.reward_mails.get(RW_MAIL_ARENA)
        levels = {}
        lv_count = 30  #批量读取等级 global arena_level
        ranks = self.ranks[:]
        log.info('arena_reward:%s', len(ranks))
        for index, pid in enumerate(ranks):
            rank = index + 1
            pids = ranks[index:index + lv_count]
            if pid not in levels:  #批量获取等级
                self._get_rivals(pids)
                rs = PlayerData.get_players_levels(pids)
                if rs:
                    levels.update(rs)
            if pid not in levels:  #玩家不存在
                continue
            rs, items, rid = self.get_reward(rank, levels[pid])
            if not rs:
                break
            #content = rw_mail.content % dict(name=self.get_name(pid), rank=rank)
            content = rw_mail.content % dict(rank=rank)
            mail_mgr.send_mails(pid,
                                MAIL_REWARD,
                                rw_mail.title,
                                RW_MAIL_ARENA,
                                items,
                                param=content,
                                rid=rid)

    @grpc_monitor
    def get_reward(self, rk, level):
        """ 获取排行榜奖励内容 """
        key = (rk, level)
        v = self.rewards.get(key)
        if v:
            return v

        rid = arena_rewards(rk)
        if not rid:
            v = (0, errcode.EC_NOFOUND, 0)
        else:
            reward = Game.reward_mgr.get(rid)
            items = reward.reward(dict(level=level, rank=rk))
            v = (1, items, rid)
        self.rewards.set(key, v)
        return v

    @grpc_monitor
    def get_ranks(self, start, end):
        """ 获取排名列表 """
        #rs = [pid for pid in self.ranks if not is_bot(pid)]
        #return rs[start:end]
        return self.ranks[start:end]

    def gm_add_count(self, pid, c):
        parena = self.init_player(pid)
        parena.buy(c)

    def gm_get_rid_byrank(self, rank):
        """ gm听过竞技场获取排名 """
        if rank > len(self.ranks):
            return
        return self.ranks[rank - 1]

    def gm_change_rank(self, pid, rid, fp_id, vip):
        """ gm改变排行榜等级 """
        self.end_arena(pid, rid, 1, fp_id, vip, gm=True)
Example #17
0
 def __init__(self):
     setattr(Game, self._rpc_name_, self)
     self.cache = TimeMemCache(default_timeout=10, name='report_mgr.cache')
     self.thread_pool = GlobalThreadPool(max_pool_size=5)
     self.report_base_dir = None
     self.report_base_url = None
Example #18
0
class ReportMgr(object):
    """ 战报处理类 """
    _rpc_name_ = 'rpc_report_mgr'
    def __init__(self):
        setattr(Game, self._rpc_name_, self)
        self.cache = TimeMemCache(default_timeout=10, name='report_mgr.cache')
        self.thread_pool = GlobalThreadPool(max_pool_size=5)
        self.report_base_dir = None
        self.report_base_url = None

    def init(self, url, dir):
        self.report_base_dir = dir
        self.report_base_url = url
        if not os.path.exists(self.report_base_dir):
            log.info('mkdir report_base_dir:%s', self.report_base_dir)
            os.makedirs(self.report_base_dir)

    def get_cur_path(self):
        return strftime(fmt='%Y%m')

    @grpc_monitor
    def save(self, type, pids, news, url=None):
        """ 写战报:
        pids: 相关玩家id列表
        news:战报数据
        url:可以指定url, 路径列表如['tbox', 'file_name']
        返回: 战报id
        """
        if url is None:
            url = (self.get_cur_path(), md5(news).hexdigest())
        #目录
        path = os.path.join(self.report_base_dir, *url[:-1])
        if not os.path.exists(path):
            os.makedirs(path)
        file_path = os.path.join(path, url[-1])
        self.thread_pool.addTask(self._save_data, (file_path, news))
        #处理url
        return self._save_message(type, '/'.join(url), pids)

    def _save_data(self, url, news):
        """ 保存战报 """
        #保存数据
        with open(url, 'w') as file:
                file.writelines(news)

    def _save_message(self, type, url, pids):
        """ 保存战报信息 """
        #保存战报信息
        message = {}
        message[REPORT_TYPE] = type
        message[REPORT_URL] = url
        message[REPORT_PIDS] = pids
        message[REPORT_CT] = int(time.time())
        id = Game.rpc_store.insert(TN_F_REPORT, message)
        self.cache.set(id, (id, message))
        return id

    @grpc_monitor
    def get_url(self, id):
        """ 获取战报绝对地址url """
        #获取战报信息
        _id, v = self.cache.get(id, (None, None))
        if v is None:
            #从数据库读取数据
            querys = dict(id=id)
            values = Game.rpc_store.query_loads(TN_F_REPORT, querys)
            if not values:
                return False, None
            v = values[0]
            self.cache.set(id, (id, v))
        url = '%s/%s' % (self.report_base_url, v[REPORT_URL])
        return True, url
Example #19
0
 def __init__(self):
     setattr(Game, self._rpc_name_, self)
     self.cache = TimeMemCache(default_timeout=10, name='status_mgr.cache')
     self._slock = RLock()
Example #20
0
class GameServers(object):
    """ 游戏服组管理类 """
    TIMEOUT = 30

    def __init__(self):
        self.server_time = 0
        self.servers = None
        self.rpc_caches = TimeMemCache(default_timeout=60)

    def _init_servers(self):
        """ 初始化游戏服数据 """
        if self.servers and (time.time() - self.server_time < self.TIMEOUT):
            return
        self.server_time = time.time()
        servers = model.logon_store.get_servers(all=1)
        self.servers = dict([(s.sid, s) for s in servers
                             if s.status in s.OPEN_STATUSES])

    def get_servers(self):
        self._init_servers()
        return self.servers

    def iter_servers(self, sids=None):
        self._init_servers()
        if sids is None:
            sids = self.servers.keys()
        for sid in sids:
            if sid not in self.servers:
                continue
            s = self.servers.get(sid)
            host, port = s.host, s.port
            log.debug('iter_servers, host:%s, port:%s', host, port)
            rpc_client = with_timeout(3,
                                      grpc.get_proxy_by_addr, (host, port - 1),
                                      'rpc_client',
                                      timeout_value=None)
            if not rpc_client:
                continue
            #缓存代理类,保持连接一段时间
            self.rpc_caches.set(sid, rpc_client)
            yield sid, rpc_client

    def get_players(self, sns, sns_id, sids=None):
        """ 获取账号在对应服务器上的角色列表 """
        rs = {}

        def _players(rpc_client):
            try:
                return with_timeout(3,
                                    rpc_client.user_players,
                                    sns,
                                    sns_id,
                                    timeout_value=None)
            except:
                return None

        for sid, rpc_client in self.iter_servers(sids):
            log.debug('get_players, sid:%s', sid)
            if not rpc_client:
                continue
            players = _players(rpc_client)
            log.debug('get_players, sid:%s, players:%s', sid, players)
            if not players:
                continue
            rs[str(sid)] = players
        return rs
Example #21
0
class ReportMgr(object):
    """ 战报处理类 """
    _rpc_name_ = 'rpc_report_mgr'

    def __init__(self):
        setattr(Game, self._rpc_name_, self)
        self.cache = TimeMemCache(default_timeout=10, name='report_mgr.cache')
        self.thread_pool = GlobalThreadPool(max_pool_size=5)
        self.report_base_dir = None
        self.report_base_url = None

    def init(self, url, dir):
        self.report_base_dir = dir
        self.report_base_url = url
        if not os.path.exists(self.report_base_dir):
            log.info('mkdir report_base_dir:%s', self.report_base_dir)
            os.makedirs(self.report_base_dir)

    def get_cur_path(self):
        return strftime(fmt='%Y%m')

    @grpc_monitor
    def save(self, type, pids, news, url=None):
        """ 写战报:
        pids: 相关玩家id列表
        news:战报数据
        url:可以指定url, 路径列表如['tbox', 'file_name']
        返回: 战报id
        """
        if url is None:
            url = (self.get_cur_path(), md5(news).hexdigest())
        #目录
        path = os.path.join(self.report_base_dir, *url[:-1])
        if not os.path.exists(path):
            os.makedirs(path)
        file_path = os.path.join(path, url[-1])
        self.thread_pool.addTask(self._save_data, (file_path, news))
        #处理url
        return self._save_message(type, '/'.join(url), pids)

    def _save_data(self, url, news):
        """ 保存战报 """
        #保存数据
        with open(url, 'w') as file:
            file.writelines(news)

    def _save_message(self, type, url, pids):
        """ 保存战报信息 """
        #保存战报信息
        message = {}
        message[REPORT_TYPE] = type
        message[REPORT_URL] = url
        message[REPORT_PIDS] = pids
        message[REPORT_CT] = int(time.time())
        id = Game.rpc_store.insert(TN_F_REPORT, message)
        self.cache.set(id, (id, message))
        return id

    @grpc_monitor
    def get_url(self, id):
        """ 获取战报绝对地址url """
        #获取战报信息
        _id, v = self.cache.get(id, (None, None))
        if v is None:
            #从数据库读取数据
            querys = dict(id=id)
            values = Game.rpc_store.query_loads(TN_F_REPORT, querys)
            if not values:
                return False, None
            v = values[0]
            self.cache.set(id, (id, v))
        url = '%s/%s' % (self.report_base_url, v[REPORT_URL])
        return True, url
Example #22
0
 def __init__(self):
     setattr(Game, self._rpc_name_, self)
     self.cache = TimeMemCache(default_timeout=10, name='report_mgr.cache')
     self.thread_pool = GlobalThreadPool(max_pool_size=5)
     self.report_base_dir = None
     self.report_base_url = None
Example #23
0
class StatusMgr(object):
    """ 单服状态管理类 """
    _rpc_name_ = 'rpc_status_mgr'

    def __init__(self):
        setattr(Game, self._rpc_name_, self)
        self.cache = TimeMemCache(default_timeout=10, name='status_mgr.cache')
        self._slock = RLock()

    def _get(self, key):
        querys = dict(key=key)
        values = Game.rpc_store.query_loads(TN_STATUS, querys)
        if values:
            return values[0]['id'], values[0]['value']
        return None, None

    def get(self, key, default=None):
        """ 获取服状态 """
        _id, v = self.cache.get(key, (None, None))
        if v is not None:
            return v
        with self._slock:
            _id, v = self._get(key)
            if _id is None:
                return default
            self.cache.set(key, (_id, v))
        return v

    def _set(self, id, key, value):
        if id is None:
            id = Game.rpc_store.insert(TN_STATUS, dict(key=key, value=value))
            self.cache.set(key, (id, value))
        else:
            self.cache.set(key, (id, value))
            Game.rpc_store.save(TN_STATUS, dict(id=id, key=key, value=value))
        return id

    def set(self, key, value, orig_value=None):
        """ 设置服状态,
        orig_value=None 强制覆盖
        失败返回False """
        with self._slock:
            _id, v = self.cache.get(key, (None, None))
            if v is not None and orig_value is not None and orig_value != v:
                return False
            if v is None or _id is None:
                _id, v = self._get(key)
            if v is not None and orig_value is not None and v != orig_value:
                return False
            self._set(_id, key, value)
            return True

    def update_dict(self, key, adict):
        """更新 值 是字典类型的数据"""
        with self._slock:
            _id, v = self._get(key)
            if v is None:
                v = adict
            else:
                v.update(adict)
            self._set(_id, key, v)

    def _add(self, key, num=None):
        """ num=None时,清零 """
        with self._slock:
            _id, v = self.cache.get(key, (None, None))
            if _id is not None:
                v += num if num is not None else -v
                self.cache.set(key, (_id, v))
            else:
                _id, v = self._get(key)
                if v is None:
                    v = 0
                v += num if num is not None else -v
            self._set(_id, key, v)

    def inc(self, key, num=1):
        """ key对应的值+1 """
        spawn(self._add, key, num)

    def dec(self, key, num=-1):
        spawn(self._add, key, num)

    def zero(self, key):
        """ 清零 """
        spawn(self._add, key)

    def get_config(self, key, default=None):
        """ 获取gconfig全局配置 """
        return Game.rpc_res_store.get_config(key, default=default)
Example #24
0
 def __init__(self):
     self.server_time = 0
     self.servers = None
     self.rpc_caches = TimeMemCache(default_timeout=60)
Example #25
0
class GPlayerMgr(object):
    """ 联合进程使用的总角色管理类 """
    _rpc_name_ = 'rpc_player_mgr'
    _rpc_attr_pre = 'rc_'
    TIME_OUT = 0.1

    def __init__(self):
        setattr(Game, self._rpc_name_, self)
        self.max_players = config.max_players
        self.logic_players = config.logic_players
        self._users = {}
        self._players = {}
        self._sub_mgrs = {}
        self.mgr2addrs = {}
        self.logons = TimeMemCache(size=10000,
                                   default_timeout=2,
                                   name='rpc_player_mgr.logons')
        #        self.names = TimeMemCache(size=10000, default_timeout=1*30) #缓存保证不重名
        self.name2pids = {}
        self.pid2names = {}
        self._name_lock = RLock()
        self._new_player_lock = RLock()
        self.names4ad = {}
        self.overload_time = 0
        self._debug_ips = None
        self._debug_status = False
        self._area_url = None
        self._area_legal = None
        import app
        from game.base import msg_define
        app.sub(msg_define.MSG_START, self.start)

    def start(self):
        self._svr = new_stream_server(config.player_addr,
                                      self._on_client_accept)
        self.sns_client = SNSClient(*config.logon_url)
        from game.base.msg_define import MSG_RES_RELOAD
        Game.res_mgr.sub(MSG_RES_RELOAD, self.load)
        Game.mail_mgr.start_expire_mail()
        self.load()

    def load(self):
        self._area_url = None
        self._area_legal = None
        op_lis = Game.rpc_status_mgr.get_config(GF_AREA_URLS)
        if not op_lis:
            return
        self._area_url = tuple(op_lis[:3])
        self._area_legal = op_lis[-1]

        data = Game.rpc_status_mgr.get(constant.STATUS_DEBUG_FT)
        if data:
            self._debug_ips = data['ip'].split(",")
            self._debug_status = bool(data['status'])

    def _on_client_accept(self, sock, addr):
        """ 处理玩家登陆请求 """
        log.debug(u'client发起连接(%s)', addr)
        _rpc = ClientRpc(sock, addr, self)
        _rpc.call_link_rpc = True
        _rpc.start()
        sleep(120)
        _rpc.stop()  #该链接只用于登录接口,之后断开

    def on_close(self, rpcobj):
        pass

    def reg_sub_mgr(self, rpc_sub_mgr, sub_name, addr, _proxy=True):
        log.info('reg_player_mgr:%s', sub_name)
        self._sub_mgrs[sub_name] = [rpc_sub_mgr, set()]
        self.mgr2addrs[sub_name] = addr
        return sub_name

    def unreg_sub_mgr(self, sub_mgr_id, _no_result=True):
        log.info('unreg_player_mgr:%s', sub_mgr_id)
        self._sub_mgrs.pop(sub_mgr_id, None)
        self.mgr2addrs.pop(sub_mgr_id, None)

    def get_sub_mgr(self, pid):
        """ 获取玩家所在进程的player_mgr对象 """
        mid = self._players.get(pid)
        if not mid:
            return 0, None
        sub_mgr_ids = self._sub_mgrs.get(mid)
        if not sub_mgr_ids:
            return 0, None
        return mid, sub_mgr_ids[0]

    @wrap_pickle_result
    def get_sub_game(self, pid):
        """ 获取玩家所在进程的game对象 """
        mid, sub_mgr = self.get_sub_mgr(pid)
        if not mid:
            return
        addr = self.mgr2addrs.get(mid)
        return get_obj(addr, 'game')

    @grpc_monitor
    def pre_add(self, pid, uid):
        """ 玩家预备登陆,为防止重复,先踢在线的玩家 """
        old_mid, sub_mgr = self.get_sub_mgr(pid)
        if sub_mgr:
            sub_mgr.del_player_by_id(pid)
            self.delete(old_mid, pid, uid)
            return 1
        if not uid in self._users:
            return 1
        mid, _ = self._users[uid]
        sub_mgr = self._sub_mgrs[mid]
        sub_mgr[0].del_user_by_id(uid)
        return 1

    @grpc_monitor
    def add(self, mid, pid, name, rid, uid):
        """ 玩家登陆,防止在短时间内重复登录 """
        self._add_name_id(pid, name, rid)
        if self.logons.get(pid):
            log.info(u'禁止玩家(%s-%s)短时登录', pid, name)
            return False
        self.logons.set(pid, 1)
        self._users[uid] = mid, pid
        self._players[pid] = mid
        self._sub_mgrs[mid][1].add(pid)
        self.safe_pub(MSG_LOGON, pid)
        return True

    @grpc_monitor
    def delete(self, mid, pid, uid):
        """ sub_mgr调用,通知玩家退出 """
        self._users.pop(uid, None)
        self._players.pop(pid, None)
        if mid in self._sub_mgrs:
            pids = self._sub_mgrs[mid][1]
            if pid in pids:
                pids.remove(pid)
        self.safe_pub(MSG_LOGOUT, pid)

    @property
    def count(self):
        return len(self._players)

    def get_count(self):
        return self.count

    def have(self, pid):
        return pid in self._players

    def _add_name_id(self, pid, name, rid):
        if pid in self.pid2names:
            return
        self.name2pids[name] = pid
        self.pid2names[pid] = (name, rid)

    def change_name(self, pid, name, rid):
        """
        改名
        """
        if pid not in self.pid2names:
            return False, errcode.EC_VALUE
        self.del_player(pid)
        self.name2pids[name] = pid
        self.pid2names[pid] = (name, rid)
        return True, None


#    def valid_name(self, name):
#        """ 检查角色名是否没重复,可以用来新建角色 """
#        with self._name_lock:
#            pid = self.names.get(name)
#            if pid is not None:
#                return False
#            rs = Game.rpc_store.values(TN_PLAYER, ['name'], dict(name=name))
#            if rs:
#                pid = rs[0]['id']
#                self.names.set(name, pid)
#                return False
#            self.names.set(name, 0)
#            return True

    def get_id_by_name(self, name):
        """ 根据名称获取对应玩家id """
        try:
            return self.name2pids[name]
        except KeyError:
            pid_rid = PlayerData.name_to_id(name)
            if pid_rid is None:
                return
            self._add_name_id(pid_rid[0], name, pid_rid[1])
            return pid_rid[0]

    def get_name_by_id(self, pid, rid=0):
        """ 查询pid,
        rid: 1 一起查询主配将id
        return:
           name,
           name, rid
        """
        try:
            if rid:
                return self.pid2names[pid]
            return self.pid2names[pid][0]
        except KeyError:
            name_rid = PlayerData.id_to_name(pid)
            if name_rid is None:
                return
            self._add_name_id(pid, name_rid[0], name_rid[1])
            if rid:
                return name_rid
            return name_rid[0]

    def get_names(self, ids):
        """ 获取玩家名列表 """
        rs = {}
        for i in ids:
            n = self.get_name_by_id(i)
            if n is None:
                continue
            rs[i] = n
        return rs

    def get_name_rids(self, ids):
        """ 获取玩家名rid列表 """
        rs = {}
        for i in ids:
            n = self.get_name_by_id(i, rid=1)
            if n is None:
                continue
            rs[i] = n
        return rs

    def get_player_infos(self, pids, CBE=0):
        """ 获取玩家信息
        返回: onlines, {pid:(name, rid, level, CBE)}
        """
        onlines = self.get_online_ids(pids)
        rs = {}
        #等级
        if CBE:
            levels = self.exec_players_func(onlines,
                                            _get_level_CBE,
                                            has_result=1,
                                            _pickle=True)
        else:
            levels = self.exec_players_func(onlines,
                                            _get_level,
                                            has_result=1,
                                            _pickle=True)
        off_ids = set(pids).difference(levels.keys())
        if off_ids:
            off_lvs = PlayerData.get_players_levels(off_ids, CBE=CBE)
            if off_lvs:
                levels.update(off_lvs)

        for pid in pids:
            n_rid = self.get_name_by_id(pid, rid=1)
            if not n_rid:
                continue
            if CBE:
                lv, cbe = levels.get(pid, (1, 0))
                rs[pid] = (n_rid[0], n_rid[1], lv, cbe)
            else:
                rs[pid] = (n_rid[0], n_rid[1], levels.get(pid, 1))
        return onlines, rs

    def get_pids_by_level(self, level, start_chapter=False):
        """ 获取大于等于指定等级的所有在线pid """
        all_pids = []
        for sub_mgr in self._sub_mgrs.itervalues():
            player_mgr = sub_mgr[0]
            pids = player_mgr.get_partpids_by_level(level, start_chapter)
            all_pids.extend(pids)
        return all_pids

    def get_player_detail(self, pids, cols):
        """ 返回玩家详细信息 """
        return PlayerData.get_players_values(pids, cols)

    def get_user_detail_by_playername(self, name, *argv, **kw):
        """ 返回玩家详细信息 """
        return PlayerData.userinfo_from_name(name, *argv, **kw)

    @grpc_monitor
    def get_onlines(self, start, end, name=0, rid=0):
        """ 返回在线玩家列表,
        返回 根据传入的参数:
            默认: [pid, ....]
            name=1: [(pid, name), ....]
            rid=1: [(pid, name, rid), ...]
            level=1: [(pid, name, rid, level), ...]
        """
        rs = []
        for index, pid in enumerate(self._players.iterkeys()):
            if index < start:
                continue
            if index >= end:
                break
            if name or rid:
                n_rid = self.get_name_by_id(pid, rid=1)
            if rid:
                rs.append((pid, n_rid[0], n_rid[1]))
            elif name:
                rs.append((pid, n_rid[0]))
            else:
                rs.append(pid)
        return rs

    @grpc_monitor
    def get_online_ids(self, pids=None, random_num=None):
        """ 返回在线的玩家id列表,
        pids: 查询的玩家列表,返回在线的ids
        random:整形, 随机选择random个pid返回
        """
        if random_num is not None:
            if len(self._players) <= random_num:
                return self._players.keys()
            return random.sample(self._players, random_num)
        if not pids:
            return self._players.keys()
        return [pid for pid in pids if pid in self._players]

    @grpc_monitor
    def new_player(self, uid, name, rid):
        """ 创建玩家对象,防止重名 """
        with self._new_player_lock:
            if self.get_id_by_name(name) is not None:
                return
            pid, data = PlayerData.new_player(uid, name, rid)
            self._add_name_id(pid, name, rid)
            return data

    def del_player(self, pid):
        name = self.pid2names.pop(pid, None)
        self.name2pids.pop(name, None)

    def _new_user(self, t, user, pwd, UDID, DT, MAC, DEV, VER):
        u = dict(sns=t,
                 name=user,
                 pwd=pwd,
                 UDID=UDID,
                 DT=DT,
                 MAC=MAC,
                 DEV=DEV,
                 VER=VER,
                 tNew=int(time.time()))
        u = User(adict=u)
        u.save(Game.rpc_store)
        return u

    def _get_login_params(self, user, uid, sns_type=0):
        """ 选择一个逻辑进程,返回登录用参数 """
        if uid in self._users:  #重复登陆
            mid, pid = self._users.get(uid)
            self.pre_add(pid, uid)
            self._users.pop(uid, None)

        key = uuid()
        rs, address = self._login_sub(user, uid, key, sns_type)
        return dict(uid=uid,
                    key=key,
                    time=int(time.time()),
                    ip=address[0],
                    port=address[1])

    @wrap_wait4init
    @grpc_monitor
    def rc_login(self, user, pwd, UDID, DT, MAC='', DEV='', VER='', **kw):
        """ 用户登录请求 """
        log.debug(u'收到用户登录请求:%s, %s, %s, %s, %s, %s, %s, %s', user, pwd, UDID,
                  DT, MAC, DEV, VER, kw)
        resp_f = 'login'
        if self.count >= self.max_players:
            return pack_msg(resp_f, 0, err=language.STR_PLAYER_3)

        if not user:  #游客登录
            u = Game.rpc_store.query_loads(TN_USER, dict(UDID=UDID, name=''))
        else:
            #检查user,pwd是否正确,返回uid
            u = Game.rpc_store.query_loads(TN_USER, dict(name=user))
        if not u:
            #不存在自动增加
            u = self._new_user(SNS_NONE, user, pwd, UDID, DT, MAC, DEV, VER)
        else:
            u = u[0]
            u = User(adict=u)
        if u.data.pwd != pwd:
            return pack_msg(resp_f, 0, err=language.LOGIN_PWD_ERROR)
        params = self._get_login_params(user, u.data.id)
        return pack_msg(resp_f, 1, data=params)

    def bindSNS(self, uid, t, sid, session):
        """ 绑定平台账号 """
        rs, data = self.sns_client.login(t, sid, session)
        if not rs:
            return 0, data
        u = Game.rpc_store.load(TN_USER, uid)
        if not u:
            return 0, errcode.EC_NOFOUND
        Game.rpc_store.update(TN_USER, uid, dict(name=sid))
        return 1, None

    def area_legal(self):
        """登陆时区域是不是合法"""
        if not self._area_url or not self._area_legal:
            #未配置则所有人合法登陆
            return True
        rpc = client_rpc.get_cur_rpc()
        data = urllib.urlencode({'ip': rpc.addr[0], 'check': str(0)})
        host, port, url = self._area_url
        try:
            area = tools.http_post_ex(host,
                                      port,
                                      url,
                                      params=data,
                                      timeout=GPlayerMgr.TIME_OUT)
            area = json.loads(area)
            country = area['country']
            log.debug('area_legal:%s in %s', rpc.addr[0], country)
            return not country or country in self._area_legal
        except BaseException as e:
            log.warn("area_legal error:%s", e)
            return True

    def is_debug_time(self):
        """
        测试期间只允许特定IP登陆
        """
        if not self._debug_status or not self._debug_ips:
            return True
        rpc = client_rpc.get_cur_rpc()
        ip = rpc.addr[0]
        if ip in self._debug_ips:
            return True
        log.info('during debug time in_ip:%s forbid :%s', self._debug_ips, ip)
        return False

    @wrap_wait4init
    @grpc_monitor
    def rc_loginSNS(self,
                    t,
                    sid,
                    session,
                    UDID,
                    DT,
                    MAC='',
                    DEV='',
                    VER='',
                    **kw):
        """ 平台登录接口 """
        resp_f = 'loginSNS'
        if not self.area_legal():
            return pack_msg(resp_f, 0, err=errcode.EC_LOGIN_AREA_ERR)
        if not self.is_debug_time():
            return pack_msg(resp_f, 0, err=errcode.EC_LOGIN_DEBUG_TIME)

        log.debug(u'平台(%s)用户登录请求:%s, %s, %s, %s, %s, %s, %s, %s', t, sid,
                  session, UDID, DT, MAC, DEV, VER, kw)
        if self.count >= self.max_players:
            return pack_msg(resp_f, 0, err=errcode.EC_TEAM_ROLE_FULL)

        if not sid and t not in SNS_LOGINS:  #游客登录
            return pack_msg(resp_f, 0, err=errcode.EC_VALUE)
            #u = Game.rpc_store.query_loads(TN_USER, dict(UDID=UDID, name=''))
        else:
            rs, data = self.sns_client.login(t, sid, session)
            if not rs:
                return pack_msg(resp_f, 0, err=data)
            if data:  #login返回sid
                sid = data
            u = UserData.user_by_sns(t, sid)
        if not u:
            #不存在自动增加
            u = self._new_user(t, sid, '', UDID, DT, MAC, DEV, VER)
        else:
            u = u[0]
            u = User(adict=u)
            #如果mac地址不同,记录
            if u.data.UDID != UDID or u.data.DT != DT or \
                u.data.DEV != DEV or \
                u.data.MAC != MAC or u.data.VER != VER:

                def _log_mac():
                    if 1:  #强制保存更新信息, not u.data.MAC:
                        u.data.UDID = UDID
                        u.data.DT = DT
                        u.data.MAC = MAC
                        u.data.DEV = DEV
                        u.data.VER = VER
                        u.save(Game.rpc_store)
                    else:
                        self.glog(PM_MAC,
                                  u=u.data.id,
                                  UDID=UDID,
                                  MAC=MAC,
                                  DEV=DEV,
                                  VER=VER)

                spawn(_log_mac)

        params = self._get_login_params(sid, u.data.id, t)
        log.debug(u'loginSNS finish:%s', params)
        return pack_msg(resp_f, 1, data=params)

    def glog(self, type, **kw):
        kw['t'] = type
        Game.glog.log(kw)

    def _login_sub(self, user_name, uid, key, sns_type):
        """ 选取subgame """
        sub_ids = None
        while not sub_ids:
            sub_ids = self._sub_mgrs.keys()
            if sub_ids:
                break
            log.info('_login_sub wait game init')
            sleep(1)

        sub_ids.sort()
        for sub_mgr_id in sub_ids:
            mgr, pids = self._sub_mgrs[sub_mgr_id]
            if len(pids) < self.logic_players:
                rs, address = mgr.logon(user_name, uid, key, sns_type)
                return rs, address
        #如果全部都满人,随机选择
        sub_id = random.choice(sub_ids)
        mgr, count = self._sub_mgrs[sub_id]
        rs, address = mgr.logon(user_name, uid, key, sns_type)
        return rs, address

    @grpc_monitor
    def distribute(self, func_name, pids, *args, **kw):
        """ 分发方法调用到各个自进程:
         func_name: SubPlayerMgr中的方法名
         pids: 玩家id列表, pids=None广播所有玩家
        """
        if pids is not None:
            pids = set(pids)
        for mid, (mgr, mids) in self._sub_mgrs.items():
            if not mids:
                continue
            if pids is None:
                mpids = None
            else:
                mpids = list(pids.intersection(mids))
            func = getattr(mgr, func_name)
            try:
                func(mpids, *args, **kw)
            except Exception as err:
                log.log_except('distribute error:%s(%s, %s)', func_name, args,
                               kw)

    @wrap_distribute
    def player_mails(self, pids, mids, _no_result=True):
        """ 玩家收到新的邮件 """

    @wrap_distribute
    def player_send_msg(self, pids, msg, _no_result=True):
        """
        广播消息给玩家
        pids:None 时广播所有在线玩家
       """

    @wrap_pickle_result
    def get_rpc_player(self, pid):
        mid, sub_mgr = self.get_sub_mgr(pid)
        if not mid:
            return
        addr = self.mgr2addrs.get(mid)
        proxy = SubPlayerMgr.cls_get_player_proxy(pid, addr=addr, local=0)
        return proxy

    @wrap_pickle_result
    @grpc_monitor
    def get_rpc_players(self, pids):
        """ 获取rpc_player列表,用于少量玩家操作 """
        rs = []
        for pid in pids:
            proxy = self.get_rpc_player(pid)
            if proxy:
                rs.append(proxy)
        return rs

    @grpc_monitor
    def exec_players_func(self, pids, func, has_result=False, _pickle=True):
        """ 在玩家所在的逻辑进程执行方法,用于一般的玩家操作
        func: 定义: def func(player)
        """
        pids = set(pids)
        rs = {}
        for mid, (mgr, mids) in self._sub_mgrs.iteritems():
            mpids = pids.intersection(mids)
            if not mpids:
                continue
            mpids = tuple(mpids)
            if has_result:
                sub_rs = mgr.exec_players_func(mpids, func, _pickle=True)
                rs.update(sub_rs)
            else:
                mgr.exec_players_func(mpids,
                                      func,
                                      _pickle=True,
                                      _no_result=True)
        return rs

    def overload(self, m):
        """ 启动压力测试m分钟 """
        self.overload_time = time.time() + m * 60
        log.warn('overload start to %s',
                 datetime.datetime.fromtimestamp(self.overload_time))

    def is_overload(self):
        """ 是否处于压力测试状态 """
        return time.time() < self.overload_time

    def set_debug_data(self, ips, status):
        """
        设置测试的数据
        """
        self._debug_ips = ips
        self._debug_status = bool(status)
        self._players.keys()
        #状态开启了
        if not self._debug_status:
            return
        pids = self.get_online_ids()
        for pid in pids:
            rpc = self.get_rpc_player(pid)
            if rpc and rpc.get_ip() not in self._debug_ips:
                rpc.debug_kick()