SammyRigdon496
SammyRigdon496

Reputation: 25

Using subprocess to control Minecraft servers

I run a number of modded Minecraft servers for friends on my PC, I am trying to build a program that makes starting them and sending commands to them much easier.

I launch the servers using a bat file and have been able to get subprocess to do that no problem, but I am unsure how to go about adding the functionality of issuing commands to the server via the console.

I've thought of using stdin.write() and in the interactive console it works great. The issue is that when I add it to the code it executes the stop command before the server has even started therefore the server never stops. I have tried doing it in a separate function but that didn't work either.

Here is my code so far:

Class file:

import subprocess

class Server:
    def __init__(self, server_start_bat, dir):
        self.server_start_bat = server_start_bat
        self.dir =dir


    def start_server(self):
        server = subprocess.Popen(self.server_start_bat, cwd=self.dir, shell=True, stdin=subprocess.PIPE, text=True)
        server.communicate()


    def stop_server(self):
        server = subprocess.Popen(self.server_start_bat, cwd=self.dir, shell=True, stdin=subprocess.PIPE, text=True)
        server.stdin.write('stop\n')


    def command(self, command):
        server = subprocess.Popen(self.server_start_bat, cwd=self.dir, shell=True, stdin=subprocess.PIPE, text=True)
        self.command = command
        server.stdin.write(f'{self.command}\n')

Simple GUI I ran it through:

from tkinter import *

import Servers

server = Servers.Server('path\\to\\bat\\file\\batfile.bat', 'dir\\to\\run\\command\\in')

main = Tk()
main.title('Server Commander')
server_title = Label(main, text="server, hosted on port ")
server_title.pack()
server_start = Button(main, text='Start', command=server.start_server)
server_start.pack()
server_stop = Button(main, text='Stop', command=server.stop_server)
server_stop.pack()

main.mainloop()

Upvotes: 1

Views: 837

Answers (1)

mkrieger1
mkrieger1

Reputation: 23244

There are two issues, I think:

  1. stop_server and command each start a new subprocess, which should only be done in start_server.

  2. start_server uses server.communicate() which blocks until the subprocess is done, preventing the program to send any other commands to the server while it is running.

Instead,

  • start_server should create the subprocess, then store it in a variable which can be accessed by stop_server and command,
  • server.communicate should be done in stop_server.

stop_server is also just a special case of command.

import subprocess

class Server:
    def __init__(self, server_start_bat, dir):
        self.server_start_bat = server_start_bat
        self.dir = dir

    def start_server(self):
        self.server = subprocess.Popen(self.server_start_bat, cwd=self.dir, shell=True, stdin=subprocess.PIPE, text=True)

    def stop_server(self):
        self.command('stop')
        self.server.communicate()

    def command(self, command):
        self.server.stdin.write(f'{command}\n')

Upvotes: 1

Related Questions