Last active
March 17, 2023 05:08
-
-
Save KillerGoldFisch/5754965 to your computer and use it in GitHub Desktop.
Returns the Status of a Minecraft Server.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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