Ejemplo n.º 1
0
	def load_languages(self):
		self.translations = {}
		tool.touch_folder(self.language_folder)
		for file in tool.list_file(self.language_folder, constant.LANGUAGE_FILE_SUFFIX):
			language = tool.remove_suffix(os.path.basename(file), constant.LANGUAGE_FILE_SUFFIX)
			with open(file, encoding='utf8') as f:
				self.translations[language] = yaml.round_trip_load(f)
Ejemplo n.º 2
0
	def list_plugin(self, info):
		file_list_all = self.server.plugin_manager.get_plugin_file_list_all()
		file_list_disabled = self.server.plugin_manager.get_plugin_file_list_disabled()
		file_list_loaded = self.server.plugin_manager.get_loaded_plugin_file_name_list()
		file_list_not_loaded = [file_name for file_name in file_list_all if file_name not in file_list_loaded]

		self.send_message(info, self.t('command_manager.list_plugin.info_loaded_plugin', len(file_list_loaded)))
		for file_name in file_list_loaded:
			self.send_message(
				info, '§7-§r {}'.format(file_name)
				+ SText(' [×]', color=SColor.gray)
				.set_click_event(SAction.run_command, '!!MCDR plugin disable {}'.format(file_name))
				.set_hover_text(self.t('command_manager.list_plugin.suggest_disable', file_name))
				+ SText(' [▷]', color=SColor.gray)
				.set_click_event(SAction.run_command, '!!MCDR plugin load {}'.format(file_name))
				.set_hover_text(self.t('command_manager.list_plugin.suggest_reload', file_name))
			)

		self.send_message(info, self.t('command_manager.list_plugin.info_disabled_plugin', len(file_list_disabled)))
		for file_name in file_list_disabled:
			file_name = tool.remove_suffix(file_name, constant.DISABLED_PLUGIN_FILE_SUFFIX)
			self.send_message(
				info, '§7-§r {}'.format(file_name) +
				SText(' [✔]', color=SColor.gray)
				.set_click_event(SAction.run_command, '!!MCDR plugin enable {}'.format(file_name))
				.set_hover_text(self.t('command_manager.list_plugin.suggest_enable', file_name))
			)

		self.send_message(info, self.t('command_manager.list_plugin.info_not_loaded_plugin', len(file_list_not_loaded)))
		for file_name in file_list_not_loaded:
			self.send_message(info, '§7-§r {}'.format(file_name)
				+ SText(' [✔]', color=SColor.gray)
				.set_click_event(SAction.run_command, '!!MCDR plugin load {}'.format(file_name))
				.set_hover_text(self.t('command_manager.list_plugin.suggest_load', file_name))
			)
Ejemplo n.º 3
0
	def enable_plugin(self, file_name) -> bool:
		file_name = tool.format_plugin_file_name_disabled(file_name)
		file_path = os.path.join(self.plugin_folder, file_name)
		new_file_path = tool.remove_suffix(file_path, constant.DISABLED_PLUGIN_FILE_SUFFIX)
		if os.path.isfile(file_path):
			os.rename(file_path, new_file_path)
			return bool(self.load_plugin(os.path.basename(new_file_path)))
		return False
Ejemplo n.º 4
0
class WaterfallParser(BungeecordParser):
    # The logging format of waterfall server is spigot like

    NAME = tool.remove_suffix(os.path.basename(__file__), '.py')

    def parse_server_stdout(self, text):
        return bukkit_parser.get_parser(
            self.parser_manager).parse_server_stdout(text)
Ejemplo n.º 5
0
 def __init__(self, server, file_path):
     self.server = server
     self.file_path = file_path
     self.file_name = os.path.basename(file_path)
     self.plugin_name = tool.remove_suffix(self.file_name, '.py')
     self.module = None
     self.old_module = None
     self.help_messages = []
     self.file_hash = None
Ejemplo n.º 6
0
 def __init__(self, server, file_path):
     self.server = server
     self.file_path = file_path
     self.file_name = os.path.basename(file_path)
     self.plugin_name = tool.remove_suffix(self.file_name, '.py')
     self.module = None
     self.old_module = None
     self.help_messages = []
     self.file_hash = None
     self.loaded_modules = []
     self.thread_pool = self.server.plugin_manager.thread_pool
     self.load_lock = self.server.plugin_manager.plugin_load_lock
Ejemplo n.º 7
0
class BukkitParser14(VanillaParser):
    # 1.14.4+ bukkit / spigot change it's console logger into vanilla like format
    # idk why they did this
    # paper is not included

    NAME = tool.remove_suffix(os.path.basename(__file__), '.py')

    def __init__(self, parser_manager):
        super().__init__(parser_manager)

    def parse_player_joined(self, info):
        return bukkit_parser.get_parser(
            self.parser_manager).parse_player_joined(info)
