Skip to content

Instantly share code, notes, and snippets.

@iMoD1998
Last active April 3, 2023 17:13
Show Gist options
  • Save iMoD1998/50fc916904ccacf8a8a010e3d05aac65 to your computer and use it in GitHub Desktop.
Save iMoD1998/50fc916904ccacf8a8a010e3d05aac65 to your computer and use it in GitHub Desktop.
Get list of SCUM servers and info directly from the master server. [0.8] Thanks to me and @yobmef
import struct
import socket
import ipaddress
import pprint
from typing import Optional
SERVER_INFO_STRUCT = struct.Struct("<I H 100s x B B B 9s I H B B")
SERVER_INFO_STRUCT_SIZE = SERVER_INFO_STRUCT.size
def parse_server_info(server_info_raw: bytes):
server_ip, server_port, server_name, server_player_count, server_player_max_count, server_time_hour, server_unk, server_version_build, server_version_patch, server_version_minor, server_version_major = SERVER_INFO_STRUCT.unpack(server_info_raw)
server_name = server_name.decode("latin-1").rstrip("\x00")
return {
"name": server_name,
"ip": str(ipaddress.ip_address(server_ip)),
"port": server_port,
"player_count": server_player_count,
"max_player_count": server_player_max_count,
"time": server_time_hour,
"version": f"{server_version_major}.{server_version_minor}.{server_version_patch}.{server_version_build}",
"unk": server_unk
}
def connect_to_master_server(ip: str, port: int) -> Optional[socket.socket]:
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
try:
sock.connect((ip, port))
return sock
except Exception as e:
print(f"Failed to connect to {ip}:{port}: {e}")
sock.close()
return None
master_servers = [
("176.57.138.2", 1040),
("172.107.16.215", 1040),
("206.189.248.133", 1040)
]
def get_server_list() -> dict[str, dict]:
#
# Try to connect to the first master server we can reach.
#
sock = None
for ip, port in master_servers:
print(f"Trying to connect to {ip}:{port}")
sock = connect_to_master_server(ip, port)
if sock:
break
if not sock:
print("Failed to connect to any of the master servers")
exit(1)
#
# Send command to retrieve server list
#
sock.send(b"\x04\x03\x00\x00")
#
# First two bytes are the number of servers that are being sent.
#
num_servers = struct.unpack("<H", sock.recv(2))[0]
#
# Read the whole server list.
#
server_data_raw = b""
while len(server_data_raw) < (num_servers * SERVER_INFO_STRUCT_SIZE):
chunk = sock.recv(1024)
if not chunk:
break
server_data_raw += chunk
#
# process each server info item
#
server_list = {}
for i in range(0, len(server_data_raw), SERVER_INFO_STRUCT_SIZE):
server_info_raw = server_data_raw[i:i+SERVER_INFO_STRUCT_SIZE]
server_info = parse_server_info(server_info_raw)
server_list[f"{server_info['ip']}:{server_info['port']}"] = server_info
return server_list
server_list = get_server_list()
pprint.pprint(server_list["194.140.197.202:32002"])
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment