Browse Source

feat(monitor): prepare for gamedig 5 (#4510)

* feat: gamedig 5

* install gamedig in lgsm dir if node exists

* and

* use local gamedig version

* local

* palworld

* pw query port

* mbe

* fix ro

system

system

a

* public ip

* jc2m

* fix(ti): update default map

The default map in the tiserver configuration file has been updated from "/Game/TheIsle/Maps/Game/Isla_Spiro/Isla_Spiro" to "/Game/TheIsle/Maps/Game/Gateway/Gateway". This change ensures that the server starts with the correct default map.

* fix: _default.cfg NOT SET

* download package.json and run npm install

* update samp

* disable query for squad

* correct name

* feat: update querymode and querytype in server configs

Changed querymode to 3 and set querytype to "eco" for ecoserver.
Updated querymode to 2 and changed querytype to "protocol-valve" for sdtdserver.

* feat: add new port command for bfv game

Added a new port command for the "bfv" game in the info_messages script.

* queryport eco

* add eco rconport

* adding message

* if node 16 or above

* rename to check_gamedig
Daniel Gibbs 2 năm trước cách đây
mục cha
commit
fce9f65d6a

+ 2 - 2
lgsm/config-default/config-lgsm/ecoserver/_default.cfg

@@ -131,8 +131,8 @@ stopmode="2"
 # 3: gamedig
 # 4: gsquery
 # 5: tcp
-querymode="1"
-querytype=""
+querymode="3"
+querytype="eco"
 
 ## Console type
 consoleverbose="yes"

+ 1 - 1
lgsm/config-default/config-lgsm/jc2server/_default.cfg

@@ -132,7 +132,7 @@ stopmode="2"
 # 4: gsquery
 # 5: tcp
 querymode="2"
-querytype="jc2mp"
+querytype="jc2m"
 
 ## Console type
 consoleverbose="yes"

+ 1 - 1
lgsm/config-default/config-lgsm/mcbserver/_default.cfg

@@ -125,7 +125,7 @@ stopmode="5"
 # 4: gsquery
 # 5: tcp
 querymode="2"
-querytype="minecraftbe"
+querytype="mbe"
 
 ## Console type
 consoleverbose="yes"

+ 2 - 2
lgsm/config-default/config-lgsm/pwserver/_default.cfg

@@ -139,8 +139,8 @@ stopmode="2"
 # 3: gamedig
 # 4: gsquery
 # 5: tcp
-querymode="1"
-querytype="1"
+querymode="3"
+querytype="palworld"
 
 ## Console type
 consoleverbose="yes"

+ 1 - 1
lgsm/config-default/config-lgsm/sampserver/_default.cfg

@@ -123,7 +123,7 @@ stopmode="2"
 # 4: gsquery
 # 5: tcp
 querymode="3"
-querytype="samp"
+querytype="gtasam"
 
 ## Console type
 consoleverbose="no"

+ 1 - 1
lgsm/config-default/config-lgsm/sdtdserver/_default.cfg

@@ -134,7 +134,7 @@ stopmode="8"
 # 3: gamedig
 # 4: gsquery
 # 5: tcp
-querymode="5"
+querymode="2"
 querytype="protocol-valve"
 
 ## Console type

+ 2 - 2
lgsm/config-default/config-lgsm/squadserver/_default.cfg

@@ -136,8 +136,8 @@ stopmode="2"
 # 3: gamedig
 # 4: gsquery
 # 5: tcp
-querymode="2"
-querytype="protocol-valve"
+querymode="1"
+querytype=""
 
 ## Console type
 consoleverbose="yes"

+ 7 - 0
lgsm/modules/check.sh

@@ -99,3 +99,10 @@ for allowed_command in "${allowed_commands_array[@]}"; do
 		check_system_requirements.sh
 	fi
 done
+
+allowed_commands_array=(DETAILS MONITOR START STOP UPDATE VALIDATE POST-DETAILS)
+for allowed_command in "${allowed_commands_array[@]}"; do
+	if [ "${allowed_command}" == "${commandname}" ]; then
+		check_gamedig.sh
+	fi
+done

+ 15 - 0
lgsm/modules/check_gamedig.sh

@@ -0,0 +1,15 @@
+#!/bin/bash
+# LinuxGSM check_gamedig.sh module
+# Author: Daniel Gibbs
+# Contributors: http://linuxgsm.com/contrib
+# Website: https://linuxgsm.com
+# Description: Installs nodejs and gamedig
+
+if [ "$(command -v node)" ] && [ "$(node -v | cut -d 'v' -f 2 | cut -d '.' -f 1)" -ge 16 ] && [ ! -f "${lgsmdir}/node_modules/gamedig/bin/gamedig.js" ]; then
+	echo -e ""
+	echo -e "${bold}${lightyellow}Installing Gamedig${default}"
+	fn_script_log_info "Installing Gamedig"
+	cd "${lgsmdir}" || exit
+	wget -N --no-check-certificate "https://raw.githubusercontent.com/GameServerManagers/LinuxGSM/${githubbranch}/package.json"
+	npm install
+fi

+ 4 - 4
lgsm/modules/check_ip.sh

@@ -38,25 +38,25 @@ function fn_is_valid_ip() {
 
 # If the IP variable has been set by user.
 if fn_is_valid_ip "${ip}"; then
-	queryips=("${ip}")
+	queryips=("${ip}" "${publicip}")
 	httpip=("${ip}")
 	telnetip=("${ip}")
 # If the game config has an IP set.
 elif fn_is_valid_ip "${configip}"; then
-	queryips=("${configip}")
+	queryips=("${configip}" "${publicip}")
 	ip="${configip}"
 	httpip=("${configip}")
 	telnetip=("${configip}")
 # If there is only 1 server IP address.
 # Some IP details can automatically use the one IP.
 elif [ "${#current_ips[@]}" == "1" ]; then
-	queryips=("127.0.0.1" "${current_ips[@]}")
+	queryips=("127.0.0.1" "${current_ips[@]}" "${publicip}")
 	ip="0.0.0.0"
 	httpip=("${current_ips[@]}")
 	telnetip=("${current_ips[@]}")
 # If no ip is set by the user and server has more than one IP.
 else
-	queryips=("127.0.0.1" "${current_ips[@]}")
+	queryips=("127.0.0.1" "${current_ips[@]}" "${publicip}")
 	ip="0.0.0.0"
 	httpip=("${ip}")
 	telnetip=("${ip}")

+ 1 - 1
lgsm/modules/command_dev_query_raw.sh

@@ -207,7 +207,7 @@ echo -e ""
 echo -e "${lightgreen}Gamedig Raw Output${default}"
 fn_messages_separator
 echo -e ""
-if [ ! "$(command -v gamedig 2> /dev/null)" ]; then
+if [ ! "$(command -v gamedig 2> /dev/null)" ] || [ ! -f "${lgsmdir}/node_modules/gamedig/bin/gamedig.js" ]; then
 	fn_print_failure_nl "gamedig not installed"
 fi
 if [ ! "$(command -v jq 2> /dev/null)" ]; then

+ 3 - 0
lgsm/modules/command_install.sh

@@ -30,6 +30,9 @@ else
 		install_server_files.sh
 	fi
 
+	# Install gamedig
+	check_gamedig.sh
+
 	# Configuration.
 	install_config.sh
 	if [ -v gslt ]; then

+ 1 - 1
lgsm/modules/command_monitor.sh

@@ -369,7 +369,7 @@ fn_monitor_loop() {
 	for querymethod in "${query_methods_array[@]}"; do
 		# Will check if gamedig is installed and bypass if not.
 		if [ "${querymethod}" == "gamedig" ]; then
-			if [ "$(command -v gamedig 2> /dev/null)" ] && [ "$(command -v jq 2> /dev/null)" ]; then
+			if [ "$(command -v gamedig 2> /dev/null)" ] || [ -f "${lgsmdir}/node_modules/gamedig/bin/gamedig.js" ] && [ "$(command -v jq 2> /dev/null)" ]; then
 				if [ -z "${monitorpass}" ]; then
 					fn_monitor_query
 				fi

+ 1 - 0
lgsm/modules/command_update_linuxgsm.sh

@@ -13,6 +13,7 @@ fn_firstcommand_set
 fn_print_dots ""
 check.sh
 info_distro.sh
+info_game.sh
 
 fn_script_log_info "Updating LinuxGSM"
 

+ 5 - 0
lgsm/modules/core_modules.sh

@@ -714,6 +714,11 @@ install_factorio_save.sh() {
 	fn_fetch_module
 }
 
+check_gamedig.sh() {
+	modulefile="${FUNCNAME[0]}"
+	fn_fetch_module
+}
+
 install_dst_token.sh() {
 	modulefile="${FUNCNAME[0]}"
 	fn_fetch_module

+ 1 - 1
lgsm/modules/fix.sh

@@ -52,7 +52,7 @@ fn_apply_fix() {
 	fi
 }
 
-apply_pre_start_fix=(arma3 armar ark av bt bo csgo cmw dst hw ins kf nmrih onset pvr rust rw samp sdtd sfc sof2 squad st tf2 terraria ts3 mcb mta unt vh wurm zmr)
+apply_pre_start_fix=(arma3 armar ark av bt bo csgo cmw dst hw ins kf nmrih onset pvr ro rust rw samp sdtd sfc sof2 squad st tf2 terraria ts3 mcb mta unt vh wurm zmr)
 apply_post_install_fix=(av kf kf2 ro ut2k4 ut ut3)
 
 # validate registered fixes for safe development

+ 106 - 28
lgsm/modules/fix_ro.sh

@@ -3,37 +3,115 @@
 # Author: Daniel Gibbs
 # Contributors: http://linuxgsm.com/contrib
 # Website: https://linuxgsm.com
-# Description: Resolves issues with Red Orchestra.
+# Description: Resolves issues with Red Orchestra: Ostfront 41-45.
 
 moduleselfname="$(basename "$(readlink -f "${BASH_SOURCE[0]}")")"
 
-echo -e "applying webinterface ROOst.css fix."
-echo -e "http://forums.tripwireinteractive.com/showpost.php?p=585435&postcount=13"
+# echo -e "applying WebAdmin ROOst.css fix."
+# echo -e "http://forums.tripwireinteractive.com/showpost.php?p=585435&postcount=13"
 sed -i 's/none}/none;/g' "${serverfiles}/Web/ServerAdmin/ROOst.css"
 sed -i 's/underline}/underline;/g' "${serverfiles}/Web/ServerAdmin/ROOst.css"
-fn_sleep_time
-echo -e "applying webinterface CharSet fix."
-echo -e "http://forums.tripwireinteractive.com/showpost.php?p=442340&postcount=1"
+# echo -e "applying WebAdmin CharSet fix."
+# echo -e "http://forums.tripwireinteractive.com/showpost.php?p=442340&postcount=1"
 sed -i 's/CharSet="iso-8859-1"/CharSet="utf-8"/g' "${systemdir}/uweb.int"
-fn_sleep_time
-echo -e "applying Steam AppID fix."
-sed -i 's/1210/1200/g' "${systemdir}/steam_appid.txt"
-fn_sleep_time
-echo -e "applying server name fix."
-fn_sleep_time
-echo -e "forcing server restart..."
-fn_sleep_time
-exitbypass=1
-command_start.sh
-fn_firstcommand_reset
-fn_sleep_time_5
-exitbypass=1
-command_stop.sh
-fn_firstcommand_reset
-exitbypass=1
-command_start.sh
-fn_firstcommand_reset
-fn_sleep_time_5
-exitbypass=1
-command_stop.sh
-fn_firstcommand_reset
+
+# get md5sum of steamclient.so
+if [ -f "${serverfiles}/system/steamclient.so" ]; then
+	steamclientmd5=$(md5sum "${serverfiles}/system/steamclient.so" | awk '{print $1;}')
+fi
+#get md5sum of libtier0_s.so
+if [ -f "${serverfiles}/system/libtier0_s.so" ]; then
+	libtier0_smd5=$(md5sum "${serverfiles}/system/libtier0_s.so" | awk '{print $1;}')
+fi
+#get md5sum of libvstdlib_s.so
+if [ -f "${serverfiles}/system/libvstdlib_s.so" ]; then
+	libvstdlib_smd5=$(md5sum "${serverfiles}/system/libvstdlib_s.so" | awk '{print $1;}')
+fi
+
+# get md5sum of steamclient.so from steamcmd
+if [ -f "${HOME}/.steam/steamcmd/linux32/steamclient.so" ]; then
+	steamcmdsteamclientmd5=$(md5sum "${HOME}/.steam/steamcmd/linux32/steamclient.so" | awk '{print $1;}')
+elif [ -f "${steamcmddir}/linux32/steamclient.so" ]; then
+	steamcmdsteamclientmd5=$(md5sum "${steamcmddir}/linux32/steamclient.so" | awk '{print $1;}')
+elif [ -f "${HOME}/.local/share/Steam/steamcmd/linux32/steamclient.so" ]; then
+	steamcmdsteamclientmd5=$(md5sum "${HOME}/.local/share/Steam/steamcmd/linux32/steamclient.so" | awk '{print $1;}')
+fi
+
+# get md5sum of libtier0_s.so from steamcmd
+if [ -f "${HOME}/.steam/steamcmd/linux32/libtier0_s.so" ]; then
+	steamcmdlibtier0_smd5=$(md5sum "${HOME}/.steam/steamcmd/linux32/libtier0_s.so" | awk '{print $1;}')
+elif [ -f "${steamcmddir}/linux32/libtier0_s.so" ]; then
+	steamcmdlibtier0_smd5=$(md5sum "${steamcmddir}/linux32/libtier0_s.so" | awk '{print $1;}')
+elif [ -f "${HOME}/.local/share/Steam/steamcmd/linux32/libtier0_s.so" ]; then
+	steamcmdlibtier0_smd5=$(md5sum "${HOME}/.local/share/Steam/steamcmd/linux32/libtier0_s.so" | awk '{print $1;}')
+fi
+
+# get md5sum of libvstdlib_s.so from steamcmd
+if [ -f "${HOME}/.steam/steamcmd/linux32/libvstdlib_s.so" ]; then
+	steamcmdlibvstdlib_smd5=$(md5sum "${HOME}/.steam/steamcmd/linux32/libvstdlib_s.so" | awk '{print $1;}')
+elif [ -f "${steamcmddir}/linux32/libvstdlib_s.so" ]; then
+	steamcmdlibvstdlib_smd5=$(md5sum "${steamcmddir}/linux32/libvstdlib_s.so" | awk '{print $1;}')
+elif [ -f "${HOME}/.local/share/Steam/steamcmd/linux32/libvstdlib_s.so" ]; then
+	steamcmdlibvstdlib_smd5=$(md5sum "${HOME}/.local/share/Steam/steamcmd/linux32/libvstdlib_s.so" | awk '{print $1;}')
+fi
+
+if [ ! -f "${serverfiles}/system/steamclient.so" ] || [ "${steamcmdsteamclientmd5}" != "${steamclientmd5}" ]; then
+	fixname="steamclient.so x86"
+	fn_fix_msg_start
+	if [ -f "${HOME}/.steam/steamcmd/linux32/steamclient.so" ]; then
+		cp "${HOME}/.steam/steamcmd/linux32/steamclient.so" "${serverfiles}/system/steamclient.so"
+	elif [ -f "${steamcmddir}/linux32/steamclient.so" ]; then
+		cp "${steamcmddir}/linux32/steamclient.so" "${serverfiles}/system/steamclient.so"
+	elif [ -f "${HOME}/.local/share/Steam/steamcmd/linux32/steamclient.so" ]; then
+		cp "${HOME}/.local/share/Steam/steamcmd/linux32/steamclient.so" "${serverfiles}/system/steamclient.so"
+	fi
+	fn_fix_msg_end
+fi
+
+if [ ! -f "${serverfiles}/system/libtier0_s.so" ] || [ "${steamcmdlibtier0_smd5}" != "${libtier0_smd5}" ]; then
+	fixname="libtier0_s.so"
+	fn_fix_msg_start
+	if [ -f "${HOME}/.steam/steamcmd/linux32/libtier0_s.so" ]; then
+		cp "${HOME}/.steam/steamcmd/linux32/libtier0_s.so" "${serverfiles}/system/libtier0_s.so"
+	elif [ -f "${steamcmddir}/linux32/libtier0_s.so" ]; then
+		cp "${steamcmddir}/linux32/libtier0_s.so" "${serverfiles}/system/libtier0_s.so"
+	elif [ -f "${HOME}/.local/share/Steam/steamcmd/linux32/libtier0_s.so" ]; then
+		cp "${HOME}/.local/share/Steam/steamcmd/linux32/libtier0_s.so" "${serverfiles}/system/libtier0_s.so"
+	fi
+	fn_fix_msg_end
+fi
+
+if [ ! -f "${serverfiles}/system/libvstdlib_s.so" ] || [ "${steamcmdlibvstdlib_smd5}" != "${libvstdlib_smd5}" ]; then
+	fixname="libvstdlib_s.so"
+	fn_fix_msg_start
+	if [ -f "${HOME}/.steam/steamcmd/linux32/libvstdlib_s.so" ]; then
+		cp "${HOME}/.steam/steamcmd/linux32/libvstdlib_s.so" "${serverfiles}/system/libvstdlib_s.so"
+	elif [ -f "${steamcmddir}/linux32/libvstdlib_s.so" ]; then
+		cp "${steamcmddir}/linux32/libvstdlib_s.so" "${serverfiles}/system/libvstdlib_s.so"
+	elif [ -f "${HOME}/.local/share/Steam/steamcmd/linux32/libvstdlib_s.so" ]; then
+		cp "${HOME}/.local/share/Steam/steamcmd/linux32/libvstdlib_s.so" "${serverfiles}/system/libvstdlib_s.so"
+	fi
+	fn_fix_msg_end
+fi
+
+# if running install command
+if [ "${commandname}" == "INSTALL" ]; then
+	echo -e "applying server name fix."
+	fn_sleep_time
+	echo -e "forcing server restart..."
+	fn_sleep_time
+	exitbypass=1
+	command_start.sh
+	fn_firstcommand_reset
+	fn_sleep_time_5
+	exitbypass=1
+	command_stop.sh
+	fn_firstcommand_reset
+	exitbypass=1
+	command_start.sh
+	fn_firstcommand_reset
+	fn_sleep_time_5
+	exitbypass=1
+	command_stop.sh
+	fn_firstcommand_reset
+fi

+ 4 - 0
lgsm/modules/info_game.sh

@@ -621,6 +621,7 @@ fn_info_game_pvr() {
 fn_info_game_pw() {
 	servername="${servername:-"NOT SET"}"
 	port="${port:-"0"}"
+	queryport="${port:-"0"}"
 	steamport="${steamport:-"0"}"
 	unknownport="1985"
 }
@@ -1242,6 +1243,7 @@ fn_info_game_eco() {
 		fn_info_game_json "httpport" ".WebServerPort"
 		fn_info_game_json "maxplayers" ".MaxConnections"
 		fn_info_game_json "port" ".GameServerPort"
+		fn_info_game_json "rconport" ".RconServerPort"
 		fn_info_game_json "servername" ".Description"
 		fn_info_game_json "serverpassword" ".Password"
 		fn_info_game_json "tickrate" ".Rate"
@@ -1250,6 +1252,8 @@ fn_info_game_eco() {
 	httpport="${httpport:-"0"}"
 	maxplayers="${maxplayers:-"0"}"
 	port="${port:-"0"}"
+	queryport="${port:-"0"}"
+	rconport="${rconport:-"0"}"
 	servername="${servername:-"NOT SET"}"
 	serverpassword="${serverpassword:-"NOT SET"}"
 	tickrate="${tickrate:-"0"}"

+ 4 - 0
lgsm/modules/info_messages.sh

@@ -692,6 +692,8 @@ fn_info_messages_ports() {
 		portcommand="ss -tuplwn | grep AvorionServer"
 	elif [ "${shortname}" == "bf1942" ]; then
 		portcommand="ss -tuplwn | grep bf1942_lnxded"
+	elif [ "${shortname}" == "bfv" ]; then
+		portcommand="ss -tuplwn | grep bfv_linded"
 	elif [ "${shortname}" == "dayz" ]; then
 		portcommand="ss -tuplwn | grep enfMain"
 	elif [ "${shortname}" == "q4" ]; then
@@ -1015,7 +1017,9 @@ fn_info_messages_eco() {
 	{
 		fn_port "header"
 		fn_port "Game" port udp
+		fn_port "Query" queryport udp
 		fn_port "Web Interface" httpport tcp
+		fn_port "RCON" rconport tcp
 	} | column -s $'\t' -t
 }
 

+ 10 - 3
lgsm/modules/query_gamedig.sh

@@ -10,7 +10,14 @@ moduleselfname="$(basename "$(readlink -f "${BASH_SOURCE[0]}")")"
 # Default query status to failure. Will be changed to 0 if query is successful.
 querystatus="2"
 # Check if gamedig and jq are installed.
-if [ "$(command -v gamedig 2> /dev/null)" ] && [ "$(command -v jq 2> /dev/null)" ]; then
+
+if [ -f "${lgsmdir}/node_modules/gamedig/bin/gamedig.js" ]; then
+	gamedigbinary="${lgsmdir}/node_modules/gamedig/bin/gamedig.js"
+else
+	gamedigbinary="gamedig"
+fi
+
+if [ "$(command -v "${gamedigbinary}" 2> /dev/null)" ] && [ "$(command -v jq 2> /dev/null)" ]; then
 
 	# will bypass query if server offline.
 	check_status.sh
@@ -20,8 +27,8 @@ if [ "$(command -v gamedig 2> /dev/null)" ] && [ "$(command -v jq 2> /dev/null)"
 			queryport="${port}"
 		fi
 		# checks if query is working null = pass.
-		gamedigcmd=$(echo -e "gamedig --type \"${querytype}\" \"${queryip}:${queryport}\"|jq")
-		gamedigraw=$(gamedig --type "${querytype}" "${queryip}:${queryport}")
+		gamedigcmd=$(echo -e "${gamedigbinary} --type \"${querytype}\" \"${queryip}:${queryport}\"|jq")
+		gamedigraw=$(${gamedigbinary} --type "${querytype}" "${queryip}:${queryport}")
 		querystatus=$(echo "${gamedigraw}" | jq '.error|length')
 
 		if [ "${querytype}" == "teamspeak3" ]; then

+ 24 - 16
lgsm/modules/query_gsquery.py

@@ -10,23 +10,26 @@ import argparse
 import socket
 import sys
 
-engine_types=('protocol-valve','protocol-quake2','protocol-quake3','protocol-gamespy1','protocol-unreal2','ut3','minecraft','minecraftbe','jc2mp','mumbleping','soldat','teeworlds')
+engine_types = ('protocol-valve', 'protocol-quake2', 'protocol-quake3', 'protocol-gamespy1',
+                'protocol-unreal2', 'ut3', 'minecraft', 'minecraftbe', 'jc2m', 'mumbleping', 'soldat', 'teeworlds')
+
 
 class gsquery:
     server_response_timeout = 2
     default_buffer_length = 1024
-    sourcequery=('protocol-valve','avalanche3.0','barotrauma','madness','quakelive','realvirtuality','refractor','source','goldsrc','spark','starbound','unity3d','unreal4','wurm')
-    idtech2query=('protocol-quake2','idtech2','quake','iw2.0')
-    idtech3query=('protocol-quake3','iw3.0','ioquake3','qfusion')
-    minecraftquery=('minecraft','lwjgl2')
-    minecraftbequery=('minecraftbe',)
-    jc2mpquery=('jc2mp',)
-    mumblequery=('mumbleping',)
-    soldatquery=('soldat',)
-    twquery=('teeworlds',)
-    unrealquery=('protocol-gamespy1','unreal')
-    unreal2query=('protocol-unreal2','unreal2')
-    unreal3query=('ut3','unreal3')
+    sourcequery = ('protocol-valve', 'avalanche3.0', 'barotrauma', 'madness', 'quakelive', 'realvirtuality',
+                   'refractor', 'source', 'goldsrc', 'spark', 'starbound', 'unity3d', 'unreal4', 'wurm')
+    idtech2query = ('protocol-quake2', 'idtech2', 'quake', 'iw2.0')
+    idtech3query = ('protocol-quake3', 'iw3.0', 'ioquake3', 'qfusion')
+    minecraftquery = ('minecraft', 'lwjgl2')
+    minecraftbequery = ('minecraftbe',)
+    jc2mquery = ('jc2m',)
+    mumblequery = ('mumbleping',)
+    soldatquery = ('soldat',)
+    twquery = ('teeworlds',)
+    unrealquery = ('protocol-gamespy1', 'unreal')
+    unreal2query = ('protocol-unreal2', 'unreal2')
+    unreal3query = ('ut3', 'unreal3')
 
     def __init__(self, arguments):
         self.argument = arguments
@@ -37,7 +40,7 @@ class gsquery:
             self.query_prompt_string = b'\xff\xff\xff\xffstatus\x00'
         elif self.argument.engine in self.idtech3query:
             self.query_prompt_string = b'\xff\xff\xff\xffgetstatus'
-        elif self.argument.engine in self.jc2mpquery:
+        elif self.argument.engine in self.jc2mquery:
             self.query_prompt_string = b'\xFE\xFD\x09\x10\x20\x30\x40'
         elif self.argument.engine in self.minecraftquery:
             self.query_prompt_string = b'\xFE\xFD\x09\x3d\x54\x1f\x93'
@@ -48,7 +51,8 @@ class gsquery:
         elif self.argument.engine in self.soldatquery:
             self.query_prompt_string = b'\x69\x00'
         elif self.argument.engine in self.twquery:
-            self.query_prompt_string = b'\x04\x00\x00\xff\xff\xff\xff\x05' + bytearray(511)
+            self.query_prompt_string = b'\x04\x00\x00\xff\xff\xff\xff\x05' + \
+                bytearray(511)
         elif self.argument.engine in self.unrealquery:
             self.query_prompt_string = b'\x5C\x69\x6E\x66\x6F\x5C'
         elif self.argument.engine in self.unreal2query:
@@ -74,7 +78,8 @@ class gsquery:
         connection = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
         connection.settimeout(self.server_response_timeout)
         try:
-            self.connected = connection.connect((self.argument.address, int(self.argument.port)))
+            self.connected = connection.connect(
+                (self.argument.address, int(self.argument.port)))
         except socket.timeout:
             self.fatal_error('Request timed out', 1)
         except Exception:
@@ -95,6 +100,7 @@ class gsquery:
         else:
             self.exit_success(str(self.response))
 
+
 def parse_args():
     parser = argparse.ArgumentParser(
         description='Allows querying of various game servers.',
@@ -142,10 +148,12 @@ def parse_args():
     )
     return parser.parse_args()
 
+
 def main():
     arguments = parse_args()
     server = gsquery(arguments)
     server.responding()
 
+
 if __name__ == '__main__':
     main()

+ 639 - 0
package-lock.json

@@ -6,17 +6,503 @@
     "": {
       "name": "linuxgsm",
       "license": "MIT",
+      "dependencies": {
+        "gamedig": "^5.0.0-beta.2"
+      },
       "devDependencies": {
         "prettier": "^3.0.3",
         "prettier-plugin-sh": "^0.13.1"
       }
     },
+    "node_modules/@sindresorhus/is": {
+      "version": "5.6.0",
+      "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-5.6.0.tgz",
+      "integrity": "sha512-TV7t8GKYaJWsn00tFDqBw8+Uqmr8A0fRU1tvTQhyZzGv0sJCGRQL3JGMI3ucuKo3XIZdUP+Lx7/gh2t3lewy7g==",
+      "engines": {
+        "node": ">=14.16"
+      },
+      "funding": {
+        "url": "https://github.com/sindresorhus/is?sponsor=1"
+      }
+    },
+    "node_modules/@szmarczak/http-timer": {
+      "version": "5.0.1",
+      "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-5.0.1.tgz",
+      "integrity": "sha512-+PmQX0PiAYPMeVYe237LJAYvOMYW1j2rH5YROyS3b4CTVJum34HfRvKvAzozHAQG0TnHNdUfY9nCeUyRAs//cw==",
+      "dependencies": {
+        "defer-to-connect": "^2.0.1"
+      },
+      "engines": {
+        "node": ">=14.16"
+      }
+    },
+    "node_modules/@types/http-cache-semantics": {
+      "version": "4.0.4",
+      "resolved": "https://registry.npmjs.org/@types/http-cache-semantics/-/http-cache-semantics-4.0.4.tgz",
+      "integrity": "sha512-1m0bIFVc7eJWyve9S0RnuRgcQqF/Xd5QsUZAZeQFr1Q3/p9JWoQQEqmVy+DPTNpGXwhgIetAoYF8JSc33q29QA=="
+    },
+    "node_modules/any-promise": {
+      "version": "1.3.0",
+      "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz",
+      "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A=="
+    },
+    "node_modules/barse": {
+      "version": "0.4.3",
+      "resolved": "https://registry.npmjs.org/barse/-/barse-0.4.3.tgz",
+      "integrity": "sha512-UEpvriJqAn8zuVinYICuKoPttZy3XxXEoqX/V2uYAL4zzJRuNzCK3+20nAu3YUIa2U7G53kf90wfBIp9/A+Odw==",
+      "dependencies": {
+        "readable-stream": "~1.0.2"
+      }
+    },
+    "node_modules/boolbase": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz",
+      "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww=="
+    },
+    "node_modules/cacheable-lookup": {
+      "version": "7.0.0",
+      "resolved": "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-7.0.0.tgz",
+      "integrity": "sha512-+qJyx4xiKra8mZrcwhjMRMUhD5NR1R8esPkzIYxX96JiecFoxAXFuz/GpR3+ev4PE1WamHip78wV0vcmPQtp8w==",
+      "engines": {
+        "node": ">=14.16"
+      }
+    },
+    "node_modules/cacheable-request": {
+      "version": "10.2.14",
+      "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-10.2.14.tgz",
+      "integrity": "sha512-zkDT5WAF4hSSoUgyfg5tFIxz8XQK+25W/TLVojJTMKBaxevLBBtLxgqguAuVQB8PVW79FVjHcU+GJ9tVbDZ9mQ==",
+      "dependencies": {
+        "@types/http-cache-semantics": "^4.0.2",
+        "get-stream": "^6.0.1",
+        "http-cache-semantics": "^4.1.1",
+        "keyv": "^4.5.3",
+        "mimic-response": "^4.0.0",
+        "normalize-url": "^8.0.0",
+        "responselike": "^3.0.0"
+      },
+      "engines": {
+        "node": ">=14.16"
+      }
+    },
+    "node_modules/cheerio": {
+      "version": "1.0.0-rc.12",
+      "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.0.0-rc.12.tgz",
+      "integrity": "sha512-VqR8m68vM46BNnuZ5NtnGBKIE/DfN0cRIzg9n40EIq9NOv90ayxLBXA8fXC5gquFRGJSTRqBq25Jt2ECLR431Q==",
+      "dependencies": {
+        "cheerio-select": "^2.1.0",
+        "dom-serializer": "^2.0.0",
+        "domhandler": "^5.0.3",
+        "domutils": "^3.0.1",
+        "htmlparser2": "^8.0.1",
+        "parse5": "^7.0.0",
+        "parse5-htmlparser2-tree-adapter": "^7.0.0"
+      },
+      "engines": {
+        "node": ">= 6"
+      },
+      "funding": {
+        "url": "https://github.com/cheeriojs/cheerio?sponsor=1"
+      }
+    },
+    "node_modules/cheerio-select": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/cheerio-select/-/cheerio-select-2.1.0.tgz",
+      "integrity": "sha512-9v9kG0LvzrlcungtnJtpGNxY+fzECQKhK4EGJX2vByejiMX84MFNQw4UxPJl3bFbTMw+Dfs37XaIkCwTZfLh4g==",
+      "dependencies": {
+        "boolbase": "^1.0.0",
+        "css-select": "^5.1.0",
+        "css-what": "^6.1.0",
+        "domelementtype": "^2.3.0",
+        "domhandler": "^5.0.3",
+        "domutils": "^3.0.1"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/fb55"
+      }
+    },
+    "node_modules/commander": {
+      "version": "6.2.1",
+      "resolved": "https://registry.npmjs.org/commander/-/commander-6.2.1.tgz",
+      "integrity": "sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA==",
+      "engines": {
+        "node": ">= 6"
+      }
+    },
+    "node_modules/core-util-is": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz",
+      "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ=="
+    },
+    "node_modules/css-select": {
+      "version": "5.1.0",
+      "resolved": "https://registry.npmjs.org/css-select/-/css-select-5.1.0.tgz",
+      "integrity": "sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg==",
+      "dependencies": {
+        "boolbase": "^1.0.0",
+        "css-what": "^6.1.0",
+        "domhandler": "^5.0.2",
+        "domutils": "^3.0.1",
+        "nth-check": "^2.0.1"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/fb55"
+      }
+    },
+    "node_modules/css-what": {
+      "version": "6.1.0",
+      "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz",
+      "integrity": "sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==",
+      "engines": {
+        "node": ">= 6"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/fb55"
+      }
+    },
+    "node_modules/decompress-response": {
+      "version": "6.0.0",
+      "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz",
+      "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==",
+      "dependencies": {
+        "mimic-response": "^3.1.0"
+      },
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/decompress-response/node_modules/mimic-response": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz",
+      "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==",
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/defer-to-connect": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-2.0.1.tgz",
+      "integrity": "sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg==",
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/dom-serializer": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz",
+      "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==",
+      "dependencies": {
+        "domelementtype": "^2.3.0",
+        "domhandler": "^5.0.2",
+        "entities": "^4.2.0"
+      },
+      "funding": {
+        "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1"
+      }
+    },
+    "node_modules/domelementtype": {
+      "version": "2.3.0",
+      "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz",
+      "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==",
+      "funding": [
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/fb55"
+        }
+      ]
+    },
+    "node_modules/domhandler": {
+      "version": "5.0.3",
+      "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz",
+      "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==",
+      "dependencies": {
+        "domelementtype": "^2.3.0"
+      },
+      "engines": {
+        "node": ">= 4"
+      },
+      "funding": {
+        "url": "https://github.com/fb55/domhandler?sponsor=1"
+      }
+    },
+    "node_modules/domutils": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.1.0.tgz",
+      "integrity": "sha512-H78uMmQtI2AhgDJjWeQmHwJJ2bLPD3GMmO7Zja/ZZh84wkm+4ut+IUnUdRa8uCGX88DiVx1j6FRe1XfxEgjEZA==",
+      "dependencies": {
+        "dom-serializer": "^2.0.0",
+        "domelementtype": "^2.3.0",
+        "domhandler": "^5.0.3"
+      },
+      "funding": {
+        "url": "https://github.com/fb55/domutils?sponsor=1"
+      }
+    },
+    "node_modules/entities": {
+      "version": "4.5.0",
+      "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz",
+      "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==",
+      "engines": {
+        "node": ">=0.12"
+      },
+      "funding": {
+        "url": "https://github.com/fb55/entities?sponsor=1"
+      }
+    },
+    "node_modules/event-to-promise": {
+      "version": "0.7.0",
+      "resolved": "https://registry.npmjs.org/event-to-promise/-/event-to-promise-0.7.0.tgz",
+      "integrity": "sha512-VOBBfyaADfe378ZzG0tgkzmsvzUyeU5arehrFzNRt5yaASUDshgctTwSrPI17ocAwR3+YftsxRClHF+GBKFByQ==",
+      "deprecated": "Use promise-toolbox/fromEvent instead"
+    },
+    "node_modules/form-data-encoder": {
+      "version": "2.1.4",
+      "resolved": "https://registry.npmjs.org/form-data-encoder/-/form-data-encoder-2.1.4.tgz",
+      "integrity": "sha512-yDYSgNMraqvnxiEXO4hi88+YZxaHC6QKzb5N84iRCTDeRO7ZALpir/lVmf/uXUhnwUr2O4HU8s/n6x+yNjQkHw==",
+      "engines": {
+        "node": ">= 14.17"
+      }
+    },
+    "node_modules/gamedig": {
+      "version": "5.0.0-beta.2",
+      "resolved": "https://registry.npmjs.org/gamedig/-/gamedig-5.0.0-beta.2.tgz",
+      "integrity": "sha512-YsHoGdb6rXyzdErakd9eSJvUAZCa8Hy+nQpiWZMps158wOovsH35Yrr/Y9wCvn1FDm6NJnHhQYkvtk3zhlmKWQ==",
+      "dependencies": {
+        "cheerio": "^1.0.0-rc.12",
+        "gbxremote": "^0.2.1",
+        "got": "^13.0.0",
+        "iconv-lite": "^0.6.3",
+        "long": "^5.2.3",
+        "minimist": "^1.2.8",
+        "punycode": "^2.3.0",
+        "seek-bzip": "^2.0.0",
+        "varint": "^6.0.0"
+      },
+      "bin": {
+        "gamedig": "bin/gamedig.js"
+      },
+      "engines": {
+        "node": ">=16.20.0"
+      }
+    },
+    "node_modules/gbxremote": {
+      "version": "0.2.1",
+      "resolved": "https://registry.npmjs.org/gbxremote/-/gbxremote-0.2.1.tgz",
+      "integrity": "sha512-SMehu6Y6ndq2Qgp9VxAb8Np3f+UUD+RWoW2SAMaxzGS96rWXyr4T1GGkecO0HHtxeH1m7pEh4FJWB8a/6aM2XQ==",
+      "dependencies": {
+        "any-promise": "^1.1.0",
+        "barse": "~0.4.2",
+        "event-to-promise": "^0.7.0",
+        "string-to-stream": "^1.0.1",
+        "xmlrpc": "^1.3.1"
+      },
+      "engines": {
+        "node": ">=0.10"
+      }
+    },
+    "node_modules/get-stream": {
+      "version": "6.0.1",
+      "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz",
+      "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==",
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/got": {
+      "version": "13.0.0",
+      "resolved": "https://registry.npmjs.org/got/-/got-13.0.0.tgz",
+      "integrity": "sha512-XfBk1CxOOScDcMr9O1yKkNaQyy865NbYs+F7dr4H0LZMVgCj2Le59k6PqbNHoL5ToeaEQUYh6c6yMfVcc6SJxA==",
+      "dependencies": {
+        "@sindresorhus/is": "^5.2.0",
+        "@szmarczak/http-timer": "^5.0.1",
+        "cacheable-lookup": "^7.0.0",
+        "cacheable-request": "^10.2.8",
+        "decompress-response": "^6.0.0",
+        "form-data-encoder": "^2.1.2",
+        "get-stream": "^6.0.1",
+        "http2-wrapper": "^2.1.10",
+        "lowercase-keys": "^3.0.0",
+        "p-cancelable": "^3.0.0",
+        "responselike": "^3.0.0"
+      },
+      "engines": {
+        "node": ">=16"
+      },
+      "funding": {
+        "url": "https://github.com/sindresorhus/got?sponsor=1"
+      }
+    },
+    "node_modules/htmlparser2": {
+      "version": "8.0.2",
+      "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-8.0.2.tgz",
+      "integrity": "sha512-GYdjWKDkbRLkZ5geuHs5NY1puJ+PXwP7+fHPRz06Eirsb9ugf6d8kkXav6ADhcODhFFPMIXyxkxSuMf3D6NCFA==",
+      "funding": [
+        "https://github.com/fb55/htmlparser2?sponsor=1",
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/fb55"
+        }
+      ],
+      "dependencies": {
+        "domelementtype": "^2.3.0",
+        "domhandler": "^5.0.3",
+        "domutils": "^3.0.1",
+        "entities": "^4.4.0"
+      }
+    },
+    "node_modules/http-cache-semantics": {
+      "version": "4.1.1",
+      "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz",
+      "integrity": "sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ=="
+    },
+    "node_modules/http2-wrapper": {
+      "version": "2.2.1",
+      "resolved": "https://registry.npmjs.org/http2-wrapper/-/http2-wrapper-2.2.1.tgz",
+      "integrity": "sha512-V5nVw1PAOgfI3Lmeaj2Exmeg7fenjhRUgz1lPSezy1CuhPYbgQtbQj4jZfEAEMlaL+vupsvhjqCyjzob0yxsmQ==",
+      "dependencies": {
+        "quick-lru": "^5.1.1",
+        "resolve-alpn": "^1.2.0"
+      },
+      "engines": {
+        "node": ">=10.19.0"
+      }
+    },
+    "node_modules/iconv-lite": {
+      "version": "0.6.3",
+      "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz",
+      "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==",
+      "dependencies": {
+        "safer-buffer": ">= 2.1.2 < 3.0.0"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/inherits": {
+      "version": "2.0.4",
+      "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
+      "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
+    },
+    "node_modules/isarray": {
+      "version": "0.0.1",
+      "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz",
+      "integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ=="
+    },
+    "node_modules/json-buffer": {
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz",
+      "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ=="
+    },
+    "node_modules/keyv": {
+      "version": "4.5.4",
+      "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz",
+      "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==",
+      "dependencies": {
+        "json-buffer": "3.0.1"
+      }
+    },
+    "node_modules/long": {
+      "version": "5.2.3",
+      "resolved": "https://registry.npmjs.org/long/-/long-5.2.3.tgz",
+      "integrity": "sha512-lcHwpNoggQTObv5apGNCTdJrO69eHOZMi4BNC+rTLER8iHAqGrUVeLh/irVIM7zTw2bOXA8T6uNPeujwOLg/2Q=="
+    },
+    "node_modules/lowercase-keys": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-3.0.0.tgz",
+      "integrity": "sha512-ozCC6gdQ+glXOQsveKD0YsDy8DSQFjDTz4zyzEHNV5+JP5D62LmfDZ6o1cycFx9ouG940M5dE8C8CTewdj2YWQ==",
+      "engines": {
+        "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/mimic-response": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-4.0.0.tgz",
+      "integrity": "sha512-e5ISH9xMYU0DzrT+jl8q2ze9D6eWBto+I8CNpe+VI+K2J/F/k3PdkdTdz4wvGVH4NTpo+NRYTVIuMQEMMcsLqg==",
+      "engines": {
+        "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/minimist": {
+      "version": "1.2.8",
+      "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz",
+      "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==",
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
     "node_modules/mvdan-sh": {
       "version": "0.10.1",
       "resolved": "https://registry.npmjs.org/mvdan-sh/-/mvdan-sh-0.10.1.tgz",
       "integrity": "sha512-kMbrH0EObaKmK3nVRKUIIya1dpASHIEusM13S4V1ViHFuxuNxCo+arxoa6j/dbV22YBGjl7UKJm9QQKJ2Crzhg==",
       "dev": true
     },
+    "node_modules/normalize-url": {
+      "version": "8.0.0",
+      "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-8.0.0.tgz",
+      "integrity": "sha512-uVFpKhj5MheNBJRTiMZ9pE/7hD1QTeEvugSJW/OmLzAp78PB5O6adfMNTvmfKhXBkvCzC+rqifWcVYpGFwTjnw==",
+      "engines": {
+        "node": ">=14.16"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/nth-check": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz",
+      "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==",
+      "dependencies": {
+        "boolbase": "^1.0.0"
+      },
+      "funding": {
+        "url": "https://github.com/fb55/nth-check?sponsor=1"
+      }
+    },
+    "node_modules/p-cancelable": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-3.0.0.tgz",
+      "integrity": "sha512-mlVgR3PGuzlo0MmTdk4cXqXWlwQDLnONTAg6sm62XkMJEiRxN3GL3SffkYvqwonbkJBcrI7Uvv5Zh9yjvn2iUw==",
+      "engines": {
+        "node": ">=12.20"
+      }
+    },
+    "node_modules/parse5": {
+      "version": "7.1.2",
+      "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.1.2.tgz",
+      "integrity": "sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==",
+      "dependencies": {
+        "entities": "^4.4.0"
+      },
+      "funding": {
+        "url": "https://github.com/inikulin/parse5?sponsor=1"
+      }
+    },
+    "node_modules/parse5-htmlparser2-tree-adapter": {
+      "version": "7.0.0",
+      "resolved": "https://registry.npmjs.org/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-7.0.0.tgz",
+      "integrity": "sha512-B77tOZrqqfUfnVcOrUvfdLbz4pu4RopLD/4vmu3HUPswwTA8OH0EMW9BlWR2B0RCoiZRAHEUu7IxeP1Pd1UU+g==",
+      "dependencies": {
+        "domhandler": "^5.0.2",
+        "parse5": "^7.0.0"
+      },
+      "funding": {
+        "url": "https://github.com/inikulin/parse5?sponsor=1"
+      }
+    },
     "node_modules/prettier": {
       "version": "3.0.3",
       "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.0.3.tgz",
@@ -51,6 +537,87 @@
         "prettier": "^3.0.0"
       }
     },
+    "node_modules/process-nextick-args": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
+      "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag=="
+    },
+    "node_modules/punycode": {
+      "version": "2.3.1",
+      "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz",
+      "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==",
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/quick-lru": {
+      "version": "5.1.1",
+      "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz",
+      "integrity": "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==",
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/readable-stream": {
+      "version": "1.0.34",
+      "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz",
+      "integrity": "sha512-ok1qVCJuRkNmvebYikljxJA/UEsKwLl2nI1OmaqAu4/UE+h0wKCHok4XkL/gvi39OacXvw59RJUOFUkDib2rHg==",
+      "dependencies": {
+        "core-util-is": "~1.0.0",
+        "inherits": "~2.0.1",
+        "isarray": "0.0.1",
+        "string_decoder": "~0.10.x"
+      }
+    },
+    "node_modules/resolve-alpn": {
+      "version": "1.2.1",
+      "resolved": "https://registry.npmjs.org/resolve-alpn/-/resolve-alpn-1.2.1.tgz",
+      "integrity": "sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g=="
+    },
+    "node_modules/responselike": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/responselike/-/responselike-3.0.0.tgz",
+      "integrity": "sha512-40yHxbNcl2+rzXvZuVkrYohathsSJlMTXKryG5y8uciHv1+xDLHQpgjG64JUO9nrEq2jGLH6IZ8BcZyw3wrweg==",
+      "dependencies": {
+        "lowercase-keys": "^3.0.0"
+      },
+      "engines": {
+        "node": ">=14.16"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/safe-buffer": {
+      "version": "5.1.2",
+      "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
+      "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
+    },
+    "node_modules/safer-buffer": {
+      "version": "2.1.2",
+      "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
+      "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
+    },
+    "node_modules/sax": {
+      "version": "1.2.4",
+      "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz",
+      "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw=="
+    },
+    "node_modules/seek-bzip": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/seek-bzip/-/seek-bzip-2.0.0.tgz",
+      "integrity": "sha512-SMguiTnYrhpLdk3PwfzHeotrcwi8bNV4iemL9tx9poR/yeaMYwB9VzR1w7b57DuWpuqR8n6oZboi0hj3AxZxQg==",
+      "dependencies": {
+        "commander": "^6.0.0"
+      },
+      "bin": {
+        "seek-bunzip": "bin/seek-bunzip",
+        "seek-table": "bin/seek-bzip-table"
+      }
+    },
     "node_modules/sh-syntax": {
       "version": "0.4.1",
       "resolved": "https://registry.npmjs.org/sh-syntax/-/sh-syntax-0.4.1.tgz",
@@ -66,11 +633,83 @@
         "url": "https://opencollective.com/unts"
       }
     },
+    "node_modules/string_decoder": {
+      "version": "0.10.31",
+      "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz",
+      "integrity": "sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ=="
+    },
+    "node_modules/string-to-stream": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/string-to-stream/-/string-to-stream-1.1.1.tgz",
+      "integrity": "sha512-QySF2+3Rwq0SdO3s7BAp4x+c3qsClpPQ6abAmb0DGViiSBAkT5kL6JT2iyzEVP+T1SmzHrQD1TwlP9QAHCc+Sw==",
+      "dependencies": {
+        "inherits": "^2.0.1",
+        "readable-stream": "^2.1.0"
+      }
+    },
+    "node_modules/string-to-stream/node_modules/isarray": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
+      "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ=="
+    },
+    "node_modules/string-to-stream/node_modules/readable-stream": {
+      "version": "2.3.8",
+      "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz",
+      "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==",
+      "dependencies": {
+        "core-util-is": "~1.0.0",
+        "inherits": "~2.0.3",
+        "isarray": "~1.0.0",
+        "process-nextick-args": "~2.0.0",
+        "safe-buffer": "~5.1.1",
+        "string_decoder": "~1.1.1",
+        "util-deprecate": "~1.0.1"
+      }
+    },
+    "node_modules/string-to-stream/node_modules/string_decoder": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
+      "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
+      "dependencies": {
+        "safe-buffer": "~5.1.0"
+      }
+    },
     "node_modules/tslib": {
       "version": "2.6.2",
       "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz",
       "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==",
       "dev": true
+    },
+    "node_modules/util-deprecate": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
+      "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="
+    },
+    "node_modules/varint": {
+      "version": "6.0.0",
+      "resolved": "https://registry.npmjs.org/varint/-/varint-6.0.0.tgz",
+      "integrity": "sha512-cXEIW6cfr15lFv563k4GuVuW/fiwjknytD37jIOLSdSWuOI6WnO/oKwmP2FQTU2l01LP8/M5TSAJpzUaGe3uWg=="
+    },
+    "node_modules/xmlbuilder": {
+      "version": "8.2.2",
+      "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-8.2.2.tgz",
+      "integrity": "sha512-eKRAFz04jghooy8muekqzo8uCSVNeyRedbuJrp0fovbLIi7wlsYtdUn3vBAAPq2Y3/0xMz2WMEUQ8yhVVO9Stw==",
+      "engines": {
+        "node": ">=4.0"
+      }
+    },
+    "node_modules/xmlrpc": {
+      "version": "1.3.2",
+      "resolved": "https://registry.npmjs.org/xmlrpc/-/xmlrpc-1.3.2.tgz",
+      "integrity": "sha512-jQf5gbrP6wvzN71fgkcPPkF4bF/Wyovd7Xdff8d6/ihxYmgETQYSuTc+Hl+tsh/jmgPLro/Aro48LMFlIyEKKQ==",
+      "dependencies": {
+        "sax": "1.2.x",
+        "xmlbuilder": "8.2.x"
+      },
+      "engines": {
+        "node": ">=0.8",
+        "npm": ">=1.0.0"
+      }
     }
   }
 }

+ 4 - 1
package.json

@@ -20,5 +20,8 @@
   "bugs": {
     "url": "https://github.com/GameServerManagers/LinuxGSM/issues"
   },
-  "homepage": "https://github.com/GameServerManagers/LinuxGSM#readme"
+  "homepage": "https://github.com/GameServerManagers/LinuxGSM#readme",
+  "dependencies": {
+    "gamedig": "^5.0.0-beta.2"
+  }
 }