Ejemplo n.º 8
0
class CatServerParser(BukkitParser):
    # https://github.com/Luohuayu/CatServer
    # CatServer uses vanilla logging format but spigot like player joined message
    # And has color code around the player left message

    NAME = tool.remove_suffix(os.path.basename(__file__), '.py')

    def parse_server_stdout(self, text):
        return VanillaParser.parse_server_stdout(self, text)

    def parse_player_left(self, info):
        # §eSteve left the game§r
        return super().parse_player_left(cleaned_info(info))

    def parse_player_made_advancement(self, info):
        # § before advancement name
        return super().parse_player_made_advancement(cleaned_info(info))
Ejemplo n.º 9
0
class ForgeParser(VanillaParser):
    NAME = tool.remove_suffix(os.path.basename(__file__), '.py')
    LOGGER_NAME_CHAR_SET = VanillaParser.LOGGER_NAME_CHAR_SET + r'.'

    def __init__(self, parser_manager):
        super().__init__(parser_manager)

    def parse_server_stdout(self, text):
        result = self._parse_server_stdout_raw(text)

        # [18:26:03] [Server thread/INFO] [FML]: Unloading dimension 1
        # [18:26:03] [Server thread/INFO] [minecraft/DedicatedServer]: Done (9.855s)! For help, type "help" or "?"
        # [18:29:30] [Server thread/INFO] [minecraft/DedicatedServer]: <Steve> test
        time_data = re.search(r'\[[0-9]*:[0-9]*:[0-9.]*\] ', text).group()
        elements = time_data[1:-2].split(':')
        result.hour = int(elements[0])
        result.min = int(elements[1])
        result.sec = int(float(elements[2]))

        text = text.replace(time_data, '', 1)
        # [Server thread/INFO] [FML]: Unloading dimension 1
        # [Server thread/INFO] [minecraft/DedicatedServer]: Done (9.855s)! For help, type "help" or "?"
        # [Server thread/INFO] [minecraft/DedicatedServer]: <Steve> test

        logging = re.match(r'^\[[{}]*?\] '.format(self.LOGGER_NAME_CHAR_SET),
                           text).group()
        result.logging_level = re.search(r'(?<=/)\w+(?=\] )', logging).group()
        text = text.replace(logging, '', 1)
        # [FML]: Unloading dimension 1
        # [minecraft/DedicatedServer]: Done (9.855s)! For help, type "help" or "?"
        # [minecraft/DedicatedServer]: <Steve> test

        matched = re.match(r'^\[[{}]*\]: '.format(self.LOGGER_NAME_CHAR_SET),
                           text).group()
        text = text.replace(matched, '', 1)
        # Unloading dimension 1
        # Done (9.855s)! For help, type "help" or "?"
        # <Steve> test

        result.player = re.match(r'<\w+> ', text)
        if result.player is None:
            result.content = text
        else:
            result.player = result.player.group()[1:-2]
            result.content = text.replace(f'<{result.player}> ', '', 1)
        return result
Ejemplo n.º 10
0
class BukkitParser(VanillaParser):
	NAME = tool.remove_suffix(os.path.basename(__file__), '.py')

	# Fallen_Breath[/127.0.0.1:50099] logged in with entity id 11 at ([lobby]0.7133817548136454, 4.0, 5.481879061970788)
	# Fake_player[local] logged in with entity id 11 at ([lobby]100.19, 22.33, 404.0)
	PLAYER_JOINED_PATTERN = re.compile(r'\w{1,16}\[(?:/[\d.:]+|local)\] logged in with entity id \d+ at \((\[\w+\])?[\dE\-., ]+\)')

	def parse_server_stdout(self, text):
		result = self._parse_server_stdout_raw(text)

		# [09:00:01 INFO]: <Steve> hi
		# [09:00:03 WARN]: Alex moved too quickly!
		# [09:00:04 INFO]: [world_nether]<Alex> hello
		time_data = re.search(r'\[[0-9]*:[0-9]*:[0-9]* \w*\]: ', text).group()
		elements = time_data[1:-2].split(':')
		result.hour = int(elements[0])
		result.min = int(elements[1])
		result.sec = int(elements[2].split(' ')[0])
		result.logging_level = re.search(r'(?<= )\w+(?=\])', elements[2]).group()

		text = text.replace(time_data, '', 1)
		# <Steve> hi
		# Alex moved too quickly!
		# [world_nether]<Alex> hello

		dim = re.match(r'\[\w+\](?=<\w+> )', text)
		if dim is not None:
			text = text.replace(dim.group(), '', 1)
		# <Steve> hi
		# Alex moved too quickly!
		# <Alex> hello

		result.player = re.match(r'<\w+> ', text)
		if result.player is None:
			result.content = text
		else:
			result.player = result.player.group()[1:-2]
			result.content = text.replace(f'<{result.player}> ', '', 1)
		return result
Ejemplo n.º 11
0
class BasicParser(AbstractParser):
    NAME = tool.remove_suffix(os.path.basename(__file__), '.py')

    def parse_server_stdout(self, text):
        return self._parse_server_stdout_raw(text)

    def parse_player_joined(self, info):
        return None

    def parse_player_left(self, info):
        return None

    def parse_player_made_advancement(self, info):
        return None

    def parse_server_startup_done(self, info):
        return False

    def parse_rcon_started(self, info: Info):
        return False

    def parse_server_stopping(self, info: Info):
        return False
Ejemplo n.º 12
0
class AbstractParser:
    NAME = tool.remove_suffix(os.path.basename(__file__), '.py')
    STOP_COMMAND = ''

    def __init__(self, parser_manager):
        self.parser_manager = parser_manager

    @staticmethod
    def _parse_server_stdout_raw(text: str):
        """
		Base raw parsing, returns an almost un-parsed Info instance
		Use as the first step of the parsing process, or as the return value if you give up parsing this text

		:param str text: A line of the server stdout to be parsed
		:return: An Info instance
		:rtype: Info
		"""
        if type(text) is not str:
            raise TypeError('The text to parse should be a string')
        result = Info()
        result.source = InfoSource.SERVER
        result.content = result.raw_content = text
        return result

    def pre_parse_server_stdout(self, text):
        """
		Remove useless things like console color code in the text before parse

		:param str text: A line of the server stdout to be parsed
		:return: Trimmed line
		:rtype: str
		"""
        return tool.clean_console_color_code(text)

    @staticmethod
    def parse_console_command(text):
        """
		Base parsing, returns an almost un-parsed Info instance
		Don't use this unless

		:param str text: A line of the server stdout to be parsed
		:return: An Info instance
		:rtype: Info
		"""
        if type(text) is not str:
            raise TypeError('The text to parse should be a string')
        result = Info()
        result.raw_content = text
        t = time.localtime(time.time())
        result.hour = t.tm_hour
        result.min = t.tm_min
        result.sec = t.tm_sec
        result.content = text
        result.source = InfoSource.CONSOLE
        return result

    def parse_death_message(self, info):
        """
		Check if the info matches a death message and return a bool
		It will search all death message format from itself to its all base class and try to match the info with them

		:param Info info: The info instance that will be checked
		:return: If the info matches a death message
		:rtype: bool
		"""
        if info.is_user:
            return False
        re_list = self.parser_manager.get_death_message_list(type(self))
        for re_exp in re_list:
            if re.fullmatch(re_exp, info.content):
                return True
        return False

    # ----------------------------------------
    #    Things that need to be implemented
    # ----------------------------------------

    def parse_server_stdout(self, text):
        """
		Main parsing operation. Parse a string from the stdout of the server
		It may raise any exceptions if the format of the input string is not correct

		:param str text: A line of the server stdout to be parsed
		:return: An parsed Info instance
		:rtype: Info
		"""
        raise NotImplementedError()

    def parse_player_joined(self, info):
        """
		Check if the info indicating a player joined message
		If it is, returns the name of the player, otherwise returns None

		:param Info info: The info instance that will be checked
		:return: The name of the player or None
		:rtype: str or None
		"""
        raise NotImplementedError()

    def parse_player_left(self, info):
        """
		Check if the info indicates a player left message
		If it is, returns the name of the player, otherwise returns None

		:param Info info: The info instance that will be checked
		:return: The name of the player or None
		:rtype: str or None
		"""
        raise NotImplementedError()

    def parse_player_made_advancement(self, info):
        """
		Check if the info indicates a player made advancement message
		If it is, returns a tuple of two str: the name of the player and the name of the advancement, otherwise returns None

		:param Info info: The info instance that will be checked
		:return: (player_name, advancement_name), or None
		:rtype: tuple[str, str] or None
		"""
        raise NotImplementedError()

    def parse_server_startup_done(self, info):
        """
		Check if the info indicates a server startup message and return a bool

		:param Info info: The info instance that will be checked
		:return: If the info indicates a server startup message
		:rtype: bool
		"""
        raise NotImplementedError()

    def parse_rcon_started(self, info: Info):
        """
		Check if rcon has started and return a bool

		:param Info info: The info instance that will be checked
		:return: If rcon has started
		:rtype: bool
		"""
        raise NotImplementedError()

    def parse_server_stopping(self, info: Info):
        """
		Check if the server is stopping and return a bool

		:param Info info: The info instance that will be checked
		:return: If the server is stopping
		:rtype: bool
		"""
        raise NotImplementedError()
Ejemplo n.º 13
0
class VanillaParser(AbstractParser):
	NAME = tool.remove_suffix(os.path.basename(__file__), '.py')
	PLAYER_JOINED_PATTERN = re.compile(r'\w{1,16}\[(?:/[\d.:]+|local)\] logged in with entity id \d+ at \([\dE\-., ]+\)')
	STOP_COMMAND = 'stop'
	LOGGER_NAME_CHAR_SET = r'\w /\#\-'

	def parse_server_stdout(self, text):
		result = self._parse_server_stdout_raw(text)

		# [09:00:00] [Server thread/INFO]: <Steve> Hello
		# [09:00:01] [Server thread/WARN]: Can't keep up!
		time_data = re.search(r'\[[0-9]*:[0-9]*:[0-9]*\] ', text).group()
		elements = time_data[1:-2].split(':')
		result.hour = int(elements[0])
		result.min = int(elements[1])
		result.sec = int(elements[2])

		text = text.replace(time_data, '', 1)
		# [Server thread/INFO]: <Steve> Hello
		# [Server thread/WARN]: Can't keep up!
		logging = re.match(r'^\[[{}]*?\]: '.format(self.LOGGER_NAME_CHAR_SET), text).group()
		result.logging_level = re.search(r'(?<=/)\w+(?=\]: )', logging).group()
		text = text.replace(logging, '', 1)
		# <Steve> Hello
		# Can't keep up!

		result.player = re.match(r'<(.*?)> ', text)
		if result.player is None:
			result.content = text
		else:
			result.player = result.player.group()[1:-2]
			result.content = text.replace(f'<{result.player}> ', '', 1)
			result.player = re.sub('\[(.*?)+\]','',result.player)
		return result

	def parse_player_joined(self, info):
		# Steve[/127.0.0.1:9864] logged in with entity id 131 at (187.2703, 146.79014, 404.84718)
		if not info.is_user and self.PLAYER_JOINED_PATTERN.fullmatch(info.content):
			return info.content.split('[', 1)[0]
		return None

	def parse_player_left(self, info):
		# Steve left the game
		if not info.is_user and re.fullmatch(r'\w{1,16} left the game', info.content):
			return info.content.split(' ')[0]
		return None

	def parse_player_made_advancement(self, info):
		# Steve has made the advancement [Stone Age]
		# Steve has completed the challenge [Uneasy Alliance]
		# Steve has reached the goal [Sky's the Limit]
		if info.is_user:
			return None
		for action in ['made the advancement', 'completed the challenge', 'reached the goal']:
			match = re.fullmatch(r'\w{1,16} has %s \[.+\]' % action, info.content)
			if match is not None:
				player, rest = info.content.split(' ', 1)
				adv = re.search(r'(?<=%s \[).+(?=\])' % action, rest).group()
				return player, adv
		return None

	def parse_server_startup_done(self, info):
		# 1.13+ Done (3.500s)! For help, type "help"
		# 1.13- Done (3.500s)! For help, type "help" or "?"
		if info.is_user:
			return False
		match = re.fullmatch(r'Done \([0-9.]*s\)! For help, type "help"( or "\?")?', info.content)
		return match is not None

	def parse_rcon_started(self, info):
		# RCON running on 0.0.0.0:25575
		if info.is_user:
			return False
		match = re.fullmatch(r'RCON running on [\w.]+:\d+', info.content)
		return match is not None

	def parse_server_stopping(self, info):
		# Stopping server
		if info.is_user:
			return False
		return info.content == 'Stopping server'
Ejemplo n.º 14
0
    def list_plugin(self, info):
        file_list_all = self.server.plugin_manager.get_plugin_file_list_all()
        file_list_disabled = self.server.plugin_manager.get_plugin_file_list_disabled(
        )
        file_list_loaded = self.server.plugin_manager.get_loaded_plugin_file_name_list(
        )
        file_list_not_loaded = [
            file_name for file_name in file_list_all
            if file_name not in file_list_loaded
        ]

        self.send_message(
            info,
            self.t('command_manager.list_plugin.info_loaded_plugin',
                   len(file_list_loaded)))
        for file_name in file_list_loaded:
            texts = RText('§7-§r {}'.format(file_name))
            if self.display_buttons(info):
                texts += RTextList(
                    RText(' [×]', color=RColor.gray).c(
                        RAction.run_command,
                        '!!MCDR plugin disable {}'.format(file_name)).h(
                            self.t(
                                'command_manager.list_plugin.suggest_disable',
                                file_name)),
                    RText(' [↻]', color=RColor.gray).c(
                        RAction.run_command,
                        '!!MCDR plugin load {}'.format(file_name)).h(
                            self.t(
                                'command_manager.list_plugin.suggest_reload',
                                file_name)))
            self.send_message(info, texts)

        self.send_message(
            info,
            self.t('command_manager.list_plugin.info_disabled_plugin',
                   len(file_list_disabled)))
        for file_name in file_list_disabled:
            file_name = tool.remove_suffix(
                file_name, constant.DISABLED_PLUGIN_FILE_SUFFIX)
            texts = RText('§7-§r {}'.format(file_name))
            if self.display_buttons(info):
                texts += (RText(' [✔]', color=RColor.gray).c(
                    RAction.run_command,
                    '!!MCDR plugin enable {}'.format(file_name)).h(
                        self.t('command_manager.list_plugin.suggest_enable',
                               file_name)))
            self.send_message(info, texts)

        self.send_message(
            info,
            self.t('command_manager.list_plugin.info_not_loaded_plugin',
                   len(file_list_not_loaded)))
        for file_name in file_list_not_loaded:
            texts = RText('§7-§r {}'.format(file_name))
            if self.display_buttons(info):
                texts += (RText(' [✔]', color=RColor.gray).c(
                    RAction.run_command,
                    '!!MCDR plugin load {}'.format(file_name)).h(
                        self.t('command_manager.list_plugin.suggest_load',
                               file_name)))
            self.send_message(info, texts)
Ejemplo n.º 15
0
class BungeecordParser(AbstractParser):
    NAME = tool.remove_suffix(os.path.basename(__file__), '.py')
    STOP_COMMAND = 'end'

    def __init__(self, parser_manager):
        super().__init__(parser_manager)

    def parse_server_stdout(self, text):
        result = self._parse_server_stdout_raw(text)

        # 09:00:02 [信息] Listening on /0.0.0.0:25565
        # 09:00:01 [信息] [Steve] -> UpstreamBridge has disconnected
        time_data = re.search(r'[0-9]*:[0-9]*:[0-9]* ', text).group()
        elements = time_data[0:-1].split(':')
        result.hour = int(elements[0])
        result.min = int(elements[1])
        result.sec = int(elements[2])

        text = text.replace(time_data, '', 1)
        result.logging_level = text.split(' ')[0][1:-1]
        # [信息] Listening on /0.0.0.0:25565
        # [信息] [Steve] -> UpstreamBridge has disconnected

        text = text.replace(re.match(r'\[\w+?\] ', text).group(), '', 1)
        # Listening on /0.0.0.0:25565
        # [Steve] -> UpstreamBridge has disconnected

        result.content = text
        return result

    def pre_parse_server_stdout(self, text):
        text = super().pre_parse_server_stdout(text)
        match = re.match(r'>*\r', text)
        if match is not None:
            text = text.replace(match.group(), '', 1)
        return text

    def parse_player_joined(self, info):
        # [Steve,/127.0.0.1:3631] <-> InitialHandler has connected
        if not info.is_user and re.fullmatch(
                r'\[\w{1,16},/[0-9.]+:[0-9]+\] <-> InitialHandler has connected',
                info.content):
            return info.content[1:].split(',/')[0]
        return None

    def parse_player_left(self, info):
        # [Steve] -> UpstreamBridge has disconnected
        if not info.is_user and re.fullmatch(
                r'\[\w{1,16}\] -> UpstreamBridge has disconnected',
                info.content):
            return info.content[1:].split('] -> ')[0]
        return None

    def parse_server_startup_done(self, info):
        # Listening on /0.0.0.0:25577
        return not info.is_user and re.fullmatch(
            r'Listening on /[0-9.]+:[0-9]+', info.content) is not None

    def parse_rcon_started(self, info):
        return self.parse_server_startup_done(info)

    def parse_server_stopping(self, info) -> bool:
        # Closing listener [id: 0x3acae0b0, L:/0:0:0:0:0:0:0:0:25565]
        return not info.is_user and re.fullmatch(
            r'Closing listener \[id: .+, L:[\d:/]+\]',
            info.content) is not None

    def parse_death_message(self, info: Info) -> bool:
        return False

    def parse_player_made_advancement(self, info: Info):
        return None