Пример #1
0
class MinecraftBot():
	def __init__(self, username, server, port, commands):
		self.username = username
		self.server = server
		self.port = port
		self.commands = commands
		self.bot = Connection(server, port, username=username, allowed_versions=[47])
		self.bot.register_packet_listener(self.handle_join_game, clientbound.play.JoinGamePacket)

		log("INFO", "Trying to connect {0} to {1}:{2}.".format(username, server, port))
		self.bot.connect()
		threading.Thread(target=self.execute_go, args=["/go"], daemon=True).start()

	def execute_go(self, command):
		time.sleep(15)
		self.execute_command(command)

	def handle_join_game(self, join_game_packet):
		log("INFO", "{0} is connected to {1}:{2}.".format(self.username, self.server, self.port))
		time.sleep(3)
		self.execute_command(self.commands[0])

	def execute_command(self, command):
		log("INFO", "{0} is doing command {1}".format(self.username, command))
		packet = serverbound.play.ChatPacket()
		packet.message = command
		self.bot.write_packet(packet)

	def disconnect(self):
		log("INFO", "Disconnecting {0} from {1}:{2}.".format(self.username, self.server, self.port))
		self.bot.disconnect()
		log("INFO", "{0} is disconnected of {1}:{2}.".format(self.username, self.server, self.port))
Пример #2
0
def main():
    authenticate(MINECRAFT_USERNAME, MINECRAFT_PASSWORD)
    connection = Connection(SERVER_IP, 25565, auth_token=auth_token)

    connection.register_packet_listener(packet_handler.handle_join_game,
                                        packets.JoinGamePacket)

    # Lambda function is used to inject the connection so the handle_chat function can also send chat packets.
    # That's important for AFK
    connection.register_packet_listener(
        lambda chat_packet: packet_handler.handle_chat(
            chat_packet, connection), packets.ChatMessagePacket)

    connection.register_packet_listener(packet_handler.handle_player_list,
                                        packets.PlayerListItemPacket)

    connection.connect()

    # Allows user to enter chat messages in the terminal and we'll send them.
    # Sometimes needed to run /l bedwars.
    while True:
        try:
            text = input()
            packet = serverbound.play.ChatPacket()
            packet.message = text
            connection.write_packet(packet)
        except KeyboardInterrupt:
            print("Exiting bedwars bot.")
            sys.exit()
Пример #3
0
def main():
    options = get_options()

    auth_token = authentication.AuthenticationToken()
    try:
        auth_token.authenticate(options.username, options.password)
    except YggdrasilError as e:
        print(e)
        sys.exit()

    print("Logged in as " + auth_token.username)

    connection = Connection(options.address, options.port, auth_token)
    connection.connect()

    def print_chat(chat_packet):
        print("Position: " + str(chat_packet.position))
        print("Data: " + chat_packet.json_data)

    connection.register_packet_listener(print_chat, ChatMessagePacket)
    while True:
        try:
            text = input()
            packet = ChatPacket()
            packet.message = text
            connection.write_packet(packet)
        except KeyboardInterrupt:
            print("Bye!")
            sys.exit()
Пример #4
0
def main():
    options = get_options()

    auth_token = authentication.AuthenticationToken()
    try:
        auth_token.authenticate(options.username, options.password)
    except YggdrasilError as e:
        print(e)
        sys.exit()

    print("Logged in as " + auth_token.username)

    connection = Connection(options.address, options.port, auth_token)
    connection.connect()

    def print_chat(chat_packet):
        print("Position: " + str(chat_packet.position))
        print("Data: " + chat_packet.json_data)

    connection.register_packet_listener(print_chat, ChatMessagePacket)
    while True:
        try:
            text = input()
            packet = ChatPacket()
            packet.message = text
            connection.write_packet(packet)
        except KeyboardInterrupt:
            print("Bye!")
            sys.exit()
Пример #5
0
class Main(object):
    def __init__(self, options):
        self.auth_token = authentication.AuthenticationToken()
        try:
            self.auth_token.authenticate(options.username, options.password)
        except YggdrasilError as e:
            print(e)
            sys.exit()
        print("Logged in as " + self.auth_token.username)
        self.network = Connection(options.address, options.port, self.auth_token)
        self.network.connect()
        self.register_listeners()
        #sys.stdout = Speaker(self)
        while not self.network.playing: pass
        self.respawn()
        while True:
            try: self.tick()
            except KeyboardInterrupt:
                print("Bye!")
                sys.exit()

    def register_listeners(self):
        self.network.register_packet_listener(self.print_chat, ChatMessagePacket)
        self.network.register_packet_listener(self.set_pos, PlayerPositionAndLookPacket)
        self.network.register_packet_listener(self.recieve_plugin_message, PluginMessage)
        self.network.register_packet_listener(self.set_health, UpdateHealth)

    def tick(self):
        text = input()
        self.speak(text)
        
    def speak(self, message):
        packet = ChatPacket()
        packet.message = message
        self.network.write_packet(packet)
    
    def set_health(self, health_packet):
        if health_packet.health == 0.0:
            print "RESPAWN"
            self.respawn()
            
    def respawn(self):
        packet = ClientStatus()
        packet.action_id = 0
        self.network.write_packet(packet)
        #print packet
            
    def print_chat(self, chat_packet):
        print type(chat_packet)
        print("Position: " + str(chat_packet.position))
        print("Data: " + chat_packet.json_data)

    def recieve_plugin_message(self, plugin_message):
        data = plugin_message.data.split("|")
        if len(data) == 2 and data[0] == "MC":
            if data[1] == "Brand": print "Brand:", plugin_message.channel
            else:
                print "PLUGIN MESSAGE:", data[1], plugin_message.channel
Пример #6
0
def main():
    options = get_options()

    if options.offline:
        print("Connecting in offline mode")
        connection = Connection(
            options.address, options.port, username=options.username)
    else:
        auth_token = authentication.AuthenticationToken()
        try:
            auth_token.authenticate(options.username, options.password)
        except YggdrasilError as e:
            print(e)
            sys.exit()
        print("Logged in as " + auth_token.username)
        connection = Connection(
            options.address, options.port, auth_token=auth_token)

    connection.connect()

    def print_chat(chat_packet):
        print("Position: " + str(chat_packet.position))
        print("Data: " + chat_packet.json_data)

    connection.register_packet_listener(print_chat, ChatMessagePacket)
    while True:
        try:
            text = input()
            if text == "/respawn":
                print("respawning...")
                packet = ClientStatusPacket()
                packet.action_id = ClientStatusPacket.RESPAWN
                connection.write_packet(packet)
            else:
                packet = ChatPacket()
                packet.message = text
                connection.write_packet(packet)
        except KeyboardInterrupt:
            print("Bye!")
            sys.exit()
Пример #7
0
class MinecraftDiscordBridge():
    def __init__(self):
        self.return_code = os.EX_OK
        self.session_token = ""
        self.uuid_cache = bidict()
        self.webhooks = []
        self.bot_username = ""
        self.next_message_time = datetime.now(timezone.utc)
        self.previous_message = ""
        self.player_list = bidict()
        self.previous_player_list = bidict()
        self.accept_join_events = False
        self.tab_header = ""
        self.tab_footer = ""
        # Initialize the discord part
        self.discord_bot = discord.Client()
        self.config = Configuration("config.json")
        self.connection_retries = 0
        self.auth_token = None
        self.connection = None
        self.setup_logging(self.config.logging_level)
        self.database_session = DatabaseSession()
        self.logger = logging.getLogger("bridge")
        self.database_session.initialize(self.config)
        self.bot_perms = discord.Permissions()
        self.bot_perms.update(manage_messages=True, manage_webhooks=True)
        # Async http request pool
        self.req_future_session = FuturesSession(max_workers=100)
        self.reactor_thread = Thread(target=self.run_auth_server,
                                     args=(self.config.auth_port, ))
        self.aioloop = asyncio.get_event_loop()
        # We need to import twisted after setting up the logger because twisted hijacks our logging
        from . import auth_server
        auth_server.DATABASE_SESSION = self.database_session
        if self.config.es_enabled:
            if self.config.es_auth:
                self.es_logger = ElasticsearchLogger(self.req_future_session,
                                                     self.config.es_url,
                                                     self.config.es_username,
                                                     self.config.es_password)
            else:
                self.es_logger = ElasticsearchLogger(self.req_future_session,
                                                     self.config.es_url)

        @self.discord_bot.event
        async def on_ready():  # pylint: disable=W0612
            self.logger.info("Discord bot logged in as %s (%s)",
                             self.discord_bot.user.name,
                             self.discord_bot.user.id)
            self.logger.info(
                "Discord bot invite link: %s",
                discord.utils.oauth_url(client_id=self.discord_bot.user.id,
                                        permissions=self.bot_perms))
            await self.discord_bot.change_presence(
                activity=discord.Game("mc!help for help"))
            self.webhooks = []
            session = self.database_session.get_session()
            channels = session.query(DiscordChannel).all()
            session.close()
            for channel in channels:
                channel_id = channel.channel_id
                discord_channel = self.discord_bot.get_channel(channel_id)
                if discord_channel is None:
                    session = self.database_session.get_session()
                    session.query(DiscordChannel).filter_by(
                        channel_id=channel_id).delete()
                    session.close()
                    continue
                channel_webhooks = await discord_channel.webhooks()
                found = False
                for webhook in channel_webhooks:
                    if webhook.name == "_minecraft" and webhook.user == self.discord_bot.user:
                        self.webhooks.append(webhook.url)
                        found = True
                    self.logger.debug("Found webhook %s in channel %s",
                                      webhook.name, discord_channel.name)
                if not found:
                    # Create the hook
                    await discord_channel.create_webhook(name="_minecraft")

        @self.discord_bot.event
        async def on_message(message):  # pylint: disable=W0612
            # We do not want the bot to reply to itself
            if message.author == self.discord_bot.user:
                return
            this_channel = message.channel.id

            # PM Commands
            if message.content.startswith("mc!help"):
                try:
                    send_channel = message.channel
                    if isinstance(message.channel, discord.abc.GuildChannel):
                        await message.delete()
                        dm_channel = message.author.dm_channel
                        if not dm_channel:
                            await message.author.create_dm()
                        send_channel = message.author.dm_channel
                    msg = self.get_discord_help_string()
                    await send_channel.send(msg)
                    return
                except discord.errors.Forbidden:
                    if isinstance(message.author, discord.abc.User):
                        msg = "{}, please allow private messages from this bot.".format(
                            message.author.mention)
                        error_msg = await message.channel.send(msg)
                        await asyncio.sleep(3)
                        await error_msg.delete()
                    return

            elif message.content.startswith("mc!register"):
                try:
                    send_channel = message.channel
                    if isinstance(message.channel, discord.abc.GuildChannel):
                        await message.delete()
                        dm_channel = message.author.dm_channel
                        if not dm_channel:
                            await message.author.create_dm()
                        send_channel = message.author.dm_channel
                    session = self.database_session.get_session()
                    discord_account = session.query(DiscordAccount).filter_by(
                        discord_id=message.author.id).first()
                    if not discord_account:
                        new_discord_account = DiscordAccount(message.author.id)
                        session.add(new_discord_account)
                        session.commit()
                        discord_account = session.query(
                            DiscordAccount).filter_by(
                                discord_id=message.author.id).first()

                    new_token = self.generate_random_auth_token(16)
                    account_link_token = AccountLinkToken(
                        message.author.id, new_token)
                    discord_account.link_token = account_link_token
                    session.add(account_link_token)
                    session.commit()
                    msg = "Please connect your minecraft account to `{}.{}:{}` in order to link it to this bridge!"\
                        .format(new_token, self.config.auth_dns, self.config.auth_port)
                    session.close()
                    del session
                    await send_channel.send(msg)
                    return
                except discord.errors.Forbidden:
                    if isinstance(message.author, discord.abc.User):
                        msg = "{}, please allow private messages from this bot.".format(
                            message.author.mention)
                        error_msg = await message.channel.send(msg)
                        await asyncio.sleep(3)
                        await error_msg.delete()
                    return

            # Global Commands
            elif message.content.startswith("mc!chathere"):
                if isinstance(message.channel, discord.abc.PrivateChannel):
                    msg = "Sorry, this command is only available in public channels."
                    await message.channel.send(msg)
                    return
                if message.author.id not in self.config.admin_users:
                    await message.delete()
                    try:
                        dm_channel = message.author.dm_channel
                        if not dm_channel:
                            await message.author.create_dm()
                        dm_channel = message.author.dm_channel
                        msg = "Sorry, you do not have permission to execute that command!"
                        await dm_channel.send(msg)
                        return
                    except discord.errors.Forbidden:
                        if isinstance(message.author, discord.abc.User):
                            msg = "{}, please allow private messages from this bot.".format(
                                message.author.mention)
                            error_msg = await message.channel.send(msg)
                            await asyncio.sleep(3)
                            await error_msg.delete()
                        return
                session = self.database_session.get_session()
                channels = session.query(DiscordChannel).filter_by(
                    channel_id=this_channel).all()
                if not channels:
                    new_channel = DiscordChannel(this_channel)
                    session.add(new_channel)
                    session.commit()
                    session.close()
                    del session
                    webhook = await message.channel.create_webhook(
                        name="_minecraft")
                    self.webhooks.append(webhook.url)
                    msg = "The bot will now start chatting here! To stop this, run `mc!stopchathere`."
                    await message.channel.send(msg)
                else:
                    msg = "The bot is already chatting in this channel! To stop this, run `mc!stopchathere`."
                    await message.channel.send(msg)
                    return

            elif message.content.startswith("mc!stopchathere"):
                if isinstance(message.channel, discord.abc.PrivateChannel):
                    msg = "Sorry, this command is only available in public channels."
                    await message.channel.send(msg)
                    return
                if message.author.id not in self.config.admin_users:
                    await message.delete()
                    try:
                        dm_channel = message.author.dm_channel
                        if not dm_channel:
                            await message.author.create_dm()
                        dm_channel = message.author.dm_channel
                        msg = "Sorry, you do not have permission to execute that command!"
                        await dm_channel.send(msg)
                        return
                    except discord.errors.Forbidden:
                        if isinstance(message.author, discord.abc.User):
                            msg = "{}, please allow private messages from this bot.".format(
                                message.author.mention)
                            error_msg = await message.channel.send(msg)
                            await asyncio.sleep(3)
                            await error_msg.delete()
                        return
                session = self.database_session.get_session()
                deleted = session.query(DiscordChannel).filter_by(
                    channel_id=this_channel).delete()
                session.commit()
                session.close()
                for webhook in await message.channel.webhooks():
                    if webhook.name == "_minecraft" and webhook.user == self.discord_bot.user:
                        # Copy the list to avoid some problems since
                        # we're deleting indicies form it as we loop
                        # through it
                        if webhook.url in self.webhooks[:]:
                            self.webhooks.remove(webhook.url)
                        await webhook.delete()
                if deleted < 1:
                    msg = "The bot was not chatting here!"
                    await message.channel.send(msg)
                    return
                else:
                    msg = "The bot will no longer chat here!"
                    await message.channel.send(msg)
                    return

            elif message.content.startswith("mc!tab"):
                send_channel = message.channel
                try:
                    if isinstance(message.channel, discord.abc.GuildChannel):
                        await message.delete()
                        dm_channel = message.author.dm_channel
                        if not dm_channel:
                            await message.author.create_dm()
                        send_channel = message.author.dm_channel
                    player_list = ", ".join(
                        list(map(lambda x: x[1], self.player_list.items())))
                    msg = "{}\n" \
                        "Players online: {}\n" \
                        "{}".format(self.escape_markdown(
                            self.strip_colour(self.tab_header)), self.escape_markdown(
                                self.strip_colour(player_list)), self.escape_markdown(
                                    self.strip_colour(self.tab_footer)))
                    await send_channel.send(msg)
                    return
                except discord.errors.Forbidden:
                    if isinstance(message.author, discord.abc.User):
                        msg = "{}, please allow private messages from this bot.".format(
                            message.author.mention)
                        error_msg = await message.channel.send(msg)
                        await asyncio.sleep(3)
                        await error_msg.delete()
                    return

            elif message.content.startswith("mc!botlink"):
                send_channel = message.channel
                try:
                    if isinstance(message.channel, discord.abc.GuildChannel):
                        await message.delete()
                        dm_channel = message.author.dm_channel
                        if not dm_channel:
                            await message.author.create_dm()
                        send_channel = message.author.dm_channel
                    msg = "Use the following link to invite this bot to a guild:\n{}".format(
                        discord.utils.oauth_url(
                            client_id=self.discord_bot.user.id,
                            permissions=self.bot_perms))
                    await send_channel.send(msg)
                    return
                except discord.errors.Forbidden:
                    if isinstance(message.author, discord.abc.User):
                        msg = "{}, please allow private messages from this bot.".format(
                            message.author.mention)
                        error_msg = await message.channel.send(msg)
                        await asyncio.sleep(3)
                        await error_msg.delete()
                    return

            elif message.content.startswith("mc!about"):
                send_channel = message.channel
                try:
                    if isinstance(message.channel, discord.abc.GuildChannel):
                        await message.delete()
                        dm_channel = message.author.dm_channel
                        if not dm_channel:
                            await message.author.create_dm()
                        send_channel = message.author.dm_channel
                    msg = "This bot is running minecraft-discord-bridge version {}.\n" \
                          "The source code is available at https://github.com/starcraft66/minecraft-discord-bridge" \
                        .format(minecraft_discord_bridge.__version__)
                    await send_channel.send(msg)
                    return
                except discord.errors.Forbidden:
                    if isinstance(message.author, discord.abc.User):
                        msg = "{}, please allow private messages from this bot.".format(
                            message.author.mention)
                        error_msg = await message.channel.send(msg)
                        await asyncio.sleep(3)
                        await error_msg.delete()
                    return

            elif message.content.startswith("mc!"):
                # Catch-all
                send_channel = message.channel
                try:
                    if isinstance(message.channel, discord.abc.GuildChannel):
                        await message.delete()
                        dm_channel = message.author.dm_channel
                        if not dm_channel:
                            await message.author.create_dm()
                        send_channel = message.author.dm_channel
                    msg = "Unknown command, type `mc!help` for a list of commands."
                    await send_channel.send(msg)
                    return
                except discord.errors.Forbidden:
                    if isinstance(message.author, discord.abc.User):
                        msg = "{}, please allow private messages from this bot.".format(
                            message.author.mention)
                        error_msg = await message.channel.send(msg)
                        await asyncio.sleep(3)
                        await error_msg.delete()
                    return

            elif "https://discord.gg" in message.content.lower():
                await message.delete()  # Deletes the message
                # Add something more if you want to

                msg = f"{message.author.mention} invites aren't allowed!"  # Your message

                await send_channel.send(msg)

            elif not message.author.bot:
                session = self.database_session.get_session()
                channel_should_chat = session.query(DiscordChannel).filter_by(
                    channel_id=this_channel).first()
                if channel_should_chat:
                    await message.delete()
                    discord_user = session.query(DiscordAccount).filter_by(
                        discord_id=message.author.id).first()
                    if discord_user:
                        if discord_user.minecraft_account:
                            minecraft_uuid = discord_user.minecraft_account.minecraft_uuid
                            session.close()
                            del session
                            minecraft_username = self.mc_uuid_to_username(
                                minecraft_uuid)

                            # Max chat message length: 256, bot username does not count towards this
                            # Does not count|Counts
                            # <BOT_USERNAME> minecraft_username: message
                            padding = 2 + len(minecraft_username)

                            message_to_send = self.remove_emoji(
                                message.clean_content.encode('utf-8').decode(
                                    'ascii', 'replace')).strip()
                            message_to_discord = self.escape_markdown(
                                message.clean_content)

                            total_len = padding + len(message_to_send)
                            if total_len > 256:
                                message_to_send = message_to_send[:(256 -
                                                                    padding)]
                                message_to_discord = message_to_discord[:(
                                    256 - padding)]
                            elif not message_to_send:
                                return

                            session = self.database_session.get_session()
                            channels = session.query(DiscordChannel).all()
                            session.close()
                            del session
                            if message_to_send == self.previous_message or \
                                    datetime.now(timezone.utc) < self.next_message_time:
                                send_channel = message.channel
                                try:
                                    if isinstance(message.channel,
                                                  discord.abc.GuildChannel):
                                        dm_channel = message.author.dm_channel
                                        if not dm_channel:
                                            await message.author.create_dm()
                                        send_channel = message.author.dm_channel
                                    msg = "Your message \"{}\" has been rate-limited.".format(
                                        message.clean_content)
                                    await send_channel.send(msg)
                                    return
                                except discord.errors.Forbidden:
                                    if isinstance(message.author,
                                                  discord.abc.User):
                                        msg = "{}, please allow private messages from this bot.".format(
                                            message.author.mention)
                                        error_msg = await message.channel.send(
                                            msg)
                                        await asyncio.sleep(3)
                                        await error_msg.delete()
                                    return

                            self.previous_message = message_to_send
                            self.next_message_time = datetime.now(
                                timezone.utc) + timedelta(
                                    seconds=self.config.message_delay)

                            self.logger.info(
                                "Outgoing message from discord: Username: %s Message: %s",
                                minecraft_username, message_to_send)

                            for channel in channels:
                                discord_channel = self.discord_bot.get_channel(
                                    channel.channel_id)
                                if not discord_channel:
                                    session = self.database_session.get_session(
                                    )
                                    session.query(DiscordChannel).filter_by(
                                        channel_id=channel.channel_id).delete(
                                        )
                                    session.close()
                                    continue
                                webhooks = await discord_channel.webhooks()
                                for webhook in webhooks:
                                    if webhook.name == "_minecraft":
                                        await webhook.send(
                                            username=minecraft_username,
                                            avatar_url=
                                            "https://visage.surgeplay.com/face/160/{}"
                                            .format(minecraft_uuid),
                                            content=message_to_discord)

                            packet = serverbound.play.ChatPacket()
                            packet.message = "{}: {}".format(
                                minecraft_username, message_to_send)
                            self.connection.write_packet(packet)
                    else:
                        send_channel = message.channel
                        try:
                            if isinstance(message.channel,
                                          discord.abc.GuildChannel):
                                dm_channel = message.author.dm_channel
                                if not dm_channel:
                                    await message.author.create_dm()
                                send_channel = message.author.dm_channel
                            msg = "Unable to send chat message: there is no Minecraft account linked to this discord " \
                                "account, please run `mc!register`."
                            await send_channel.send(msg)
                            return
                        except discord.errors.Forbidden:
                            if isinstance(message.author, discord.abc.User):
                                msg = "{}, please allow private messages from this bot.".format(
                                    message.author.mention)
                                error_msg = await message.channel.send(msg)
                                await asyncio.sleep(3)
                                await error_msg.delete()
                            return
                        finally:
                            session.close()
                            del session
                else:
                    session.close()
                    del session

    def run(self):
        self.logger.debug(
            "Checking if the server {} is online before connecting.")

        if not self.config.mc_online:
            self.logger.info("Connecting in offline mode...")
            while not self.is_server_online():
                self.logger.info(
                    'Not connecting to server because it appears to be offline.'
                )
                time.sleep(15)
            self.bot_username = self.config.mc_username
            self.connection = Connection(
                self.config.mc_server,
                self.config.mc_port,
                username=self.config.mc_username,
                handle_exception=self.minecraft_handle_exception)
        else:
            self.auth_token = authentication.AuthenticationToken()
            try:
                self.auth_token.authenticate(self.config.mc_username,
                                             self.config.mc_password)
            except YggdrasilError as ex:
                self.logger.info(ex)
                sys.exit(os.EX_TEMPFAIL)
            self.bot_username = self.auth_token.profile.name
            self.logger.info("Logged in as %s...",
                             self.auth_token.profile.name)
            while not self.is_server_online():
                self.logger.info(
                    'Not connecting to server because it appears to be offline.'
                )
                time.sleep(15)
            self.connection = Connection(
                self.config.mc_server,
                self.config.mc_port,
                auth_token=self.auth_token,
                handle_exception=self.minecraft_handle_exception)

        self.register_handlers(self.connection)
        self.connection_retries += 1
        self.reactor_thread.start()
        self.connection.connect()
        try:
            self.aioloop.run_until_complete(
                self.discord_bot.start(self.config.discord_token))
        except (KeyboardInterrupt, SystemExit):
            # log out of discord
            self.aioloop.run_until_complete(self.discord_bot.logout())
            # log out of minecraft
            self.connection.disconnect()
            # shut down auth server
            from twisted.internet import reactor
            reactor.callFromThread(reactor.stop)
            # clean up auth server thread
            self.reactor_thread.join()
        finally:
            # close the asyncio event loop discord uses
            self.aioloop.close()
        return self.return_code

    def mc_uuid_to_username(self, mc_uuid: str):
        if mc_uuid not in self.uuid_cache:
            try:
                short_uuid = mc_uuid.replace("-", "")
                mojang_response = self.req_future_session.get(
                    "https://api.mojang.com/user/profiles/{}/names".format(
                        short_uuid)).result().json()
                if len(mojang_response) > 1:
                    # Multiple name changes
                    player_username = mojang_response[-1]["name"]
                else:
                    # Only one name
                    player_username = mojang_response[0]["name"]
                self.uuid_cache[mc_uuid] = player_username
                return player_username
            except RequestException as ex:
                self.logger.error(ex, exc_info=True)
                self.logger.error(
                    "Failed to lookup %s's username using the Mojang API.",
                    mc_uuid)
        else:
            return self.uuid_cache[mc_uuid]

    def mc_username_to_uuid(self, username: str):
        if username not in self.uuid_cache.inv:
            try:
                player_uuid = self.req_future_session.get(
                    "https://api.mojang.com/users/profiles/minecraft/{}".
                    format(username)).result().json()["id"]
                long_uuid = uuid.UUID(player_uuid)
                self.uuid_cache.inv[username] = str(long_uuid)
                return player_uuid
            except RequestException:
                self.logger.error(
                    "Failed to lookup %s's username using the Mojang API.",
                    username)
        else:
            return self.uuid_cache.inv[username]

    def get_discord_help_string(self):
        help_str = (
            "Admin commands:\n"
            "`mc!chathere`: Starts outputting server messages in this channel\n"
            "`mc!stopchathere`: Stops outputting server messages in this channel\n"
            "User commands:\n"
            "`mc!tab`: Sends you the content of the server's player/tab list\n"
            "`mc!register`: Starts the minecraft account registration process\n"
            "`mc!botlink`: Sends you the link to invite this bot to a guild\n"
            "`mc!about`: Sends you information about the running bridge\n"
            "To start chatting on the minecraft server, please register your account using `mc!register`."
        )
        return help_str

    # https://stackoverflow.com/questions/33404752/removing-emojis-from-a-string-in-python
    def remove_emoji(self, dirty_string):
        emoji_pattern = re.compile(
            "["
            u"\U0001F600-\U0001F64F"  # emoticons
            u"\U0001F300-\U0001F5FF"  # symbols & pictographs
            u"\U0001F680-\U0001F6FF"  # transport & map symbols
            u"\U0001F1E0-\U0001F1FF"  # flags (iOS)
            u"\U0001F900-\U0001FAFF"  # CJK Compatibility Ideographs
            # u"\U00002702-\U000027B0"
            # u"\U000024C2-\U0001F251"
            "]+",
            flags=re.UNICODE)
        return emoji_pattern.sub(r'', dirty_string)

    def escape_markdown(self, md_string):
        # Don't mess with urls
        url_regex = re.compile(
            r'^(?:http|ftp)s?://'  # http:// or https://
            r'(?:(?:[A-Z0-9](?:[A-Z0-9-]{0,61}[A-Z0-9])?\.)+(?:[A-Z]{2,6}\.?|[A-Z0-9-]{2,}\.?)|'  # domain...
            r'localhost|'  # localhost...
            r'\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}|'  # ...or ipv4
            r'\[?[A-F0-9]*:[A-F0-9:]+\]?)'  # ...or ipv6
            r'(?::\d+)?'  # optional port
            r'(?:/?|[/?]\S+)$',
            re.IGNORECASE)
        escaped_string = ""
        # Split the message into pieces, each "word" speparated into a string is a piece
        # Discord ignores formatting characters in urls so we can't just replace the whole
        # string... We need to go through words one by one to find out what is a url (don't)
        # escape) and what isn't (escape).
        for piece in md_string.split(" "):
            if url_regex.match(piece):
                escaped_string += "{} ".format(piece)
                continue
            # Absolutely needs to go first or it will replace our escaping slashes!
            piece = piece.replace("\\", "\\\\")
            piece = piece.replace("_", "\\_")
            piece = piece.replace("*", "\\*")
            escaped_string += "{} ".format(piece)
        if escaped_string.startswith(">"):
            escaped_string = "\\" + escaped_string
        escaped_string.strip()
        return escaped_string

    def strip_colour(self, dirty_string):
        colour_pattern = re.compile(
            u"\U000000A7"  # selection symbol
            ".",
            flags=re.UNICODE)
        return colour_pattern.sub(r'', dirty_string)

    def setup_logging(self, level):
        if level.lower() == "debug":
            log_level = logging.DEBUG
        else:
            log_level = logging.INFO
        log_format = "%(asctime)s:%(name)s:%(levelname)s:%(message)s"
        logging.basicConfig(filename="bridge_log.log",
                            format=log_format,
                            level=log_level)
        stdout_logger = logging.StreamHandler(sys.stdout)
        stdout_logger.setFormatter(logging.Formatter(log_format))
        logging.getLogger().addHandler(stdout_logger)

    def run_auth_server(self, port):
        # We need to import twisted after setting up the logger because twisted hijacks our logging
        from twisted.internet import reactor
        from .auth_server import AuthFactory

        # Create factory
        factory = AuthFactory()

        # Listen
        self.logger.info("Starting authentication server on port %d", port)

        factory.listen("", port)
        reactor.run(installSignalHandlers=False)

    def generate_random_auth_token(self, length):
        letters = string.ascii_lowercase + string.digits + string.ascii_uppercase
        return ''.join(random.choice(letters) for i in range(length))

    def handle_disconnect(self, json_data=""):
        self.logger.info('Disconnected.')
        if json_data:
            self.logger.info("Disconnect json data: %s", json_data)
        if self.connection_retries >= self.config.failsafe_retries:
            self.logger.info(
                "Failed to join the server %s times in a row. Exiting.",
                self.connection_retries)
            self.logger.info(
                "Use a process supervisor if you wish to automatically restart the bridge."
            )
            # This is possibly a huge hack... Since we cannot reliably raise exceptions on this thread
            # for them to be caught on the main thread, we call interrupt_main to raise a KeyboardInterrupt
            # on main and tell it to shut the bridge down.
            self.return_code = os.EX_TEMPFAIL
            _thread.interrupt_main()
            return
        self.previous_player_list = self.player_list.copy()
        self.accept_join_events = False
        self.player_list = bidict()
        if self.connection.connected:
            self.logger.info(
                "Forced a disconnection because the connection is still connected."
            )
            self.connection.disconnect(immediate=True)
        time.sleep(15)
        while not self.is_server_online():
            self.logger.info(
                'Not reconnecting to server because it appears to be offline.')
            time.sleep(15)
        self.logger.info('Reconnecting.')
        self.connection_retries += 1
        self.connection.connect()

    def handle_disconnect_packet(self, disconnect_packet):
        self.handle_disconnect(disconnect_packet.json_data)

    def minecraft_handle_exception(self, exception, exc_info):
        self.logger.error("A minecraft exception occured! %s:",
                          exception,
                          exc_info=exc_info)
        self.handle_disconnect()

    def is_server_online(self):
        server = MinecraftServer.lookup("{}:{}".format(self.config.mc_server,
                                                       self.config.mc_port))
        try:
            status = server.status()
            del status
            return True
        except ConnectionRefusedError:
            return False
        # AttributeError: 'TCPSocketConnection' object has no attribute 'socket'
        # This might not be required as it happens upstream
        except AttributeError:
            return False

    def register_handlers(self, connection):
        connection.register_packet_listener(self.handle_join_game,
                                            clientbound.play.JoinGamePacket)

        connection.register_packet_listener(self.handle_chat,
                                            clientbound.play.ChatMessagePacket)

        connection.register_packet_listener(
            self.handle_health_update, clientbound.play.UpdateHealthPacket)

        connection.register_packet_listener(self.handle_disconnect_packet,
                                            clientbound.play.DisconnectPacket)

        connection.register_packet_listener(
            self.handle_tab_list, clientbound.play.PlayerListItemPacket)

        connection.register_packet_listener(
            self.handle_player_list_header_and_footer_update,
            clientbound.play.PlayerListHeaderAndFooterPacket)

    def handle_player_list_header_and_footer_update(self,
                                                    header_footer_packet):
        self.logger.debug("Got Tablist H/F Update: header=%s",
                          header_footer_packet.header)
        self.logger.debug("Got Tablist H/F Update: footer=%s",
                          header_footer_packet.footer)
        self.tab_header = json.loads(header_footer_packet.header)["text"]
        self.tab_footer = json.loads(header_footer_packet.footer)["text"]

    def handle_tab_list(self, tab_list_packet):
        self.logger.debug("Processing tab list packet")
        for action in tab_list_packet.actions:
            if isinstance(
                    action,
                    clientbound.play.PlayerListItemPacket.AddPlayerAction):
                self.logger.debug(
                    "Processing AddPlayerAction tab list packet, name: %s, uuid: %s",
                    action.name, action.uuid)
                username = action.name
                player_uuid = action.uuid
                if action.name not in self.player_list.inv:
                    self.player_list.inv[action.name] = action.uuid
                else:
                    # Sometimes we get a duplicate add packet on join idk why
                    return
                if action.name not in self.uuid_cache.inv:
                    self.uuid_cache.inv[action.name] = action.uuid
                # Initial tablist backfill
                if self.accept_join_events:
                    webhook_payload = {
                        'username':
                        username,
                        'avatar_url':
                        "https://visage.surgeplay.com/face/160/{}".format(
                            player_uuid),
                        'content':
                        '',
                        'embeds': [{
                            'color': 65280,
                            'title': '**Joined the game**'
                        }]
                    }
                    for webhook in self.webhooks:
                        self.req_future_session.post(webhook,
                                                     json=webhook_payload)
                    if self.config.es_enabled:
                        self.es_logger.log_connection(
                            uuid=action.uuid,
                            reason=ConnectionReason.CONNECTED,
                            count=len(self.player_list))
                    return
                else:
                    # The bot's name is sent last after the initial back-fill
                    if action.name == self.bot_username:
                        self.accept_join_events = True
                        if self.config.es_enabled:
                            diff = set(self.previous_player_list.keys()) - set(
                                self.player_list.keys())
                            for idx, player_uuid in enumerate(diff):
                                self.es_logger.log_connection(
                                    uuid=player_uuid,
                                    reason=ConnectionReason.DISCONNECTED,
                                    count=len(self.previous_player_list) -
                                    (idx + 1))
                        # Don't bother announcing the bot's own join message (who cares) but log it for analytics still
                        if self.config.es_enabled:
                            self.es_logger.log_connection(
                                uuid=action.uuid,
                                reason=ConnectionReason.CONNECTED,
                                count=len(self.player_list))

                if self.config.es_enabled:
                    self.es_logger.log_connection(uuid=action.uuid,
                                                  reason=ConnectionReason.SEEN)
            if isinstance(
                    action,
                    clientbound.play.PlayerListItemPacket.RemovePlayerAction):
                self.logger.debug(
                    "Processing RemovePlayerAction tab list packet, uuid: %s",
                    action.uuid)
                username = self.mc_uuid_to_username(action.uuid)
                player_uuid = action.uuid
                webhook_payload = {
                    'username':
                    username,
                    'avatar_url':
                    "https://visage.surgeplay.com/face/160/{}".format(
                        player_uuid),
                    'content':
                    '',
                    'embeds': [{
                        'color': 16711680,
                        'title': '**Left the game**'
                    }]
                }
                for webhook in self.webhooks:
                    self.req_future_session.post(webhook, json=webhook_payload)
                del self.uuid_cache[action.uuid]
                if action.uuid in self.player_list:
                    del self.player_list[action.uuid]
                if self.config.es_enabled:
                    self.es_logger.log_connection(
                        uuid=action.uuid,
                        reason=ConnectionReason.DISCONNECTED,
                        count=len(self.player_list))

    def handle_join_game(self, join_game_packet):
        self.logger.info('Connected and joined game as entity id %d',
                         join_game_packet.entity_id)
        self.player_list = bidict()
        self.connection_retries = 0

    def handle_chat(self, chat_packet):
        json_data = json.loads(chat_packet.json_data)
        if "extra" not in json_data:
            return
        chat_string = ""
        for chat_component in json_data["extra"]:
            chat_string += chat_component["text"]

        # Handle chat message
        regexp_match = re.match("<(.*?)> (.*)", chat_string, re.M | re.I)
        if regexp_match:
            username = regexp_match.group(1)
            original_message = regexp_match.group(2)
            player_uuid = self.mc_username_to_uuid(username)
            if username.lower() == self.bot_username.lower():
                # Don't relay our own messages
                if self.config.es_enabled:
                    bot_message_match = re.match(
                        "<{}> (.*?): (.*)".format(self.bot_username.lower()),
                        chat_string, re.M | re.I)
                    if bot_message_match:
                        self.es_logger.log_chat_message(
                            uuid=self.mc_username_to_uuid(
                                bot_message_match.group(1)),
                            display_name=bot_message_match.group(1),
                            message=bot_message_match.group(2),
                            message_unformatted=chat_string)
                        self.es_logger.log_raw_message(
                            msg_type=chat_packet.Position.name_from_value(
                                chat_packet.position),
                            message=chat_packet.json_data)
                return
            self.logger.info(
                "Incoming message from minecraft: Username: %s Message: %s",
                username, original_message)
            self.logger.debug("msg: %s", repr(original_message))
            message = self.escape_markdown(
                self.remove_emoji(original_message.strip().replace(
                    "@", "@\N{zero width space}")))
            webhook_payload = {
                'username':
                username,
                'avatar_url':
                "https://visage.surgeplay.com/face/160/{}".format(player_uuid),
                'content':
                '{}'.format(message)
            }
            for webhook in self.webhooks:
                self.req_future_session.post(webhook, json=webhook_payload)
            if self.config.es_enabled:
                self.es_logger.log_chat_message(
                    uuid=player_uuid,
                    display_name=username,
                    message=original_message,
                    message_unformatted=chat_string)
        if self.config.es_enabled:
            self.es_logger.log_raw_message(
                msg_type=chat_packet.Position.name_from_value(
                    chat_packet.position),
                message=chat_packet.json_data)

    def handle_health_update(self, health_update_packet):
        if health_update_packet.health <= 0:
            self.logger.debug("Respawned the player because it died")
            packet = serverbound.play.ClientStatusPacket()
            packet.action_id = serverbound.play.ClientStatusPacket.RESPAWN
            self.connection.write_packet(packet)
Пример #8
0
def main() -> int:

    # Handle program arguments
    ap = argparse.ArgumentParser(
        prog="mchat",
        description="A console chat client for most Minecraft server versions")
    ap.add_argument("server_address", help="IP address of a Minecraft server")
    ap.add_argument("-p",
                    "--port",
                    help="Minecraft server port (default: %(default)s)",
                    type=int,
                    default=25565)
    ap.add_argument("-u", "--username", help="Minecraft username or email")
    ap.add_argument(
        "-v",
        "--version",
        help="Client -> Server protocol version to use (default: %(default)s)",
        default="1.16.4")
    args = ap.parse_args()

    # Verify server version to keep the terminal looking clean
    if args.version not in SUPPORTED_MINECRAFT_VERSIONS.keys():
        console.print(
            f"[bold yellow]{args.version} is not a valid Minecraft version. Versions from {list(SUPPORTED_MINECRAFT_VERSIONS.keys())[0]} to {list(SUPPORTED_MINECRAFT_VERSIONS.keys())[-1]} are allowed."
        )
        return 1

    # Do authentication
    if not args.username:
        username = Prompt.ask("Username or email")
    else:
        username = args.username

    password = getpass.getpass("Password: "******"[bright_black]Loaded authentication information")

    # Determine the actual protocol version number
    protocol_version_num = SUPPORTED_MINECRAFT_VERSIONS[args.version]
    console.print(
        f"[bright_black]Selecting protocol version {protocol_version_num}")

    # Authenticate with Mojang
    auth_token = AuthenticationToken()
    console.print(f"[bright_black]Contacting Yggdrasil...")

    try:
        auth_token.authenticate(username, password)
    except YggdrasilError as e:
        console.print(f"[bold red]Failed to authenticate Minecraft session")
        return 1

    # Open a connection
    server_connection = Connection(args.server_address,
                                   args.port,
                                   auth_token,
                                   allowed_versions=[protocol_version_num])

    try:
        server_connection.connect()
    except:
        console.print(f"[bold red]Could not connect to server")
        return 1

    # Set up an incoming chat handler
    server_connection.register_packet_listener(incomingChatHandler,
                                               ChatMessagePacket)
    console.print(f"[bright_black]Listen to incoming chat packets")

    # Set up input loop
    console.print(
        "All further inputs will be sent to server chat. Press CTRL+C to stop")
    try:
        while True:

            # Get a line from the user
            chat_message = console.input()

            # Send the chat message
            packet = serverbound.play.ChatPacket()
            packet.message = chat_message
            server_connection.write_packet(packet)

    except KeyboardInterrupt as e:
        print("\rGoodbye")

    return 0
Пример #9
0
class bot:
    def __init__(self,
                 username,
                 password,
                 bot_ign,
                 reply_rate=20,
                 whitelist=False):
        self.username = username
        self.password = password
        self.bot_ign = bot_ign
        self.debug = False
        self.whitelist = whitelist

        self.reply_rate = int(reply_rate)

        self.auth_token = authentication.AuthenticationToken()
        try:
            self.auth_token.authenticate(self.username, self.password)
        except YggdrasilError as error:
            print(error)
            exit()
        print("Logged in as %s." % self.auth_token.username)
        self.connection = Connection("mc.hypixel.net",
                                     25565,
                                     auth_token=self.auth_token)

        self.command_delay = 0
        self.msgQueue = []
        self.partyQueue = []
        self.commandQueue = []
        self.msgCurrentChannel = ""
        self.party = {"inP": False, "from": "", "timestamp": 0}
        self.partyConfig = {}
        self.playercooldown = {}
        self.cooldownTimer = time.time()
        self.heartbeat = time.time() + 120
        self.heartbeatCooldown = time.time() + 120
        self.msgformat = msgformat.formats(self.bot_ign, 24)
        self.bots = {x: 0 for x in msgformat.bots if x != self.bot_ign}
        self.current_load = 0
        self.inQueue = False
        self.inQueueTime = 0
        self.muted = False
        self.muteDuration = 3600
        self.unmutetime = 0
        self.muteheartbeat = 0
        self.leaderBuffer = []
        self.mods = []
        self.whitelisted = []
        try:
            with open("whitelisted.txt", "r") as file:
                self.whitelisted = [x for x in file.read().split("\n")]
        except Exception:
            self.whitelisted = []
        print("whitelisted loaded", len(self.whitelisted))

    def initialize(self):
        self.connection.register_packet_listener(
            self.handle_join_game, clientbound.play.JoinGamePacket)
        self.connection.register_packet_listener(
            self.handle_chat, clientbound.play.ChatMessagePacket)
        self.connection.connect()

    def disconnect(self):
        self.msgQueue = []
        self.partyQueue = []
        self.friendQueue = []
        self.connection.disconnect(True)
        exit()

    def send_chat(self, text, delay=0.6, bypass=False):
        if not self.inQueue or bypass:
            text = text[:255]  # limit to 255 characters
            packet = serverbound.play.ChatPacket()
            packet.message = text
            self.connection.write_packet(packet)
            if self.debug:
                debugtext = "".join(x for x in text if x not in "-⛬⛫⛭⛮⛶_")
                print(debugtext)
        self.command_delay = time.time()
        time.sleep(delay * 1.05)

    def handle_join_game(self, packet):
        print(packet)
        self.heartbeat = time.time() - 50
        self.heartbeatCooldown = time.time() - 50
        time.sleep(0.5)
        self.send_chat("/p leave")
        print('Connected.')

    def handle_chat(self, chat_packet):
        try:
            chat_raw = str(chat_packet.json_data)
            chat_json = json.loads(chat_raw)
            msg = util.raw_to_msg(chat_json)
            if not (self.muted):
                if ("red" in chat_raw and len(msg) < 75
                        and "+]" not in msg) or self.debug:
                    debugtext = "".join(x for x in msg if x not in "-⛬⛫⛭⛮⛶_")
                    print(debugtext)

                if ("red" in chat_raw and len(msg) < 75 and "+]" not in msg):
                    mutedetect = "".join(x for x in msg if x not in "-⛬⛫⛭⛮⛶_")
                    if "Your mute will expire in" in mutedetect:
                        muted = True
                        duration = mutedetect[
                            mutedetect.index("Your mute will expire in") + 25:]
                        duration = duration.split(' Find')
                        del duration[1]
                        duration = duration.pop(0)
                        print(f'You are muted for {duration}.')

                if "extra" in chat_json:
                    # On party request
                    if chat_raw.count("/party accept") >= 2:
                        for data in chat_json["extra"]:
                            if "/party accept" in str(data):
                                user = data["clickEvent"]["value"].split()[-1]
                                if (user not in self.whitelisted
                                    ) and self.whitelist:
                                    return  # whitelist
                                if self.cooldowncheck(user, 5):
                                    return  # cooldown
                                self.partyQueue.append({
                                    "mode": "queue",
                                    "user": user
                                })
                                return
                        return

                    # On heartbeat
                    elif "HeartBeat-KeepAlive" in chat_raw and "from" not in chat_raw.lower(
                    ) and self.bot_ign in chat_raw:
                        if time.time() - self.heartbeat > 70 and self.debug:
                            self.debug = False
                        self.heartbeat = time.time()
                        onlinehb = ['bwstatsv2']
                        onlinehb.append([
                            int(time.time()), self.bot_ign,
                            min(
                                int(
                                    max(self.current_load, 1) /
                                    max(self.reply_rate, 0.1) * 100), 100)
                        ])
                        onlinehb = [
                            x for x in onlinehb if time.time() - x[0] < 130
                        ]
                        msgformat.bots = list(
                            set([
                                x[1] for x in onlinehb
                                if time.time() - x[0] < 130
                            ]))
                        self.bots = {}
                        for bot in onlinehb:
                            if bot[1] in self.bots:
                                self.bots[bot[1]] = max(
                                    bot[2], self.bots[bot[1]])
                            else:
                                self.bots[bot[1]] = bot[2]
                        if self.debug:
                            for bot in self.bots:
                                print(bot, self.bots[bot], "%")
                            # print(msgformat.bots)
                        return

                    elif "Party Leader" in chat_raw and "●" in chat_raw:
                        leader = [
                            leader
                            for leader in msg[msg.index(":") + 1:].split("●")
                            if len(leader) > 1
                        ]
                        leader = [leader.split()[-1] for leader in leader]
                        leader = leader.pop(0)
                        self.leaderBuffer.append(leader)

                    elif "Party Moderators" in chat_raw and "●" in chat_raw:
                        mods = [
                            mods
                            for mods in msg[msg.index(":") + 1:].split("●")
                            if len(mods) > 1
                        ]
                        mods = [mods.split()[-1] for mods in mods]
                        self.mods.append(self.leaderBuffer[0])

                    # On party list return
                    elif "Party Members" in chat_raw and "●" in chat_raw:
                        # Party members (2): [VIP] MinuteBrain ● [MVP+] Its_Me_Me ●
                        users = [
                            user
                            for user in msg[msg.index(":") + 1:].split("●")
                            if len(user) > 1
                        ]
                        users = [user.split()[-1]
                                 for user in users]  # remove ranks
                        users.append(self.leaderBuffer[0])
                        users.extend(self.mods)
                        self.leaderBuffer = []
                        self.mods = []
                        users.remove(self.bot_ign)  # remove bot from the list
                        self.partyQueue = [{
                            "mode": "list",
                            "user": users
                        }] + self.partyQueue  # put on top of the queue
                        return

                    # On msg request
                    elif ("From "
                          in chat_raw) and ("light_purple"
                                            in chat_raw) and (self.bot_ign
                                                              not in chat_raw):
                        self.chat_msg(msg)
                        return

                    # On open PM channel
                    elif {
                            "text": " for the next 5 minutes. Use ",
                            "color": "green"
                    } in chat_json["extra"]:
                        user = msg[msg.index("with") +
                                   4:msg.index("for")].split()[-1]
                        #print(user)
                        self.msgCurrentChannel = user
                        return

                    # On friend request
                    elif ("Click to" in chat_raw) and ("/f accept "
                                                       in chat_raw):
                        for data in chat_json["extra"]:
                            if "/f accept " in str(data).lower():
                                user = data["clickEvent"]["value"].split()[-1]
                                if self.cooldowncheck(user, 2):
                                    return  # cooldown
                                self.commandQueue.append({
                                    "command": "friend_request",
                                    "user": user
                                })
                                return
                        return

                    # On queue
                    elif ("The game starts in" in chat_raw) or (
                            "has joined" in msg and "/" in msg
                    ) or ("has quit" in msg
                          and "/" in msg) or ("The party leader, " in chat_raw
                                              and "yellow" in chat_raw):
                        if not (self.inQueue
                                ) and time.time() - self.inQueueTime > 5:
                            self.inQueue = True
                            self.inQueueTime = time.time()
                            print("Blocked - " + self.party["from"])
                            self.cooldowncheck(self.party["from"], 60)
                            self.party["inP"] = True
                            self.party["timestamp"] = time.time() + 99999
                            time.sleep(1)
                            self.party["inP"] = True
                            self.send_chat("/pchat :( hey! don't warp me!",
                                           0.07, True)
                            self.send_chat("/p leave", 1, True)
                            self.send_chat("/hub bw", 0.7, True)
                            for _ in range(15):
                                self.send_chat("/golimbo", 0.07, True)
                            self.party["inP"] = True
                            self.party["timestamp"] = time.time() + 5
                            self.inQueue = False
                            self.inQueueTime = time.time()
                        return

                    # On whereami respond
                    elif "You are currently connected to server" in msg and "aqua" in chat_raw.lower(
                    ):
                        if "lobby" in msg:
                            self.commandQueue.append({"command": "in_lobby"})
                        else:
                            self.commandQueue.append({"command": "in_game"})
                        return
            else:  # while muted
                print('idk ur muted or smth')

        except Exception as error_code:
            print("chat handle error!!", error_code)

    def chat_msg(self, msg):
        # >>> msg = 'From [MVP+] FatDubs: FatDubs gamerboy80 5'
        if "+send" not in msg.lower():
            msg = "".join([
                char for char in msg if char.lower() in
                "[]:abcdefghijklmnopqrstuvwxyz0123456789_ +/"
            ])
        msg = " ".join(msg.split())  # remove double space
        msg = msg.replace("+ ", "+").replace("++", "+").replace("+]", "]")
        user = msg[:msg.index(":")].split()[-1]
        if (user not in self.whitelisted) and self.whitelist:
            return  # whitelist
        agus = msg[msg.index(":") + 1:].split()
        # user = '******'
        # agus = ['FatDubs', 'gamerboy80', '5']

        mode = 0  # stats mode
        if len(agus) > 1 and "+send" not in "".join(agus).lower():
            mode = agus[-1]
            if mode in [str(x) for x in range(6)]:
                mode = int(mode)
                agus.pop(-1)
            else:
                mode = 0

        # user = '******'
        # agus = ['FatDubs', 'gamerboy80']
        # mode = 5

        if self.cooldowncheck(user, 1) and user.lower() not in ["fatdubs"]:
            return  # player cooldown

        # commands
        if "+" in msg:
            command = agus[0]

            if command.lower() == "+send" and user.lower() in [
                    "fatdubs"
            ] and len(agus) >= 2:
                self.commandQueue.append({
                    "command": "send_command",
                    "send": " ".join(agus[1:])
                })

            elif command.lower() == "+limbo" and user.lower() in ["fatdubs"]:
                print("Warp to Limbo")
                for _ in range(15):
                    self.send_chat("/golimbo", 0.07, True)
                self.send_chat("/whereami")

            elif command.lower() == "+whitelist" and user.lower() in [
                    "fatdubs"
            ] and len(agus) >= 2:
                self.whitelistChange = ("".join(agus[1:]))
                print('whitelist queue - ' + self.whitelistChange)

            elif command.lower() == "+stop" and user.lower() in ["fatdubs"]:
                print('disconnecting..')
                self.disconnect()

            elif command.lower() in ["+pmode", "+setpartymode"]:
                self.partyConfig[user] = mode
                self.msgQueue = [{
                    "msgMode": "party_mode",
                    "user": user,
                    "mode": mode
                }] + self.msgQueue

            elif command.lower() == "+resetcooldown" and user.lower() in [
                    "fatdubs"
            ]:
                self.playercooldown = {}
                print('reset cooldown')

            elif command.lower() in ["+reload", "+reloadall"] and user.lower(
            ) in ["fatdubs"] + [x.lower() for x in list(self.bots)]:
                print("Reloading...")
                try:
                    reload(msgformat)
                    self.msgformat = msgformat.formats(self.bot_ign, 24)
                    self.bots = {
                        x: 0
                        for x in msgformat.bots if x != self.bot_ign
                    }
                except Exception:
                    print("Fail to reload msgformat")
                try:
                    reload(hypixelapi)
                except Exception:
                    print("Fail to reload hypixelapi")

            elif command.lower() == "+debug" and user.lower() in ["fatdubs"]:
                self.debug = not (self.debug)
                print(f"Debug : {self.debug}")
            else:
                self.msgQueue = [{
                    "msgMode": "wrong_syntax",
                    "user": user
                }] + self.msgQueue

            return

        # stats request
        if self.current_load <= self.reply_rate:
            if len(agus) > 0:
                if len(agus[0]) <= 16:
                    if len(agus) == 1:
                        self.msgQueue = [{
                            "msgMode": "stats",
                            "replyto": user,
                            "username": agus[0],
                            "mode": mode
                        }] + self.msgQueue
                    elif len(agus) > 1 and len(agus) <= 4:
                        self.msgQueue = [{
                            "msgMode": "stats_multiple",
                            "replyto": user,
                            "username": agus,
                            "mode": mode
                        }] + self.msgQueue
                    else:
                        self.msgQueue = [{
                            "msgMode": "wrong_syntax",
                            "user": user
                        }] + self.msgQueue
                else:
                    self.msgQueue = [{
                        "msgMode": "wrong_syntax",
                        "user": user
                    }] + self.msgQueue
            else:
                self.msgQueue = [{
                    "msgMode": "wrong_syntax",
                    "user": user
                }] + self.msgQueue

    def cooldowncheck(self, user, n=1):
        if user not in self.playercooldown:
            self.playercooldown[user] = n
        else:
            if self.playercooldown[user] > 6:
                self.playercooldown[user] += 3
            else:
                self.playercooldown[user] += n

        if self.playercooldown[user] > 100 and user.lower() not in ["fatdubs"]:
            self.commandQueue.append({"command": "ignore", "user": user})
            print("Ignored", user, self.playercooldown[user])
            return True
        elif self.playercooldown[user] > 6 and user.lower() not in ["fatdubs"]:
            print("Reject spam from", user, self.playercooldown[user])
            return True
        else:
            self.current_load += 1
            return False

    def cooldown_tick(self):
        if time.time() - self.cooldownTimer >= 6:
            self.cooldownTimer = time.time()
            for user in list(self.playercooldown):
                self.playercooldown[user] -= 1
            self.playercooldown = {
                x: self.playercooldown[x]
                for x in list(self.playercooldown)
                if self.playercooldown[x] > 0
            }

    def msg_tick(self):
        if len(self.msgQueue) > 0:
            currentQueue = self.msgQueue.pop(0)
            if currentQueue["msgMode"] == "stats":
                replyTo = currentQueue["replyto"]
                username = currentQueue["username"]
                if currentQueue["username"].lower() == "me":
                    username = currentQueue["replyto"]
                mode = currentQueue["mode"]
                if self.msgCurrentChannel != replyTo:
                    while time.time() - self.command_delay < 0.5:
                        time.sleep(0.05)
                    self.send_chat("/r", 0)
                data = hypixelapi.getPlayer(username, hypixelapi.nextKey())
                raw = hypixelapi.convert(data, mode, "msg")
                msg = self.msgformat.msg(raw,
                                         replyTo.lower() == username.lower())
                while time.time() - self.command_delay < 0.7:
                    time.sleep(0.05)
                if replyTo.lower() == self.msgCurrentChannel.lower():
                    print(f"(R) {replyTo} --> {username}")
                    self.send_chat(msg, 0.4)
                else:
                    if hypixelapi.getPlayer(
                            replyTo, hypixelapi.nextKey())["msgsetting"]:
                        print(f"(MSG) {replyTo} --> {username}")
                        self.send_chat(f"/msg {replyTo} " + msg, 0.4)
                    else:
                        print(f"(MSG) Couldn't reply to {replyTo}")
                self.msgCurrentChannel = ""

            if currentQueue["msgMode"] == "stats_multiple":
                replyTo = currentQueue["replyto"]
                usernames = currentQueue["username"]
                mode = currentQueue["mode"]
                #util.dict_increment(self.quotaChange,replyTo,len(usernames))
                if self.msgCurrentChannel != replyTo:
                    while time.time() - self.command_delay < 0.6:
                        time.sleep(0.05)
                    self.send_chat("/r", 0)
                handle = util.multithreading(usernames, mode)
                handle.start()
                raws = [handle.output[x] for x in list(handle.output)]
                msg = list(self.msgformat.party(raws, mode))[0]
                msg = msgformat.insertInvis(msg, 20)
                while time.time() - self.command_delay < 0.7:
                    time.sleep(0.05)
                if replyTo.lower() == self.msgCurrentChannel.lower():
                    print(f"(R) {replyTo} --> {usernames}")
                    self.send_chat(msg, 0.4)
                else:
                    if hypixelapi.getPlayer(
                            replyTo, hypixelapi.nextKey())["msgsetting"]:
                        print(f"(MSG) {replyTo} --> {username}")
                        self.send_chat(f"/msg {replyTo} " + msg, 0.4)
                    else:
                        print(f"(MSG) Can't send msg {replyTo}")
                self.msgCurrentChannel = ""

            elif currentQueue["msgMode"] == "wrong_syntax":
                print(f"Wrong_syntax: {currentQueue['user']}")
                while time.time() - self.command_delay < 0.5:
                    time.sleep(0.05)
                self.send_chat("/r " + self.msgformat.wrong_syntax(), 0.5)

            elif currentQueue["msgMode"] == "party_mode":
                print(
                    f"Party Mode: {currentQueue['user']} --> {currentQueue['mode']}"
                )
                while time.time() - self.command_delay < 0.5:
                    time.sleep(0.05)
                self.send_chat(
                    "/r " + self.msgformat.party_mode(currentQueue["mode"]),
                    0.5)

    def party_chat_transit(self, msg, delay=0.5):
        while len(self.msgQueue) > 0:
            self.msg_tick()
            time.sleep(0.05)
        while time.time() - self.command_delay < delay:
            time.sleep(0.05)
        self.send_chat(msg, delay)
        self.party["timestamp"] = time.time()

    def party_tick(self):
        if len(self.partyQueue) > 0 and len(self.msgQueue) == 0:
            currentQueue = self.partyQueue.pop(0)
            if currentQueue["mode"] == "queue" and self.party[
                    "inP"]:  # requeue if in party
                #print("Party Requeued !!")
                self.partyQueue.append(currentQueue)
            else:
                if currentQueue["mode"] == "queue":
                    self.party = {"inP": True, "from": currentQueue["user"]}
                    #util.dict_increment(self.quotaChange,self.party["from"],1)
                    while time.time() - self.command_delay < 0.5:
                        time.sleep(0.05)  # prevent sending command too fast
                    self.party_chat_transit(f"/p accept {self.party['from']}",
                                            0.4)
                    self.party_chat_transit(f"/pl", 0.3)
                elif currentQueue["mode"] == "list":
                    users = currentQueue['user']
                    print("Party list -", " ".join(users))
                    for user in users:
                        if user.lower() != self.bot_ign and user in list(
                                self.bots):
                            print("multiple bots in party!!!!!")
                            self.cooldowncheck(self.party["from"], 20)
                            while time.time() - self.command_delay < 2:
                                self.msg_tick()
                                time.sleep(0.05)
                            self.send_chat("/p leave")
                            self.party["inP"] = False
                            return
                    if len(users) <= self.msgformat.party_max:
                        if self.party["from"] in self.partyConfig:
                            mode = self.partyConfig[self.party["from"]]
                        else:
                            mode = 0
                        handle = util.multithreading(users, mode)
                        handle.start()
                        raws = [handle.output[x] for x in list(handle.output)]
                        msgs = self.msgformat.party(raws, mode)
                        while time.time() - self.command_delay < 0.3:
                            time.sleep(0.05)
                        for msg in msgs:
                            self.party_chat_transit(f"/pchat {msg}", 0.3)
                    else:
                        while time.time() - self.command_delay < 0.3:
                            time.sleep(0.05)
                        self.party_chat_transit(
                            "/pchat " + self.msgformat.party_too_large(), 0.3)
                    while time.time() - self.command_delay < 1:
                        self.msg_tick()
                        time.sleep(0.05)
                    self.send_chat("/p leave")
                    self.party["inP"] = False
        if self.party["inP"] and time.time() - self.party["timestamp"] > 2:
            print("Party timeout", self.party["from"])
            while time.time() - self.command_delay < 0.8:
                time.sleep(0.05)
            self.send_chat("/p leave", 0.3)
            self.party["inP"] = False

    def command_tick(self):
        if len(self.commandQueue) > 0:
            currentQueue = self.commandQueue.pop(0)

            if currentQueue["command"] == "friend_request":
                print(f"Friend accepted - {currentQueue['user']}")
                while time.time() - self.command_delay < 0.7:
                    time.sleep(0.05)
                self.send_chat(f"/f accept {currentQueue['user']}", 0.3)

            elif currentQueue["command"] == "send_command":
                print(f"Command sent - {currentQueue['send']}")
                while time.time() - self.command_delay < 0.7:
                    time.sleep(0.05)
                self.send_chat(currentQueue["send"], 0.3, True)

            elif currentQueue["command"] == "in_game":
                print("Warp to Lobby")
                while time.time() - self.command_delay < 0.5:
                    time.sleep(0.05)
                self.send_chat("/hub bw", 0.3, True)

            elif currentQueue["command"] == "in_lobby":
                print("Warp to Limbo")
                for _ in range(15):
                    self.send_chat("/golimbo", 0.07, True)
                self.send_chat("/whereami")

            elif currentQueue["command"] == "ignore":
                print(f"Ignored - {currentQueue['user']}")
                while time.time() - self.command_delay < 0.7:
                    time.sleep(0.05)
                self.send_chat(f"/ignore add {currentQueue['user']}")

    def heartbeat_tick(self):
        if time.time() - self.heartbeat > 610:
            self.connection.disconnect(True)
            raise Exception("No heartbeat detect! Reconnecting")
            return

        if time.time() - self.heartbeat > 120 and not (self.debug):
            #self.debug = True
            self.connection.connect()
            #print("Debug : True")
            print("Reconnecting")

        if time.time() - self.heartbeat > 60 and time.time(
        ) - self.heartbeatCooldown > 30:
            heartbeat_length = time.time() - self.heartbeat
            random_msg = "".join(
                [chr(random.randint(64, 125)) for _ in range(30)])
            while time.time() - self.command_delay < 0.5:
                time.sleep(0.7)
            self.send_chat(
                f"/msg {self.bot_ign} HeartBeat-KeepAlive {random_msg}",
                0.3)  #comment this to test heartbeat restart system.
            self.heartbeatCooldown = time.time()
            self.send_chat("/whereami", 0.2)

            if self.current_load > self.reply_rate:
                print("Overloaded!! <-----")
            self.current_load = 0

            if time.time() - self.heartbeat > 300:
                self.connection.connect()
                print("Reconnecting")

            print(f"Heartbeat ({int(heartbeat_length)}sec)")
            return

    def tick(self):
        self.heartbeat_tick()
        try:
            self.party_tick()
            self.msg_tick()
            self.command_tick()
            self.cooldown_tick()
        except Exception as error_code:
            print("Tick error! (skiped) -", error_code)
Пример #10
0
def main():
    options = get_options()

    if options.offline:
        print("Connecting in offline mode...")
        connection = Connection(options.address,
                                options.port,
                                username=options.username)
    else:
        auth_token = authentication.AuthenticationToken()
        try:
            auth_token.authenticate(options.username, options.password)
        except YggdrasilError as e:
            print(e)
            sys.exit()
        print("Logged in as %s..." % auth_token.username)
        connection = Connection(options.address,
                                options.port,
                                auth_token=auth_token)

    if options.dump_packets:

        def print_incoming(packet):
            if type(packet) is Packet:
                # This is a direct instance of the base Packet type, meaning
                # that it is a packet of unknown type, so we do not print it.
                return
            print('--> %s' % packet, file=sys.stderr)

        def print_outgoing(packet):
            print('<-- %s' % packet, file=sys.stderr)

        connection.register_packet_listener(print_incoming, Packet, early=True)
        connection.register_packet_listener(print_outgoing,
                                            Packet,
                                            outgoing=True)

    def handle_join_game(join_game_packet):
        print('Connected.')

    connection.register_packet_listener(handle_join_game,
                                        clientbound.play.JoinGamePacket)

    def print_chat(chat_packet, output="default"):

        if output == "raw":
            print(
                "Message (%s): %s" %
                (chat_packet.field_string('position'), chat_packet.json_data))

        chat_json = json.loads(chat_packet.json_data)

        if output == "pretty":
            print(
                json.dumps(chat_json,
                           sort_keys=True,
                           indent=4,
                           separators=(',', ': ')))

        if output == "default":
            message = Message(chat_json)
            ts = datetime.datetime.fromtimestamp(
                time.time()).strftime('%Y-%m-%d %H:%M:%S')
            print("[{}] {}".format(colored(ts, "grey"), message.formatted_str))

    connection.register_packet_listener(print_chat,
                                        clientbound.play.ChatMessagePacket)

    connection.connect()

    def requeue(realm):
        message = "/joinqueue " + realm
        packet = serverbound.play.ChatPacket()
        packet.message = message
        print(message)
        connection.write_packet(packet)

    # Re-join realm every 60 seconds
    rt = RepeatedTimer(60, requeue, options.realm)

    while True:
        try:
            text = input()
            if text == "/respawn":
                print("respawning...")
                packet = serverbound.play.ClientStatusPacket()
                packet.action_id = serverbound.play.ClientStatusPacket.RESPAWN
                connection.write_packet(packet)
            else:
                packet = serverbound.play.ChatPacket()
                packet.message = text
                connection.write_packet(packet)
        except KeyboardInterrupt:
            rt.stop()
            print("Bye!")
            sys.exit()
Пример #11
0
def main():
    options = get_options()

    if options.offline:
        print("Connecting in offline mode...")
        connection = Connection(options.address,
                                options.port,
                                username=options.username)
    else:
        auth_token = authentication.AuthenticationToken()
        try:
            auth_token.authenticate(options.username, options.password)
        except YggdrasilError as e:
            print(e)
            sys.exit()
        print("Logged in as %s..." % auth_token.username)
        connection = Connection(options.address,
                                options.port,
                                auth_token=auth_token)

    if options.dump_packets:

        def print_incoming(packet):
            if type(packet) is Packet:
                # This is a direct instance of the base Packet type, meaning
                # that it is a packet of unknown type, so we do not print it.
                return
            print('--> %s' % packet, file=sys.stderr)

        def print_outgoing(packet):
            print('<-- %s' % packet, file=sys.stderr)

        connection.register_packet_listener(print_incoming, Packet, early=True)
        connection.register_packet_listener(print_outgoing,
                                            Packet,
                                            outgoing=True)

    def handle_join_game(join_game_packet):
        print('Connected.')

    connection.register_packet_listener(handle_join_game,
                                        clientbound.play.JoinGamePacket)

    # debug chat callback
    def print_chat(chat_packet):
        print("Message (%s): %s" %
              (chat_packet.field_string('position'), chat_packet.json_data))

    # lists serves as output message queues
    outQueue = []

    # boolean to tell if we are running
    running = True

    # console input callback
    def input_thread():
        while running:
            text = input()
            outQueue.append(text)
            time.sleep(0.1)

    # helper function to insert into message queue
    def insert_into_queue(message, player, globalFlag):
        if globalFlag:
            outQueue.append(message)
        else:
            outQueue.append('/msg ' + player + ' ' + message)

    # helper function to handle commands
    def process_message(message, player, playerId, globalFlag):

        if message == '$whoami':
            insert_into_queue('You are ' + player + '!', player, globalFlag)

        if message == '$selling':
            try:
                dealFile = open('deals.json', 'r')
                deals = json.loads(dealFile.read())
                dealFile.close()
                items = []
                for item in deals['selling']:
                    items.append(item['item'])
                insert_into_queue('Selling these items: ' + str(items), player,
                                  globalFlag)
            except:
                insert_into_queue(
                    'Sorry! Deals are not available at this time.', player,
                    globalFlag)

        if message == '$buying':
            try:
                dealFile = open('deals.json', 'r')
                deals = json.loads(dealFile.read())
                dealFile.close()
                insert_into_queue(
                    'Buying these items: ' + str(deals['buying']), player,
                    globalFlag)
            except:
                insert_into_queue(
                    'Sorry! Deals are not available at this time.', player,
                    globalFlag)

        if message == '$reps':
            try:
                dealFile = open('deals.json', 'r')
                deals = json.loads(dealFile.read())
                dealFile.close()
                outQueue.append('Representatives of Astara: ' +
                                str(deals['representatives']))
            except:
                insert_into_queue(
                    'Sorry! Database is not available at this time.', player,
                    globalFlag)

        if message == '$help':
            insert_into_queue('Hi! I\'m the Astaran Trade Bot. Minimum trade value is 1db.' + \
                              ' Here are some commands you can use: $selling, $buying, $price <item>, ' + \
                              '$whoami, $reps, $help', player, globalFlag)

        if message.startswith('$price '):
            try:
                query = message[7:]
                dealFile = open('deals.json', 'r')
                deals = json.loads(dealFile.read())
                dealFile.close()
                name = ''
                price = ''
                for item in deals['selling']:
                    for alias in item['alias']:
                        if query.lower() == alias.lower():
                            name = item['item']
                            price = item['price']
                            break
                    if name != '':
                        break
                if name == '' or price == '':
                    insert_into_queue('Sorry! No price listed for that item.',
                                      player, globalFlag)
                else:
                    insert_into_queue('Astara sells ' + name + ' for ' + price,
                                      player, globalFlag)
            except:
                insert_into_queue('Sorry! No price listed for that item.',
                                  player, globalFlag)

    # chat processing callback
    def process_chat(chat_packet):
        position = chat_packet.field_string('position')
        if position == 'CHAT' or position == 'SYSTEM':
            data = json.loads(chat_packet.json_data)

            # Global Chat
            if data['translate'] == 'chat.type.text':
                # grab useful data from json
                message = data['with'][1]
                player = data['with'][0]['insertion']
                hoverStr = data['with'][0]['hoverEvent']['value']['text']
                start = hoverStr.index('id:\"') + 4
                end = hoverStr.index('\",type:')
                playerId = hoverStr[start:end]
                # print chat message
                outStr = playerId + ' (' + player + '): ' + message
                print(outStr)
                # log message
                log = open('log.txt', 'a')
                log.write(outStr + '\n')
                log.close()
                # process message
                process_message(message, player, playerId, True)

            # Private Chat
            if data['translate'] == 'commands.message.display.incoming':
                # grab useful data from json
                message = data['with'][1]['text']
                player = data['with'][0]['insertion']
                hoverStr = data['with'][0]['hoverEvent']['value']['text']
                start = hoverStr.index('id:\"') + 4
                end = hoverStr.index('\",type:')
                playerId = hoverStr[start:end]
                # print chat message
                outStr = playerId + ' (' + player + ') PRIVATE: ' + message
                print(outStr)
                # log message
                log = open('log.txt', 'a')
                log.write(outStr + '\n')
                log.close()
                # process message
                process_message(message, player, playerId, False)

    # Register Debug callback
    #connection.register_packet_listener(
    #    print_chat, clientbound.play.ChatMessagePacket)

    # Register our chatbot logic
    connection.register_packet_listener(process_chat,
                                        clientbound.play.ChatMessagePacket)

    # start network thread
    connection.connect()

    # start console thread
    inThread = threading.Thread(target=input_thread)
    inThread.start()

    # Main bot console loop
    while running:
        try:
            time.sleep(0.05)
            if len(outQueue) != 0:
                msg = outQueue.pop()
                if msg == '/respawn':
                    print('Respawning...')
                    packet = serverbound.play.ClientStatusPacket()
                    packet.action_id = serverbound.play.ClientStatusPacket.RESPAWN
                    connection.write_packet(packet)
                elif msg == '/exit':
                    print('Disconnecting')
                    running = False
                else:
                    print('Sent Message: ' + msg)
                    packet = serverbound.play.ChatPacket()
                    packet.message = msg
                    connection.write_packet(packet)
        except KeyboardInterrupt:
            outQueue.append('/exit')
Пример #12
0
class Minecraft():
    def __init__(self,
                 username,
                 password=None,
                 server=None,
                 versions=("1.12.2", "1.12.2"),
                 auto_connect=False):
        self.username = username
        self.password = password
        self.server = server
        self.versions = versions

        self.event = lambda x: print(x)

        self.auth_token = authentication.AuthenticationToken(
            username=self.username, access_token=self.password)
        print("authenticated: %s" % self.auth_token.authenticate(
            self.username, self.password, invalidate_previous=False))
        self.connection = Connection(self.server,
                                     auth_token=self.auth_token,
                                     allowed_versions=self.versions)

        self.connection.register_packet_listener(lambda x: self.print_chat(x),
                                                 ChatMessagePacket)

        print(self.auth_token)
        print(self.connection)

        if auto_connect:
            self._loop_reconect()

    def _loop_reconect(self):
        Timer(30.0, self._loop_reconect).start()
        try:
            self.connect()
        except:
            pass

    def add_chat_event(self, event):
        self.event = event

    def connect(self):
        self.connection.connect()

    def disconnect(self, immediate=False):
        self.connection.disconnect(immediate=immediate)

    def send_message(self, message):
        if message.strip() == "" or message == None:
            return False
        packet = ChatPacket()
        packet.message = message
        self.connection.write_packet(packet)

    def print_chat(self, chat_packet):
        try:
            a = json.loads(chat_packet.json_data)
        except Exception as e:
            pass
        else:
            self.event(self.parse_chat(a))

    def parse_chat(self, chat_data):
        try:
            chat_data["extra"][0]["extra"]
            try:
                return (True, self.parse_chat(chat_data["extra"][0])[1])
            except Exception as e:
                print(e)
        except:
            try:
                return (False, "".join([x["text"]
                                        for x in chat_data["extra"]]))
            except:
                pass
            return
Пример #13
0
def main():
    options = get_options()

    assets = AssetsManager(options.assets)
    mcdata = DataManager("./mcdata")

    if options.offline:
        print("Connecting in offline mode...")
        connection = Connection(options.address,
                                options.port,
                                username=options.username,
                                allowed_versions=[options.mcversion])
    else:
        auth_token = authentication.AuthenticationToken()
        try:
            auth_token.authenticate(options.username, options.password)
        except YggdrasilError as e:
            print(e)
            return
        print("Logged in as %s..." % auth_token.username)
        connection = Connection(options.address,
                                options.port,
                                auth_token=auth_token,
                                allowed_versions=[options.mcversion])

    if options.dump_packets:

        def print_incoming(packet):
            if type(packet) is Packet:
                # This is a direct instance of the base Packet type, meaning
                # that it is a packet of unknown type, so we do not print it.
                return
            if type(packet) in [
                    clientbound.play.EntityVelocityPacket,
                    clientbound.play.EntityLookPacket
            ]:
                # Prevents useless console spam
                return
            print('--> %s' % packet, file=sys.stderr)

        def print_outgoing(packet):
            print('<-- %s' % packet, file=sys.stderr)

        connection.register_packet_listener(print_incoming, Packet, early=True)
        connection.register_packet_listener(print_outgoing,
                                            Packet,
                                            outgoing=True)

    chat = ChatManager(assets)
    chat.register(connection)

    chunks = ChunksManager(mcdata)
    chunks.register(connection)

    def handle_join_game(join_game_packet):
        print('Connected.')

    connection.register_packet_listener(handle_join_game,
                                        clientbound.play.JoinGamePacket)

    connection.connect()

    while True:
        try:
            text = input()
            if text.startswith("!"):
                if text == "!respawn":
                    print("respawning...")
                    packet = serverbound.play.ClientStatusPacket()
                    packet.action_id = serverbound.play.ClientStatusPacket.RESPAWN
                    connection.write_packet(packet)
                elif text.startswith("!print "):
                    p = text.split(" ")
                    chunks.print_chunk(
                        chunks.get_chunk(int(p[1]), int(p[2]), int(p[3])),
                        int(p[4]))
                elif text == "!chunks":
                    area = chunks.get_loaded_area()
                    y_count = area[1][1] - area[0][1]
                    print("Bounds: %s" % (area, ))
                    for y in range(area[0][1], area[1][1]):
                        print("Slice %d:" % (y))
                        for z in range(area[0][2], area[1][2]):
                            for x in range(area[0][0], area[1][0]):
                                if (x, y, z) in chunks.chunks:
                                    c = 'X'
                                else:
                                    c = '.'
                                print(c, end="")
                            print()
                elif text == "!export":
                    area = chunks.get_loaded_area(True)
                    export_area(area[0][0] * 16, area[0][1] * 16,
                                area[0][2] * 16, area[1][0] * 16,
                                area[1][1] * 16, area[1][2] * 16, chunks,
                                assets, mcdata)
                else:
                    print("Unknow test command: %s" % (text))
            else:
                chat.send(connection, text)

        except KeyboardInterrupt:
            print("Bye!")
            sys.exit()

        except Exception as ex:
            print("Exception: %s" % (ex))
            traceback.print_exc()
Пример #14
0
def main():
    """Our main function for running the simple pyCraft implementation.

    This function handles and maintains:
     - Gaining authentication tokens & 'logging in'
     - Connecting to the provided server, online or offline
     - Prints the chat packet data to standard out on Clientbound Packet
     - Writes Serverbound chat Packets when required
     - Dumping all packets to standard out

    Notes
    -----
    This is a blocking function.

    """
    options = get_options()

    if options.offline:
        print("Connecting in offline mode...")
        connection = Connection(options.address,
                                options.port,
                                username=options.username)
    else:
        auth_token = authentication.AuthenticationToken()
        try:
            auth_token.authenticate(options.username, options.password)
        except YggdrasilError as e:
            print(e)
            sys.exit()
        print("Logged in as %s..." % auth_token.username)
        connection = Connection(options.address,
                                options.port,
                                auth_token=auth_token)

    if options.dump_packets:

        def print_incoming(packet):
            if type(packet) is Packet:
                # This is a direct instance of the base Packet type, meaning
                # that it is a packet of unknown type, so we do not print it
                # unless explicitly requested by the user.
                if options.dump_unknown:
                    print("--> [unknown packet] %s" % packet, file=sys.stderr)
            else:
                print("--> %s" % packet, file=sys.stderr)

        def print_outgoing(packet):
            print("<-- %s" % packet, file=sys.stderr)

        connection.register_packet_listener(print_incoming, Packet, early=True)
        connection.register_packet_listener(print_outgoing,
                                            Packet,
                                            outgoing=True)

    def handle_join_game(join_game_packet):
        print("Connected.")

    connection.register_packet_listener(handle_join_game,
                                        clientbound.play.JoinGamePacket)

    def print_chat(chat_packet):
        print("Message (%s): %s" %
              (chat_packet.field_string("position"), chat_packet.json_data))

    connection.register_packet_listener(print_chat,
                                        clientbound.play.ChatMessagePacket)

    connection.connect()

    while True:
        try:
            text = input()
            if text == "/respawn":
                print("respawning...")
                packet = serverbound.play.ClientStatusPacket()
                packet.action_id = serverbound.play.ClientStatusPacket.RESPAWN
                connection.write_packet(packet)
            else:
                packet = serverbound.play.ChatPacket()
                packet.message = text
                connection.write_packet(packet)
        except KeyboardInterrupt:
            print("Bye!")
            sys.exit()
Пример #15
0
def main():
    options = get_options()

    if options.offline:
        print("Connecting in offline mode...")
        connection = Connection(options.address,
                                options.port,
                                username=options.username)
    else:
        auth_token = authentication.AuthenticationToken()
        try:
            auth_token.authenticate(options.username, options.password)
        except YggdrasilError as e:
            print(e)
            sys.exit()
        print("Logged in as %s..." % auth_token.username)
        connection = Connection(options.address,
                                options.port,
                                auth_token=auth_token)

    if options.dump_packets:

        def print_incoming(packet):
            if type(packet) is Packet:
                # This is a direct instance of the base Packet type, meaning
                # that it is a packet of unknown type, so we do not print it.
                return
            print('--> %s' % packet, file=sys.stderr)

        def print_outgoing(packet):
            print('<-- %s' % packet, file=sys.stderr)

        connection.register_packet_listener(print_incoming, Packet, early=True)
        connection.register_packet_listener(print_outgoing,
                                            Packet,
                                            outgoing=True)

    def handle_join_game(join_game_packet):
        print('Connected.')

    connection.register_packet_listener(handle_join_game,
                                        clientbound.play.JoinGamePacket)

    def print_raw_json(chat_packet):
        print("Message (%s): %s" %
              (chat_packet.field_string('position'), chat_packet.json_data))

    def print_raw_text(chat_packet):
        print("Message (%s): " % chat_packet.field_string('position'), end="")
        printRawText(json.loads(chat_packet.json_data))
        print("")

    def print_color_text(chat_packet):
        print("Message (%s): " % chat_packet.field_string('position'), end="")
        printColorText(json.loads(chat_packet.json_data))
        print("")

    def keep_alive(packet):
        print("keep_alive[%d] packet receive." % packet.keep_alive_id)
        from random import randint
        ret = serverbound.play.KeepAlivePacket()
        ret.keep_alive_id = randint(0, 10000)
        connection.write_packet(ret)
        print("Write packet ok.")

    connection.register_packet_listener(print_color_text,
                                        clientbound.play.ChatMessagePacket)
    connection.register_packet_listener(keep_alive,
                                        clientbound.play.KeepAlivePacket)

    connection.connect()

    while True:
        try:
            text = input()
            if text == "/respawn":
                print("respawning...")
                packet = serverbound.play.ClientStatusPacket()
                packet.action_id = serverbound.play.ClientStatusPacket.RESPAWN
                connection.write_packet(packet)
            else:
                packet = serverbound.play.ChatPacket()
                packet.message = text
                connection.write_packet(packet)
        except KeyboardInterrupt:
            print("Bye!")
            sys.exit()
Пример #16
0
class Player:
    __retries = 0

    def __init__(self, account: str, password: str, server_address: str,
                 port: int, version: int, auto_reconnect: bool,
                 auto_respawn: bool, lang: Lang):
        self.__email = account
        self.__password = base64.b64encode(password.encode())
        self.__lang = lang

        self.__logger = logging.getLogger("Auth")
        logging.basicConfig(level=logging.INFO)

        tokens = self.__get_tokens()
        self.__auth = authentication.AuthenticationToken(
            username=self.__email,
            access_token=tokens["access"],
            client_token=tokens["client"])
        self.auth()

        self.__auto_reconnect = auto_reconnect
        self.__auto_respawn = auto_respawn
        self.__connection = Connection(address=server_address,
                                       port=port,
                                       initial_version=version,
                                       auth_token=self.__auth)
        if not self.__auth.authenticated:
            return
        self.username = self.__auth.profile.name

        self.__logger = logging.getLogger(self.username)

        self.__connection.register_packet_listener(
            self.handle_join_game, clientbound.play.JoinGamePacket)
        self.__connection.register_packet_listener(
            self.print_chat, clientbound.play.ChatMessagePacket)
        self.__connection.register_packet_listener(
            self.handle_disconnect, clientbound.play.DisconnectPacket)
        self.__connection.register_packet_listener(
            self.handle_health_change, clientbound.play.UpdateHealthPacket)
        self.__connection.register_exception_handler(self.handle_exception)
        try:
            self.__connection.connect()
        except Exception as e:
            self.__logger.error(str(e))
            self.__retry()

    # def connect(self, ip, port):
    #     self.__init(self.username Connection)

    def __get_tokens(self) -> dict:
        try:
            with open('./data.json', 'r') as fs:
                auth = json.load(fs)
        except FileNotFoundError:
            return {"access": None, "client": None}
        else:
            if self.__email in auth:
                return auth[self.__email]
            else:
                return {"access": None, "client": None}

    def __refresh_tokens(self, access: str, client: str):
        auth = {}
        try:
            with open('./data.json', 'r') as fs:
                auth = json.load(fs)
        except FileNotFoundError:
            pass
        finally:
            auth[self.__email] = {"access": access, "client": client}
            with open('./data.json', 'w') as fs:
                json.dump(auth, fs, indent=2)

    def auth(self):
        try:
            self.__auth.refresh()
        except YggdrasilError:
            self.__login()
        except ValueError:
            self.__login()
        else:
            self.__logger.info(
                self.__lang.lang("main.auth.still_valid").format(
                    email=self.__email))
            self.__refresh_tokens(access=self.__auth.access_token,
                                  client=self.__auth.client_token)

    def __login(self):
        self.__logger.info(
            self.__lang.lang("main.auth.login").format(email=self.__email))
        try:
            self.__auth.authenticate(username=self.__email,
                                     password=base64.b64decode(
                                         self.__password).decode())
        except YggdrasilError as e:
            self.__logger.error(
                self.__lang.lang("main.auth.error").format(email=self.__email,
                                                           message=str(e)))
        else:
            self.__refresh_tokens(access=self.__auth.access_token,
                                  client=self.__auth.client_token)

    def reconnect(self):
        try:
            self.__connection.connect()
        except Exception as e:
            self.__logger.error(str(e))
            self.__retry()

    # noinspection PyUnusedLocal
    def handle_join_game(self, join_game_packet):
        self.__logger.info(
            self.__lang.lang("player.connected").format(
                server=self.__connection.options.address,
                port=self.__connection.options.port))
        self.__retries = 0
        packet = serverbound.play.ClientSettingsPacket()
        packet.locale = self.__lang.lang_name
        packet.view_distance = 10
        packet.chat_mode = packet.ChatMode.FULL
        packet.chat_colors = False
        packet.displayed_skin_parts = packet.SkinParts.ALL
        packet.main_hand = AbsoluteHand.RIGHT
        self.__connection.write_packet(packet)

    def print_chat(self, chat_packet):
        self.__logger.info("[{position}] {message}".format(
            position=chat_packet.field_string('position'),
            message=self.__lang.parse_json(json.loads(chat_packet.json_data))))

    def handle_disconnect(self, disconnect_packet):
        self.__logger.warning(
            self.__lang.lang("player.connection.lost").format(
                reason=self.__lang.parse_json(
                    json.loads(disconnect_packet.json_data))))
        if self.__auto_reconnect:
            self.__retry()

    def handle_health_change(self, health_packet):
        self.__logger.warning(
            self.__lang.lang("player.health.changed").format(
                health=str(health_packet.health),
                food=str(health_packet.food),
                saturation=str(health_packet.food_saturation)))

        if self.__auto_respawn and health_packet.health == 0:
            self.__logger.info(self.__lang.lang("player.respawn.hint"))
            timer = threading.Timer(1.0, self.respawn)
            timer.start()

    def handle_exception(self, e, info):
        if type(info[1]) == LoginDisconnect:
            message = str(e).replace(
                'The server rejected our login attempt with: "',
                '').replace('".', '')
            try:
                self.__logger.error(
                    self.__lang.lang("player.connection.rejected").format(
                        reason=self.__lang.parse_json(json.loads(message))))
            except json.decoder.JSONDecodeError:
                self.__logger.error(
                    self.__lang.lang("player.connection.rejected").format(
                        reason=message))
        elif type(info[1]) == YggdrasilError:
            self.__logger.error(self.__lang.lang("player.session.expired"))
            self.auth()
            timer = threading.Timer(1.0, self.reconnect)
            timer.start()
            return
        else:
            self.__logger.error("{type}: {message}".format(type=type(info[1]),
                                                           message=str(e)))
        if self.__auto_reconnect:
            if not self.__connection.connected:
                self.__retry()

    def __retry(self):
        self.__retries += 1
        if self.__retries >= 6:
            self.__retries = 0
            return
        self.__logger.info(
            self.__lang.lang("player.connection.retry").format(
                times=str(self.__retries)))
        timer = threading.Timer(5.0, self.reconnect)
        timer.start()

    def respawn(self):
        packet = serverbound.play.ClientStatusPacket()
        packet.action_id = serverbound.play.ClientStatusPacket.RESPAWN
        self.__connection.write_packet(packet)
        self.__logger.info(self.__lang.lang("player.respawned"))

    def disconnect(self):
        self.__connection.disconnect()
        self.__logger.info(self.__lang.lang("player.disconnected"))

    def toggle_auto_respawn(self):
        self.__auto_respawn = not self.__auto_respawn
        self.__logger.info(
            self.__lang.lang("player.auto_respawn.toggle").format(
                value=self.__auto_respawn))

    def toggle_auto_reconnect(self):
        self.__auto_reconnect = not self.__auto_reconnect
        self.__logger.info(
            self.__lang.lang("player.auto_reconnect.toggle").format(
                value=self.__auto_reconnect))

    def chat(self, text: str):
        if text == "":
            return
        packet = serverbound.play.ChatPacket()
        packet.message = text
        self.__connection.write_packet(packet)
Пример #17
0
connection.register_packet_listener(
    handle_join_game, clientbound.play.JoinGamePacket)
    
connection.register_packet_listener(
    print_chat, clientbound.play.ChatMessagePacket)


connection.register_packet_listener(
    sound, clientbound.play.SoundEffectPacket)

connection.connect()
time.sleep(3)
useitem()
    
    
while True:
    try:
        text = input()
        if text == "/respawn":
            print("respawning...")
            packet = serverbound.play.ClientStatusPacket()
            packet.action_id = serverbound.play.ClientStatusPacket.RESPAWN
            connection.write_packet(packet)
        else:
            packet = serverbound.play.ChatPacket()
            packet.message = text
            connection.write_packet(packet)
    except KeyboardInterrupt:
        print("Bye!")
        sys.exit()
Пример #18
0
def main():
    options = get_options()

    if options.offline:
        print("Connecting in offline mode...")
        connection = Connection(
            options.address, options.port, username=options.username)
    else:
        auth_token = authentication.AuthenticationToken()
        try:
            auth_token.authenticate(options.username, options.password)
        except YggdrasilError as e:
            print(e)
            sys.exit()
        print("Logged in as %s..." % auth_token.username)
        connection = Connection(
            options.address, options.port, auth_token=auth_token)

    if options.dump_packets:
        def print_incoming(packet):
            if type(packet) is Packet:
                # This is a direct instance of the base Packet type, meaning
                # that it is a packet of unknown type, so we do not print it.
                return
            print('--> %s' % packet, file=sys.stderr)

        def print_outgoing(packet):
            print('<-- %s' % packet, file=sys.stderr)

        connection.register_packet_listener(
            print_incoming, Packet, early=True)
        connection.register_packet_listener(
            print_outgoing, Packet, outgoing=True)

    once = False

    def handle_join_game(join_game_packet):
        message_queue.append(("CONNECTION", "**Connected**"))
        once = True
        print('Connected.')

    connection.register_packet_listener(
        handle_join_game, clientbound.play.JoinGamePacket)

    def print_chat(chat_packet):
        print("[%s]: %s" % (
            chat_packet.field_string('position'), parse_chat_item(json.loads(chat_packet.json_data))))

    connection.register_packet_listener(
        print_chat, clientbound.play.ChatMessagePacket)

    # Add a deque for chat messages and register a method to get them
    message_queue = deque()

    def forward_chat(chat_packet):
        msg = parse_chat_item(json.loads(chat_packet.json_data))
        if msg.startswith("<"):
            author, message = parse_message(msg)
            if (author != auth_token.username and message != ""): # Don't put in queue your own messages!
                message_queue.append((author, message))

    connection.register_packet_listener(
        forward_chat, clientbound.play.ChatMessagePacket)

    # More maybe? Add here shit for a chatbot

    # Auto respawn because we can't send chat while dead
    def auto_respawn(update_health_packet):
        if update_health_packet.health <= 0:
            print("Respawning")
            packet = serverbound.play.ClientStatusPacket()
            packet.action_id = serverbound.play.ClientStatusPacket.RESPAWN
            connection.write_packet(packet)

    connection.register_packet_listener(
        auto_respawn, clientbound.play.UpdateHealthPacket)

    # Start the discord thread and provide the message deque

    botThread = DiscordBotThread(message_queue, connection)
    botThread.daemon = True
    botThread.start()

    connection.connect()

    while True:
        try:
            text = input()
            if text == "/respawn":
                print("respawning...")
                packet = serverbound.play.ClientStatusPacket()
                packet.action_id = serverbound.play.ClientStatusPacket.RESPAWN
                connection.write_packet(packet)
            else:
                packet = serverbound.play.ChatPacket()
                packet.message = text
                connection.write_packet(packet)
        except KeyboardInterrupt:
            print("Bye!")
            sys.exit()
Пример #19
0
def main():
    args = sys.argv[1:]
    if (len(args) != 1):
        print("Uso : bot.py queue\nEx: bot.py towny")
        sys.exit()
    else:
        EMAIL = ""
        PASSWORD = ""
        MULTIMC_INSTANCE = ""

        auth = authentication.AuthenticationToken()
        try:
            auth.authenticate(EMAIL, PASSWORD)
        except YggdrasilError as e:
            print(e)
            sys.exit()
        print("Logado como %s" % auth.username)
        connection = Connection("dc-f626de6d73b7.earthmc.net",
                                25577,
                                auth_token=auth,
                                allowed_versions=[477])

        def entra_server(join_game_packet):
            print("Conectado no servidor")
            packet = serverbound.play.ChatPacket()
            packet.message = ("/joinqueue %s" % (args[0]))
            connection.write_packet(packet)

        connection.register_packet_listener(entra_server,
                                            clientbound.play.JoinGamePacket)

        def mensagem(chat_packet):
            if (chat_packet.field_string(
                    'position'
            ) == "SYSTEM" and chat_packet.json_data.startswith(
                    '{"extra":[{"color":"yellow","text":"You are currently in position '
            )):

                result = queue_message_from_dict(
                    json.loads(chat_packet.json_data))
                print(
                    "Pos : (%s) %s [%s]" %
                    (result.extra[1].text[:-1], result.extra[3].text, args[0]))
                if (int(result.extra[1].text[:-1].replace(" ", ""), 10) <= 5):
                    connection.disconnect()
                    os.system('multimc -l "%s"' % (MULTIMC_INSTANCE))
            elif (chat_packet.field_string('position') == "CHAT"):

                result = chat_message_from_dict(
                    json.loads(chat_packet.json_data))
                print("[%s] %s > %s" %
                      (result.extra[0].hover_event.value[0].extra[1].text[:-1],
                       result.extra[0].extra[0].text[:-2],
                       result.extra[1].extra[0].text))
            elif (chat_packet.field_string('position') != "SYSTEM"):
                print("UNHANDLED %s MESSAGE : \n(%s)" %
                      (chat_packet.field_string('position'),
                       chat_packet.json_data))

        connection.register_packet_listener(mensagem,
                                            clientbound.play.ChatMessagePacket)
        connection.connect()

        while True:
            try:
                text = input()
                if text == "/respawn":
                    print("Respawnando ...")
                    packet = serverbound.play.ClientStatusPacket()
                    packet.action_id = serverbound.play.ClientStatusPacket.RESPAWN
                    connection.write_packet(packet)
                else:
                    packet = serverbound.play.ChatPacket()
                    packet.message = text
                    connection.write_packet(packet)
            except KeyboardInterrupt:
                print("Tchau!")
                sys.exit()
Пример #20
0
def main():

    auth_token = authentication.AuthenticationToken()
    try:
        with open('minecraft.auth', 'r') as f:
            auth_token.client_token, auth_token.access_token = f.read().splitlines()

        # Library has issues need to do some hackey stuff to make sure it works.
        # I would use validate, but that would require some rewriting as well.
        auth_token.username = "******"
        auth_token.refresh()
    except (IOError, YggdrasilError):
        # IF there is no authentication file authenticate using username and password
        try:
            options = get_options()
            auth_token.authenticate(options["username"], options["password"])
        except YggdrasilError as e:
            print(e)
            sys.exit()

    with open('minecraft.auth', 'w') as fout:
        fout.write(auth_token.client_token + '\n')
        fout.write(auth_token.access_token)

    print("Logged in as %s..." % auth_token.username)
    connection = Connection(
        "localhost", 25565, auth_token=auth_token)

    def handle_join_game(join_game_packet):
        print('Connected.')

    connection.register_packet_listener(
        handle_join_game, clientbound.play.JoinGamePacket)

    def print_chat(chat_packet):
        print("Message (%s): %s" % (
            chat_packet.field_string('position'), chat_packet.json_data))

    connection.register_packet_listener(
        print_chat, clientbound.play.ChatMessagePacket)

    global connected
    connected = True

    def disconnect(disconnect_packet):
        print("You were disconnected: %s" % disconnect_packet.json_data)
        global connected
        connected = False

    connection.register_packet_listener(disconnect, 
            clientbound.play.DisconnectPacket)
    connection.connect()

    while connected:
        try:
            text = input()
            if text == "/respawn":
                print("respawning...")
                packet = serverbound.play.ClientStatusPacket()
                packet.action_id = serverbound.play.ClientStatusPacket.RESPAWN
                connection.write_packet(packet)
            else:
                packet = serverbound.play.ChatPacket()
                packet.message = text
                connection.write_packet(packet)
        except KeyboardInterrupt:
            print("Bye!")
            sys.exit()
Пример #21
0
def main():
    options = get_options()

    if options.offline:
        print("Connecting in offline mode...")
        connection = Connection(options.address,
                                options.port,
                                username=options.username)
    else:
        auth_token = authentication.AuthenticationToken()
        try:
            auth_token.authenticate(options.username, options.password)
        except YggdrasilError as e:
            print(e)
            sys.exit()
        print("Logged in as %s..." % auth_token.profile.name)
        connection = Connection(options.address,
                                options.port,
                                auth_token=auth_token)

    if options.dump_packets:

        def print_incoming(packet):
            if type(packet) is Packet:
                # This is a direct instance of the base Packet type, meaning
                # that it is a packet of unknown type, so we do not print it
                # unless explicitly requested by the user.
                if options.dump_unknown:
                    print('--> [unknown packet] %s' % packet, file=sys.stderr)
            else:
                print('--> %s' % packet, file=sys.stderr)

        def print_outgoing(packet):
            print('<-- %s' % packet, file=sys.stderr)

        connection.register_packet_listener(print_incoming, Packet, early=True)
        connection.register_packet_listener(print_outgoing,
                                            Packet,
                                            outgoing=True)

    def handle_join_game(join_game_packet):
        print('Connected.')

    connection.register_packet_listener(handle_join_game,
                                        clientbound.play.JoinGamePacket)

    def print_chat(chat_packet):
        js = ujson.loads(chat_packet.json_data)
        if len(js) == 1 and js.get('text'):
            js['translate'] = "MCDR"
            js['with'] = [0, 0, 0]
        try:
            translate = js['translate']
            msg = js['with'][-1]
            if type(msg) is dict:
                msg = msg['text']  # 1.15.2 server
            message = '[{} {}] '.format(
                datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
                chat_packet.field_string('position'))
            try:
                name = js['with'][0]['insertion']
            except:
                name = None
            if translate == 'chat.type.announcement':  # from server
                message += '[Server] {}'.format(msg)
            elif translate == 'chat.type.text':  # chat
                message += '<{}> {}'.format(name, msg)
                try:
                    uuid = js['with'][0]['hoverEvent']['contents'][
                        'id']  # 1.16 server
                except:
                    try:
                        text = js['with'][0]['hoverEvent']['value']['text']
                    except TypeError:  # 1.15.2 server
                        text = js['with'][0]['hoverEvent']['value'][0]['text']
                    uuid = text[text.find(',id:"'):].split('"')[1]
            elif translate == 'commands.message.display.incoming':  # tell
                message += '<{}>(tell) {}'.format(name, msg['text'])
            elif translate in [
                    'multiplayer.player.joined', 'multiplayer.player.left'
            ]:  # login in/out game
                message += '{} {} the game'.format(name,
                                                   translate.split('.')[2])
            elif translate == 'chat.type.emote':  # me
                message += '* {} {}'.format(name, msg)
            elif translate == 'MCDR':
                message += js.get('text')
            else:
                message = chat_packet.json_data
            print(message)
        except:
            print('Cannot resolve chat json data: \n    {}'.format(
                chat_packet.json_data))
            pass

    connection.register_packet_listener(print_chat,
                                        clientbound.play.ChatMessagePacket)

    connection.connect()

    while True:
        try:
            text = input()
            if text == "/respawn":
                print("respawning...")
                packet = serverbound.play.ClientStatusPacket()
                packet.action_id = serverbound.play.ClientStatusPacket.RESPAWN
                connection.write_packet(packet)
            else:
                packet = serverbound.play.ChatPacket()
                packet.message = text
                connection.write_packet(packet)
        except KeyboardInterrupt:
            print("Bye!")
            sys.exit()
Пример #22
0
def main():
    options = get_options()

    if options.offline:
        print("Connecting in offline mode...")
        connection = Connection(
            options.address, options.port, username=options.username)
    else:
        auth_token = authentication.AuthenticationToken()
        try:
            auth_token.authenticate(options.username, options.password)
        except YggdrasilError as e:
            print(e)
            sys.exit()
        print("Logged in as %s..." % auth_token.username)
        connection = Connection(
            options.address, options.port, auth_token=auth_token)

    if options.dump_packets:
        def print_incoming(packet):
            if type(packet) is Packet:
                # This is a direct instance of the base Packet type, meaning
                # that it is a packet of unknown type, so we do not print it
                # unless explicitly requested by the user.
                if options.dump_unknown:
                    print('--> [unknown packet] %s' % packet, file=sys.stderr)
            else:
                print('--> %s' % packet, file=sys.stderr)

        def print_outgoing(packet):
            print('<-- %s' % packet, file=sys.stderr)

        connection.register_packet_listener(
            print_incoming, Packet, early=True)
        connection.register_packet_listener(
            print_outgoing, Packet, outgoing=True)

    def handle_join_game(join_game_packet):
        print('Connected.')

    connection.register_packet_listener(
        handle_join_game, clientbound.play.JoinGamePacket)

    def print_chat(chat_packet):
        print("Message (%s): %s" % (
            chat_packet.field_string('position'), chat_packet.json_data))

    connection.register_packet_listener(
        print_chat, clientbound.play.ChatMessagePacket)

    def handle_zzz(chat_packet):
        if json.loads(chat_packet.json_data).get("with", " ")[-1] == "zzz":
            connection.disconnect()
            time.sleep(5)
            connection.connect()
            
    connection.register_packet_listener(
        handle_zzz, clientbound.play.ChatMessagePacket)        

    connection.connect()

    while True:
        try:
            text = input()
            if text == "/respawn":
                print("respawning...")
                packet = serverbound.play.ClientStatusPacket()
                packet.action_id = serverbound.play.ClientStatusPacket.RESPAWN
                connection.write_packet(packet)
            else:
                packet = serverbound.play.ChatPacket()
                packet.message = text
                connection.write_packet(packet)
        except KeyboardInterrupt:
            print("Bye!")
            sys.exit()
Пример #23
0
class Main(object):
    def __init__(self, options):
        self.auth_token = authentication.AuthenticationToken()
        try:
            self.auth_token.authenticate(options.username, options.password)
        except YggdrasilError as e:
            print(e)
            sys.exit()
        print("Logged in as " + self.auth_token.username)
        self.network = Connection(options.address, options.port,
                                  self.auth_token)
        self.network.connect()
        self.register_listeners()
        #sys.stdout = Speaker(self)
        while not self.network.playing:
            pass
        self.respawn()
        while True:
            try:
                self.tick()
            except KeyboardInterrupt:
                print("Bye!")
                sys.exit()

    def register_listeners(self):
        self.network.register_packet_listener(self.print_chat,
                                              ChatMessagePacket)
        self.network.register_packet_listener(self.set_pos,
                                              PlayerPositionAndLookPacket)
        self.network.register_packet_listener(self.recieve_plugin_message,
                                              PluginMessage)
        self.network.register_packet_listener(self.set_health, UpdateHealth)

    def tick(self):
        text = input()
        self.speak(text)

    def speak(self, message):
        packet = ChatPacket()
        packet.message = message
        self.network.write_packet(packet)

    def set_health(self, health_packet):
        if health_packet.health == 0.0:
            print "RESPAWN"
            self.respawn()

    def respawn(self):
        packet = ClientStatus()
        packet.action_id = 0
        self.network.write_packet(packet)
        #print packet

    def print_chat(self, chat_packet):
        print type(chat_packet)
        print("Position: " + str(chat_packet.position))
        print("Data: " + chat_packet.json_data)

    def recieve_plugin_message(self, plugin_message):
        data = plugin_message.data.split("|")
        if len(data) == 2 and data[0] == "MC":
            if data[1] == "Brand": print "Brand:", plugin_message.channel
            else:
                print "PLUGIN MESSAGE:", data[1], plugin_message.channel