Skip to content

Instantly share code, notes, and snippets.

@KillerGoldFisch
Last active March 17, 2023 05:08
Show Gist options
  • Save KillerGoldFisch/5754965 to your computer and use it in GitHub Desktop.
Save KillerGoldFisch/5754965 to your computer and use it in GitHub Desktop.
Returns the Status of a Minecraft Server.
#!/usr/bin/env python
# coding: utf8
"""mcstat.py: Returns the Status of a Minecraft Server."""
__author__ = "Kevin Gliewe aka KillerGoldFisch"
__copyright__ = "Copyright 2014, Kevin Gliewe"
__credits__ = ["kevin Gliewe",]
__license__ = "MIT"
__version__ = "1.2.1"
__date__ = "2014-09-11"
__maintainer__ = "Kevin Gliewe"
__email__ = "kevingliewe@gmail,com"
__status__ = "Production"
"""
Changelog:
- v 1.2.1: 2014-09-11
Unicode fix
- v 1.2.0: 2014-09-11
Realy fixed for 1.7.x protocol,
Thanks by "barneygale" with his sample: https://gist.github.com/barneygale/1209061
Also see: http://wiki.vg/Server_List_Ping
- v 1.1.2: 2014-01-06
Fixed for Minecraft 1.7.2 protokol
- v 1.1.1:
Fixed for Minecraft 1.6.2 protokol
- v 1.1.0:
Fixed for Minecraft 1.6 protokol
"""
import socket
import struct
import json
def unpack_varint(s):
d = 0
for i in range(5):
b = ord(s.recv(1))
d |= (b & 0x7F) << 7*i
if not b & 0x80:
break
return d
def pack_varint(d):
o = ""
while True:
b = d & 0x7F
d >>= 7
o += struct.pack("B", b | (0x80 if d > 0 else 0))
if d == 0:
break
return o
def pack_data(d):
return pack_varint(len(d)) + d
def pack_port(i):
return struct.pack('>H', i)
class status:
def __init__(self, data):
# Map data
self.protocol_version = unicode(data['version']['protocol']).encode( "utf-8" )
self.game_version = unicode(data['version']['name']).encode( "utf-8" )
self.motd = unicode(data['description']).encode( "utf-8" )
self.online_players = data['players']['online']
self.max_players = data['players']['max']
self.data = data
def __str__(self):
return ("protocoll version: %s\n"+
"game version: %s\n"+
"motd: %s\n"+
"player: %s/%s")%(
self.protocol_version,
self.game_version,
self.motd,
self.online_players,
self.max_players
)
def __repr__(self):
return self.__str__()
def getStat(server, port = 25565, timeout = 1):
# connect
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.settimeout(timeout)
s.connect((server, port))
# Send handshake + status request
s.send(pack_data("\x00\x00" + pack_data(server.encode('utf8')) + pack_port(port) + "\x01"))
s.send(pack_data("\x00"))
# Read response
unpack_varint(s) # Packet length
unpack_varint(s) # Packet ID
l = unpack_varint(s) # String length
d = ""
while len(d) < l:
d += s.recv(1024)
# Close our socket
s.close()
# Load json and return status object
return status(json.loads(d.decode('utf8')))
def main():
from argparse import ArgumentParser
import sys
parser = ArgumentParser(description="Checks status of Minecraft multiplayer server",
epilog="Exit status: 0 if the server can be reached, otherwise nonzero."
)
parser.add_argument("host", help="target hostname")
parser.add_argument("-p", "--port", type=int, default=25565,
help='TCP port of server [25565]')
parser.add_argument("-t", "--timeout", type=int, default=10,
help='retry timeout in seconds [10]')
options = parser.parse_args()
returncode = 1
try:
status = getStat(options.host, options.port, options.timeout)
if status == None:
print "Server is off"
else:
print "Protokoll : " + str(status.protocol_version)
print "Game Version : " + status.game_version
print "motd : " + status.motd
print "Online players : " + str(status.online_players)
print "Max players : " + str(status.max_players)
returncode = 0
except Exception, e:
print "ERROR : ", e
sys.exit(returncode)
if __name__=="__main__":
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment