Browse Source

Merge cbaf0af14f into 68ae13c069

pull/4186/merge
FliesWithWind 2 years ago
committed by GitHub
parent
commit
0cbaa131da
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 7
      lgsm/config-default/config-lgsm/arma3server/_default.cfg
  2. 46
      lgsm/functions/command_workshop_install.sh
  3. 36
      lgsm/functions/command_workshop_update.sh
  4. 22
      lgsm/functions/core_functions.sh
  5. 9
      lgsm/functions/core_getopt.sh
  6. 318
      lgsm/functions/workshop_core.sh

7
lgsm/config-default/config-lgsm/arma3server/_default.cfg

@ -27,6 +27,11 @@ mods=""
## Server-side Mods ## Server-side Mods
servermods="" servermods=""
## Mods to be downloaded from Steam Workshop
# Use workshop ids
# workshopmods="450814997;2131302796"
workshopmods=""
## Path to BattlEye ## Path to BattlEye
# Leave empty for default # Leave empty for default
bepath="" bepath=""
@ -126,6 +131,8 @@ sleeptime="0.5"
# Server appid # Server appid
appid="233780" appid="233780"
steamcmdforcewindows="no" steamcmdforcewindows="no"
# Game appid
gameappid="107410"
# SteamCMD Branch | https://docs.linuxgsm.com/steamcmd/branch # SteamCMD Branch | https://docs.linuxgsm.com/steamcmd/branch
branch="" branch=""
betapassword="" betapassword=""

46
lgsm/functions/command_workshop_install.sh

@ -0,0 +1,46 @@
#!/bin/bash
# LinuxGSM command_workshop_install.sh module
# Author: Daniel Gibbs
# Contributors: http://linuxgsm.com/contrib
# Website: https://linuxgsm.com
# Description: List and installs available mods along with mods_list.sh and mods_core.sh.
commandname="WORKSHOP-INSTALL"
commandaction="Installing Steam Workshop mods"
functionselfname="$(basename "$(readlink -f "${BASH_SOURCE[0]}")")"
fn_firstcommand_set
check.sh
workshop_core.sh
fn_print_header
fn_create_workshop_dir
fn_workshop_get_list
# Displays a list of installed mods.
echo -e ""
echo -e "Installed workshop addons/mods"
echo -e "================================="
fn_workshop_installed_list
for modid in "${workshoplist[@]}"; do
# Check if the mod is already installed and warn the user.
# if ! fn_workshop_check_mod_update $modid; then
# fn_print_warning_nl "$(fn_workshop_get_mod_name ${modid}) is already installed"
# fn_script_log_warn "$(fn_workshop_get_mod_name ${modid}) is already installed"
# echo -e " * Any configs may be overwritten."
# if ! fn_prompt_yn "Continue?" Y; then
# core_exit.sh
# fi
# fn_script_log_info "User selected to continue"
# fi
echo -e ""
echo -e "Installing $(fn_workshop_get_mod_name ${modid})."
echo -e "================================="
fn_workshop_download "${modid}"
fn_workshop_copy_destination "${modid}"s
done
fn_workshop_lowercase
core_exit.sh

36
lgsm/functions/command_workshop_update.sh

@ -0,0 +1,36 @@
#!/bin/bash
# LinuxGSM command_workshop_install.sh module
# Author: Daniel Gibbs
# Contributors: http://linuxgsm.com/contrib
# Website: https://linuxgsm.com
# Description: List and installs available mods along with mods_list.sh and mods_core.sh.
commandname="WORKSHOP-INSTALL"
commandaction="Installing Steam Workshop mods"
functionselfname="$(basename "$(readlink -f "${BASH_SOURCE[0]}")")"
fn_firstcommand_set
check.sh
workshop_core.sh
fn_print_header
fn_create_workshop_dir
fn_workshop_get_list
# Displays a list of installed mods.
echo -e "Installed workshop addons/mods"
echo -e "================================="
fn_workshop_installed_list
for modid in "${workshoplist[@]}"; do
modname="$(fn_workshop_get_mod_name ${modid})"
if [ fn_workshop_check_mod_update "${modid}" ]; then
echo "Mod ${modname} (${modid}) is not up to date."
fn_workshop_download "${modid}"
fn_workshop_copy_destination "${modid}"
else
echo "Mod ${modname} is up to date."
fi
done
fn_workshop_lowercase
core_exit.sh

