0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

itohalAdvent Calendar 2022

Day 13

minecraft serverに入力したコマンドを取りたいver.2

Posted at

前提

minecraft serverにおけるコマンドをdiscord bot経由で入力することを想定しています.

そして,

  • WSL, Ubuntu 22.04.1
  • Python 3.10.6
  • papermc

という環境で行っています.また,minecraft serverはsubprocessによる起動で実行しているため,この知識も多少必要です.stdoutstdinがわかっていれば大丈夫ではないでしょうか.

次に,私の環境のディレクトリ構成は以下のような感じです.

.
├── mcserver
│   └── logs
│       └── latest.log
└── qiita_mcmanager
    ├── MCServer.py
    └── test-getlog.py

もちろん,ファイルやディレクトリはほかにもありますが,今回利用するものはこの辺だけです.
MCServer.pyはminecraft serverの起動や停止などを行うクラスで,test-getlog.pyはminecraft server起動用のテストとして作成しているファイルです.

test-getlog.py

test-getlog.pyは以下のようなプログラムです.

test-getlog.py
from MCServer import MCServer
import time

server = MCServer()
server.start()

time.sleep(1)

print(server.get_command_log("list"))

time.sleep(1)

server.stop()

特に特筆するところはないです.強いて言うなら,serverを起動させた直後にコマンド入力させるのはちょっと不安だったのでsleepさせてるところでしょうか.まあ重要じゃないです.

コマンド結果を取得

現在のログにおける最後の行を確認しておきます.続いて,コマンドを入力した直後にログファイルを読み込みます.そして,確認済みのところまで一行ずつ戻ることでコマンドの結果が取得できます.

コードは以下の通りです.

python
def get_command_log(self, cmd: str) -> list[str]:
    if (self.process is None):
        print("server is not active")
        return

    if (self.process.poll()):
        print("server is already stopped")
        return

    log_file_path = "../mcserver/logs/latest.log"
    last_log = ""
    with open(log_file_path, "r") as log_file:
        logs = log_file.readlines()
        last_log = logs[-1]

    self.process.stdin.write(f"{cmd}\n".encode("utf-8"))
    self.process.stdin.flush()

    time.sleep(0.5)

    command_logs = []
    with open(log_file_path, "r") as log_file:
        logs = log_file.readlines()
        while (logs[-1] != last_log):
            command_logs.append(logs.pop(-1))

    return command_logs[::-1]

複雑なことはしていないと思います.簡単に流れを説明すると,

  1. ログファイルを開いてファイルの中身を行ごとに分けて読み込む
    • open()readlines()
  2. last_logに最後の行を保存
  3. コマンドの入力
  4. ログに書き込まれるまで少し待機
  5. 改めてログファイルを開き,last_logの行が現れるまでcommand_logsにログを入れる
  6. 末尾から入れているのでreverseして返す

という感じです.前回記事のようになんかごちゃごちゃ工夫しなくてできますね.徹夜はなるべくやめましょう.

time.sleep()で待機させていますが,これをするとdiscord botがその秒数分止まります.minecraft serverは別スレッドで動いていますし,簡単に確認してみたところ特に変な挙動はしていませんでした.ワールドが重くなるとどうなるかわからないため,asycio.sleep()に変更した方が良いかもしれません.ただ,私はasync/awaitに翻弄されたので諦めました.

以上がminecraft serverに入力したコマンドを取る方法でした.
お疲れ様でした.

0
0
1

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
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?