見出し画像

マイクラ鯖をDiscordから起動する

目的

Discordボットを使ってMinecraftサーバを操作できるようにする

準備

以下の導入が済んでいることを前提として話を進めていきます。

  • Discordボット

  • Minecraftサーバ

  • tmux

  • Java

  • Python3
    ※この記事では上記すべてのやり方を解説しません。

実行環境

OS

Ubuntu Server 24.04.1 LTS

Minecraftサーバ

CurseForge for Minecraft 1.16.5 - 36.2.34

Java

OpenJDK 11.0.25

(2025/01/13 時点)

結論

以下のコードを実行することで操作ができます。

# This example requires the 'message_content' intent.

import discord
import subprocess

intents = discord.Intents.default()
intents.message_content = True

client = discord.Client(intents=intents)
command = []
def execute(shell_script):
    subprocess.run(shell_script, shell=True)

@client.event
async def on_ready():
    print(f'We have logged in as {client.user}')

@client.event
async def on_message(message):  # メッセージへの対応
    if message.author.bot:  # 送信者がBOTのとき
        return
    elif message.content.strip():  # メッセージが空白でないとき
        try:
            await message.channel.send('wait...')
            command = message.content.split()
            match command[0]:
                case 'open':    # 先頭がopenのとき
                    await message.channel.send('now '+command[0]+'ing...')
                    execute('tmux new -s '+command[1]+' -d')
                    execute('tmux send-keys -t '+command[1]+' "cd server/'+command[1]+'"'+' ENTER')
                    execute('tmux send-keys -t '+command[1]+' "java -Xms2G -Xmx12G -jar forge-1.16.5-36.2.34.jar" ENTER')
                case 'close':   # 先頭closeのとき
                    execute('tmux send-keys -t '+command[1]+' "stop" ENTER')
                    execute('tmux send-keys -t '+command[1]+' "exit" ENTER')
        except Exception as e:  # エラーが発生したとき
            await message.channel.send(f'error: {e}')
    else:
        return

with open('token.txt', encoding='utf-8') as f:
    client.run(f.read())   # Discordにログイン

使い方

1. ディレクトリ構成をそろえる

上記のdiscordbot.pyと同じディレクトリに token.txtserver ディレクトリを作成する。

discordbot.pytoken.txtserver

2. Minecraftサーバを準備する

server ディレクトリから1段階深いディレクトリにサーバのjarファイルがくるようにする。

discordbot.pytoken.txtserver
    └ 250113_testconfigeula.txtforge-1.16.5-36.2.34.jarminecraft_server.1.16.5.jar

3. token.txtにDiscordボットのトークンをペーストする

s3dfD3ydf...

※余計なことは書かない!

3. 実行するときのコマンドを書き換える

@client.event
async def on_message(message):  # メッセージへの対応
    if message.author.bot:  # 送信者がBOTのとき
        return
    elif message.content.strip():  # メッセージが空白でないとき
        try:
            await message.channel.send('wait...')
            command = message.content.split()
            match command[0]:
                case 'open':    # 先頭がopenのとき
                    await message.channel.send('now '+command[0]+'ing...')
                    execute('tmux new -s '+command[1]+' -d')
                    execute('tmux send-keys -t '+command[1]+' "cd server/'+command[1]+'"'+' ENTER')
                    execute('tmux send-keys -t '+command[1]+' "java -Xms2G -Xmx12G -jar forge-1.16.5-36.2.34.jar" ENTER')

上記のうち一番下の "java -Xms2G -Xmx12G -jar forge-1.16.5-36.2.34.jar" 部分を書き換える。

①サーバファイル

forge-1.16.5-36.2.34.jar をサーバファイル名(拡張子含む)に書き換え

②最小メモリ容量

-Xms2G を割り当てる最小のメモリ容量に書き換え
例)-Xms1G -Xms4G

③最大メモリ容量

②最小メモリ容量と同様、-Xmx12G を割り当てる最大のメモリ容量に書き換え

3. discordbot.pyを実行

シェルから以下のコマンドを実行する。

python3 discordbot.py

解説

import discord

ディスコードボットを動かすために必要なモジュール

import subprocess

Pythonからシェルコマンドを実行するために必要

intents = discord.Intents.default()
intents.message_content = True
client = discord.Client(intents=intents)

ディスコードボットの設定

command = []

送られたメッセージリスト型にする先をつくる

def execute(shell_script):
    subprocess.run(shell_script, shell=True

シェルでのコマンドを使いやすくする

@client.event
async def on_ready():
    print(f'We have logged in as {client.user}')

適切にディスコードへとログインできたかの確認

@client.event
async def on_message(message):  # メッセージへの対応
    if message.author.bot:  # 送信者がBOTのとき
        return

ボット同士で会話しないようにする

elif message.content.strip():  # メッセージが空白でないとき
    try:
        await message.channel.send('wait...')
    except Exception as e:  # エラーが発生したとき
        await message.channel.send(f'error: {e}')
else:
    return

何かしらの読み取れるメッセージが送られたとき、wait... と返信する

command = message.content.split()

メッセージを区切ってリスト型に変換

match command[0]:
    case 'open':    # 先頭がopenのとき
    case 'close':   # 先頭closeのとき

メッセージの先頭がopen のときとclose のときの分岐

await message.channel.send('now '+command[0]+'ing...')

ディスコードにnow opening... やnow closeing... と送信
closeingのスペルがおかしいのは無視

execute('tmux new -s '+command[1]+' -d')

tmuxで新しいセッションを作る
(subprocessをそのまま使うと鯖にstopコマンドが使えなくなってしまうため)

execute('tmux send-keys -t '+command[1]+' "cd server/'+command[1]+'"'+' ENTER')

サーバーディレクトリに移動

execute('tmux send-keys -t '+command[1]+' "java -Xms2G -Xmx12G -jar forge-1.16.5-36.2.34.jar" ENTER')

マイクラサーバーを起動

execute('tmux send-keys -t '+command[1]+' "stop" ENTER')

マイクラサーバーを停止

execute('tmux send-keys -t '+command[1]+' "exit" ENTER')

tmuxのセッションを停止

with open('token.txt', encoding='utf-8') as f:
    client.run(f.read())   # Discordにログイン

おわりに

最後まで読んでいただき、ありがとうございます。
何か不具合や要望がありましたら、気軽に連絡してください。

参考記事

プログラミング初心者のためのQiita記事投稿テンプレート

いいなと思ったら応援しよう!