我想获取在Minecraft服务器上输入的命令的版本2

前提 tí)

假设您希望通过Discord机器人输入Minecraft服务器的命令。

然后,

    WSL, Ubuntu 22.04.1
    Python 3.10.6
    papermc

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

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

.
├── 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させてるところでしょうか.まあ重要じゃないです.

コマンド結果を取得

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

代码如下:

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]

我认为这不是一件复杂的事情。简单地解释一下,

    打开日志文件并按行读取文件内容。
    使用open()函数和readlines()函数。
    将最后一行保存到last_log。
    输入命令。
    等待一段时间直到日志被写入。
    重新打开日志文件,将日志存入command_logs直到出现last_log的行。
    由于是从末尾开始存放,因此进行反转并返回。

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

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

以上是获取输入到Minecraft服务器的命令的方法。
辛苦了。

bannerAds