Explorar o código

feat(cs2server): add Metamod:Source 2.0 and CounterStrikeSharp mod support (#4961)

- Enable mod installation, updates and removal for CS2
- Add Metamod:Source 2.0 dev builds with gameinfo.gi configuration
- Add CounterStrikeSharp using the latest Linux release with runtime
- Require Metamod:Source 2.0 before installing CounterStrikeSharp
- Preserve the shared Metamod directory when removing CounterStrikeSharp

Co-authored-by: Daniel Gibbs <me@danielgibbs.co.uk>
Attila hai 1 semana
pai
achega
0a7c1e17d0

+ 10 - 0
lgsm/modules/command_mods_install.sh

@@ -109,6 +109,11 @@ if [ -f "${modsinstalledlistfullpath}" ]; then
 fi
 
 ## Installation.
+# CounterStrikeSharp requires Metamod:Source 2.0.
+if [ "${modcommand}" == "counterstrikesharp" ]; then
+	fn_mod_exist "metamodsource2"
+fi
+
 # If amxmodx check if metamod exists first
 if [ "${modcommand}" == "amxmodx" ]; then
 	fn_mod_exist "metamod"
@@ -133,6 +138,11 @@ fn_mod_add_list
 fn_mod_tidy_files_list
 fn_mods_clear_tmp_dir
 
+# Install the Metamod:Source search path for CS2.
+if [ "${modcommand}" == "metamodsource2" ]; then
+	fn_mod_install_gameinfo_gi_file
+fi
+
 # Create/modify existing liblist.gam file for Metamod
 if [ "${modcommand}" == "metamod" ]; then
 	fn_mod_install_liblist_gam_file

+ 5 - 0
lgsm/modules/command_mods_remove.sh

@@ -151,6 +151,11 @@ if [ "${engine}" == "unity3d" ] && [[ "${modprettyname}" == *"Oxide"* ]]; then
 	unset exitbypass
 fi
 
+# Remove the Metamod:Source search path for CS2.
+if [ "${modcommand}" == "metamodsource2" ]; then
+	fn_mod_remove_gameinfo_gi_file
+fi
+
 # Remove/modify existing liblist.gam file for Metamod
 if [ "${modcommand}" == "metamod" ]; then
 	fn_mod_remove_liblist_gam_file

+ 4 - 0
lgsm/modules/command_mods_update.sh

@@ -93,6 +93,10 @@ while [ "${installedmodsline}" -le "${installedmodscount}" ]; do
 			fn_mod_add_list
 			fn_mod_tidy_files_list
 			fn_mods_clear_tmp_dir
+			# Restore the Metamod:Source search path if a CS2 update removed it.
+			if [ "${modcommand}" == "metamodsource2" ]; then
+				fn_mod_install_gameinfo_gi_file
+			fi
 		fi
 		((installedmodsline++))
 	else

+ 1 - 1
lgsm/modules/core_getopt.sh

@@ -137,7 +137,7 @@ if [ "${shortname}" == "squad" ]; then
 fi
 
 ## Mods commands.
-if [ "${engine}" == "source" ] || [ "${shortname}" == "rust" ] || [ "${shortname}" == "hq" ] || [ "${shortname}" == "sdtd" ] || [ "${shortname}" == "cs" ] || [ "${shortname}" == "dod" ] || [ "${shortname}" == "tfc" ] || [ "${shortname}" == "ns" ] || [ "${shortname}" == "ts" ] || [ "${shortname}" == "hldm" ] || [ "${shortname}" == "vh" ]; then
+if [ "${engine}" == "source" ] || [ "${shortname}" == "cs2" ] || [ "${shortname}" == "rust" ] || [ "${shortname}" == "hq" ] || [ "${shortname}" == "sdtd" ] || [ "${shortname}" == "cs" ] || [ "${shortname}" == "dod" ] || [ "${shortname}" == "tfc" ] || [ "${shortname}" == "ns" ] || [ "${shortname}" == "ts" ] || [ "${shortname}" == "hldm" ] || [ "${shortname}" == "vh" ]; then
 	currentopt+=("${cmd_mods_install[@]}" "${cmd_mods_remove[@]}" "${cmd_mods_update[@]}")
 fi
 

+ 65 - 0
lgsm/modules/mods_core.sh

@@ -158,6 +158,11 @@ fn_mod_tidy_files_list() {
 		sed -i "/^addons\/metamod\/sourcemod.vdf$/d" "${modsdir}/${modcommand}-files.txt"
 	fi
 
+	# Keep Metamod:Source when removing CounterStrikeSharp, but remove its own VDF.
+	if [ "${modcommand}" == "counterstrikesharp" ]; then
+		sed -i "/^addons\/metamod$/d" "${modsdir}/${modcommand}-files.txt"
+	fi
+
 	# Remove common paths from deletion list (Add your sourcemod mod here)
 	if [ "${modcommand}" == "gokz" ] || [ "${modcommand}" == "ttt" ] || [ "${modcommand}" == "steamworks" ] || [ "${modcommand}" == "get5" ]; then
 		sed -i "/^addons\/sourcemod$/d" "${modsdir}/${modcommand}-files.txt"
@@ -693,6 +698,66 @@ fn_mod_remove_liblist_gam_file() {
 	fi
 }
 
+# modifiers for gameinfo.gi to add/remove the Metamod:Source search path
+# Counter-Strike 2 only: the csgo paths below are specific to that game.
+fn_mod_install_gameinfo_gi_file() {
+	local gameinfofile="${modinstalldir}/gameinfo.gi"
+	local metamodpattern='^[[:space:]]*"?Game"?[[:space:]]+"?csgo/addons/metamod"?[[:space:]]*(//.*)?$'
+	local lowviolencepattern='^[[:space:]]*"?Game_LowViolence"?[[:space:]]+"?csgo_lv"?[[:space:]]*(//.*)?$'
+
+	if [ -f "${gameinfofile}" ]; then
+		# the search path survives a mod update, only add it when it is missing
+		if grep -Eq "${metamodpattern}" "${gameinfofile}"; then
+			fn_script_log_info "Metamod:Source search path already set in ${gameinfofile}"
+		else
+			# insert the search path below Game_LowViolence as documented by Metamod:Source
+			logentry="line (Game csgo/addons/metamod) inserted into ${gameinfofile}"
+			echo -en "adding Metamod:Source search path in gameinfo.gi..."
+			sed -i -E "\\@${lowviolencepattern}@a\\\\t\\t\\tGame\\tcsgo/addons/metamod" "${gameinfofile}"
+			grep -Eq "${metamodpattern}" "${gameinfofile}"
+			exitcode=$?
+			# if the insert didn't happen, error out
+			if [ "${exitcode}" -ne 0 ]; then
+				fn_script_log_fail "${logentry}"
+				fn_print_fail_eol_nl
+				core_exit.sh
+			else
+				fn_script_log_pass "${logentry}"
+				fn_print_ok_eol_nl
+			fi
+		fi
+	else
+		fn_script_log_fail "Unable to find ${gameinfofile}"
+		fn_print_fail_nl "Unable to find ${gameinfofile}"
+		core_exit.sh
+	fi
+}
+
+# Unlike the install counterpart this does not call core_exit.sh on failure:
+# command_mods_remove.sh ends with fn_script_log, which leaves exitcode alone,
+# while command_mods_install.sh ends with fn_script_log_pass, which resets it to 0.
+fn_mod_remove_gameinfo_gi_file() {
+	local gameinfofile="${modinstalldir}/gameinfo.gi"
+	local metamodpattern='^[[:space:]]*"?Game"?[[:space:]]+"?csgo/addons/metamod"?[[:space:]]*(//.*)?$'
+
+	if [ -f "${gameinfofile}" ]; then
+		# is the search path found? If so remove it and keep the rest of the file
+		if grep -Eq "${metamodpattern}" "${gameinfofile}"; then
+			logentry="line (Game csgo/addons/metamod) removed from ${gameinfofile}"
+			echo -en "removing Metamod:Source search path in gameinfo.gi..."
+			# delete the line we inserted
+			sed -i -E "\\@${metamodpattern}@d" "${gameinfofile}"
+			if grep -Eq "${metamodpattern}" "${gameinfofile}"; then
+				fn_script_log_fail "${logentry}"
+				fn_print_fail_eol_nl
+			else
+				fn_script_log_pass "${logentry}"
+				fn_print_ok_eol_nl
+			fi
+		fi
+	fi
+}
+
 fn_mod_install_amxmodx_file() {
 	# does plugins.ini exist?
 	if [ -f "${modinstalldir}/addons/metamod/plugins.ini" ]; then

+ 17 - 1
lgsm/modules/mods_list.sh

@@ -60,6 +60,12 @@ metamodsourcescrapeurl="https://mms.alliedmods.net/mmsdrop/${metamodsourceversio
 metamodsourcelatestfile=$(wget "${metamodsourcescrapeurl}" -q -O -)
 metamodsourcedownloadurl="https://www.metamodsource.net/latest.php?os=linux&version=${metamodsourceversion}"
 metamodsourceurl="${metamodsourcedownloadurl}"
+# Metamod:Source 2.0
+metamodsource2version="2.0"
+metamodsource2scrapeurl="https://mms.alliedmods.net/mmsdrop/${metamodsource2version}/mmsource-latest-linux"
+metamodsource2latestfile=$(wget "${metamodsource2scrapeurl}" -q -O -)
+metamodsource2downloadurl="https://www.metamodsource.net/latest.php?os=linux&version=${metamodsource2version}"
+metamodsource2url="${metamodsource2downloadurl}"
 # Sourcemod
 sourcemodversion="1.13"
 sourcemodscrapeurl="https://sm.alliedmods.net/smdrop/${sourcemodversion}/sourcemod-latest-linux"
@@ -77,6 +83,12 @@ stripperlatestfile="stripper-${stripperversion}-linux.tar.gz"
 stripperdownloadurl="http://www.bailopan.net/stripper/snapshots/1.2/${stripperlatestfile}"
 stripperurl="${stripperdownloadurl}"
 
+# CS2 Mods
+counterstrikesharprelease=$(curl --connect-timeout 3 -sL https://api.github.com/repos/roflmuffin/CounterStrikeSharp/releases/latest)
+counterstrikesharplastbuild=$(printf '%s\n' "${counterstrikesharprelease}" | jq '.assets[]? | select(.name | startswith("counterstrikesharp-with-runtime-linux-") and endswith(".zip"))' 2> /dev/null)
+counterstrikesharplatestfile=$(printf '%s\n' "${counterstrikesharplastbuild}" | jq -r '.name')
+counterstrikesharplatestlink=$(printf '%s\n' "${counterstrikesharplastbuild}" | jq -r '.browser_download_url')
+
 # CS:GO Mods
 get5lastbuild=$(curl --connect-timeout 3 -sL https://api.github.com/repos/splewis/get5/releases/latest | jq '.assets[] |select(.browser_download_url | endswith(".tar.gz"))')
 get5latestfile=$(echo -e "${get5lastbuild}" | jq -r '.name')
@@ -157,6 +169,10 @@ mod_info_sourcemod=(MOD "sourcemod" "SourceMod" "${sourcemodurl}" "${sourcemodla
 mod_info_steamworks=(MOD "steamworks" "SteamWorks" "${steamworksurl}" "${steamworkslatestfile}" "0" "LowercaseOff" "${systemdir}" "OVERWRITE" "ENGINES" "Counter-Strike: Global Offensive;" "NOTGAMES" "https://github.com/KyleSanderson/SteamWorks" "Exposing SteamWorks functions to SourcePawn")
 mod_info_stripper=(MOD "stripper" "Stripper Source" "${stripperurl}" "${stripperlatestfile}" "0" "LowercaseOff" "${systemdir}" "addons/stripper/maps;" "ENGINES" "Counter-Strike: Global Offensive;Counter-Strike: Source;Day of Defeat: Source;Half Life: Deathmatch;Half Life 2: Deathmatch;Insurgency;Left 4 Dead;Left 4 Dead 2;Nuclear Dawn;Team Fortress 2;" "NOTGAMES" "http://www.bailopan.net/stripper/" "Add or remove objects from map (requires MetaMod)")
 
+# CS2 Mods
+mod_info_metamodsource2=(MOD "metamodsource2" "Metamod:Source 2.0" "${metamodsource2url}" "${metamodsource2latestfile}" "0" "LowercaseOff" "${systemdir}" "addons/metamod/metaplugins.ini;" "ENGINES" "Counter-Strike 2;" "NOTGAMES" "https://www.metamodsource.net" "Plugins Framework (Dev Build)")
+mod_info_counterstrikesharp=(MOD "counterstrikesharp" "CounterStrikeSharp" "${counterstrikesharplatestlink}" "${counterstrikesharplatestfile}" "0" "LowercaseOff" "${systemdir}" "OVERWRITE" "ENGINES" "Counter-Strike 2;" "NOTGAMES" "https://docs.cssharp.dev/" "Write server plugins in C# (requires Metamod:Source 2.0)")
+
 # CS:GO Mods
 mod_info_gokz=(MOD "gokz" "GOKZ" "${gokzlatestlink}" "${gokzlatestfile}" "0" "LowercaseOff" "${systemdir}" "cfg;addons/sourcemod/configs;" "ENGINES" "Counter-Strike: Global Offensive;" "NOTGAMES" "https://github.com/KZGlobalTeam/gokz" "GOKZ ${gokzlatestversion} - Implements the KZ game mode (requires SourceMod and MetaMod)")
 mod_info_ttt=(MOD "ttt" "Trouble in Terrorist Town" "https://csgottt.com/downloads/ttt-latest-dev-${sourcemodversion}.zip" "ttt-latest.zip" "0" "LowercaseOff" "${systemdir}" "cfg;addons/sourcemod/configs;" "ENGINES" "Counter-Strike: Global Offensive;" "NOTGAMES" "https://github.com/Bara/TroubleinTerroristTown" "Implements the TTT game mode (requires SourceMod and MetaMod)")
@@ -211,4 +227,4 @@ mod_info_valheimplus=(MOD "valheimplus" "Valheim PLUS" "${valheimpluslatestlink}
 mod_info_bepinexvh=(MOD "bepinexvh" "BepInEx Valheim" "${bepinexvhlatestlink}" "denikson-BepInExPack_Valheim.zip" "BepInExPack_Valheim" "LowercaseOff" "${systemdir}" "OVERWRITE" "ENGINES" "Valheim;" "NOTGAMES" "https://valheim.thunderstore.io/package/denikson/BepInExPack_Valheim/" "Unity / XNA game patcher and plugin framework")
 
 # REQUIRED: Set all mods info into the global array
-mods_global_array=("${mod_info_metamod[@]}" "${mod_info_base_amxx[@]}" "${mod_info_cs_amxx[@]}" "${mod_info_dod_amxx[@]}" "${mod_info_tfc_amxx[@]}" "${mod_info_ns_amxx[@]}" "${mod_info_ts_amxx[@]}" "${mod_info_metamodsource[@]}" "${mod_info_sourcemod[@]}" "${mod_info_steamworks[@]}" "${mod_info_gokz[@]}" "${mod_info_ttt[@]}" "${mod_info_get5[@]}" "${mod_info_prac[@]}" "${mod_info_pug[@]}" "${mod_info_dhook[@]}" "${mod_info_movement[@]}" "${mod_info_cleaner[@]}" "${mod_info_ulib[@]}" "${mod_info_ulx[@]}" "${mod_info_utime[@]}" "${mod_info_uclip[@]}" "${mod_info_acf[@]}" "${mod_info_acf_missiles[@]}" "${mod_info_acf_sweps[@]}" "${mod_info_advdupe2[@]}" "${mod_info_pac3[@]}" "${mod_info_wiremod[@]}" "${mod_info_wiremodextras[@]}" "${mod_info_darkrp[@]}" "${mod_info_darkrpmodification[@]}" "${mod_info_rustcarbon[@]}" "${mod_info_rustoxide[@]}" "${mod_info_hwoxide[@]}" "${mod_info_sdtdoxide[@]}" "${mod_info_advduplicator[@]}" "${mod_info_trackassemblytool[@]}" "${mod_info_physpropertiesadv[@]}" "${mod_info_controlsystemse2[@]}" "${mod_info_e2pistontiming[@]}" "${mod_info_propcannontool[@]}" "${mod_info_gearassemblytool[@]}" "${mod_info_spinnertool[@]}" "${mod_info_surfacefrictiontool[@]}" "${mod_info_magneticdipole[@]}" "${mod_info_environmentorganizer[@]}" "${mod_info_precision_alignment[@]}" "${mod_info_improved_stacker[@]}" "${mod_info_improved_weight[@]}" "${mod_info_improved_antinoclip[@]}" "${mod_info_laserstool[@]}" "${mod_info_valheimplus[@]}" "${mod_info_bepinexvh[@]}")
+mods_global_array=("${mod_info_metamod[@]}" "${mod_info_base_amxx[@]}" "${mod_info_cs_amxx[@]}" "${mod_info_dod_amxx[@]}" "${mod_info_tfc_amxx[@]}" "${mod_info_ns_amxx[@]}" "${mod_info_ts_amxx[@]}" "${mod_info_metamodsource[@]}" "${mod_info_metamodsource2[@]}" "${mod_info_counterstrikesharp[@]}" "${mod_info_sourcemod[@]}" "${mod_info_steamworks[@]}" "${mod_info_gokz[@]}" "${mod_info_ttt[@]}" "${mod_info_get5[@]}" "${mod_info_prac[@]}" "${mod_info_pug[@]}" "${mod_info_dhook[@]}" "${mod_info_movement[@]}" "${mod_info_cleaner[@]}" "${mod_info_ulib[@]}" "${mod_info_ulx[@]}" "${mod_info_utime[@]}" "${mod_info_uclip[@]}" "${mod_info_acf[@]}" "${mod_info_acf_missiles[@]}" "${mod_info_acf_sweps[@]}" "${mod_info_advdupe2[@]}" "${mod_info_pac3[@]}" "${mod_info_wiremod[@]}" "${mod_info_wiremodextras[@]}" "${mod_info_darkrp[@]}" "${mod_info_darkrpmodification[@]}" "${mod_info_rustcarbon[@]}" "${mod_info_rustoxide[@]}" "${mod_info_hwoxide[@]}" "${mod_info_sdtdoxide[@]}" "${mod_info_advduplicator[@]}" "${mod_info_trackassemblytool[@]}" "${mod_info_physpropertiesadv[@]}" "${mod_info_controlsystemse2[@]}" "${mod_info_e2pistontiming[@]}" "${mod_info_propcannontool[@]}" "${mod_info_gearassemblytool[@]}" "${mod_info_spinnertool[@]}" "${mod_info_surfacefrictiontool[@]}" "${mod_info_magneticdipole[@]}" "${mod_info_environmentorganizer[@]}" "${mod_info_precision_alignment[@]}" "${mod_info_improved_stacker[@]}" "${mod_info_improved_weight[@]}" "${mod_info_improved_antinoclip[@]}" "${mod_info_laserstool[@]}" "${mod_info_valheimplus[@]}" "${mod_info_bepinexvh[@]}")