def init_from_dict(self, bdict): super(SpaceStub, self).init_from_dict(bdict) from hexm.server.utils.entity_timer_manager_wrapper import EntityTickerKeyTimerManager self._ticker_mgr = EntityTickerKeyTimerManager(self) self._ticker_mgr.run_ticker() # @TEMP 预先生成默认数量的space # @note 如果创建太快, 引擎那边会导致on_load失败, 不知道为啥, 先简单, 每隔一段时间创建一个分线 from hexm import debug_profile scene_no, count = debug_profile.get_server_default_scene_config() self._ticker_mgr.add_ticker_key_repeat_timer('create_space', 0.5, lambda : self.apply_create_space(scene_no, IdManager.genid()), run_num=count) # 自动每隔一段时间推送当前所有的分线列表信息到game进程 self._ticker_mgr.add_ticker_key_repeat_timer( space_consts.STUB_TICKER_TIMER_KEY_PUSH_SEP_LINE, space_consts.STUB_TIME_INTERVAL_PUSH_SEP_LINE, self._on_tick_send_sep_line ) # 更新世界BOSS玩法状态和同步数据 self._ticker_mgr.add_ticker_key_repeat_timer( space_consts.STUB_TICKER_TIMER_KEY_WORLD_BOSS, space_consts.STUB_TIME_INTERVAL_WORLD_BOSS, self._on_tick_world_boss )
class SpaceStub(StubBase): def __init__(self, eid): super(SpaceStub, self).__init__(eid) self.space_managers = {} self._need_to_push_ctrl_info = {} self._world_boss_stub = WorldBossStub(self) def init_from_dict(self, bdict): super(SpaceStub, self).init_from_dict(bdict) from hexm.server.utils.entity_timer_manager_wrapper import EntityTickerKeyTimerManager self._ticker_mgr = EntityTickerKeyTimerManager(self) self._ticker_mgr.run_ticker() # @TEMP 预先生成默认数量的space # @note 如果创建太快, 引擎那边会导致on_load失败, 不知道为啥, 先简单, 每隔一段时间创建一个分线 from hexm import debug_profile scene_no, count = debug_profile.get_server_default_scene_config() self._ticker_mgr.add_ticker_key_repeat_timer('create_space', 0.5, lambda : self.apply_create_space(scene_no, IdManager.genid()), run_num=count) # 自动每隔一段时间推送当前所有的分线列表信息到game进程 self._ticker_mgr.add_ticker_key_repeat_timer( space_consts.STUB_TICKER_TIMER_KEY_PUSH_SEP_LINE, space_consts.STUB_TIME_INTERVAL_PUSH_SEP_LINE, self._on_tick_send_sep_line ) # 更新世界BOSS玩法状态和同步数据 self._ticker_mgr.add_ticker_key_repeat_timer( space_consts.STUB_TICKER_TIMER_KEY_WORLD_BOSS, space_consts.STUB_TIME_INTERVAL_WORLD_BOSS, self._on_tick_world_boss ) def reload_script(self): self._ticker_mgr.change_ticker_key_repeater_timer_delay( space_consts.STUB_TICKER_TIMER_KEY_PUSH_SEP_LINE, space_consts.STUB_TIME_INTERVAL_PUSH_SEP_LINE ) def change_push_sep_line_next_delay(self, new_delay): # 有最小时间间隔保证流量压力 new_delay = max(abs(new_delay), space_consts.STUB_MIN_TIME_INTERVAL_PUSH_SEP_LINE) self._ticker_mgr.change_ticker_key_next_run_delay( space_consts.STUB_TICKER_TIMER_KEY_PUSH_SEP_LINE, new_delay, force=False, log_timer=False ) def on_meet_time_to_client(self, spaceno, spaceid = None, new_delay = 0, set_new_delay = True): '''遇到加急的消息, 那么标记, 并立刻推送给game级别, 然后推送到client''' mgr = self.space_managers.get(spaceno, None) if mgr is None: return spaceno_info = self._need_to_push_ctrl_info.setdefault('space_ctrl_info', {}).setdefault(spaceno, {}) spaceno_info['syn_now'] = True # @note 现在逻辑是, 如果有推送, 那么整个spaceno下的所有分线都立刻同步一次 mem_info = spaceno_info.setdefault('mem', {}) for one_id in mgr.get_all_spaces_id_list(): mem_info.setdefault(one_id, {})['syn_now'] = True # 标记实际变化的id, @note 如果没有设置, 表示只是通知当前spaceno下数据变化, 不具体针对某一个id下的数据变化 if spaceid is not None: mem_info.setdefault(spaceid, {})['change_now'] = True if set_new_delay: self.change_push_sep_line_next_delay(new_delay) def on_meet_new_sep_line_spaceid(self, spaceno, spaceid, seq_num, new_delay = 0): '''遇到建立了新的分线, 标记, 同时表示加急的消息, 需要推送到client''' spaceno_info = self._need_to_push_ctrl_info.setdefault('space_ctrl_info', {}).setdefault(spaceno, {}) spaceno_info.setdefault('mem', {}).setdefault(spaceid, {})['new'] = True self.on_meet_time_to_client(spaceno, spaceid, new_delay) self._world_boss_stub.on_new_space(spaceno, spaceid, seq_num) def _on_tick_send_sep_line(self): ''' 得到所有分线的信息 ''' if not self.space_managers: return all_info = {spaceno : mgr.get_space_sep_line_info() for spaceno, mgr in self.space_managers.iteritems() if mgr.is_space_need_sep()} syn_info = {'ts' : DateTimeManager.now, 'info' : all_info} # 将额外的ctrl_info加到syn包中 if self._need_to_push_ctrl_info: syn_info.update(self._need_to_push_ctrl_info) self._need_to_push_ctrl_info = {} # @TODO 使用这个方式比较效率不高, 也会增加当前game_manager的工作压力 hex_api.global_message(space_consts.GMSG_EVENT_NAME_STUB_PUSH_SEP_LINE, syn_info) def _on_tick_world_boss(self): self._world_boss_stub.check_state() def setdefault_space_manager(self, spaceno): if spaceno not in self.space_managers: self.space_managers[spaceno] = SpaceManagerInStub(self, spaceno) return self.space_managers[spaceno] def is_valid_spaceno(self, spaceno): return G.spacem.is_valid_spaceno(spaceno) def call_applier_client(self, applier, method_name, para = {}, e_c = None, ctrl_info = {}): if not applier: return if para is None: para = {} if e_c is None: e_c = errcode.ERR_OK self.call(applier, method_name, self.mailbox, e_c, para, ctrl_info) def call_applier_enter_space_back(self, applier, para = {}, e_c = None, ctrl_info = {}): return self.call_applier_client(applier, 'rpc_from_stub_enter_space_back', para = para, e_c = e_c, ctrl_info = ctrl_info) @rpc_method(SERVER_ONLY, Int(), EntityID()) def apply_create_space(self, spaceno, spaceid): if not self.is_valid_spaceno(spaceno): return self.setdefault_space_manager(spaceno).create_space(spaceid) @rpc_method(SERVER_ONLY, MailBox(), Int(), EntityID(), Dict(name = 'ctrl_info')) def apply_enter_space(self, applier, spaceno, spaceid, ctrl_info): if not self.is_valid_spaceno(spaceno): return self.call_applier_enter_space_back(applier, e_c = errcode.ERR_ENTER_SPACE_OF_INVALID_SPACENO, para = {"spaceno": spaceno}, ctrl_info = ctrl_info) self.setdefault_space_manager(spaceno).apply_enter_space(applier, spaceid, ctrl_info = ctrl_info) @rpc_method(SERVER_ONLY, MailBox(), Int(), EntityID(), EntityID(), Dict(name = 'ctrl_info')) def apply_create_and_enter_space(self, applier, spaceno, spaceid, teamid, ctrl_info): if not self.is_valid_spaceno(spaceno): return self.call_applier_enter_space_back(applier, e_c = errcode.ERR_ENTER_SPACE_OF_INVALID_SPACENO, para = {"spaceno": spaceno}, ctrl_info = ctrl_info) self.setdefault_space_manager(spaceno).apply_create_and_enter_space(applier, spaceid, teamid, ctrl_info = ctrl_info) @rpc_method(SERVER_ONLY, MailBox(), Int()) def on_space_created(self, space, spaceno): if not self.is_valid_spaceno(spaceno): return self.setdefault_space_manager(spaceno).on_space_created(space) @rpc_method(SERVER_ONLY, EntityID(), Int()) def on_space_destroy(self, spaceid, spaceno): if not self.is_valid_spaceno(spaceno): return self.setdefault_space_manager(spaceno).on_space_destroy(spaceid) @rpc_method(SERVER_ONLY, Dict(), Dict()) def rpc_game_syn_space_sep_line_info_to_stub(self, syn_data, syn_ctrl_info): '''强制用汇报的信息写回当前分线信息''' time_to_client_dict = syn_ctrl_info.get('time_to_client', {}) for spaceno, v in syn_data.iteritems(): if not self.is_valid_spaceno(spaceno): continue self.setdefault_space_manager(spaceno).syn_space_sep_line_info(v, time_to_client_dict) # boss信息变化, 将当前所有boss的分线信息重新整理一遍 if syn_ctrl_info.get('world_boss_info_change', False): self._on_world_boss_info_change() def _on_world_boss_info_change(self): # 需要通知所有人数据变化 self._need_to_push_ctrl_info['syn_all_client'] = True # 通知立刻推送数据 self.change_push_sep_line_next_delay(new_delay = 0) @rpc_method(SERVER_ONLY, Int(), Str(), List(), Dict()) def rpc_call_all_space_method(self, spaceno, fun_name, args = None, kwargs = None): if not self.is_valid_spaceno(spaceno): return self.setdefault_space_manager(spaceno).call_all_space_method(fun_name, args, kwargs) @rpc_method(SERVER_ONLY, Int(), EntityID(), Str(), List(), Dict()) def rpc_call_one_space_method(self, spaceno, spaceid, fun_name, args = None, kwargs = None): if not self.is_valid_spaceno(spaceno): return self.setdefault_space_manager(spaceno).call_one_space_method(spaceid, fun_name, args, kwargs) @rpc_method(SERVER_ONLY, Str(), List(), Dict()) def rpc_call_every_space_method(self, fun_name, args = None, kwargs = None): for spacem in self.space_managers.itervalues(): spacem.call_all_space_method(fun_name, args, kwargs) @rpc_method(SERVER_ONLY, MailBox(), EntityID(), Int(), EntityID()) def rpc_get_spaceid_by_teamid(self, applier, teamid, spaceno, cb_id): spaceid = self.setdefault_space_manager(spaceno).get_spaceid_by_teamid(teamid) space_mailbox = self.setdefault_space_manager(spaceno).get_space_mailbox_by_spaceid(spaceid) self.call(applier, "rpc_get_spaceid_by_teamid_cb", space_mailbox, spaceid, cb_id) @rpc_method(SERVER_ONLY) def restart_world_boss(self): self._world_boss_stub.restart_world_boss() @rpc_method(SERVER_ONLY) def end_world_boss(self): self._world_boss_stub.end_world_boss() def create_space_and_call_init_func(self, spaceno, spaceid, *args, **kwargs): """创建一个space, 并且创建成功之后, 调用其初始化代码, 通过`Space.init_func_from_init_controller`代码""" spacem = self.setdefault_space_manager(spaceno) if not spacem: return spacem.create_space_and_call_init_func(spaceid, *args, **kwargs) @rpc_method(SERVER_ONLY, EntityID()) def rpc_on_team_dismissed(self, teamid): for space_manager in self.space_managers.itervalues(): space_manager.try_destroy_space_when_team_is_dismissed(teamid)