请在Discord机器人中注册Minecraft的坐标,并创建一个传送命令

前提這篇文章是一篇關於使用 Discord 機器人來掃描 Minecraft 伺服器的聖誕日曆文章。

    • WSL, Ubuntu 22.04.1

 

    • discord.py 2.1.0

 

    Python 3.10.6

我正在这样的环境中进行。

我想做的事情当在Minecraft中发现海底神殿等地点时,我想制作一个能够通过命令将坐标整理到Discord机器人并发送到另一个频道的工具。
而且,仅此还不够有趣,所以我还想复制tp命令以便能够暂时传送到那个地点。

所以让我们来做吧。

实施首先,让我们创建一个命令来输入并显示坐标。

创建命令

import os
import discord
from discord import app_commands, Client, Intents, Interaction
from discord.ui import View, Button
from discord.app_commands import CommandTree
from dotenv import load_dotenv


load_dotenv()


class MyClient(Client):
    def __init__(self, intents: Intents) -> None:
        super().__init__(intents=intents)
        self.tree = CommandTree(self)

    async def setup_hook(self) -> None:
        await self.tree.sync()

    async def on_ready(self):
        print(f"login: {self.user.name} [{self.user.id}]")


intents = Intents.default()
client = MyClient(intents=intents)


@client.tree.command()
@app_commands.describe(what="what you found?")
async def set_locate(
    interaction: Interaction,
    what: str,
    x: int,
    y: int,
    z: int,
):
    message = f"{what} is located: x:{x}, y:{y}, z:{z}"
    await interaction.response.send_message(message)


client.run(os.getenv("TOKEN"))

试一下就知道了,目前看起来应该没有问题。

次にやることは,このメッセージを別のチャンネルに送ることです.チャンネルのIDからGuildChannelを取得します.そのチャンネルに対してメッセージをsendメソッドで送ります.

请发送到其他频道。

import os
import discord
from discord import app_commands, Client, Intents, Interaction
from discord.ui import View, Button
from discord.app_commands import CommandTree
from dotenv import load_dotenv


load_dotenv()


class MyClient(Client):
    def __init__(self, intents: Intents) -> None:
        super().__init__(intents=intents)
        self.tree = CommandTree(self)

    async def setup_hook(self) -> None:
        await self.tree.sync()

    async def on_ready(self):
        print(f"login: {self.user.name} [{self.user.id}]")


intents = Intents.default()
client = MyClient(intents=intents)


@client.tree.command()
@app_commands.describe(what="what you found?")
async def set_locate(
    interaction: Interaction,
    what: str,
    x: int,
    y: int,
    z: int,
):
    message = f"{what} is located: x:{x}, y:{y}, z:{z}"

+   log_channel = client.get_channel(1052926772607463456)
+   await log_channel.send(message)

-   await interaction.response.send_message(message)
+   await interaction.response.send_message("add location!")


client.run(os.getenv("TOKEN"))

image.png

image.png別のチャンネルに送れました.

では続いて,別チャンネルに送信したメッセージにtpコマンドのコピーができるボタンを作ります.とりあえずコピーのところは置いておいて,ボタンを作りましょう.
Viewを継承したサブクラスに,discord.ui.button()デコレータを使用しサブクラスにボタンを追加します.この下に書いた処理がcallbackとして扱われます.
注意点として,スーパークラスのコンストラクタの呼び出しを忘れないようにしましょう.1時間溶かすことになります(1敗).

import os
import discord
from discord import app_commands, Client, Intents, Interaction
from discord.ui import View, Button
from discord.app_commands import CommandTree
from dotenv import load_dotenv


load_dotenv()


+ class TpCommandView(View):
+     def __init__(self):
+         super().__init__()
+ 
+     @discord.ui.button(label="get tp command")
+     async def getTpCmddButton(self, interaction: Interaction, button: Button):
+         await interaction.response.send_message(
+             "copy to your clipboard!", ephemeral=True
+         )


class MyClient(Client):
    def __init__(self, intents: Intents) -> None:
        super().__init__(intents=intents)
        self.tree = CommandTree(self)

    async def setup_hook(self) -> None:
        await self.tree.sync()

    async def on_ready(self):
        print(f"login: {self.user.name} [{self.user.id}]")


intents = Intents.default()
client = MyClient(intents=intents)


@client.tree.command()
@app_commands.describe(what="what you found?")
async def set_locate(
    interaction: Interaction,
    what: str,
    x: int,
    y: int,
    z: int,
):
    message = f"{what} is located: x:{x}, y:{y}, z:{z}"

+   tp_cmd_view = TpCommandView()

    log_channel = client.get_channel(1052926772607463456)
-   await log_channel.send(message)
+   await log_channel.send(message, view=tp_cmd_view)

    await interaction.response.send_message("add location!")


client.run(os.getenv("TOKEN"))

当我试运行时,按钮显示的是下面的图像,点击按钮后,消息被发送了出去。

image.png
因此,讓我們確保實際上進行複製。

复制tp命令コピーされるというのは,ボタンを押した後Ctr+Vでコマンドが貼り付けられる,という意味です.自分でドラッグしてコピーは面倒なのでそうします.
そのためにはクリップボードに対して操作をしないといけません.どうやらPythonではpyperclipを使うとそれができるみたいです.公式ドキュメントを見てみると,copy()でコピーさせることができるみたいです.

在使用pyperclip之前,需要进行安装。虽然在文档中没有提到,但在pypi上有相关说明。

$ pip install pyperclip

如果安装成功,那就立即试用一下吧。我们将对TpCommandView输入的坐标进行更改,创建一个tp命令,并将其复制过去。顺便提一下,tp命令是通过/tp x y z来让自己传送到指定坐标的。虽然可以选择目标进行传送,但是考虑到用户选择可能会麻烦,我们先不做。

import os
import discord
from discord import app_commands, Client, Intents, Interaction
from discord.ui import View, Button
from discord.app_commands import CommandTree
+ import pyperclip
from dotenv import load_dotenv


load_dotenv()


class TpCommandView(View):
-   def __init__(self):
+   def __init__(self, locate: list):
        super().__init__()
+       self.locate = locate

    @discord.ui.button(label="get tp command")
    async def getTpCmddButton(self, interaction: Interaction, button: Button):
+       tp_cmd = f"tp {self.locate[0]} {self.locate[1]} {self.locate[2]}"
+       pyperclip.copy(tp_cmd)

        await interaction.response.send_message(
            "copy to your clipboard!", ephemeral=True
        )


class MyClient(Client):
    def __init__(self, intents: Intents) -> None:
        super().__init__(intents=intents)
        self.tree = CommandTree(self)

    async def setup_hook(self) -> None:
        await self.tree.sync()

    async def on_ready(self):
        print(f"login: {self.user.name} [{self.user.id}]")


intents = Intents.default()
client = MyClient(intents=intents)


@client.tree.command()
@app_commands.describe(what="what you found?")
async def set_locate(
    interaction: Interaction,
    what: str,
    x: int,
    y: int,
    z: int,
):
    message = f"{what} is located: x:{x}, y:{y}, z:{z}"

-   tp_cmd_view = TpCommandView()
+   tp_cmd_view = TpCommandView([x, y, z])

    log_channel = client.get_channel(1052926772607463456)
    await log_channel.send(message, view=tp_cmd_view)

    await interaction.response.send_message("add location!")


client.run(os.getenv("TOKEN"))

因为写三个参数很麻烦,所以我尝试用数组来接收它们。嗯,当建造通往下界的道路时,需要将数值缩小为1/8,所以使用数组也是一个妥协吧。

tpcmd.gif
我已将其正确地复制到剪贴板了。由于Discord正在Windows上运行,所以我不太清楚在其他操作系统上会发生什么情况。

但是我认为总体上是一样的,应该没问题的。

现在可以复制tp命令,这样在Minecraft中就可以方便地使用命令了。嗯,虽然在生存模式下无法输入命令。

总之,我成功地在Discord机器人中注册了Minecraft的坐标并得到了tp指令。辛苦了。

bannerAds