Python Minecraft 服务器的包装器或处理程序

A Python Wrapper or Handler for A Minecraft Server

我正在使用 Windows 并正在为 Minecraft 服务器寻找使用 Python 的处理程序或包装器,以便我可以在没有用户输入的情况下自动输入命令。我在网站上搜索了很多问题,但只找到了一半的答案(至少就我而言)。我相信我将需要使用 subprocess 模块,但在我试验 Popen 函数时无法决定使用哪个。我找到了一个针对我的案例修改的答案:

server = Popen("java -jar minecraft_server.jar nogui", stdin=PIPE, stdout=PIPE, stderr=STDOUT)
while True:
    print(server.stdout.readline())
    server.stdout.flush()
    command = input("> ")
    if command:
        server.stdin.write(bytes(command + "\r\n", "ascii"))
        server.stdin.flush()

这在某种程度上确实有效,但每次输入命令时只打印一行,这是行不通的,我为改变这一点所做的所有努力最终导致程序无法执行任何其他操作,而只能读取。这不是一个重复的问题,因为类似问题中的 none 个答案可以帮助我。

如您所知,您的 server.stdout.readline()input("> ") 正在阻止您的代码执行。
你需要让你的代码成为非阻塞的,而不是等待 return 你真正想要的东西,而是通过检查,如果有任何东西可以阅读并忽略它,如果没有并继续做其他事情。

在 Linux 系统上您可以使用 select module,但在 Windows 上它仅适用于套接字。

我能够通过使用线程和队列使其在 Windows 上运行。 (注:是Python2码)

import subprocess, sys
from Queue import Queue, Empty
from threading import Thread

def process_line(line):

    if line == "stop\n": # lines have trailing new line characters
        print "SERVER SHUTDOWN PREVENTED"
        return None
    elif line == "quit\n":
        return "stop\n"
    elif line == "l\n":
        return "list\n"

    return line

s = subprocess.Popen("java -jar minecraft_server.jar nogui", stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)

def read_lines(stream, queue):
    while True:
        queue.put(stream.readline())

# terminal reading thread
q = Queue()
t = Thread(target=read_lines, args=(sys.stdin, q))
t.daemon = True
t.start()

# server reading thread
qs = Queue()
ts = Thread(target=read_lines, args=(s.stdout, qs))
ts.daemon = True
ts.start()

while s.poll() == None: # loop while the server process is running

    # get a user entered line and send it to the server
    try:
        line = q.get_nowait()
    except Empty:
        pass
    else:
        line = process_line(line) # do something with the user entered line
        if line != None:
            s.stdin.write(line)
            s.stdin.flush()

    # just pass-through data from the server to the terminal output
    try:
        line = qs.get_nowait()
    except Empty:
        pass
    else:
        sys.stdout.write(line)
        sys.stdout.flush()