discord botとminecraftサーバーを連携させていろいろやった話
マイクラサーバーのステータスと/startをdiscordbotに連携させる話
必要なもの
python
Minecraft Server
あとChatGPT
マイクラサーバーのステータスをdiscordbotのステータスに表示
code(ChatGPT産)
import discord
from discord.ext import commands, tasks
from discord import Activity, ActivityType
from mcstatus import JavaServer
# Discord Botの設定
TOKEN = "とーくん" #DiscordBotのトークン
# server設定
server_ip = "サーバーip" #ステータスを表示させたいサーバーのIPを入れてね、自分のサーバーならlocalhostと入力すればいける。
server_port = 25565
intents = discord.Intents.default()
bot = commands.Bot(command_prefix="!", intents=intents)
@tasks.loop(seconds=30) # 10分おきに実行
async def update_mcstatus():
channel = bot.get_channel(1306972521446506496)
try:
# Minecraftサーバーの状態を取得
server = JavaServer.lookup(f"{server_ip}:{server_port}")
status = server.status()
# サーバー情報を取得
online_players = status.players.online
version = status.version.name
latency = status.latency
#サーバー情報をステータスに表示
await bot.change_presence(activity=Activity(type=ActivityType.custom, name='LINDA Server', state="サーバー稼働中"))
# チャンネルにステータスを送信
# await channel.send(
# f"**Minecraft Server Status**\n"
# f"IP: {server_ip}\n"
# f"Version: {version}\n"
# f"Players Online: {online_players}\n"
# f"Latency: {latency}ms"
# )
except Exception as e:
# エラーが発生した場合
# await channel.send(f"Error: Unable to reach the server. Details: {e}")
await bot.change_presence(activity=Activity(type=ActivityType.custom, name='LINDA Server', state="サーバー停止中"))
# Botが準備完了した際にタスクをスタート
@bot.event
async def on_ready():
if not update_mcstatus.is_running():
update_mcstatus.start()
print(f'Logged in as {bot.user}')
# ボットの名前を変更
# await bot.user.edit(username="ServerStatusBot") # 新しい名前に変更
# print(f'Changed bot name to {bot.user.name}')
# Botの実行
bot.run(TOKEN)
これでサーバーのステータスをdiscordbotのステータスに表示されます。
このぐらいでいいんだよ、シンプルさがいいんだよ。
次はマイクラサーバーを/startさせるやつ
code(https://qiita.com/insane_cattさん産をChatGPTでいじったやつ)
import discord
from discord import app_commands, Activity, ActivityType
import asyncio
import psutil
# 環境設定
TOKEN = "とーくん" # Discord botのトークン(必ずご自身のトークンに差し替えてください)
SERVER_PATH = r"ふぉるだ" # Minecraft実行ファイルのあるフォルダ
JAR_FILE = ".jarふぁいる" # 使用するMinecraftサーバー実行ファイル名
MAX_RAM = 6 # 最大メモリ(整数に変更)
MIN_RAM = 2 # 最小メモリ(整数に変更)
JAVA_PROCESS_NAME = "java.exe" # Javaプロセス名
SERVER_NAME = "Minecraftをプレイ中" #ここに入力した名前がBotのステータスになります。
intents = discord.Intents.default()
client = discord.Client(intents=intents)
tree = app_commands.CommandTree(client)
# hello コマンド
@tree.command(name="hello", description="Hello, world!")
async def hello(interaction: discord.Interaction):
await interaction.response.send_message(f'Hello, {interaction.user.mention}!')
# サーバー起動コマンド
@tree.command(name="start", description="サーバーを起動する")
async def start(interaction: discord.Interaction):
if is_server_running():
await interaction.response.send_message('サーバーは既に起動しています')
else:
# 非同期でサーバーを起動する
await interaction.response.send_message('サーバーの起動を開始しました。しばらくお待ちください...')
try:
# 非同期でサーバーを起動する
result = await start_server() # start_server関数を非同期で呼び出し
await interaction.followup.send(f'サーバーが正常に起動しました。{result}')
except Exception as e:
await interaction.followup.send(f"サーバー起動中にエラーが発生しました: {str(e)}")
print(f"Error during server start: {str(e)}")
traceback.print_exc()
# サーバーを非同期で起動する
async def start_server():
try:
# 非同期でMinecraftサーバーを起動
process = await asyncio.create_subprocess_exec(
r"C:\Program Files\Java\jdk-17.0.5\bin\java.exe",
"-Xmx" + str(MAX_RAM) + "G", # 数値を文字列に変換
"-Xms" + str(MIN_RAM) + "G", # 数値を文字列に変換
"-jar", JAR_FILE,
"nogui",
cwd=SERVER_PATH,
stdout=asyncio.subprocess.PIPE,
stderr=asyncio.subprocess.PIPE
)
# 非同期で出力を待機
stdout, stderr = await process.communicate()
# エラーがあれば出力
if process.returncode != 0:
print(f"サーバー起動エラー: {stderr.decode()}")
return f"サーバーの起動に失敗しました: {stderr.decode()}"
print(f"サーバーのプロセス {process.pid} を起動しました。")
return "Minecraftサーバーの起動を開始しました。"
except asyncio.TimeoutError:
return "サーバー起動に時間がかかりすぎています。タイムアウトしました。"
except Exception as e:
return f"サーバーの起動に失敗しました: {e}"
# サーバー停止コマンド
@tree.command(name="stop", description="サーバーを停止する")
async def stop(interaction: discord.Interaction):
if not is_server_running():
await interaction.response.send_message('サーバーは起動していません。')
else:
stop_server()
await interaction.response.send_message('サーバーを停止しました。')
# botログアウトコマンド
@tree.command(name="logout", description="このbotをログアウトさせる")
@app_commands.default_permissions(administrator=True)
async def exitbot(interaction: discord.Interaction):
await interaction.response.send_message('ログアウトを実行します')
await client.close() # ボットを正常にログアウト
# サーバーが実行中かどうかを確認
def is_server_running():
try:
# psutilを使ってプロセスを調べる
for proc in psutil.process_iter(['pid', 'name', 'cmdline']):
if JAVA_PROCESS_NAME in proc.info['name'] and JAR_FILE in ' '.join(proc.info['cmdline']):
return True
return False
except Exception as e:
print(f"Error checking if server is running: {e}")
return False
# サーバーを停止する
def stop_server():
try:
# サーバーのプロセスIDを検索して停止
for proc in psutil.process_iter(['pid', 'name', 'cmdline']):
if JAVA_PROCESS_NAME in proc.info['name'] and JAR_FILE in ' '.join(proc.info['cmdline']):
proc.terminate() # プロセスを停止
print(f"サーバーのプロセス {proc.info['pid']} を停止しました。")
break
except Exception as e:
print(f"Error stopping server: {e}")
# botがオンラインになったときの処理
@client.event
async def on_ready():
await client.change_presence(activity=Activity(type=ActivityType.custom, name='LINDA Server', state=SERVER_NAME))
await tree.sync()
print(f'Logged in as {client.user}')
# ボットの名前を変更
# await client.user.edit(username="ServerStartBot") # 新しい名前に変更
# print(f'Changed bot name to {client.user.name}')
# botを実行
client.run(TOKEN)
えーまず、まともでない猫さんありがとうございます。GPTで汚してすみません。
で、何をいじったのかというとWindowsだけで動くようになってます。
Linuxのscreenって機能?持ってないが?なんとかならんの?GPTさん???
っておねがいしたらこうなりました。
よくわかんね
でも稼働はします。
/stop?
それもしらないな。なにそれ。
これらのcodeを私は二つのBotに割り当てて動かしてます。
このコードは自分用に変更することで初めて動くので、変更する場所を言っていきます。
ステータスBOT
server_ip = "ここ"
TOKEN = "ここ"
あとお好みでBOTの名前を変更したい場合(ニックネームだけど)
await bot.user.edit(username="ここ")
スタートBOT
TOKEN = "ここ"
SERVER_PATH = r"ここ"
JAR_FILE = "ここ"
BOTのステータスをいじりたい場合は
SERVER_NAME = "ここ"
BOTの名前をいじりたい場合は
await client.user.edit(username="ここ")
これで機能するはず、まあ他にも不具合はあるんで、暇なときに直す。