22
lgsm/functions/core_functions.sh

@ -151,6 +151,21 @@ command_mods_remove.sh() {
fn_fetch_function fn_fetch_function
} }
command_workshop_install.sh() {
functionfile="${FUNCNAME[0]}"
fn_fetch_function
}
command_workshop_update.sh() {
functionfile="${FUNCNAME[0]}"
fn_fetch_function
}
command_workshop_remove.sh() {
functionfile="${FUNCNAME[0]}"
fn_fetch_function
}
command_fastdl.sh() { command_fastdl.sh() {
functionfile="${FUNCNAME[0]}" functionfile="${FUNCNAME[0]}"
fn_fetch_function fn_fetch_function
@ -287,6 +302,13 @@ mods_core.sh() {
fn_fetch_function fn_fetch_function
} }
# Steam Workshop
workshop_core.sh() {
functionfile="${FUNCNAME[0]}"
fn_fetch_function
}
# Dev # Dev
command_dev_clear_functions.sh() { command_dev_clear_functions.sh() {

9
lgsm/functions/core_getopt.sh

@ -37,6 +37,10 @@ cmd_validate=("v;validate" "command_validate.sh" "Validate server files with Ste
cmd_mods_install=("mi;mods-install" "command_mods_install.sh" "View and install available mods/addons.") cmd_mods_install=("mi;mods-install" "command_mods_install.sh" "View and install available mods/addons.")
cmd_mods_remove=("mr;mods-remove" "command_mods_remove.sh" "View and remove an installed mod/addon.") cmd_mods_remove=("mr;mods-remove" "command_mods_remove.sh" "View and remove an installed mod/addon.")
cmd_mods_update=("mu;mods-update" "command_mods_update.sh" "Update installed mods/addons.") cmd_mods_update=("mu;mods-update" "command_mods_update.sh" "Update installed mods/addons.")
# Server with Steam Workshop
cmd_workshop_install=("wi;workshop-install" "command_workshop_install.sh" "View and install mods/addons from Steam Workshop.")
cmd_workshop_remove=("wr;workshop-remove" "command_workshop_remove.sh" "View and remove an installed mod/addon from Steam Workshop.")
cmd_workshop_update=("wu;workshop-update" "command_workshop_update.sh" "Update installed mods/addons from Steam Workshop.")
# Server specific. # Server specific.
cmd_change_password=("pw;change-password" "command_ts3_server_pass.sh" "Change TS3 serveradmin password.") cmd_change_password=("pw;change-password" "command_ts3_server_pass.sh" "Change TS3 serveradmin password.")
cmd_install_default_resources=("ir;install-default-resources" "command_install_resources_mta.sh" "Install the MTA default resources.") cmd_install_default_resources=("ir;install-default-resources" "command_install_resources_mta.sh" "Install the MTA default resources.")
@ -139,6 +143,11 @@ if [ "${engine}" == "source" ] || [ "${shortname}" == "rust" ] || [ "${shortname
currentopt+=("${cmd_mods_install[@]}" "${cmd_mods_remove[@]}" "${cmd_mods_update[@]}") currentopt+=("${cmd_mods_install[@]}" "${cmd_mods_remove[@]}" "${cmd_mods_update[@]}")
fi fi
## Workshop commands.
if [ "${engine}" == "realvirtuality" ]; then
currentopt+=("${cmd_workshop_install[@]}" "${cmd_workshop_remove[@]}" "${cmd_workshop_update[@]}")
fi
## Installer. ## Installer.
currentopt+=("${cmd_install[@]}" "${cmd_auto_install[@]}") currentopt+=("${cmd_install[@]}" "${cmd_auto_install[@]}")

318
lgsm/functions/workshop_core.sh

@ -0,0 +1,318 @@
#!/bin/bash
# LinuxGSM workshop_core.sh module
# Author: Daniel Gibbs
# Contributors: http://linuxgsm.com/contrib
# Website: https://linuxgsm.com
# Description: Core functions for mods list/install/update/remove
functionselfname="$(basename "$(readlink -f "${BASH_SOURCE[0]}")")"
# Files and Directories.
steam="${steamcmd}/steam"
workshopmodsdir="${serverfiles}/mods"
keysdir="${serverfiles}/keys"
workshopmodsdldir="${lgsmdir}/workshop"
workshopmodslist="workshop-mods.txt"
workshopmodslistfullpath="${configdir}/${workshopmodslist}"
workshopmoddownloaddir="${steam}/steamapps/workshop/content/${appid}"
## Installation.
core_steamcmd.sh
fn_check_steamcmd_exec
# # Download management.
# For Workshop Mod Downloads, we need to use game app id, not the server app id.
fn_workshop_download() {
local modid=$1
local workshopmodsrcdir="${workshopmoddownloaddir}/${modid}"
if [ -d "${steamcmddir}" ]; then
cd "${steamcmddir}" || exit
fi
# Unbuffer will allow the output of steamcmd not buffer allowing a smooth output.
# unbuffer us part of the expect package.
if [ "$(command -v unbuffer)" ]; then
unbuffer="unbuffer"
fi
# To do error checking for SteamCMD the output of steamcmd will be saved to a log.
steamcmdlog="${lgsmlogdir}/${selfname}-steamcmd.log"
# clear previous steamcmd log
if [ -f "${steamcmdlog}" ]; then
rm -f "${steamcmdlog:?}"
fi
counter=0
while [ "${counter}" == "0" ] || [ "${exitcode}" != "0" ]; do
counter=$((counter + 1))
# Select SteamCMD parameters
${unbuffer} ${steamcmdcommand} +force_install_dir "${workshopmodsdldir}" +login "${steamuser}" "${steampass}" +workshop_download_item "${gameappid}" "${modid}" +quit | uniq | tee -a "${lgsmlog}" "${steamcmdlog}"
# Error checking for SteamCMD. Some errors will loop to try again and some will just exit.
# Check also if we have more errors than retries to be sure that we do not loop to many times and error out.
exitcode=$?
if [ -n "$(grep -i "Error!" "${steamcmdlog}" | tail -1)" ] && [ "$(grep -ic "Error!" "${steamcmdlog}")" -ge "${counter}" ]; then
# Not enough space.
if [ -n "$(grep "0x202" "${steamcmdlog}" | tail -1)" ]; then
fn_print_failure_nl "${commandaction} ${selfname}: ${remotelocation}: Not enough disk space to download workshop mod"
fn_script_log_fatal "${commandaction} ${selfname}: ${remotelocation}: Not enough disk space to download workshop mod"
core_exit.sh
# Not enough space.
elif [ -n "$(grep "0x212" "${steamcmdlog}" | tail -1)" ]; then
fn_print_failure_nl "${commandaction} ${selfname}: ${remotelocation}: Not enough disk space to download workshop mod"
fn_script_log_fatal "${commandaction} ${selfname}: ${remotelocation}: Not enough disk space to download workshop mod"
core_exit.sh
# Need tp purchase game.
elif [ -n "$(grep "No subscription" "${steamcmdlog}" | tail -1)" ]; then
fn_print_failure_nl "${commandaction} ${selfname}: ${remotelocation}: Steam account does not have a license for the required game"
fn_script_log_fatal "${commandaction} ${selfname}: ${remotelocation}: Steam account does not have a license for the required game"
core_exit.sh
# Two-factor authentication failure
elif [ -n "$(grep "Two-factor code mismatch" "${steamcmdlog}" | tail -1)" ]; then
fn_print_failure_nl "${commandaction} ${selfname}: ${remotelocation}: Two-factor authentication failure"
fn_script_log_fatal "${commandaction} ${selfname}: ${remotelocation}: Two-factor authentication failure"
core_exit.sh
# Incorrect Branch password
elif [ -n "$(grep "Password check for AppId" "${steamcmdlog}" | tail -1)" ]; then
fn_print_failure_nl "${commandaction} ${selfname}: ${remotelocation}: betapassword is incorrect"
fn_script_log_fatal "${commandaction} ${selfname}: ${remotelocation}: betapassword is incorrect"
core_exit.sh
# Update did not finish.
elif [ -n "$(grep "0x402" "${steamcmdlog}" | tail -1)" ] || [ -n "$(grep "0x602" "${steamcmdlog}" | tail -1)" ]; then
fn_print_error2_nl "${commandaction} ${selfname}: ${remotelocation}: Update required but not completed - check network"
fn_script_log_error "${commandaction} ${selfname}: ${remotelocation}: Update required but not completed - check network"
else
fn_print_error2_nl "${commandaction} ${selfname}: ${remotelocation}: Unknown error occured"
echo -en "Please provide content log to LinuxGSM developers https://linuxgsm.com/steamcmd-error"
fn_script_log_error "${commandaction} ${selfname}: ${remotelocation}: Unknown error occured"
fi
elif [ "${exitcode}" != "0" ]; then
fn_print_error2_nl "${commandaction} ${selfname}: ${remotelocation}: Exit code: ${exitcode}"
fn_script_log_error "${commandaction} ${selfname}: ${remotelocation}: Exit code: ${exitcode}"
else
fn_print_complete_nl "${commandaction} ${selfname}: ${remotelocation}"
fn_script_log_pass "${commandaction} ${selfname}: ${remotelocation}"
fi
if [ "${counter}" -gt "10" ]; then
fn_print_failure_nl "${commandaction} ${selfname}: ${remotelocation}: Did not complete the download, too many retrys"
fn_script_log_fatal "${commandaction} ${selfname}: ${remotelocation}: Did not complete the download, too many retrys"
core_exit.sh
fi
done
}
fn_workshop_get_list() {
workshoplist=($(echo "${workshopmods}" | tr ";" "\n"))
}
fn_workshop_get_latest_mod_version() {
local modid="$1"
local serverresp="$(curl -s -d "itemcount=1&publishedfileids[0]=${modid}" "http://api.steampowered.com/ISteamRemoteStorage/GetPublishedFileDetails/v1")"
local remupd=
if [[ "${serverresp}" =~ \"hcontent_file\":[[:space:]]*([^,]*) ]]; then
remupd="${BASH_REMATCH[1]}"
fi
echo "${remupd}" | tr -d '"'
}
fn_workshop_get_name_from_steam() {
local modid="$1"
local serverresp="$(curl -s -d "itemcount=1&publishedfileids[0]=${modid}" "http://api.steampowered.com/ISteamRemoteStorage/GetPublishedFileDetails/v1")"
local title=
if [[ "${serverresp}" =~ \"title\":[[:space:]]*([^,]*) ]]; then
title="${BASH_REMATCH[1]}"
fi
echo "${title}" | tr -d '"'
}
fn_workshop_check_mod_update() {
local modid="$1"
if [ ! -f "${workshopmodsdldir}/steamapps/workshop/appworkshop_${gameappid}.acf" ]; then return 0; fi
local instmft="$(sed -n '/^\t"WorkshopItemsInstalled"$/,/^\t[}]$/{/^\t\t"'"${modid}"'"$/,/^\t\t[}]$/{s|^\t\t\t"manifest"\t\t"\(.*\)"$|\1|p}}' <"${workshopmodsdldir}/steamapps/workshop/appworkshop_${gameappid}.acf")"
if [ -z "${instmft}" ]; then return 0; fi
local remmft="$(fn_workshop_get_latest_mod_version "${modid}")"
if [[ -n "${remmft}" && "${instmft}" != "${remmft}" ]]; then
return 0 # true
fi
return 1 # false
}
fn_workshop_is_mod_copy_needed(){
local modid="$1"
local modsrc="${workshopmodsdldir}/steamapps/workshop/content/${gameappid}/${modid}"
if [ ! -f "${workshopmodsdir}/${modid}/meta.cpp" ]; then return 0; fi
local instmft="$(grep "timestamp" ${workshopmodsdir}/${modid}/meta.cpp)"
if [ -z "${instmft}" ]; then return 0; fi
local remmft="$(grep "timestamp" ${modsrc}/meta.cpp)"
if [[ -n "${remmft}" && "${instmft}" != "${remmft}" ]]; then
return 0 # true
fi
return 1
}
fn_workshop_get_mod_name(){
local modid="$1"
# Each game has different Steam Workshop structure, so mod id will be stored in a different place
if [ "${engine}" == "realvirtuality" ]; then
if ! [ -d "${workshopmodsdir}/${modid}" ]; then
echo "$(grep -Po '(?<=name = ").+?(?=")' ${workshopmodsdir}/${modid}/mod.cpp)"
elif ! [ -d "${workshopmodsdldir}/steamapps/workshop/content/${gameappid}/${modid}" ]; then
echo "$(grep -Po '(?<=name = ").+?(?=")' ${workshopmodsdldir}/steamapps/workshop/content/${gameappid}/${modid}/mod.cpp)"
else
echo "$(fn_workshop_get_name_from_steam ${modid})"
fi
else
echo "$(fn_workshop_get_name_from_steam ${modid})"
fi
}
# Convert workshop mod files to lowercase if needed.
fn_workshop_lowercase() {
# local modid="$1"
# local modname="$(fn_workshop_get_mod_name $modid)"
# Arma 3 requires lowercase
if [ "${engine}" == "realvirtuality" ]; then
echo -en "Converting ${modname} files to lowercase..."
fn_sleep_time
fn_script_log_info "Converting ${modname} files to lowercase"
# Total files and directories for the mod, to output to the user
fileswc=$(find "${workshopmodsdir}" | wc -l)
# Total uppercase files and directories for the mod, to output to the user
filesupperwc=$(find "${workshopmodsdir}/" -name '*[[:upper:]]*' | wc -l)
fn_script_log_info "Found ${filesupperwc} uppercase files out of ${fileswc}, converting"
echo -en "Found ${filesupperwc} uppercase files out of ${fileswc}, converting..."
#
# Coudln't get this to work on WSL. Needs to be verified on an acutal linux server.
#
# Convert files and directories starting from the deepest to prevent issues (-depth argument)
while IFS= read -r -d '' src; do
# We have to convert only the last file from the path, otherwise we will fail to convert anything if a parent dir has any uppercase
# therefore, we have to separate the end of the filename to only lowercase it rather than the whole line
# Gather parent dir, filename lowercase filename, and set lowercase destination name
latestparentdir=$(dirname "${src}")
latestfilelc=$(basename "${src}" | tr '[:upper:]' '[:lower:]')
dst="${latestparentdir}/${latestfilelc}"
# Only convert if destination does not already exist for some reason
if [ ! -e "${dst}" ]; then
# Finally we can rename the file
mv "${src}" "${dst}"
# Exit if it fails for any reason
local exitcode=$?
if [ "${exitcode}" != 0 ]; then
fn_print_fail_eol_nl
core_exit.sh
fi
fi
done < <(find "${workshopmodsdir}" -depth -name '*[[:upper:]]*' -print0)
fn_print_ok_eol_nl
fi
}
# # Copy the mod into serverfiles.
fn_workshop_copy_destination() {
local modid="$1"
local modname="$(fn_workshop_get_mod_name ${modid})"
if fn_workshop_is_mod_copy_needed ${modid}; then
echo "Copying mod ${modname} (${modid})"
# If workshop mod exists in installation folder, delete it for clean install
if [ -d "${workshopmodsdir}/${modid}" ]; then
rm -rf "${workshopmodsdir}/${modid}"
fi
modsrc="${workshopmodsdldir}/steamapps/workshop/content/${gameappid}/${modid}"
cp -fa ${modsrc} ${workshopmodsdir}
if [ "${engine}" == "realvirtuality" ]; then
modkey="${workshopmodsdldir}/steamapps/workshop/content/${gameappid}/${modid}/keys"
if ! [ -d "${modkey}" ]; then
modkey="$steamcmd/steamapps/workshop/content/${gameappid}/${modid}/Keys"
fi
if ! [ -d "${modkey}" ]; then
modkey="$steamcmd/steamapps/workshop/content/${gameappid}/${modid}/key"
fi
if ! [ -d "${modkey}" ]; then
modkey="$steamcmd/steamapps/workshop/content/${gameappid}/${modid}/Key"
fi
if ! [ -d "${modkey}" ]; then
echo "Mod ${modname} seems to be missing key folder. Tring to copy key from the main folder."
cp -fa "${workshopmodsdir}/${modid}/*.bikey" ${keysdir}
else
cp -fa ${modkey}/*.bikey ${keysdir}
fi
fi
else
echo "Mod ${modname} is already in mods folder."
fi
}
# ## Directory management.
# Create mods files and directories if it doesn't exist.
fn_create_workshop_dir() {
# Create lgsm data modsdir.
if [ ! -d "${workshopmodsdldir}" ]; then
echo -en "creating LinuxGSM Steam Workshop data directory ${workshopmodsdldir}..."
mkdir -p "${workshopmodsdldir}"
exitcode=$?
if [ "${exitcode}" != 0 ]; then
fn_print_fail_eol_nl
fn_script_log_fatal "Creating mod download dir ${workshopmodsdldir}"
core_exit.sh
else
fn_print_ok_eol_nl
fn_script_log_pass "Creating mod download dir ${workshopmodsdldir}"
fi
fi
# Create mod install directory.
if [ ! -d "${workshopmodsdir}" ]; then
echo -en "creating Steam Workshop install directory ${workshopmodsdir}..."
mkdir -p "${workshopmodsdir}"
exitcode=$?
if [ "${exitcode}" != 0 ]; then
fn_print_fail_eol_nl
fn_script_log_fatal "Creating mod install directory ${workshopmodsdir}"
core_exit.sh
else
fn_print_ok_eol_nl
fn_script_log_pass "Creating mod install directory ${workshopmodsdir}"
fi
fi
}
# Counts how many mods were installed.
fn_workshop_count_installed() {
if [ -f "${workshopmodsdir}" ]; then
installedworkshopmodscount=$(ls -l "${workshopmodsdir}" | grep -c ^d)
else
installedworkshopmodscount=0
fi
}
# Exits if no mods were installed.
fn_workshop_check_installed() {
# Count installed mods.
fn_workshop_count_installed
# If no mods are found.
if [ ${installedworkshopmodscount}/* -eq 0 ]; then
echo -e ""
fn_print_failure_nl "No installed workshop mods or addons were found"
echo -e " * Install mods using LinuxGSM first with: ./${selfname} workshop-install"
fn_script_log_error "No installed workshop mods or addons were found."
core_exit.sh
fi
}
# Builds list of installed Steam Workshop mods.
fn_workshop_installed_list() {
fn_workshop_count_installed
for folder in ${workshopmodsdir}/*; do
# If it is a folder, then use it's name as Steam Workshop Mod Id
if [ -d "${folder}" ]; then
echo -e "$(fn_workshop_get_mod_name $(basename ${f})) ($(basename ${f}))"
fi
done
if [ "${installedworkshopmodscount}" ]; then
fn_script_log_info "${installedworkshopmodscount} addons/mods are currently installed"
fi
}
Loading…
Cancel
Save