LoginSignup
2
0

More than 1 year has passed since last update.

Minecraftのサーバーをdiscordから起動したい

Posted at

経緯

MinecraftのサーバーをAWS lightsailで作ったのだが、常設はお金がかかる。しかし管理者しか起動できないなら、サーバーをレンタルした意味がない。じゃあbotに管理してもらおう。

内容

image.png
このように、
・サーバーの残りキャパシティの表示。 (AWSの仕様でサーバーの体力みたいなもんです)
・サーバーの開始。
・サーバーの強制終了。
が可能です。
また、サーバーのステータスによってdiscord上のbotのステータスも変化します。
image.png
image.png

ソース

以下です。

bot本体

sys.path.appendがないと、sysytemctlで常時実行させた際に、discordがimoportできなかった気がします。
事前にMinecraftServerを起動できるrun.shを作成しておいてください。
/killについてですが、javaと名のつくプロセスを軒並み終了させてるだけなので、他のjavaプロセスと併用する際は気をつけてください。

#!/usr/bin/env python3
import sys

sys.path.append('/home/ubuntu/.local/lib/python3.8/site-packages')

import discord
from discord.ext import tasks
import psutil
import os
CHANNEL_ID = 0000 # your channel id
CLIENT_TOKEN = "YourDiscordClientToken"

svprocess = None
client = discord.Client()

@tasks.loop(seconds=10)
async def check_minecraft_status():
  is_run = False
  for proc in psutil.process_iter():
    try:
      if proc.name() == 'java':
        is_run = True
    except (psutil.NoSuchProcess, psutil.AccessDenied, psutil.ZombieProcess):
      pass
  if is_run:
    game = discord.Game("Minecraft")
    await client.change_presence(status=discord.Status.online, activity=game)
  else:
    await client.change_presence(status=discord.Status.idle, activity=None)

@client.event
async def on_ready():
  print('Logged in as')
  print(client.user.name)
  print(client.user.id)
  print('------')
  check_minecraft_status.start()

@client.event
async def on_message(message):
  ch = client.get_channel(CHANNEL_ID)
  if message.content == "/start":
    global svprocess 
    is_run = False
    print('Check existing server')
    for proc in psutil.process_iter():
      try:
        if proc.name() == 'java':
          is_run = True
      except (psutil.NoSuchProcess, psutil.AccessDenied, psutil.ZombieProcess):
        await ch.send('Error1')
    if is_run:
      await ch.send('Server has been running already. Login the server and type /stop in Minecraft game.\n You can also use /kill command in discord to kill the process (I recommend /stop).')
    else:
      os.system('/home/ubuntu/run.sh')
#      svprocess = subprocess.Popen('/home/ubuntu/run.sh', shell=True,  stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
#      logmsg = ''
#      while True:
#        line = svprocess.stdout.readline().decode().strip()
#        if line:
#          logmsg = line  
#        if not line and svprocess.poll() is not None:
#          print("[SERVER] Line ended. Is the server stopped?")
#          break  
      await ch.send("Wait a minute.")

  if message.content == '/isRun':
    is_run = False
    for proc in psutil.process_iter():
      try:
        if proc.name() == 'java':
          is_run = True
      except (psutil.NoSuchProcess, psutil.AccessDenied, psutil.ZombieProcess):
        ch.send('No process. Server is Down.')
        pass
    if is_run:
      await ch.send('Server is Running.')
    else:
      await ch.send('Server is Down.')

  if message.content == '/kill':
    for proc in psutil.process_iter():
      try:
        if proc.name() == 'java':
          command = 'kill -KILL ' + str(proc.pid)
          os.system(command)
      except (psutil.NoSuchProcess, psutil.AccessDenied, psutil.ZombieProcess):
        pass
    await ch.send('Kill confirmed.')

  if message.content == '/psaux':
    msg = ''
    for proc in psutil.process_iter():
      try:
        msg = msg + 'NAME: ' + proc.name() + ' \tPID: ' + str(proc.pid) + '\n'
      except (psutil.NoSuchProcess, psutil.AccessDenied, psutil.ZombieProcess):
        pass
    print(msg)
    try:
      await ch.send(msg)
    except (Exception):
      await ch.send("Process list is too large. Extracted last 2000 char.\n" + msg[-1900:])

  if message.content == '/status':
    await ch.send(file=discord.File('/home/ubuntu/tmppictures/stat.png'))






client.run(CLIENT_TOKEN)

サーバーのキャパシティのグラフを生成するやつ

AWSのboto3を使用します。AWS CLI, Boto3のインストールが必要です。Boto3はAWS CLIの認証情報に基づいて動作するので、AWS CLIのconfigureを済ませておいてください。

#!/usr/bin/env python3
import sys

sys.path.append('/home/ubuntu/.local/lib/python3.8/site-packages')

import boto3
from datetime import datetime
from datetime import timedelta
from matplotlib import pyplot
import pandas
import seaborn as sns

def make_statistics_file():
  client = boto3.client('lightsail')


  responce = client.get_instance_metric_data( instanceName='Minecraft1',
                                              metricName='BurstCapacityPercentage',
                                              period=120,
                                              startTime=datetime.now() + timedelta(days=-2),
                                              endTime=datetime.now(),
                                              unit='Percent',
                                              statistics=['Maximum'])

  df = pandas.DataFrame(columns=['Capacity','Time'])


  for h,i in enumerate(responce['metricData']):
    df.loc[h] = [(i['maximum']),i['timestamp']]
  df.set_index('Time',inplace=True)
  sns.set()
  sns.set_style(style='dark')
  df.plot(grid=True)
  pyplot.tick_params(labelsize=9)
  pyplot.ylim(-1, 101)
  pyplot.title(datetime.now().strftime('%m/%d %H:%M') + " created.")
  pyplot.savefig('/home/ubuntu/tmppictures/stat.png')
  pyplot.close('all')




if __name__=='__main__':
  make_statistics_file()

その他

systemctl用の.serviceファイルなどはgithubにあげておきます。
User, Groupの指定をしないと動かなかった気がするので、気をつけてください。
https://github.com/ha191180/qiita_entry/tree/master/qiita%20minecraft

2
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0