소스 검색

feat(newserver): add Half-Life WON2 server (#5104)

* feat(hlwon): add native Half-Life WON2 server

* fix(hlwon): satisfy Python lint conventions

* fix(hlwon): match hlds_i686 process and hide fastdl

The WON server runs as hlds_i686 rather than hlds_linux, so the details
port command and the HLDS PID lookup now match that binary for hlwon.

FastDL is no longer offered for hlwon: protocol 46 clients predate
sv_downloadurl, so the generated HTTP download setup would never be used.

* refactor(hlwon): install from a single linuxgsm.download archive

The WON2 server is a fixed legacy release, so it now installs like the
other archived servers through fn_install_server_files. The archive bundles
HLDS 3.1.1.1 with the 3.1.1.1e update, the patched hlds_run, the WON2
protection libraries and valvecomm.lst.

This removes install_hlwon.sh, which carved a tarball out of a Wayback
Machine copy of the 4Players installer and pulled six files from a
third-party repository, and the unused WON query test script.

* fix(hlwon): drop unneeded ncurses dependency on RHEL family

hlds_i686, the engine and the WON2 libraries only link libc, libm, libdl
and libpthread, which glibc.i686 in the base dependency list already
provides. On Rocky 9 the server installed, started and answered queries
with ncurses-libs.i686 removed.
Daniel Gibbs 12 시간 전
부모
커밋
1ed97ac26e

+ 202 - 0
lgsm/config-default/config-lgsm/hlwonserver/_default.cfg

@@ -0,0 +1,202 @@
+##################################
+######## Default Settings ########
+##################################
+# DO NOT EDIT, ANY CHANGES WILL BE OVERWRITTEN!
+# Copy settings from here and use them in either:
+# common.cfg - applies settings to every instance.
+# [instance].cfg - applies settings to a specific instance.
+
+#### Game Server Settings ####
+
+## Predefined Parameters | https://docs.linuxgsm.com/configuration/start-parameters
+ip="0.0.0.0"
+port="27015"
+clientport="27005"
+defaultmap="crossfire"
+maxplayers="16"
+
+## Server Parameters | https://docs.linuxgsm.com/configuration/start-parameters#additional-parameters
+startparameters="-game valve -binary ./hlds_i686 -noipx -insecure +ip ${ip} -port ${port} +clientport ${clientport} +map ${defaultmap} +servercfgfile ${servercfg} -maxplayers ${maxplayers}"
+
+#### LinuxGSM Settings ####
+
+## LinuxGSM Stats
+# Send useful stats to LinuxGSM developers.
+# https://docs.linuxgsm.com/configuration/linuxgsm-stats
+# (on|off)
+stats="off"
+
+## Notification Alerts
+# (on|off)
+
+# Display IP | https://docs.linuxgsm.com/alerts#display-ip
+displayip=""
+
+# More info | https://docs.linuxgsm.com/alerts#more-info
+postalert="off"
+
+# Alert on Start/Stop/Restart
+statusalert="off"
+
+# Discord Alerts | https://docs.linuxgsm.com/alerts/discord
+discordalert="off"
+discordwebhook="webhook"
+
+# Email Alerts | https://docs.linuxgsm.com/alerts/email
+emailalert="off"
+email="email@example.com"
+emailfrom=""
+
+# Gotify Alerts | https://docs.linuxgsm.com/alerts/gotify
+gotifyalert="off"
+gotifytoken="token"
+gotifywebhook="webhook"
+
+# IFTTT Alerts | https://docs.linuxgsm.com/alerts/ifttt
+iftttalert="off"
+ifttttoken="accesstoken"
+iftttevent="linuxgsm_alert"
+
+# ntfy Alerts | https://docs.linuxgsm.com/alerts/ntfy
+ntfyalert="off"
+ntfytopic="LinuxGSM"
+ntfyserver="https://ntfy.sh"
+ntfytoken=""
+ntfyusername=""
+ntfypassword=""
+ntfypriority=""
+ntfytags=""
+
+# Matrix Alerts | https://docs.linuxgsm.com/alerts/matrix
+matrixalert="off"
+matrixhomeserver="matrix.org"
+matrixtoken="accesstoken"
+matrixroom=""
+
+# Pushbullet Alerts | https://docs.linuxgsm.com/alerts/pushbullet
+pushbulletalert="off"
+pushbullettoken="accesstoken"
+channeltag=""
+
+# Pushover Alerts | https://docs.linuxgsm.com/alerts/pushover
+pushoveralert="off"
+pushovertoken="accesstoken"
+pushoveruserkey="userkey"
+
+# Rocket.Chat Alerts | https://docs.linuxgsm.com/alerts/rocket.chat
+rocketchatalert="off"
+rocketchatwebhook="webhook"
+
+# Slack Alerts | https://docs.linuxgsm.com/alerts/slack
+slackalert="off"
+slackwebhook="webhook"
+
+# Telegram Alerts | https://docs.linuxgsm.com/alerts/telegram
+# You can add a custom cURL string eg proxy (useful in Russia) in "curlcustomstring".
+# For example "--socks5 ipaddr:port" for socks5 proxy see more in "curl --help all".
+telegramapi="api.telegram.org"
+telegramalert="off"
+telegramtoken="accesstoken"
+telegramchatid=""
+telegramthreadid=""
+telegramsilentnotification="false"
+curlcustomstring=""
+
+## Stop | https://docs.linuxgsm.com/commands/start-stop-restart
+stoponlyifnoplayers="off"
+stoponlyifnoplayersallcommands="on"
+
+## Player Warnings | https://docs.linuxgsm.com/features/player-warnings
+# Minutes to warn players in-game before a stop, restart or update. 0 to disable.
+# e.g. 15 warns at 15, 10, 5, 3 and 1 minutes.
+warnplayerstimer="0"
+
+## Updating | https://docs.linuxgsm.com/commands/update
+updateonstart="off"
+
+## Backup | https://docs.linuxgsm.com/commands/backup
+maxbackups="4"
+maxbackupdays="30"
+stoponbackup="on"
+
+## Logging | https://docs.linuxgsm.com/features/logging
+consolelogging="on"
+logdays="7"
+
+## Monitor | https://docs.linuxgsm.com/commands/monitor
+# Query delay time
+querydelay="1"
+
+## ANSI Colors | https://docs.linuxgsm.com/features/ansi-colors
+ansi="on"
+
+#### Advanced Settings ####
+
+## Message Display Time | https://docs.linuxgsm.com/features/message-display-time
+sleeptime="0.5"
+
+## Stop Mode | https://docs.linuxgsm.com/features/stop-mode
+# 1: tmux kill
+# 2: CTRL+c
+# 3: quit
+# 4: quit 120s
+# 5: stop
+# 6: q
+# 7: exit
+# 8: 7 Days to Die
+# 9: GoldSrc
+# 10: Avorion
+# 11: end
+stopmode="9"
+
+## Query mode
+# 1: session only
+# 2: gamedig (gsquery fallback)
+# 3: gamedig
+# 4: gsquery
+# 5: tcp
+querymode="4"
+querytype="protocol-valve-won"
+
+## Console type
+consoleverbose="yes"
+consoleinteract="yes"
+
+## Game Server Details
+# Do not edit
+gamename="Half-Life: WON2"
+engine="goldsrc"
+glibc="2.0"
+
+#### Directories ####
+# Edit with care
+
+## Game Server Directories
+systemdir="${serverfiles}/valve"
+executabledir="${serverfiles}"
+executable="./hlds_run"
+servercfgdir="${systemdir}"
+servercfg="${selfname}.cfg"
+servercfgdefault="server.cfg"
+servercfgfullpath="${servercfgdir}/${servercfg}"
+
+## Backup Directory
+backupdir="${lgsmdir}/backup"
+
+## Logging Directories
+[ -n "${LGSM_LOGDIR}" ] && logdir="${LGSM_LOGDIR}" || logdir="${rootdir}/log"
+gamelogdir="${systemdir}/logs"
+lgsmlogdir="${logdir}/script"
+consolelogdir="${logdir}/console"
+lgsmlog="${lgsmlogdir}/${selfname}-script.log"
+consolelog="${consolelogdir}/${selfname}-console.log"
+alertlog="${lgsmlogdir}/${selfname}-alert.log"
+postdetailslog="${lgsmlogdir}/${selfname}-postdetails.log"
+
+## Logs Naming
+lgsmlogdate="${lgsmlogdir}/${selfname}-script-$(date '+%Y-%m-%d-%H:%M:%S').log"
+consolelogdate="${consolelogdir}/${selfname}-console-$(date '+%Y-%m-%d-%H:%M:%S').log"
+
+## Log Parameters
+logtimestamp="off"
+logtimestampformat="%Y-%m-%d %H:%M:%S"

+ 1 - 0
lgsm/data/almalinux-8.csv

@@ -54,6 +54,7 @@ hcu
 hl2dm
 hldm
 hldms
+hlwon
 hw,zlib-devel
 hyt
 hz

+ 1 - 0
lgsm/data/almalinux-9.csv

@@ -54,6 +54,7 @@ hcu
 hl2dm
 hldm
 hldms
+hlwon
 hw,zlib-devel
 hyt,java-25-openjdk
 hz

+ 1 - 0
lgsm/data/centos-7.csv

@@ -54,6 +54,7 @@ hcu
 hl2dm
 hldm
 hldms
+hlwon
 hw,zlib-devel
 hyt
 hz

+ 1 - 0
lgsm/data/centos-8.csv

@@ -54,6 +54,7 @@ hcu
 hl2dm
 hldm
 hldms
+hlwon
 hw,zlib-devel
 hyt
 hz

+ 1 - 0
lgsm/data/centos-9.csv

@@ -54,6 +54,7 @@ hcu
 hl2dm
 hldm
 hldms
+hlwon
 hw,zlib-devel
 hyt,java-25-openjdk
 hz

+ 1 - 0
lgsm/data/debian-10.csv

@@ -53,6 +53,7 @@ hcu
 hl2dm
 hldm
 hldms
+hlwon,libc6:i386
 hw,lib32z1
 hyt
 hz

+ 1 - 0
lgsm/data/debian-11.csv

@@ -54,6 +54,7 @@ hcu
 hl2dm
 hldm
 hldms
+hlwon,libc6:i386
 hw,lib32z1
 hyt
 hz

+ 1 - 0
lgsm/data/debian-12.csv

@@ -54,6 +54,7 @@ hcu
 hl2dm
 hldm
 hldms
+hlwon,libc6:i386
 hw,lib32z1
 hyt
 hz

+ 1 - 0
lgsm/data/debian-13.csv

@@ -54,6 +54,7 @@ hcu
 hl2dm
 hldm
 hldms
+hlwon,libc6:i386
 hw,lib32z1
 hyt,openjdk-25-jre
 hz

+ 1 - 0
lgsm/data/debian-9.csv

@@ -54,6 +54,7 @@ hcu
 hl2dm
 hldm
 hldms
+hlwon,libc6:i386
 hw,lib32z1
 hyt
 hz

BIN
lgsm/data/gameicons/hlwon-icon.png


+ 1 - 0
lgsm/data/rhel-7.csv

@@ -55,6 +55,7 @@ hcu
 hl2dm
 hldm
 hldms
+hlwon
 hw,zlib-devel
 hyt
 hz

+ 1 - 0
lgsm/data/rhel-8.csv

@@ -54,6 +54,7 @@ hcu
 hl2dm
 hldm
 hldms
+hlwon
 hw,zlib-devel
 hyt
 hz

+ 1 - 0
lgsm/data/rhel-9.csv

@@ -54,6 +54,7 @@ hcu
 hl2dm
 hldm
 hldms
+hlwon
 hw,zlib-devel
 hyt,java-25-openjdk
 hz

+ 1 - 0
lgsm/data/rocky-8.csv

@@ -54,6 +54,7 @@ hcu
 hl2dm
 hldm
 hldms
+hlwon
 hw,zlib-devel
 hyt
 hz

+ 1 - 0
lgsm/data/rocky-9.csv

@@ -54,6 +54,7 @@ hcu
 hl2dm
 hldm
 hldms
+hlwon
 hw,zlib-devel
 hyt,java-25-openjdk
 hz

+ 1 - 0
lgsm/data/serverlist.csv

@@ -53,6 +53,7 @@ hcu,hcuserver,HYPERCHARGE: Unboxed,ubuntu-26.04
 hl2dm,hl2dmserver,Half-Life 2: Deathmatch,ubuntu-26.04
 hldm,hldmserver,Half-Life: Deathmatch,ubuntu-26.04
 hldms,hldmsserver,Half-Life Deathmatch: Source,ubuntu-26.04
+hlwon,hlwonserver,Half-Life: WON2,ubuntu-26.04
 hw,hwserver,Hurtworld,ubuntu-26.04
 hyt,hytserver,Hytale,ubuntu-26.04
 hz,hzserver,Humanitz,ubuntu-26.04

+ 1 - 0
lgsm/data/ubuntu-16.04.csv

@@ -55,6 +55,7 @@ hcu
 hl2dm
 hldm
 hldms
+hlwon,libc6:i386
 hw,lib32z1
 hyt
 hz

+ 1 - 0
lgsm/data/ubuntu-18.04.csv

@@ -55,6 +55,7 @@ hcu
 hl2dm
 hldm
 hldms
+hlwon,libc6:i386
 hw,lib32z1
 hyt
 hz

+ 1 - 0
lgsm/data/ubuntu-20.04.csv

@@ -54,6 +54,7 @@ hcu
 hl2dm
 hldm
 hldms
+hlwon,libc6:i386
 hw,lib32z1
 hyt
 hz

+ 1 - 0
lgsm/data/ubuntu-22.04.csv

@@ -54,6 +54,7 @@ hcu
 hl2dm
 hldm
 hldms
+hlwon,libc6:i386
 hw,lib32z1
 hyt,openjdk-25-jre
 hz

+ 1 - 0
lgsm/data/ubuntu-23.04.csv

@@ -54,6 +54,7 @@ hcu
 hl2dm
 hldm
 hldms
+hlwon,libc6:i386
 hw,lib32z1
 hyt
 hz

+ 1 - 0
lgsm/data/ubuntu-23.10.csv

@@ -54,6 +54,7 @@ hcu
 hl2dm
 hldm
 hldms
+hlwon,libc6:i386
 hw,lib32z1
 hyt
 hz

+ 1 - 0
lgsm/data/ubuntu-24.04.csv

@@ -54,6 +54,7 @@ hcu
 hl2dm
 hldm
 hldms
+hlwon,libc6:i386
 hw,lib32z1
 hyt,openjdk-25-jre
 hz

+ 1 - 0
lgsm/data/ubuntu-26.04.csv

@@ -54,6 +54,7 @@ hcu
 hl2dm
 hldm
 hldms
+hlwon,libc6:i386
 hw,lib32z1
 hyt,openjdk-25-jre
 hz

+ 2 - 2
lgsm/modules/core_getopt.sh

@@ -69,7 +69,7 @@ currentopt+=("${cmd_update_linuxgsm[@]}")
 
 # Exclude noupdate games here.
 if [ "${shortname}" == "jk2" ] || [ "${shortname}" == "jk3" ] || [ "${shortname}" == "etl" ] || [ "${engine}" != "idtech3" ]; then
-	if [ "${shortname}" != "bf1942" ] && [ "${shortname}" != "bfv" ] && [ "${engine}" != "idtech2" ] && [ "${engine}" != "iw2.0" ] && [ "${engine}" != "iw3.0" ] && [ "${engine}" != "quake" ] && [ "${shortname}" != "samp" ] && [ "${shortname}" != "ut2k4" ]; then
+	if [ "${shortname}" != "hlwon" ] && [ "${shortname}" != "bf1942" ] && [ "${shortname}" != "bfv" ] && [ "${engine}" != "idtech2" ] && [ "${engine}" != "iw2.0" ] && [ "${engine}" != "iw3.0" ] && [ "${engine}" != "quake" ] && [ "${shortname}" != "samp" ] && [ "${shortname}" != "ut2k4" ]; then
 		currentopt+=("${cmd_update[@]}" "${cmd_check_update[@]}")
 		# force update for SteamCMD, Multi Theft Auto or Hytale only.
 		if [ "${appid}" ] || [ "${shortname}" == "mta" ] || [ "${shortname}" == "hyt" ]; then
@@ -97,7 +97,7 @@ fi
 ## Game server exclusive commands.
 
 # FastDL command.
-if [ "${engine}" == "source" ] || [ "${engine}" == "goldsrc" ]; then
+if { [ "${engine}" == "source" ] || [ "${engine}" == "goldsrc" ]; } && [ "${shortname}" != "hlwon" ]; then
 	currentopt+=("${cmd_fastdl[@]}")
 fi
 

+ 2 - 0
lgsm/modules/info_distro.sh

@@ -14,6 +14,8 @@ if [ "${status}" == "1" ]; then
 	gameserverpid="$(TERM=screen tmux -L "${socketname}" list-sessions -F "#{session_name} #{pane_pid}" | grep "^${sessionname} " | awk '{print $NF}')"
 	if [ "${engine}" == "source" ]; then
 		srcdslinuxpid="$(pgrep -P "${gameserverpid}" -x srcds_linux 2> /dev/null | head -n 1)"
+	elif [ "${shortname}" == "hlwon" ]; then
+		hldslinuxpid="$(pgrep -P "${gameserverpid}" -x hlds_i686 2> /dev/null | head -n 1)"
 	elif [ "${engine}" == "goldsrc" ]; then
 		hldslinuxpid="$(pgrep -P "${gameserverpid}" -x hlds_linux 2> /dev/null | head -n 1)"
 	fi

+ 7 - 1
lgsm/modules/info_messages.sh

@@ -771,6 +771,8 @@ fn_info_messages_ports() {
 		portcommand="ss -tuplwn | grep Main"
 	elif [ "${shortname}" == "sm" ]; then
 		portcommand="ss -tuplwn | grep WSServer-Linux"
+	elif [ "${shortname}" == "hlwon" ]; then
+		portcommand="ss -tuplwn | grep hlds_i686"
 	elif [ "${engine}" == "source" ]; then
 		portcommand="ss -tuplwn | grep srcds_linux"
 	elif [ "${engine}" == "goldsrc" ]; then
@@ -1121,7 +1123,11 @@ fn_info_messages_goldsrc() {
 	{
 		fn_port "header"
 		fn_port "Game" port udp
-		fn_port "Query" queryport tcp
+		if [ "${shortname}" == "hlwon" ]; then
+			fn_port "Query" queryport udp
+		else
+			fn_port "Query" queryport tcp
+		fi
 		fn_port "Client" clientport udp
 	} | column -s $'\t' -t
 }

+ 1 - 1
lgsm/modules/install_config.sh

@@ -492,7 +492,7 @@ elif [ "${shortname}" == "gmod" ]; then
 	fn_default_config_remote
 	fn_set_config_vars
 	fn_list_config_locations
-elif [ "${shortname}" == "hldm" ]; then
+elif [ "${shortname}" == "hldm" ] || [ "${shortname}" == "hlwon" ]; then
 	array_configs+=(server.cfg)
 	fn_default_config_remote
 	fn_set_config_vars

+ 8 - 0
lgsm/modules/install_server_files.sh

@@ -73,6 +73,14 @@ fn_install_server_files() {
 		run="norun"
 		force="noforce"
 		md5="2c6be1bb66ea631b9b2e7ae6216c6680"
+	elif [ "${shortname}" == "hlwon" ]; then
+		remote_fileurl="https://linuxgsm.download/HalfLifeWON2/hlds_l-3111e-won2-linuxgsm.tar.xz"
+		local_filedir="${tmpdir}"
+		local_filename="hlds_l-3111e-won2-linuxgsm.tar.xz"
+		chmodx="nochmodx"
+		run="norun"
+		force="noforce"
+		md5="83164405c744a5e424814e67eacf27fb"
 	elif [ "${shortname}" == "mohaa" ]; then
 		remote_fileurl="https://linuxgsm.download/MedalofHonorAlliedAssault/moh_revival_v1.12_RC3.5.1.tar.xz"
 		local_filedir="${tmpdir}"

+ 12 - 1
lgsm/modules/query_gsquery.py

@@ -13,6 +13,7 @@ import sys
 
 engine_types = (
     "protocol-valve",
+    "protocol-valve-won",
     "protocol-quake2",
     "protocol-quake3",
     "protocol-gamespy1",
@@ -34,6 +35,7 @@ class GSQuery:
     default_buffer_length = 1024
     sourcequery = (
         "protocol-valve",
+        "protocol-valve-won",
         "avalanche3.0",
         "barotrauma",
         "madness",
@@ -65,7 +67,11 @@ class GSQuery:
 
         self.argument = arguments
         if self.argument.engine in self.sourcequery:
-            self.query_prompt_string = b"\xff\xff\xff\xffTSource Engine Query\0"
+            self.query_prompt_string = (
+                b"\xff\xff\xff\xffdetails\0"
+                if self.argument.engine == "protocol-valve-won"
+                else b"\xff\xff\xff\xffTSource Engine Query\0"
+            )
         elif self.argument.engine in self.idtech2query:
             self.query_prompt_string = b"\xff\xff\xff\xffstatus\x00"
         elif self.argument.engine in self.idtech3query:
@@ -139,6 +145,11 @@ class GSQuery:
         # Response.
         if self.response is None:
             self.fatal_error("No response", 3)
+        if self.argument.engine == "protocol-valve-won" and (
+            not self.response.startswith(b"\xff\xff\xff\xffm")
+            or len(self.response.split(b"\0")) < 7
+        ):
+            self.fatal_error("Invalid WON server response", 3)
         if len(self.response) < 5:
             sys.exit("Short response.", 3)
         else: