Exemplo n.º 1
0
	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
		)
Exemplo n.º 2
0
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)