From 3dc76a2434c1d980ddf5bccacc2f9f5938690c62 Mon Sep 17 00:00:00 2001 From: FliesWithWind Date: Sun, 12 Mar 2023 19:48:52 +0100 Subject: [PATCH 1/9] Initial Steam Workshop code --- .../config-lgsm/arma3server/_default.cfg | 7 + lgsm/functions/command_workshop_install.sh | 137 ++++++ lgsm/functions/command_workshop_update.sh | 149 +++++++ lgsm/functions/core_functions.sh | 22 + lgsm/functions/core_getopt.sh | 11 +- lgsm/functions/workshop_core.sh | 398 ++++++++++++++++++ 6 files changed, 723 insertions(+), 1 deletion(-) create mode 100644 lgsm/functions/command_workshop_install.sh create mode 100644 lgsm/functions/command_workshop_update.sh create mode 100644 lgsm/functions/workshop_core.sh diff --git a/lgsm/config-default/config-lgsm/arma3server/_default.cfg b/lgsm/config-default/config-lgsm/arma3server/_default.cfg index 7c4619c17f..50fcee6dc1 100644 --- a/lgsm/config-default/config-lgsm/arma3server/_default.cfg +++ b/lgsm/config-default/config-lgsm/arma3server/_default.cfg @@ -27,6 +27,11 @@ mods="" ## Server-side Mods servermods="" +## Mods to be downloaded from Steam Workshop +# Use workshop ids +# workshopmods="450814997;2131302796" +workshopmods="450814997;2131302796" + ## Path to BattlEye # Leave empty for default bepath="" @@ -134,6 +139,8 @@ sleeptime="0.5" # Server appid appid="233780" steamcmdforcewindows="no" +# Game appid +gameappid="107410" # SteamCMD Branch | https://docs.linuxgsm.com/steamcmd/branch branch="" betapassword="" diff --git a/lgsm/functions/command_workshop_install.sh b/lgsm/functions/command_workshop_install.sh new file mode 100644 index 0000000000..48449b24fe --- /dev/null +++ b/lgsm/functions/command_workshop_install.sh @@ -0,0 +1,137 @@ +#!/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_workshop_download "450814997" + +# # Displays a list of installed mods. +# fn_mods_installed_list +# if [ "${installedmodscount}" -gt "0" ]; then +# echo -e "Installed addons/mods" +# echo -e "=================================" +# # Go through all available commands, get details and display them to the user. +# for ((llindex = 0; llindex < ${#installedmodslist[@]}; llindex++)); do +# # Current mod is the "llindex" value of the array we're going through. +# currentmod="${installedmodslist[llindex]}" +# fn_mod_get_info +# # Display mod info to the user. +# echo -e " * ${green}${modcommand}${default}${default}" +# done +# echo -e "" +# fi + +# echo -e "Available addons/mods" +# echo -e "=================================" +# # Display available mods from mods_list.sh. +# # Set and reset vars +# compatiblemodslistindex=0 +# # As long as we're within index values. +# while [ "${compatiblemodslistindex}" -lt "${#compatiblemodslist[@]}" ]; do +# # Set values for convenience. +# displayedmodname="${compatiblemodslist[compatiblemodslistindex]}" +# displayedmodcommand="${compatiblemodslist[compatiblemodslistindex + 1]}" +# displayedmodsite="${compatiblemodslist[compatiblemodslistindex + 2]}" +# displayedmoddescription="${compatiblemodslist[compatiblemodslistindex + 3]}" +# # Output mods to the user. +# echo -e "${displayedmodname} - ${displayedmoddescription} - ${displayedmodsite}" +# echo -e " * ${cyan}${displayedmodcommand}${default}" +# # Increment index from the amount of values we just displayed. +# let "compatiblemodslistindex+=4" +# ((totalmodsavailable++)) +# done + +# # If no mods are available for a specific game. +# if [ -z "${compatiblemodslist}" ]; then +# fn_print_fail_nl "No mods are currently available for ${gamename}." +# fn_script_log_info "No mods are currently available for ${gamename}." +# core_exit.sh +# fi +# fn_script_log_info "${totalmodsavailable} addons/mods are available for install" + +# ## User selects a mod. +# echo -e "" +# while [[ ! " ${availablemodscommands[@]} " =~ " ${usermodselect} " ]]; do +# echo -en "Enter an ${cyan}addon/mod${default} to ${green}install${default} (or exit to abort): " +# read -r usermodselect +# # Exit if user says exit or abort. +# if [ "${usermodselect}" == "exit" ] || [ "${usermodselect}" == "abort" ]; then +# core_exit.sh +# # Supplementary output upon invalid user input. +# elif [[ ! " ${availablemodscommands[@]} " =~ " ${usermodselect} " ]]; then +# fn_print_error2_nl "${usermodselect} is not a valid addon/mod." +# fi +# done +# # Get mod info. +# currentmod="${usermodselect}" +# fn_mod_get_info + +# echo -e "" +# echo -e "Installing ${modprettyname}" +# echo -e "=================================" +# fn_script_log_info "${modprettyname} selected for install" + +# # Check if the mod is already installed and warn the user. +# if [ -f "${modsinstalledlistfullpath}" ]; then +# if [ "$(sed -n "/^${modcommand}$/p" "${modsinstalledlistfullpath}")" ]; then +# fn_print_warning_nl "${modprettyname} is already installed" +# fn_script_log_warn "${modprettyname} 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 +# fi + +# ## Installation. +# # If amxmodx check if metamod exists first +# if [ "${modcommand}" == "amxmodx" ]; then +# fn_mod_exist "metamod" +# fi + +# if [ "${modcommand}" == "amxmodxcs" ] \ +# || [ "${modcommand}" == "amxmodxdod" ] \ +# || [ "${modcommand}" == "amxmodxtfc" ] \ +# || [ "${modcommand}" == "amxmodxns" ] \ +# || [ "${modcommand}" == "amxmodxts" ]; then +# fn_mod_exist "amxmodx" +# fi + +# fn_create_mods_dir +# fn_mods_clear_tmp_dir +# fn_mods_create_tmp_dir +# fn_mod_install_files +# fn_mod_lowercase +# fn_mod_create_filelist +# fn_mod_copy_destination +# fn_mod_add_list +# fn_mod_tidy_files_list +# fn_mods_clear_tmp_dir + +# # Create/modify existing liblist.gam file for Metamod +# if [ "${modcommand}" == "metamod" ]; then +# fn_mod_install_liblist_gam_file +# fi + +# # Create/modify plugins.ini file for Metamod +# if [ "${modcommand}" == "amxmodx" ]; then +# fn_mod_install_amxmodx_file +# fi + +# echo -e "${modprettyname} installed" +# fn_script_log_pass "${modprettyname} installed." + +core_exit.sh diff --git a/lgsm/functions/command_workshop_update.sh b/lgsm/functions/command_workshop_update.sh new file mode 100644 index 0000000000..a0b409eda9 --- /dev/null +++ b/lgsm/functions/command_workshop_update.sh @@ -0,0 +1,149 @@ +#!/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_workshop_get_list + +for modid in "${workshoplist[@]}"; do + modname="$(fn_workshop_get_mod_name $modid)" + if fn_workshop_check_mod_update $modid; then + echo "Mod ${modname} is not up to date." + fn_workshop_download $modid + else + echo "Mod $modname is up to date." + fi +done + +#fn_workshop_download "450814997" + +# # Displays a list of installed mods. +# fn_mods_installed_list +# if [ "${installedmodscount}" -gt "0" ]; then +# echo -e "Installed addons/mods" +# echo -e "=================================" +# # Go through all available commands, get details and display them to the user. +# for ((llindex = 0; llindex < ${#installedmodslist[@]}; llindex++)); do +# # Current mod is the "llindex" value of the array we're going through. +# currentmod="${installedmodslist[llindex]}" +# fn_mod_get_info +# # Display mod info to the user. +# echo -e " * ${green}${modcommand}${default}${default}" +# done +# echo -e "" +# fi + +# echo -e "Available addons/mods" +# echo -e "=================================" +# # Display available mods from mods_list.sh. +# # Set and reset vars +# compatiblemodslistindex=0 +# # As long as we're within index values. +# while [ "${compatiblemodslistindex}" -lt "${#compatiblemodslist[@]}" ]; do +# # Set values for convenience. +# displayedmodname="${compatiblemodslist[compatiblemodslistindex]}" +# displayedmodcommand="${compatiblemodslist[compatiblemodslistindex + 1]}" +# displayedmodsite="${compatiblemodslist[compatiblemodslistindex + 2]}" +# displayedmoddescription="${compatiblemodslist[compatiblemodslistindex + 3]}" +# # Output mods to the user. +# echo -e "${displayedmodname} - ${displayedmoddescription} - ${displayedmodsite}" +# echo -e " * ${cyan}${displayedmodcommand}${default}" +# # Increment index from the amount of values we just displayed. +# let "compatiblemodslistindex+=4" +# ((totalmodsavailable++)) +# done + +# # If no mods are available for a specific game. +# if [ -z "${compatiblemodslist}" ]; then +# fn_print_fail_nl "No mods are currently available for ${gamename}." +# fn_script_log_info "No mods are currently available for ${gamename}." +# core_exit.sh +# fi +# fn_script_log_info "${totalmodsavailable} addons/mods are available for install" + +# ## User selects a mod. +# echo -e "" +# while [[ ! " ${availablemodscommands[@]} " =~ " ${usermodselect} " ]]; do +# echo -en "Enter an ${cyan}addon/mod${default} to ${green}install${default} (or exit to abort): " +# read -r usermodselect +# # Exit if user says exit or abort. +# if [ "${usermodselect}" == "exit" ] || [ "${usermodselect}" == "abort" ]; then +# core_exit.sh +# # Supplementary output upon invalid user input. +# elif [[ ! " ${availablemodscommands[@]} " =~ " ${usermodselect} " ]]; then +# fn_print_error2_nl "${usermodselect} is not a valid addon/mod." +# fi +# done +# # Get mod info. +# currentmod="${usermodselect}" +# fn_mod_get_info + +# echo -e "" +# echo -e "Installing ${modprettyname}" +# echo -e "=================================" +# fn_script_log_info "${modprettyname} selected for install" + +# # Check if the mod is already installed and warn the user. +# if [ -f "${modsinstalledlistfullpath}" ]; then +# if [ "$(sed -n "/^${modcommand}$/p" "${modsinstalledlistfullpath}")" ]; then +# fn_print_warning_nl "${modprettyname} is already installed" +# fn_script_log_warn "${modprettyname} 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 +# fi + +# ## Installation. +# # If amxmodx check if metamod exists first +# if [ "${modcommand}" == "amxmodx" ]; then +# fn_mod_exist "metamod" +# fi + +# if [ "${modcommand}" == "amxmodxcs" ] \ +# || [ "${modcommand}" == "amxmodxdod" ] \ +# || [ "${modcommand}" == "amxmodxtfc" ] \ +# || [ "${modcommand}" == "amxmodxns" ] \ +# || [ "${modcommand}" == "amxmodxts" ]; then +# fn_mod_exist "amxmodx" +# fi + +# fn_create_mods_dir +# fn_mods_clear_tmp_dir +# fn_mods_create_tmp_dir +# fn_mod_install_files +# fn_mod_lowercase +# fn_mod_create_filelist +# fn_mod_copy_destination +# fn_mod_add_list +# fn_mod_tidy_files_list +# fn_mods_clear_tmp_dir + +# # Create/modify existing liblist.gam file for Metamod +# if [ "${modcommand}" == "metamod" ]; then +# fn_mod_install_liblist_gam_file +# fi + +# # Create/modify plugins.ini file for Metamod +# if [ "${modcommand}" == "amxmodx" ]; then +# fn_mod_install_amxmodx_file +# fi + +# echo -e "${modprettyname} installed" +# fn_script_log_pass "${modprettyname} installed." + +core_exit.sh diff --git a/lgsm/functions/core_functions.sh b/lgsm/functions/core_functions.sh index 05b52e243a..fada688c73 100755 --- a/lgsm/functions/core_functions.sh +++ b/lgsm/functions/core_functions.sh @@ -151,6 +151,21 @@ command_mods_remove.sh() { 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() { functionfile="${FUNCNAME[0]}" fn_fetch_function @@ -287,6 +302,13 @@ mods_core.sh() { fn_fetch_function } +# Steam Workshop + +workshop_core.sh() { + functionfile="${FUNCNAME[0]}" + fn_fetch_function +} + # Dev command_dev_clear_functions.sh() { diff --git a/lgsm/functions/core_getopt.sh b/lgsm/functions/core_getopt.sh index fdd66ab3f5..6064942c18 100755 --- a/lgsm/functions/core_getopt.sh +++ b/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_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.") +# 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. 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.") @@ -133,10 +137,15 @@ 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}" == "rust" ] || [ "${shortname}" == "hq" ] || [ "${shortname}" == "sdtd" ] || [ "${shortname}" == "cs" ] || [ "${shortname}" == "dod" ] || [ "${shortname}" == "tfc" ] || [ "${shortname}" == "ns" ] || [ "${shortname}" == "ts" ] || [ "${shortname}" == "hldm" ] || [ "${shortname}" == "vh" ] || [ "${shortname}" == "realvirtuality" ]; then currentopt+=("${cmd_mods_install[@]}" "${cmd_mods_remove[@]}" "${cmd_mods_update[@]}") fi +## Workshop commands. +if [ "${engine}" == "realvirtuality" ]; then + currentopt+=("${cmd_workshop_install[@]}" "${cmd_workshop_remove[@]}" "${cmd_workshop_update[@]}") +fi + ## Installer. currentopt+=("${cmd_install[@]}" "${cmd_auto_install[@]}") diff --git a/lgsm/functions/workshop_core.sh b/lgsm/functions/workshop_core.sh new file mode 100644 index 0000000000..0ccc7c4907 --- /dev/null +++ b/lgsm/functions/workshop_core.sh @@ -0,0 +1,398 @@ +#!/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" +workhshopmodsdir="${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 + + # if [ -f "${workshopmodsrcdir}/meta.cpp" ]; then + # echo "Mod $modid downloaded" + # modsrcdirs[$modid]="$modsrcdir" + # return 0 + # else + # echo "Mod $modid was not successfully downloaded" + # return 1 + # fi +} + +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_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 "${workhshopmodsdir}/${modid}/meta.cpp" ]; then return 0; fi + local instmft="$(grep "timestamp" ${workhshopmodsdir}/${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" + #echo "$(grep -Po '(?<=name = ").+?(?=")' ${workshopmodsdir}/steamapps/workshop/content/${gameappid}/${modid}/mod.cpp)" + echo "$(grep -Po '(?<=name = ").+?(?=")' ${workshopmodsdldir}/steamapps/workshop/content/${gameappid}/${modid}/mod.cpp)" +} + +# Convert workshop mod files to lowercase if needed. +fn_workshop_lowercase() { + local modid="$1" + # Arma 3 requires lowercase + if [ "${engine}" == "realvirtuality" ]; then + echo -en "converting ${modprettyname} files to lowercase..." + fn_sleep_time + fn_script_log_info "Converting ${modprettyname} files to lowercase" + # Total files and directories for the mod, to output to the user + fileswc=$(find "${extractdir}" | wc -l) + # Total uppercase files and directories for the mod, to output to the user + filesupperwc=$(find "${extractdir}" -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..." + # Convert files and directories starting from the deepest to prevent issues (-depth argument) + while read -r 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 "${extractdir}" -depth -name '*[[:upper:]]*') + fn_print_ok_eol_nl + fi +} + +# # Copy the mod into serverfiles. +# fn_mod_copy_destination() { +# echo -en "copying ${modprettyname} to ${modinstalldir}..." +# fn_sleep_time +# cp -Rf "${extractdir}/." "${modinstalldir}/" +# local exitcode=$? +# if [ "${exitcode}" != 0 ]; then +# fn_print_fail_eol_nl +# fn_script_log_fatal "Copying ${modprettyname} to ${modinstalldir}" +# else +# fn_print_ok_eol_nl +# fn_script_log_pass "Copying ${modprettyname} to ${modinstalldir}" +# fi +# } + +# ## Information Gathering. + +# # Get details of a mod any (relevant and unique, such as full mod name or install command) value. +# fn_mod_get_info() { +# # Variable to know when job is done. +# modinfocommand="0" +# # Find entry in global array. +# for ((index = 0; index <= ${#mods_global_array[@]}; index++)); do +# # When entry is found. +# if [ "${mods_global_array[index]}" == "${currentmod}" ]; then +# # Go back to the previous "MOD" separator. +# for ((index = index; index <= ${#mods_global_array[@]}; index--)); do +# # When "MOD" is found. +# if [ "${mods_global_array[index]}" == "MOD" ]; then +# # Get info. +# fn_mods_define +# modinfocommand="1" +# break +# fi +# done +# fi +# # Exit the loop if job is done. +# if [ "${modinfocommand}" == "1" ]; then +# break +# fi +# done + +# # What happens if mod is not found. +# if [ "${modinfocommand}" == "0" ]; then +# fn_script_log_error "Could not find information for ${currentmod}" +# fn_print_error_nl "Could not find information for ${currentmod}" +# core_exit.sh +# fi +# } + +# # Builds list of installed mods. +# # using installed-mods.txt grabing mod info from mods_list.sh. +# fn_mods_installed_list() { +# fn_mods_count_installed +# # Set/reset variables. +# installedmodsline="1" +# installedmodslist=() +# modprettynamemaxlength="0" +# modsitemaxlength="0" +# moddescriptionmaxlength="0" +# modcommandmaxlength="0" +# # Loop through every line of the installed mods list ${modsinstalledlistfullpath}. +# while [ "${installedmodsline}" -le "${installedmodscount}" ]; do +# currentmod=$(sed "${installedmodsline}q;d" "${modsinstalledlistfullpath}") +# # Get mod info to make sure mod exists. +# fn_mod_get_info +# # Add the mod to available commands. +# installedmodslist+=("${modcommand}") +# # Increment line check. +# ((installedmodsline++)) +# done +# if [ "${installedmodscount}" ]; then +# fn_script_log_info "${installedmodscount} addons/mods are currently installed" +# 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 "${workhshopmodsdir}" ]; then + echo -en "creating Steam Workshop install directory ${workhshopmodsdir}..." + mkdir -p "${workhshopmodsdir}" + exitcode=$? + if [ "${exitcode}" != 0 ]; then + fn_print_fail_eol_nl + fn_script_log_fatal "Creating mod install directory ${workhshopmodsdir}" + core_exit.sh + else + fn_print_ok_eol_nl + fn_script_log_pass "Creating mod install directory ${workhshopmodsdir}" + fi + fi +} + +# # Create tmp download mod directory. +# fn_mods_create_tmp_dir() { +# if [ ! -d "${modstmpdir}" ]; then +# mkdir -p "${modstmpdir}" +# exitcode=$? +# echo -en "creating mod download directory ${modstmpdir}..." +# if [ "${exitcode}" != 0 ]; then +# fn_print_fail_eol_nl +# fn_script_log_fatal "Creating mod download directory ${modstmpdir}" +# core_exit.sh +# else +# fn_print_ok_eol_nl +# fn_script_log_pass "Creating mod download directory ${modstmpdir}" +# fi +# fi +# } + +# # Remove the tmp mod download directory when finished. +# fn_mods_clear_tmp_dir() { +# if [ -d "${modstmpdir}" ]; then +# echo -en "clearing mod download directory ${modstmpdir}..." +# rm -fr "${modstmpdir:?}" +# exitcode=$? +# if [ "${exitcode}" != 0 ]; then +# fn_print_fail_eol_nl +# fn_script_log_fatal "Clearing mod download directory ${modstmpdir}" +# core_exit.sh +# else +# fn_print_ok_eol_nl +# fn_script_log_pass "Clearing mod download directory ${modstmpdir}" +# fi + +# fi +# # Clear temp file list as well. +# if [ -f "${modsdir}/.removedfiles.tmp" ]; then +# rm -f "${modsdir:?}/.removedfiles.tmp" +# fi +# } + +# Counts how many mods were installed. +fn_workshop_count_installed() { + if [ -f "${workhshopmodsdir}" ]; then + installedmodscount=$(ls -l "${workhshopmodsdir}" | grep -c ^d) + else + installedmodscount=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 [ ${installedmodscount} -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 +} + +# fn_mod_exist() { +# modreq=$1 +# # requires one parameter, the mod +# if [ -f "${modsdir}/${modreq}-files.txt" ]; then +# # how many lines is the file list +# modsfilelistsize=$(wc -l < "${modsdir}/${modreq}-files.txt") +# # if file list is empty +# if [ "${modsfilelistsize}" -eq 0 ]; then +# fn_mod_required_fail_exist "${modreq}" +# fi +# else +# fn_mod_required_fail_exist "${modreq}" +# fi +# } + +# fn_mod_required_fail_exist() { +# modreq=$1 +# # requires one parameter, the mod +# fn_script_log_fatal "${modreq}-files.txt is empty: unable to find ${modreq} installed" +# echo -en "* Unable to find '${modreq}' which is required prior to installing this mod..." +# fn_print_fail_eol_nl +# core_exit.sh +# } + +# ## Database initialisation. + +# mods_list.sh +# fn_mods_available From 00baf3e711aa69c385700d9eba2c01b32016f608 Mon Sep 17 00:00:00 2001 From: FliesWithWind Date: Mon, 13 Mar 2023 11:12:38 +0100 Subject: [PATCH 2/9] Fixies & cleanup --- .../config-lgsm/arma3server/_default.cfg | 2 +- lgsm/functions/command_workshop_install.sh | 149 ++------ lgsm/functions/command_workshop_update.sh | 135 +------ lgsm/functions/workshop_core.sh | 329 +++++++----------- 4 files changed, 176 insertions(+), 439 deletions(-) diff --git a/lgsm/config-default/config-lgsm/arma3server/_default.cfg b/lgsm/config-default/config-lgsm/arma3server/_default.cfg index 50fcee6dc1..8723ef79d3 100644 --- a/lgsm/config-default/config-lgsm/arma3server/_default.cfg +++ b/lgsm/config-default/config-lgsm/arma3server/_default.cfg @@ -30,7 +30,7 @@ servermods="" ## Mods to be downloaded from Steam Workshop # Use workshop ids # workshopmods="450814997;2131302796" -workshopmods="450814997;2131302796" +workshopmods="" ## Path to BattlEye # Leave empty for default diff --git a/lgsm/functions/command_workshop_install.sh b/lgsm/functions/command_workshop_install.sh index 48449b24fe..ba2025afda 100644 --- a/lgsm/functions/command_workshop_install.sh +++ b/lgsm/functions/command_workshop_install.sh @@ -14,124 +14,33 @@ check.sh workshop_core.sh fn_print_header - -fn_workshop_download "450814997" - -# # Displays a list of installed mods. -# fn_mods_installed_list -# if [ "${installedmodscount}" -gt "0" ]; then -# echo -e "Installed addons/mods" -# echo -e "=================================" -# # Go through all available commands, get details and display them to the user. -# for ((llindex = 0; llindex < ${#installedmodslist[@]}; llindex++)); do -# # Current mod is the "llindex" value of the array we're going through. -# currentmod="${installedmodslist[llindex]}" -# fn_mod_get_info -# # Display mod info to the user. -# echo -e " * ${green}${modcommand}${default}${default}" -# done -# echo -e "" -# fi - -# echo -e "Available addons/mods" -# echo -e "=================================" -# # Display available mods from mods_list.sh. -# # Set and reset vars -# compatiblemodslistindex=0 -# # As long as we're within index values. -# while [ "${compatiblemodslistindex}" -lt "${#compatiblemodslist[@]}" ]; do -# # Set values for convenience. -# displayedmodname="${compatiblemodslist[compatiblemodslistindex]}" -# displayedmodcommand="${compatiblemodslist[compatiblemodslistindex + 1]}" -# displayedmodsite="${compatiblemodslist[compatiblemodslistindex + 2]}" -# displayedmoddescription="${compatiblemodslist[compatiblemodslistindex + 3]}" -# # Output mods to the user. -# echo -e "${displayedmodname} - ${displayedmoddescription} - ${displayedmodsite}" -# echo -e " * ${cyan}${displayedmodcommand}${default}" -# # Increment index from the amount of values we just displayed. -# let "compatiblemodslistindex+=4" -# ((totalmodsavailable++)) -# done - -# # If no mods are available for a specific game. -# if [ -z "${compatiblemodslist}" ]; then -# fn_print_fail_nl "No mods are currently available for ${gamename}." -# fn_script_log_info "No mods are currently available for ${gamename}." -# core_exit.sh -# fi -# fn_script_log_info "${totalmodsavailable} addons/mods are available for install" - -# ## User selects a mod. -# echo -e "" -# while [[ ! " ${availablemodscommands[@]} " =~ " ${usermodselect} " ]]; do -# echo -en "Enter an ${cyan}addon/mod${default} to ${green}install${default} (or exit to abort): " -# read -r usermodselect -# # Exit if user says exit or abort. -# if [ "${usermodselect}" == "exit" ] || [ "${usermodselect}" == "abort" ]; then -# core_exit.sh -# # Supplementary output upon invalid user input. -# elif [[ ! " ${availablemodscommands[@]} " =~ " ${usermodselect} " ]]; then -# fn_print_error2_nl "${usermodselect} is not a valid addon/mod." -# fi -# done -# # Get mod info. -# currentmod="${usermodselect}" -# fn_mod_get_info - -# echo -e "" -# echo -e "Installing ${modprettyname}" -# echo -e "=================================" -# fn_script_log_info "${modprettyname} selected for install" - -# # Check if the mod is already installed and warn the user. -# if [ -f "${modsinstalledlistfullpath}" ]; then -# if [ "$(sed -n "/^${modcommand}$/p" "${modsinstalledlistfullpath}")" ]; then -# fn_print_warning_nl "${modprettyname} is already installed" -# fn_script_log_warn "${modprettyname} 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 -# fi - -# ## Installation. -# # If amxmodx check if metamod exists first -# if [ "${modcommand}" == "amxmodx" ]; then -# fn_mod_exist "metamod" -# fi - -# if [ "${modcommand}" == "amxmodxcs" ] \ -# || [ "${modcommand}" == "amxmodxdod" ] \ -# || [ "${modcommand}" == "amxmodxtfc" ] \ -# || [ "${modcommand}" == "amxmodxns" ] \ -# || [ "${modcommand}" == "amxmodxts" ]; then -# fn_mod_exist "amxmodx" -# fi - -# fn_create_mods_dir -# fn_mods_clear_tmp_dir -# fn_mods_create_tmp_dir -# fn_mod_install_files -# fn_mod_lowercase -# fn_mod_create_filelist -# fn_mod_copy_destination -# fn_mod_add_list -# fn_mod_tidy_files_list -# fn_mods_clear_tmp_dir - -# # Create/modify existing liblist.gam file for Metamod -# if [ "${modcommand}" == "metamod" ]; then -# fn_mod_install_liblist_gam_file -# fi - -# # Create/modify plugins.ini file for Metamod -# if [ "${modcommand}" == "amxmodx" ]; then -# fn_mod_install_amxmodx_file -# fi - -# echo -e "${modprettyname} installed" -# fn_script_log_pass "${modprettyname} installed." - +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 +done + +fn_workshop_lowercase core_exit.sh diff --git a/lgsm/functions/command_workshop_update.sh b/lgsm/functions/command_workshop_update.sh index a0b409eda9..489411e8de 100644 --- a/lgsm/functions/command_workshop_update.sh +++ b/lgsm/functions/command_workshop_update.sh @@ -12,138 +12,25 @@ 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} is not up to date." + echo "Mod ${modname} (${modid}) is not up to date." fn_workshop_download $modid - else + fn_workshop_copy_destination $modid + else echo "Mod $modname is up to date." - fi + fi done -#fn_workshop_download "450814997" - -# # Displays a list of installed mods. -# fn_mods_installed_list -# if [ "${installedmodscount}" -gt "0" ]; then -# echo -e "Installed addons/mods" -# echo -e "=================================" -# # Go through all available commands, get details and display them to the user. -# for ((llindex = 0; llindex < ${#installedmodslist[@]}; llindex++)); do -# # Current mod is the "llindex" value of the array we're going through. -# currentmod="${installedmodslist[llindex]}" -# fn_mod_get_info -# # Display mod info to the user. -# echo -e " * ${green}${modcommand}${default}${default}" -# done -# echo -e "" -# fi - -# echo -e "Available addons/mods" -# echo -e "=================================" -# # Display available mods from mods_list.sh. -# # Set and reset vars -# compatiblemodslistindex=0 -# # As long as we're within index values. -# while [ "${compatiblemodslistindex}" -lt "${#compatiblemodslist[@]}" ]; do -# # Set values for convenience. -# displayedmodname="${compatiblemodslist[compatiblemodslistindex]}" -# displayedmodcommand="${compatiblemodslist[compatiblemodslistindex + 1]}" -# displayedmodsite="${compatiblemodslist[compatiblemodslistindex + 2]}" -# displayedmoddescription="${compatiblemodslist[compatiblemodslistindex + 3]}" -# # Output mods to the user. -# echo -e "${displayedmodname} - ${displayedmoddescription} - ${displayedmodsite}" -# echo -e " * ${cyan}${displayedmodcommand}${default}" -# # Increment index from the amount of values we just displayed. -# let "compatiblemodslistindex+=4" -# ((totalmodsavailable++)) -# done - -# # If no mods are available for a specific game. -# if [ -z "${compatiblemodslist}" ]; then -# fn_print_fail_nl "No mods are currently available for ${gamename}." -# fn_script_log_info "No mods are currently available for ${gamename}." -# core_exit.sh -# fi -# fn_script_log_info "${totalmodsavailable} addons/mods are available for install" - -# ## User selects a mod. -# echo -e "" -# while [[ ! " ${availablemodscommands[@]} " =~ " ${usermodselect} " ]]; do -# echo -en "Enter an ${cyan}addon/mod${default} to ${green}install${default} (or exit to abort): " -# read -r usermodselect -# # Exit if user says exit or abort. -# if [ "${usermodselect}" == "exit" ] || [ "${usermodselect}" == "abort" ]; then -# core_exit.sh -# # Supplementary output upon invalid user input. -# elif [[ ! " ${availablemodscommands[@]} " =~ " ${usermodselect} " ]]; then -# fn_print_error2_nl "${usermodselect} is not a valid addon/mod." -# fi -# done -# # Get mod info. -# currentmod="${usermodselect}" -# fn_mod_get_info - -# echo -e "" -# echo -e "Installing ${modprettyname}" -# echo -e "=================================" -# fn_script_log_info "${modprettyname} selected for install" - -# # Check if the mod is already installed and warn the user. -# if [ -f "${modsinstalledlistfullpath}" ]; then -# if [ "$(sed -n "/^${modcommand}$/p" "${modsinstalledlistfullpath}")" ]; then -# fn_print_warning_nl "${modprettyname} is already installed" -# fn_script_log_warn "${modprettyname} 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 -# fi - -# ## Installation. -# # If amxmodx check if metamod exists first -# if [ "${modcommand}" == "amxmodx" ]; then -# fn_mod_exist "metamod" -# fi - -# if [ "${modcommand}" == "amxmodxcs" ] \ -# || [ "${modcommand}" == "amxmodxdod" ] \ -# || [ "${modcommand}" == "amxmodxtfc" ] \ -# || [ "${modcommand}" == "amxmodxns" ] \ -# || [ "${modcommand}" == "amxmodxts" ]; then -# fn_mod_exist "amxmodx" -# fi - -# fn_create_mods_dir -# fn_mods_clear_tmp_dir -# fn_mods_create_tmp_dir -# fn_mod_install_files -# fn_mod_lowercase -# fn_mod_create_filelist -# fn_mod_copy_destination -# fn_mod_add_list -# fn_mod_tidy_files_list -# fn_mods_clear_tmp_dir - -# # Create/modify existing liblist.gam file for Metamod -# if [ "${modcommand}" == "metamod" ]; then -# fn_mod_install_liblist_gam_file -# fi - -# # Create/modify plugins.ini file for Metamod -# if [ "${modcommand}" == "amxmodx" ]; then -# fn_mod_install_amxmodx_file -# fi - -# echo -e "${modprettyname} installed" -# fn_script_log_pass "${modprettyname} installed." - +fn_workshop_lowercase core_exit.sh diff --git a/lgsm/functions/workshop_core.sh b/lgsm/functions/workshop_core.sh index 0ccc7c4907..435d56b66f 100644 --- a/lgsm/functions/workshop_core.sh +++ b/lgsm/functions/workshop_core.sh @@ -9,7 +9,7 @@ functionselfname="$(basename "$(readlink -f "${BASH_SOURCE[0]}")")" # Files and Directories. steam="${steamcmd}/steam" -workhshopmodsdir="${serverfiles}/mods" +workshopmodsdir="${serverfiles}/mods" keysdir="${serverfiles}/keys" workshopmodsdldir="${lgsmdir}/workshop" workshopmodslist="workshop-mods.txt" @@ -101,15 +101,6 @@ fn_workshop_download() { core_exit.sh fi done - - # if [ -f "${workshopmodsrcdir}/meta.cpp" ]; then - # echo "Mod $modid downloaded" - # modsrcdirs[$modid]="$modsrcdir" - # return 0 - # else - # echo "Mod $modid was not successfully downloaded" - # return 1 - # fi } fn_workshop_get_list() { @@ -118,12 +109,22 @@ fn_workshop_get_list() { 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 '"' + 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() { @@ -141,8 +142,8 @@ fn_workshop_check_mod_update() { fn_workshop_is_mod_copy_needed(){ local modid="$1" local modsrc="${workshopmodsdldir}/steamapps/workshop/content/${gameappid}/${modid}" - if [ ! -f "${workhshopmodsdir}/${modid}/meta.cpp" ]; then return 0; fi - local instmft="$(grep "timestamp" ${workhshopmodsdir}/${modid}/meta.cpp)" + 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 @@ -154,123 +155,118 @@ fn_workshop_is_mod_copy_needed(){ fn_workshop_get_mod_name(){ local modid="$1" - #echo "$(grep -Po '(?<=name = ").+?(?=")' ${workshopmodsdir}/steamapps/workshop/content/${gameappid}/${modid}/mod.cpp)" - echo "$(grep -Po '(?<=name = ").+?(?=")' ${workshopmodsdldir}/steamapps/workshop/content/${gameappid}/${modid}/mod.cpp)" + 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 } # Convert workshop mod files to lowercase if needed. fn_workshop_lowercase() { - local modid="$1" + # local modid="$1" + # local modname="$(fn_workshop_get_mod_name $modid)" # Arma 3 requires lowercase if [ "${engine}" == "realvirtuality" ]; then - echo -en "converting ${modprettyname} files to lowercase..." + echo -en "Converting ${modname} files to lowercase..." fn_sleep_time - fn_script_log_info "Converting ${modprettyname} files to lowercase" + fn_script_log_info "Converting ${modname} files to lowercase" # Total files and directories for the mod, to output to the user - fileswc=$(find "${extractdir}" | wc -l) + fileswc=$(find "${workshopmodsdir}" | wc -l) # Total uppercase files and directories for the mod, to output to the user - filesupperwc=$(find "${extractdir}" -name '*[[:upper:]]*' | wc -l) + 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..." + # Works but not on folders + # while IFS= read -r -d '' file; do + # mv -b -- "$file" "${file,,}" 2>/dev/null + # done < <(find ${workshopmodsdir} -depth -name '*[A-Z]*' -print0) + # while IFS= read -r -d '' file; do + # mv -b -- "$file" "${file,,}" 2>/dev/null + # done < <(find ${workshopmodsdir}/ -depth -name '*[A-Z]*' -print0) + + # Works bu not on WSL? + # https://unix.stackexchange.com/questions/20222/change-entire-directory-tree-to-lower-case-names/20232#20232 + # + find ${workshopmodsdir} -depth -exec sh -c ' + t=${0%/*}/$(printf %s "${0##*/}" | tr "[:upper:]" "[:lower:]"); + [ "$t" = "$0" ] || mv -i "$0" "$t" + ' {} \; + + # + # Coudln't get this to work. + # # Convert files and directories starting from the deepest to prevent issues (-depth argument) - while read -r 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 "${extractdir}" -depth -name '*[[:upper:]]*') + # 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_mod_copy_destination() { -# echo -en "copying ${modprettyname} to ${modinstalldir}..." -# fn_sleep_time -# cp -Rf "${extractdir}/." "${modinstalldir}/" -# local exitcode=$? -# if [ "${exitcode}" != 0 ]; then -# fn_print_fail_eol_nl -# fn_script_log_fatal "Copying ${modprettyname} to ${modinstalldir}" -# else -# fn_print_ok_eol_nl -# fn_script_log_pass "Copying ${modprettyname} to ${modinstalldir}" -# fi -# } - -# ## Information Gathering. - -# # Get details of a mod any (relevant and unique, such as full mod name or install command) value. -# fn_mod_get_info() { -# # Variable to know when job is done. -# modinfocommand="0" -# # Find entry in global array. -# for ((index = 0; index <= ${#mods_global_array[@]}; index++)); do -# # When entry is found. -# if [ "${mods_global_array[index]}" == "${currentmod}" ]; then -# # Go back to the previous "MOD" separator. -# for ((index = index; index <= ${#mods_global_array[@]}; index--)); do -# # When "MOD" is found. -# if [ "${mods_global_array[index]}" == "MOD" ]; then -# # Get info. -# fn_mods_define -# modinfocommand="1" -# break -# fi -# done -# fi -# # Exit the loop if job is done. -# if [ "${modinfocommand}" == "1" ]; then -# break -# fi -# done - -# # What happens if mod is not found. -# if [ "${modinfocommand}" == "0" ]; then -# fn_script_log_error "Could not find information for ${currentmod}" -# fn_print_error_nl "Could not find information for ${currentmod}" -# core_exit.sh -# fi -# } - -# # Builds list of installed mods. -# # using installed-mods.txt grabing mod info from mods_list.sh. -# fn_mods_installed_list() { -# fn_mods_count_installed -# # Set/reset variables. -# installedmodsline="1" -# installedmodslist=() -# modprettynamemaxlength="0" -# modsitemaxlength="0" -# moddescriptionmaxlength="0" -# modcommandmaxlength="0" -# # Loop through every line of the installed mods list ${modsinstalledlistfullpath}. -# while [ "${installedmodsline}" -le "${installedmodscount}" ]; do -# currentmod=$(sed "${installedmodsline}q;d" "${modsinstalledlistfullpath}") -# # Get mod info to make sure mod exists. -# fn_mod_get_info -# # Add the mod to available commands. -# installedmodslist+=("${modcommand}") -# # Increment line check. -# ((installedmodsline++)) -# done -# if [ "${installedmodscount}" ]; then -# fn_script_log_info "${installedmodscount} addons/mods are currently installed" -# fi -# } +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 + # echo -en "copying ${modprettyname} to ${modinstalldir}..." + # fn_sleep_time + # cp -Rf "${extractdir}/." "${modinstalldir}/" + # local exitcode=$? + # if [ "${exitcode}" != 0 ]; then + # fn_print_fail_eol_nl + # fn_script_log_fatal "Copying ${modprettyname} to ${modinstalldir}" + # else + # fn_print_ok_eol_nl + # fn_script_log_pass "Copying ${modprettyname} to ${modinstalldir}" + # fi +} # ## Directory management. @@ -291,66 +287,27 @@ fn_create_workshop_dir() { fi fi # Create mod install directory. - if [ ! -d "${workhshopmodsdir}" ]; then - echo -en "creating Steam Workshop install directory ${workhshopmodsdir}..." - mkdir -p "${workhshopmodsdir}" + 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 ${workhshopmodsdir}" + 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 ${workhshopmodsdir}" + fn_script_log_pass "Creating mod install directory ${workshopmodsdir}" fi fi } -# # Create tmp download mod directory. -# fn_mods_create_tmp_dir() { -# if [ ! -d "${modstmpdir}" ]; then -# mkdir -p "${modstmpdir}" -# exitcode=$? -# echo -en "creating mod download directory ${modstmpdir}..." -# if [ "${exitcode}" != 0 ]; then -# fn_print_fail_eol_nl -# fn_script_log_fatal "Creating mod download directory ${modstmpdir}" -# core_exit.sh -# else -# fn_print_ok_eol_nl -# fn_script_log_pass "Creating mod download directory ${modstmpdir}" -# fi -# fi -# } - -# # Remove the tmp mod download directory when finished. -# fn_mods_clear_tmp_dir() { -# if [ -d "${modstmpdir}" ]; then -# echo -en "clearing mod download directory ${modstmpdir}..." -# rm -fr "${modstmpdir:?}" -# exitcode=$? -# if [ "${exitcode}" != 0 ]; then -# fn_print_fail_eol_nl -# fn_script_log_fatal "Clearing mod download directory ${modstmpdir}" -# core_exit.sh -# else -# fn_print_ok_eol_nl -# fn_script_log_pass "Clearing mod download directory ${modstmpdir}" -# fi - -# fi -# # Clear temp file list as well. -# if [ -f "${modsdir}/.removedfiles.tmp" ]; then -# rm -f "${modsdir:?}/.removedfiles.tmp" -# fi -# } - # Counts how many mods were installed. fn_workshop_count_installed() { - if [ -f "${workhshopmodsdir}" ]; then - installedmodscount=$(ls -l "${workhshopmodsdir}" | grep -c ^d) + if [ -f "${workshopmodsdir}" ]; then + installedworkshopmodscount=$(ls -l "${workshopmodsdir}" | grep -c ^d) else - installedmodscount=0 + installedworkshopmodscount=0 fi } @@ -359,7 +316,7 @@ fn_workshop_check_installed() { # Count installed mods. fn_workshop_count_installed # If no mods are found. - if [ ${installedmodscount} -eq 0 ]; then + 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" @@ -368,31 +325,15 @@ fn_workshop_check_installed() { fi } -# fn_mod_exist() { -# modreq=$1 -# # requires one parameter, the mod -# if [ -f "${modsdir}/${modreq}-files.txt" ]; then -# # how many lines is the file list -# modsfilelistsize=$(wc -l < "${modsdir}/${modreq}-files.txt") -# # if file list is empty -# if [ "${modsfilelistsize}" -eq 0 ]; then -# fn_mod_required_fail_exist "${modreq}" -# fi -# else -# fn_mod_required_fail_exist "${modreq}" -# fi -# } - -# fn_mod_required_fail_exist() { -# modreq=$1 -# # requires one parameter, the mod -# fn_script_log_fatal "${modreq}-files.txt is empty: unable to find ${modreq} installed" -# echo -en "* Unable to find '${modreq}' which is required prior to installing this mod..." -# fn_print_fail_eol_nl -# core_exit.sh -# } - -# ## Database initialisation. - -# mods_list.sh -# fn_mods_available +# Builds list of installed Steam Workshop mods. +fn_workshop_installed_list() { + fn_workshop_count_installed + for f in ${workshopmodsdir}/*; do + if [ -d "$f" ]; 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 +} From 053af83169d9df61fce851ddab2126db73f278d6 Mon Sep 17 00:00:00 2001 From: FliesWithWind <7544133+FliesWithWind@users.noreply.github.com> Date: Mon, 13 Mar 2023 13:26:59 +0100 Subject: [PATCH 3/9] Delete add-to-project.yml --- .github/workflows/add-to-project.yml | 17 ----------------- 1 file changed, 17 deletions(-) delete mode 100644 .github/workflows/add-to-project.yml diff --git a/.github/workflows/add-to-project.yml b/.github/workflows/add-to-project.yml deleted file mode 100644 index 56a42c7290..0000000000 --- a/.github/workflows/add-to-project.yml +++ /dev/null @@ -1,17 +0,0 @@ -name: Add to project -on: - issues: - types: - - opened - - labeled - -jobs: - add-to-project: - name: Add game server requests to project - runs-on: ubuntu-latest - steps: - - uses: actions/add-to-project@v0.4.0 - with: - project-url: https://github.com/orgs/GameServerManagers/projects/11 - github-token: ${{ secrets.ADD_TO_PROJECT_PAT }} - labeled: "type: game server request" From c2a66e5cd3d6e6290d400986f1eba99cf2ff43df Mon Sep 17 00:00:00 2001 From: FliesWithWind Date: Mon, 13 Mar 2023 13:29:03 +0100 Subject: [PATCH 4/9] Remove arma from mods module --- lgsm/functions/core_getopt.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lgsm/functions/core_getopt.sh b/lgsm/functions/core_getopt.sh index 6064942c18..6ff8f2f1cb 100755 --- a/lgsm/functions/core_getopt.sh +++ b/lgsm/functions/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" ] || [ "${shortname}" == "realvirtuality" ]; then +if [ "${engine}" == "source" ] || [ "${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 From feab479018e421beba8f4845c38109a2e60d3fc4 Mon Sep 17 00:00:00 2001 From: FliesWithWind Date: Sun, 12 Mar 2023 19:48:52 +0100 Subject: [PATCH 5/9] Initial Steam Workshop code --- .../config-lgsm/arma3server/_default.cfg | 7 + lgsm/functions/command_workshop_install.sh | 137 ++++++ lgsm/functions/command_workshop_update.sh | 149 +++++++ lgsm/functions/core_functions.sh | 22 + lgsm/functions/core_getopt.sh | 11 +- lgsm/functions/workshop_core.sh | 398 ++++++++++++++++++ 6 files changed, 723 insertions(+), 1 deletion(-) create mode 100644 lgsm/functions/command_workshop_install.sh create mode 100644 lgsm/functions/command_workshop_update.sh create mode 100644 lgsm/functions/workshop_core.sh diff --git a/lgsm/config-default/config-lgsm/arma3server/_default.cfg b/lgsm/config-default/config-lgsm/arma3server/_default.cfg index 7c4619c17f..50fcee6dc1 100644 --- a/lgsm/config-default/config-lgsm/arma3server/_default.cfg +++ b/lgsm/config-default/config-lgsm/arma3server/_default.cfg @@ -27,6 +27,11 @@ mods="" ## Server-side Mods servermods="" +## Mods to be downloaded from Steam Workshop +# Use workshop ids +# workshopmods="450814997;2131302796" +workshopmods="450814997;2131302796" + ## Path to BattlEye # Leave empty for default bepath="" @@ -134,6 +139,8 @@ sleeptime="0.5" # Server appid appid="233780" steamcmdforcewindows="no" +# Game appid +gameappid="107410" # SteamCMD Branch | https://docs.linuxgsm.com/steamcmd/branch branch="" betapassword="" diff --git a/lgsm/functions/command_workshop_install.sh b/lgsm/functions/command_workshop_install.sh new file mode 100644 index 0000000000..48449b24fe --- /dev/null +++ b/lgsm/functions/command_workshop_install.sh @@ -0,0 +1,137 @@ +#!/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_workshop_download "450814997" + +# # Displays a list of installed mods. +# fn_mods_installed_list +# if [ "${installedmodscount}" -gt "0" ]; then +# echo -e "Installed addons/mods" +# echo -e "=================================" +# # Go through all available commands, get details and display them to the user. +# for ((llindex = 0; llindex < ${#installedmodslist[@]}; llindex++)); do +# # Current mod is the "llindex" value of the array we're going through. +# currentmod="${installedmodslist[llindex]}" +# fn_mod_get_info +# # Display mod info to the user. +# echo -e " * ${green}${modcommand}${default}${default}" +# done +# echo -e "" +# fi + +# echo -e "Available addons/mods" +# echo -e "=================================" +# # Display available mods from mods_list.sh. +# # Set and reset vars +# compatiblemodslistindex=0 +# # As long as we're within index values. +# while [ "${compatiblemodslistindex}" -lt "${#compatiblemodslist[@]}" ]; do +# # Set values for convenience. +# displayedmodname="${compatiblemodslist[compatiblemodslistindex]}" +# displayedmodcommand="${compatiblemodslist[compatiblemodslistindex + 1]}" +# displayedmodsite="${compatiblemodslist[compatiblemodslistindex + 2]}" +# displayedmoddescription="${compatiblemodslist[compatiblemodslistindex + 3]}" +# # Output mods to the user. +# echo -e "${displayedmodname} - ${displayedmoddescription} - ${displayedmodsite}" +# echo -e " * ${cyan}${displayedmodcommand}${default}" +# # Increment index from the amount of values we just displayed. +# let "compatiblemodslistindex+=4" +# ((totalmodsavailable++)) +# done + +# # If no mods are available for a specific game. +# if [ -z "${compatiblemodslist}" ]; then +# fn_print_fail_nl "No mods are currently available for ${gamename}." +# fn_script_log_info "No mods are currently available for ${gamename}." +# core_exit.sh +# fi +# fn_script_log_info "${totalmodsavailable} addons/mods are available for install" + +# ## User selects a mod. +# echo -e "" +# while [[ ! " ${availablemodscommands[@]} " =~ " ${usermodselect} " ]]; do +# echo -en "Enter an ${cyan}addon/mod${default} to ${green}install${default} (or exit to abort): " +# read -r usermodselect +# # Exit if user says exit or abort. +# if [ "${usermodselect}" == "exit" ] || [ "${usermodselect}" == "abort" ]; then +# core_exit.sh +# # Supplementary output upon invalid user input. +# elif [[ ! " ${availablemodscommands[@]} " =~ " ${usermodselect} " ]]; then +# fn_print_error2_nl "${usermodselect} is not a valid addon/mod." +# fi +# done +# # Get mod info. +# currentmod="${usermodselect}" +# fn_mod_get_info + +# echo -e "" +# echo -e "Installing ${modprettyname}" +# echo -e "=================================" +# fn_script_log_info "${modprettyname} selected for install" + +# # Check if the mod is already installed and warn the user. +# if [ -f "${modsinstalledlistfullpath}" ]; then +# if [ "$(sed -n "/^${modcommand}$/p" "${modsinstalledlistfullpath}")" ]; then +# fn_print_warning_nl "${modprettyname} is already installed" +# fn_script_log_warn "${modprettyname} 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 +# fi + +# ## Installation. +# # If amxmodx check if metamod exists first +# if [ "${modcommand}" == "amxmodx" ]; then +# fn_mod_exist "metamod" +# fi + +# if [ "${modcommand}" == "amxmodxcs" ] \ +# || [ "${modcommand}" == "amxmodxdod" ] \ +# || [ "${modcommand}" == "amxmodxtfc" ] \ +# || [ "${modcommand}" == "amxmodxns" ] \ +# || [ "${modcommand}" == "amxmodxts" ]; then +# fn_mod_exist "amxmodx" +# fi + +# fn_create_mods_dir +# fn_mods_clear_tmp_dir +# fn_mods_create_tmp_dir +# fn_mod_install_files +# fn_mod_lowercase +# fn_mod_create_filelist +# fn_mod_copy_destination +# fn_mod_add_list +# fn_mod_tidy_files_list +# fn_mods_clear_tmp_dir + +# # Create/modify existing liblist.gam file for Metamod +# if [ "${modcommand}" == "metamod" ]; then +# fn_mod_install_liblist_gam_file +# fi + +# # Create/modify plugins.ini file for Metamod +# if [ "${modcommand}" == "amxmodx" ]; then +# fn_mod_install_amxmodx_file +# fi + +# echo -e "${modprettyname} installed" +# fn_script_log_pass "${modprettyname} installed." + +core_exit.sh diff --git a/lgsm/functions/command_workshop_update.sh b/lgsm/functions/command_workshop_update.sh new file mode 100644 index 0000000000..a0b409eda9 --- /dev/null +++ b/lgsm/functions/command_workshop_update.sh @@ -0,0 +1,149 @@ +#!/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_workshop_get_list + +for modid in "${workshoplist[@]}"; do + modname="$(fn_workshop_get_mod_name $modid)" + if fn_workshop_check_mod_update $modid; then + echo "Mod ${modname} is not up to date." + fn_workshop_download $modid + else + echo "Mod $modname is up to date." + fi +done + +#fn_workshop_download "450814997" + +# # Displays a list of installed mods. +# fn_mods_installed_list +# if [ "${installedmodscount}" -gt "0" ]; then +# echo -e "Installed addons/mods" +# echo -e "=================================" +# # Go through all available commands, get details and display them to the user. +# for ((llindex = 0; llindex < ${#installedmodslist[@]}; llindex++)); do +# # Current mod is the "llindex" value of the array we're going through. +# currentmod="${installedmodslist[llindex]}" +# fn_mod_get_info +# # Display mod info to the user. +# echo -e " * ${green}${modcommand}${default}${default}" +# done +# echo -e "" +# fi + +# echo -e "Available addons/mods" +# echo -e "=================================" +# # Display available mods from mods_list.sh. +# # Set and reset vars +# compatiblemodslistindex=0 +# # As long as we're within index values. +# while [ "${compatiblemodslistindex}" -lt "${#compatiblemodslist[@]}" ]; do +# # Set values for convenience. +# displayedmodname="${compatiblemodslist[compatiblemodslistindex]}" +# displayedmodcommand="${compatiblemodslist[compatiblemodslistindex + 1]}" +# displayedmodsite="${compatiblemodslist[compatiblemodslistindex + 2]}" +# displayedmoddescription="${compatiblemodslist[compatiblemodslistindex + 3]}" +# # Output mods to the user. +# echo -e "${displayedmodname} - ${displayedmoddescription} - ${displayedmodsite}" +# echo -e " * ${cyan}${displayedmodcommand}${default}" +# # Increment index from the amount of values we just displayed. +# let "compatiblemodslistindex+=4" +# ((totalmodsavailable++)) +# done + +# # If no mods are available for a specific game. +# if [ -z "${compatiblemodslist}" ]; then +# fn_print_fail_nl "No mods are currently available for ${gamename}." +# fn_script_log_info "No mods are currently available for ${gamename}." +# core_exit.sh +# fi +# fn_script_log_info "${totalmodsavailable} addons/mods are available for install" + +# ## User selects a mod. +# echo -e "" +# while [[ ! " ${availablemodscommands[@]} " =~ " ${usermodselect} " ]]; do +# echo -en "Enter an ${cyan}addon/mod${default} to ${green}install${default} (or exit to abort): " +# read -r usermodselect +# # Exit if user says exit or abort. +# if [ "${usermodselect}" == "exit" ] || [ "${usermodselect}" == "abort" ]; then +# core_exit.sh +# # Supplementary output upon invalid user input. +# elif [[ ! " ${availablemodscommands[@]} " =~ " ${usermodselect} " ]]; then +# fn_print_error2_nl "${usermodselect} is not a valid addon/mod." +# fi +# done +# # Get mod info. +# currentmod="${usermodselect}" +# fn_mod_get_info + +# echo -e "" +# echo -e "Installing ${modprettyname}" +# echo -e "=================================" +# fn_script_log_info "${modprettyname} selected for install" + +# # Check if the mod is already installed and warn the user. +# if [ -f "${modsinstalledlistfullpath}" ]; then +# if [ "$(sed -n "/^${modcommand}$/p" "${modsinstalledlistfullpath}")" ]; then +# fn_print_warning_nl "${modprettyname} is already installed" +# fn_script_log_warn "${modprettyname} 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 +# fi + +# ## Installation. +# # If amxmodx check if metamod exists first +# if [ "${modcommand}" == "amxmodx" ]; then +# fn_mod_exist "metamod" +# fi + +# if [ "${modcommand}" == "amxmodxcs" ] \ +# || [ "${modcommand}" == "amxmodxdod" ] \ +# || [ "${modcommand}" == "amxmodxtfc" ] \ +# || [ "${modcommand}" == "amxmodxns" ] \ +# || [ "${modcommand}" == "amxmodxts" ]; then +# fn_mod_exist "amxmodx" +# fi + +# fn_create_mods_dir +# fn_mods_clear_tmp_dir +# fn_mods_create_tmp_dir +# fn_mod_install_files +# fn_mod_lowercase +# fn_mod_create_filelist +# fn_mod_copy_destination +# fn_mod_add_list +# fn_mod_tidy_files_list +# fn_mods_clear_tmp_dir + +# # Create/modify existing liblist.gam file for Metamod +# if [ "${modcommand}" == "metamod" ]; then +# fn_mod_install_liblist_gam_file +# fi + +# # Create/modify plugins.ini file for Metamod +# if [ "${modcommand}" == "amxmodx" ]; then +# fn_mod_install_amxmodx_file +# fi + +# echo -e "${modprettyname} installed" +# fn_script_log_pass "${modprettyname} installed." + +core_exit.sh diff --git a/lgsm/functions/core_functions.sh b/lgsm/functions/core_functions.sh index bca5debf94..0744226243 100755 --- a/lgsm/functions/core_functions.sh +++ b/lgsm/functions/core_functions.sh @@ -151,6 +151,21 @@ command_mods_remove.sh() { 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() { functionfile="${FUNCNAME[0]}" fn_fetch_function @@ -287,6 +302,13 @@ mods_core.sh() { fn_fetch_function } +# Steam Workshop + +workshop_core.sh() { + functionfile="${FUNCNAME[0]}" + fn_fetch_function +} + # Dev command_dev_clear_functions.sh() { diff --git a/lgsm/functions/core_getopt.sh b/lgsm/functions/core_getopt.sh index fdd66ab3f5..6064942c18 100755 --- a/lgsm/functions/core_getopt.sh +++ b/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_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.") +# 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. 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.") @@ -133,10 +137,15 @@ 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}" == "rust" ] || [ "${shortname}" == "hq" ] || [ "${shortname}" == "sdtd" ] || [ "${shortname}" == "cs" ] || [ "${shortname}" == "dod" ] || [ "${shortname}" == "tfc" ] || [ "${shortname}" == "ns" ] || [ "${shortname}" == "ts" ] || [ "${shortname}" == "hldm" ] || [ "${shortname}" == "vh" ] || [ "${shortname}" == "realvirtuality" ]; then currentopt+=("${cmd_mods_install[@]}" "${cmd_mods_remove[@]}" "${cmd_mods_update[@]}") fi +## Workshop commands. +if [ "${engine}" == "realvirtuality" ]; then + currentopt+=("${cmd_workshop_install[@]}" "${cmd_workshop_remove[@]}" "${cmd_workshop_update[@]}") +fi + ## Installer. currentopt+=("${cmd_install[@]}" "${cmd_auto_install[@]}") diff --git a/lgsm/functions/workshop_core.sh b/lgsm/functions/workshop_core.sh new file mode 100644 index 0000000000..0ccc7c4907 --- /dev/null +++ b/lgsm/functions/workshop_core.sh @@ -0,0 +1,398 @@ +#!/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" +workhshopmodsdir="${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 + + # if [ -f "${workshopmodsrcdir}/meta.cpp" ]; then + # echo "Mod $modid downloaded" + # modsrcdirs[$modid]="$modsrcdir" + # return 0 + # else + # echo "Mod $modid was not successfully downloaded" + # return 1 + # fi +} + +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_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 "${workhshopmodsdir}/${modid}/meta.cpp" ]; then return 0; fi + local instmft="$(grep "timestamp" ${workhshopmodsdir}/${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" + #echo "$(grep -Po '(?<=name = ").+?(?=")' ${workshopmodsdir}/steamapps/workshop/content/${gameappid}/${modid}/mod.cpp)" + echo "$(grep -Po '(?<=name = ").+?(?=")' ${workshopmodsdldir}/steamapps/workshop/content/${gameappid}/${modid}/mod.cpp)" +} + +# Convert workshop mod files to lowercase if needed. +fn_workshop_lowercase() { + local modid="$1" + # Arma 3 requires lowercase + if [ "${engine}" == "realvirtuality" ]; then + echo -en "converting ${modprettyname} files to lowercase..." + fn_sleep_time + fn_script_log_info "Converting ${modprettyname} files to lowercase" + # Total files and directories for the mod, to output to the user + fileswc=$(find "${extractdir}" | wc -l) + # Total uppercase files and directories for the mod, to output to the user + filesupperwc=$(find "${extractdir}" -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..." + # Convert files and directories starting from the deepest to prevent issues (-depth argument) + while read -r 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 "${extractdir}" -depth -name '*[[:upper:]]*') + fn_print_ok_eol_nl + fi +} + +# # Copy the mod into serverfiles. +# fn_mod_copy_destination() { +# echo -en "copying ${modprettyname} to ${modinstalldir}..." +# fn_sleep_time +# cp -Rf "${extractdir}/." "${modinstalldir}/" +# local exitcode=$? +# if [ "${exitcode}" != 0 ]; then +# fn_print_fail_eol_nl +# fn_script_log_fatal "Copying ${modprettyname} to ${modinstalldir}" +# else +# fn_print_ok_eol_nl +# fn_script_log_pass "Copying ${modprettyname} to ${modinstalldir}" +# fi +# } + +# ## Information Gathering. + +# # Get details of a mod any (relevant and unique, such as full mod name or install command) value. +# fn_mod_get_info() { +# # Variable to know when job is done. +# modinfocommand="0" +# # Find entry in global array. +# for ((index = 0; index <= ${#mods_global_array[@]}; index++)); do +# # When entry is found. +# if [ "${mods_global_array[index]}" == "${currentmod}" ]; then +# # Go back to the previous "MOD" separator. +# for ((index = index; index <= ${#mods_global_array[@]}; index--)); do +# # When "MOD" is found. +# if [ "${mods_global_array[index]}" == "MOD" ]; then +# # Get info. +# fn_mods_define +# modinfocommand="1" +# break +# fi +# done +# fi +# # Exit the loop if job is done. +# if [ "${modinfocommand}" == "1" ]; then +# break +# fi +# done + +# # What happens if mod is not found. +# if [ "${modinfocommand}" == "0" ]; then +# fn_script_log_error "Could not find information for ${currentmod}" +# fn_print_error_nl "Could not find information for ${currentmod}" +# core_exit.sh +# fi +# } + +# # Builds list of installed mods. +# # using installed-mods.txt grabing mod info from mods_list.sh. +# fn_mods_installed_list() { +# fn_mods_count_installed +# # Set/reset variables. +# installedmodsline="1" +# installedmodslist=() +# modprettynamemaxlength="0" +# modsitemaxlength="0" +# moddescriptionmaxlength="0" +# modcommandmaxlength="0" +# # Loop through every line of the installed mods list ${modsinstalledlistfullpath}. +# while [ "${installedmodsline}" -le "${installedmodscount}" ]; do +# currentmod=$(sed "${installedmodsline}q;d" "${modsinstalledlistfullpath}") +# # Get mod info to make sure mod exists. +# fn_mod_get_info +# # Add the mod to available commands. +# installedmodslist+=("${modcommand}") +# # Increment line check. +# ((installedmodsline++)) +# done +# if [ "${installedmodscount}" ]; then +# fn_script_log_info "${installedmodscount} addons/mods are currently installed" +# 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 "${workhshopmodsdir}" ]; then + echo -en "creating Steam Workshop install directory ${workhshopmodsdir}..." + mkdir -p "${workhshopmodsdir}" + exitcode=$? + if [ "${exitcode}" != 0 ]; then + fn_print_fail_eol_nl + fn_script_log_fatal "Creating mod install directory ${workhshopmodsdir}" + core_exit.sh + else + fn_print_ok_eol_nl + fn_script_log_pass "Creating mod install directory ${workhshopmodsdir}" + fi + fi +} + +# # Create tmp download mod directory. +# fn_mods_create_tmp_dir() { +# if [ ! -d "${modstmpdir}" ]; then +# mkdir -p "${modstmpdir}" +# exitcode=$? +# echo -en "creating mod download directory ${modstmpdir}..." +# if [ "${exitcode}" != 0 ]; then +# fn_print_fail_eol_nl +# fn_script_log_fatal "Creating mod download directory ${modstmpdir}" +# core_exit.sh +# else +# fn_print_ok_eol_nl +# fn_script_log_pass "Creating mod download directory ${modstmpdir}" +# fi +# fi +# } + +# # Remove the tmp mod download directory when finished. +# fn_mods_clear_tmp_dir() { +# if [ -d "${modstmpdir}" ]; then +# echo -en "clearing mod download directory ${modstmpdir}..." +# rm -fr "${modstmpdir:?}" +# exitcode=$? +# if [ "${exitcode}" != 0 ]; then +# fn_print_fail_eol_nl +# fn_script_log_fatal "Clearing mod download directory ${modstmpdir}" +# core_exit.sh +# else +# fn_print_ok_eol_nl +# fn_script_log_pass "Clearing mod download directory ${modstmpdir}" +# fi + +# fi +# # Clear temp file list as well. +# if [ -f "${modsdir}/.removedfiles.tmp" ]; then +# rm -f "${modsdir:?}/.removedfiles.tmp" +# fi +# } + +# Counts how many mods were installed. +fn_workshop_count_installed() { + if [ -f "${workhshopmodsdir}" ]; then + installedmodscount=$(ls -l "${workhshopmodsdir}" | grep -c ^d) + else + installedmodscount=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 [ ${installedmodscount} -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 +} + +# fn_mod_exist() { +# modreq=$1 +# # requires one parameter, the mod +# if [ -f "${modsdir}/${modreq}-files.txt" ]; then +# # how many lines is the file list +# modsfilelistsize=$(wc -l < "${modsdir}/${modreq}-files.txt") +# # if file list is empty +# if [ "${modsfilelistsize}" -eq 0 ]; then +# fn_mod_required_fail_exist "${modreq}" +# fi +# else +# fn_mod_required_fail_exist "${modreq}" +# fi +# } + +# fn_mod_required_fail_exist() { +# modreq=$1 +# # requires one parameter, the mod +# fn_script_log_fatal "${modreq}-files.txt is empty: unable to find ${modreq} installed" +# echo -en "* Unable to find '${modreq}' which is required prior to installing this mod..." +# fn_print_fail_eol_nl +# core_exit.sh +# } + +# ## Database initialisation. + +# mods_list.sh +# fn_mods_available From 8a0fcfed123bdab6bcca8bb58bc7339b4395372a Mon Sep 17 00:00:00 2001 From: FliesWithWind Date: Mon, 13 Mar 2023 11:12:38 +0100 Subject: [PATCH 6/9] Fixies & cleanup --- .../config-lgsm/arma3server/_default.cfg | 2 +- lgsm/functions/command_workshop_install.sh | 149 ++------ lgsm/functions/command_workshop_update.sh | 135 +------ lgsm/functions/workshop_core.sh | 329 +++++++----------- 4 files changed, 176 insertions(+), 439 deletions(-) diff --git a/lgsm/config-default/config-lgsm/arma3server/_default.cfg b/lgsm/config-default/config-lgsm/arma3server/_default.cfg index 50fcee6dc1..8723ef79d3 100644 --- a/lgsm/config-default/config-lgsm/arma3server/_default.cfg +++ b/lgsm/config-default/config-lgsm/arma3server/_default.cfg @@ -30,7 +30,7 @@ servermods="" ## Mods to be downloaded from Steam Workshop # Use workshop ids # workshopmods="450814997;2131302796" -workshopmods="450814997;2131302796" +workshopmods="" ## Path to BattlEye # Leave empty for default diff --git a/lgsm/functions/command_workshop_install.sh b/lgsm/functions/command_workshop_install.sh index 48449b24fe..ba2025afda 100644 --- a/lgsm/functions/command_workshop_install.sh +++ b/lgsm/functions/command_workshop_install.sh @@ -14,124 +14,33 @@ check.sh workshop_core.sh fn_print_header - -fn_workshop_download "450814997" - -# # Displays a list of installed mods. -# fn_mods_installed_list -# if [ "${installedmodscount}" -gt "0" ]; then -# echo -e "Installed addons/mods" -# echo -e "=================================" -# # Go through all available commands, get details and display them to the user. -# for ((llindex = 0; llindex < ${#installedmodslist[@]}; llindex++)); do -# # Current mod is the "llindex" value of the array we're going through. -# currentmod="${installedmodslist[llindex]}" -# fn_mod_get_info -# # Display mod info to the user. -# echo -e " * ${green}${modcommand}${default}${default}" -# done -# echo -e "" -# fi - -# echo -e "Available addons/mods" -# echo -e "=================================" -# # Display available mods from mods_list.sh. -# # Set and reset vars -# compatiblemodslistindex=0 -# # As long as we're within index values. -# while [ "${compatiblemodslistindex}" -lt "${#compatiblemodslist[@]}" ]; do -# # Set values for convenience. -# displayedmodname="${compatiblemodslist[compatiblemodslistindex]}" -# displayedmodcommand="${compatiblemodslist[compatiblemodslistindex + 1]}" -# displayedmodsite="${compatiblemodslist[compatiblemodslistindex + 2]}" -# displayedmoddescription="${compatiblemodslist[compatiblemodslistindex + 3]}" -# # Output mods to the user. -# echo -e "${displayedmodname} - ${displayedmoddescription} - ${displayedmodsite}" -# echo -e " * ${cyan}${displayedmodcommand}${default}" -# # Increment index from the amount of values we just displayed. -# let "compatiblemodslistindex+=4" -# ((totalmodsavailable++)) -# done - -# # If no mods are available for a specific game. -# if [ -z "${compatiblemodslist}" ]; then -# fn_print_fail_nl "No mods are currently available for ${gamename}." -# fn_script_log_info "No mods are currently available for ${gamename}." -# core_exit.sh -# fi -# fn_script_log_info "${totalmodsavailable} addons/mods are available for install" - -# ## User selects a mod. -# echo -e "" -# while [[ ! " ${availablemodscommands[@]} " =~ " ${usermodselect} " ]]; do -# echo -en "Enter an ${cyan}addon/mod${default} to ${green}install${default} (or exit to abort): " -# read -r usermodselect -# # Exit if user says exit or abort. -# if [ "${usermodselect}" == "exit" ] || [ "${usermodselect}" == "abort" ]; then -# core_exit.sh -# # Supplementary output upon invalid user input. -# elif [[ ! " ${availablemodscommands[@]} " =~ " ${usermodselect} " ]]; then -# fn_print_error2_nl "${usermodselect} is not a valid addon/mod." -# fi -# done -# # Get mod info. -# currentmod="${usermodselect}" -# fn_mod_get_info - -# echo -e "" -# echo -e "Installing ${modprettyname}" -# echo -e "=================================" -# fn_script_log_info "${modprettyname} selected for install" - -# # Check if the mod is already installed and warn the user. -# if [ -f "${modsinstalledlistfullpath}" ]; then -# if [ "$(sed -n "/^${modcommand}$/p" "${modsinstalledlistfullpath}")" ]; then -# fn_print_warning_nl "${modprettyname} is already installed" -# fn_script_log_warn "${modprettyname} 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 -# fi - -# ## Installation. -# # If amxmodx check if metamod exists first -# if [ "${modcommand}" == "amxmodx" ]; then -# fn_mod_exist "metamod" -# fi - -# if [ "${modcommand}" == "amxmodxcs" ] \ -# || [ "${modcommand}" == "amxmodxdod" ] \ -# || [ "${modcommand}" == "amxmodxtfc" ] \ -# || [ "${modcommand}" == "amxmodxns" ] \ -# || [ "${modcommand}" == "amxmodxts" ]; then -# fn_mod_exist "amxmodx" -# fi - -# fn_create_mods_dir -# fn_mods_clear_tmp_dir -# fn_mods_create_tmp_dir -# fn_mod_install_files -# fn_mod_lowercase -# fn_mod_create_filelist -# fn_mod_copy_destination -# fn_mod_add_list -# fn_mod_tidy_files_list -# fn_mods_clear_tmp_dir - -# # Create/modify existing liblist.gam file for Metamod -# if [ "${modcommand}" == "metamod" ]; then -# fn_mod_install_liblist_gam_file -# fi - -# # Create/modify plugins.ini file for Metamod -# if [ "${modcommand}" == "amxmodx" ]; then -# fn_mod_install_amxmodx_file -# fi - -# echo -e "${modprettyname} installed" -# fn_script_log_pass "${modprettyname} installed." - +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 +done + +fn_workshop_lowercase core_exit.sh diff --git a/lgsm/functions/command_workshop_update.sh b/lgsm/functions/command_workshop_update.sh index a0b409eda9..489411e8de 100644 --- a/lgsm/functions/command_workshop_update.sh +++ b/lgsm/functions/command_workshop_update.sh @@ -12,138 +12,25 @@ 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} is not up to date." + echo "Mod ${modname} (${modid}) is not up to date." fn_workshop_download $modid - else + fn_workshop_copy_destination $modid + else echo "Mod $modname is up to date." - fi + fi done -#fn_workshop_download "450814997" - -# # Displays a list of installed mods. -# fn_mods_installed_list -# if [ "${installedmodscount}" -gt "0" ]; then -# echo -e "Installed addons/mods" -# echo -e "=================================" -# # Go through all available commands, get details and display them to the user. -# for ((llindex = 0; llindex < ${#installedmodslist[@]}; llindex++)); do -# # Current mod is the "llindex" value of the array we're going through. -# currentmod="${installedmodslist[llindex]}" -# fn_mod_get_info -# # Display mod info to the user. -# echo -e " * ${green}${modcommand}${default}${default}" -# done -# echo -e "" -# fi - -# echo -e "Available addons/mods" -# echo -e "=================================" -# # Display available mods from mods_list.sh. -# # Set and reset vars -# compatiblemodslistindex=0 -# # As long as we're within index values. -# while [ "${compatiblemodslistindex}" -lt "${#compatiblemodslist[@]}" ]; do -# # Set values for convenience. -# displayedmodname="${compatiblemodslist[compatiblemodslistindex]}" -# displayedmodcommand="${compatiblemodslist[compatiblemodslistindex + 1]}" -# displayedmodsite="${compatiblemodslist[compatiblemodslistindex + 2]}" -# displayedmoddescription="${compatiblemodslist[compatiblemodslistindex + 3]}" -# # Output mods to the user. -# echo -e "${displayedmodname} - ${displayedmoddescription} - ${displayedmodsite}" -# echo -e " * ${cyan}${displayedmodcommand}${default}" -# # Increment index from the amount of values we just displayed. -# let "compatiblemodslistindex+=4" -# ((totalmodsavailable++)) -# done - -# # If no mods are available for a specific game. -# if [ -z "${compatiblemodslist}" ]; then -# fn_print_fail_nl "No mods are currently available for ${gamename}." -# fn_script_log_info "No mods are currently available for ${gamename}." -# core_exit.sh -# fi -# fn_script_log_info "${totalmodsavailable} addons/mods are available for install" - -# ## User selects a mod. -# echo -e "" -# while [[ ! " ${availablemodscommands[@]} " =~ " ${usermodselect} " ]]; do -# echo -en "Enter an ${cyan}addon/mod${default} to ${green}install${default} (or exit to abort): " -# read -r usermodselect -# # Exit if user says exit or abort. -# if [ "${usermodselect}" == "exit" ] || [ "${usermodselect}" == "abort" ]; then -# core_exit.sh -# # Supplementary output upon invalid user input. -# elif [[ ! " ${availablemodscommands[@]} " =~ " ${usermodselect} " ]]; then -# fn_print_error2_nl "${usermodselect} is not a valid addon/mod." -# fi -# done -# # Get mod info. -# currentmod="${usermodselect}" -# fn_mod_get_info - -# echo -e "" -# echo -e "Installing ${modprettyname}" -# echo -e "=================================" -# fn_script_log_info "${modprettyname} selected for install" - -# # Check if the mod is already installed and warn the user. -# if [ -f "${modsinstalledlistfullpath}" ]; then -# if [ "$(sed -n "/^${modcommand}$/p" "${modsinstalledlistfullpath}")" ]; then -# fn_print_warning_nl "${modprettyname} is already installed" -# fn_script_log_warn "${modprettyname} 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 -# fi - -# ## Installation. -# # If amxmodx check if metamod exists first -# if [ "${modcommand}" == "amxmodx" ]; then -# fn_mod_exist "metamod" -# fi - -# if [ "${modcommand}" == "amxmodxcs" ] \ -# || [ "${modcommand}" == "amxmodxdod" ] \ -# || [ "${modcommand}" == "amxmodxtfc" ] \ -# || [ "${modcommand}" == "amxmodxns" ] \ -# || [ "${modcommand}" == "amxmodxts" ]; then -# fn_mod_exist "amxmodx" -# fi - -# fn_create_mods_dir -# fn_mods_clear_tmp_dir -# fn_mods_create_tmp_dir -# fn_mod_install_files -# fn_mod_lowercase -# fn_mod_create_filelist -# fn_mod_copy_destination -# fn_mod_add_list -# fn_mod_tidy_files_list -# fn_mods_clear_tmp_dir - -# # Create/modify existing liblist.gam file for Metamod -# if [ "${modcommand}" == "metamod" ]; then -# fn_mod_install_liblist_gam_file -# fi - -# # Create/modify plugins.ini file for Metamod -# if [ "${modcommand}" == "amxmodx" ]; then -# fn_mod_install_amxmodx_file -# fi - -# echo -e "${modprettyname} installed" -# fn_script_log_pass "${modprettyname} installed." - +fn_workshop_lowercase core_exit.sh diff --git a/lgsm/functions/workshop_core.sh b/lgsm/functions/workshop_core.sh index 0ccc7c4907..435d56b66f 100644 --- a/lgsm/functions/workshop_core.sh +++ b/lgsm/functions/workshop_core.sh @@ -9,7 +9,7 @@ functionselfname="$(basename "$(readlink -f "${BASH_SOURCE[0]}")")" # Files and Directories. steam="${steamcmd}/steam" -workhshopmodsdir="${serverfiles}/mods" +workshopmodsdir="${serverfiles}/mods" keysdir="${serverfiles}/keys" workshopmodsdldir="${lgsmdir}/workshop" workshopmodslist="workshop-mods.txt" @@ -101,15 +101,6 @@ fn_workshop_download() { core_exit.sh fi done - - # if [ -f "${workshopmodsrcdir}/meta.cpp" ]; then - # echo "Mod $modid downloaded" - # modsrcdirs[$modid]="$modsrcdir" - # return 0 - # else - # echo "Mod $modid was not successfully downloaded" - # return 1 - # fi } fn_workshop_get_list() { @@ -118,12 +109,22 @@ fn_workshop_get_list() { 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 '"' + 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() { @@ -141,8 +142,8 @@ fn_workshop_check_mod_update() { fn_workshop_is_mod_copy_needed(){ local modid="$1" local modsrc="${workshopmodsdldir}/steamapps/workshop/content/${gameappid}/${modid}" - if [ ! -f "${workhshopmodsdir}/${modid}/meta.cpp" ]; then return 0; fi - local instmft="$(grep "timestamp" ${workhshopmodsdir}/${modid}/meta.cpp)" + 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 @@ -154,123 +155,118 @@ fn_workshop_is_mod_copy_needed(){ fn_workshop_get_mod_name(){ local modid="$1" - #echo "$(grep -Po '(?<=name = ").+?(?=")' ${workshopmodsdir}/steamapps/workshop/content/${gameappid}/${modid}/mod.cpp)" - echo "$(grep -Po '(?<=name = ").+?(?=")' ${workshopmodsdldir}/steamapps/workshop/content/${gameappid}/${modid}/mod.cpp)" + 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 } # Convert workshop mod files to lowercase if needed. fn_workshop_lowercase() { - local modid="$1" + # local modid="$1" + # local modname="$(fn_workshop_get_mod_name $modid)" # Arma 3 requires lowercase if [ "${engine}" == "realvirtuality" ]; then - echo -en "converting ${modprettyname} files to lowercase..." + echo -en "Converting ${modname} files to lowercase..." fn_sleep_time - fn_script_log_info "Converting ${modprettyname} files to lowercase" + fn_script_log_info "Converting ${modname} files to lowercase" # Total files and directories for the mod, to output to the user - fileswc=$(find "${extractdir}" | wc -l) + fileswc=$(find "${workshopmodsdir}" | wc -l) # Total uppercase files and directories for the mod, to output to the user - filesupperwc=$(find "${extractdir}" -name '*[[:upper:]]*' | wc -l) + 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..." + # Works but not on folders + # while IFS= read -r -d '' file; do + # mv -b -- "$file" "${file,,}" 2>/dev/null + # done < <(find ${workshopmodsdir} -depth -name '*[A-Z]*' -print0) + # while IFS= read -r -d '' file; do + # mv -b -- "$file" "${file,,}" 2>/dev/null + # done < <(find ${workshopmodsdir}/ -depth -name '*[A-Z]*' -print0) + + # Works bu not on WSL? + # https://unix.stackexchange.com/questions/20222/change-entire-directory-tree-to-lower-case-names/20232#20232 + # + find ${workshopmodsdir} -depth -exec sh -c ' + t=${0%/*}/$(printf %s "${0##*/}" | tr "[:upper:]" "[:lower:]"); + [ "$t" = "$0" ] || mv -i "$0" "$t" + ' {} \; + + # + # Coudln't get this to work. + # # Convert files and directories starting from the deepest to prevent issues (-depth argument) - while read -r 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 "${extractdir}" -depth -name '*[[:upper:]]*') + # 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_mod_copy_destination() { -# echo -en "copying ${modprettyname} to ${modinstalldir}..." -# fn_sleep_time -# cp -Rf "${extractdir}/." "${modinstalldir}/" -# local exitcode=$? -# if [ "${exitcode}" != 0 ]; then -# fn_print_fail_eol_nl -# fn_script_log_fatal "Copying ${modprettyname} to ${modinstalldir}" -# else -# fn_print_ok_eol_nl -# fn_script_log_pass "Copying ${modprettyname} to ${modinstalldir}" -# fi -# } - -# ## Information Gathering. - -# # Get details of a mod any (relevant and unique, such as full mod name or install command) value. -# fn_mod_get_info() { -# # Variable to know when job is done. -# modinfocommand="0" -# # Find entry in global array. -# for ((index = 0; index <= ${#mods_global_array[@]}; index++)); do -# # When entry is found. -# if [ "${mods_global_array[index]}" == "${currentmod}" ]; then -# # Go back to the previous "MOD" separator. -# for ((index = index; index <= ${#mods_global_array[@]}; index--)); do -# # When "MOD" is found. -# if [ "${mods_global_array[index]}" == "MOD" ]; then -# # Get info. -# fn_mods_define -# modinfocommand="1" -# break -# fi -# done -# fi -# # Exit the loop if job is done. -# if [ "${modinfocommand}" == "1" ]; then -# break -# fi -# done - -# # What happens if mod is not found. -# if [ "${modinfocommand}" == "0" ]; then -# fn_script_log_error "Could not find information for ${currentmod}" -# fn_print_error_nl "Could not find information for ${currentmod}" -# core_exit.sh -# fi -# } - -# # Builds list of installed mods. -# # using installed-mods.txt grabing mod info from mods_list.sh. -# fn_mods_installed_list() { -# fn_mods_count_installed -# # Set/reset variables. -# installedmodsline="1" -# installedmodslist=() -# modprettynamemaxlength="0" -# modsitemaxlength="0" -# moddescriptionmaxlength="0" -# modcommandmaxlength="0" -# # Loop through every line of the installed mods list ${modsinstalledlistfullpath}. -# while [ "${installedmodsline}" -le "${installedmodscount}" ]; do -# currentmod=$(sed "${installedmodsline}q;d" "${modsinstalledlistfullpath}") -# # Get mod info to make sure mod exists. -# fn_mod_get_info -# # Add the mod to available commands. -# installedmodslist+=("${modcommand}") -# # Increment line check. -# ((installedmodsline++)) -# done -# if [ "${installedmodscount}" ]; then -# fn_script_log_info "${installedmodscount} addons/mods are currently installed" -# fi -# } +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 + # echo -en "copying ${modprettyname} to ${modinstalldir}..." + # fn_sleep_time + # cp -Rf "${extractdir}/." "${modinstalldir}/" + # local exitcode=$? + # if [ "${exitcode}" != 0 ]; then + # fn_print_fail_eol_nl + # fn_script_log_fatal "Copying ${modprettyname} to ${modinstalldir}" + # else + # fn_print_ok_eol_nl + # fn_script_log_pass "Copying ${modprettyname} to ${modinstalldir}" + # fi +} # ## Directory management. @@ -291,66 +287,27 @@ fn_create_workshop_dir() { fi fi # Create mod install directory. - if [ ! -d "${workhshopmodsdir}" ]; then - echo -en "creating Steam Workshop install directory ${workhshopmodsdir}..." - mkdir -p "${workhshopmodsdir}" + 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 ${workhshopmodsdir}" + 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 ${workhshopmodsdir}" + fn_script_log_pass "Creating mod install directory ${workshopmodsdir}" fi fi } -# # Create tmp download mod directory. -# fn_mods_create_tmp_dir() { -# if [ ! -d "${modstmpdir}" ]; then -# mkdir -p "${modstmpdir}" -# exitcode=$? -# echo -en "creating mod download directory ${modstmpdir}..." -# if [ "${exitcode}" != 0 ]; then -# fn_print_fail_eol_nl -# fn_script_log_fatal "Creating mod download directory ${modstmpdir}" -# core_exit.sh -# else -# fn_print_ok_eol_nl -# fn_script_log_pass "Creating mod download directory ${modstmpdir}" -# fi -# fi -# } - -# # Remove the tmp mod download directory when finished. -# fn_mods_clear_tmp_dir() { -# if [ -d "${modstmpdir}" ]; then -# echo -en "clearing mod download directory ${modstmpdir}..." -# rm -fr "${modstmpdir:?}" -# exitcode=$? -# if [ "${exitcode}" != 0 ]; then -# fn_print_fail_eol_nl -# fn_script_log_fatal "Clearing mod download directory ${modstmpdir}" -# core_exit.sh -# else -# fn_print_ok_eol_nl -# fn_script_log_pass "Clearing mod download directory ${modstmpdir}" -# fi - -# fi -# # Clear temp file list as well. -# if [ -f "${modsdir}/.removedfiles.tmp" ]; then -# rm -f "${modsdir:?}/.removedfiles.tmp" -# fi -# } - # Counts how many mods were installed. fn_workshop_count_installed() { - if [ -f "${workhshopmodsdir}" ]; then - installedmodscount=$(ls -l "${workhshopmodsdir}" | grep -c ^d) + if [ -f "${workshopmodsdir}" ]; then + installedworkshopmodscount=$(ls -l "${workshopmodsdir}" | grep -c ^d) else - installedmodscount=0 + installedworkshopmodscount=0 fi } @@ -359,7 +316,7 @@ fn_workshop_check_installed() { # Count installed mods. fn_workshop_count_installed # If no mods are found. - if [ ${installedmodscount} -eq 0 ]; then + 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" @@ -368,31 +325,15 @@ fn_workshop_check_installed() { fi } -# fn_mod_exist() { -# modreq=$1 -# # requires one parameter, the mod -# if [ -f "${modsdir}/${modreq}-files.txt" ]; then -# # how many lines is the file list -# modsfilelistsize=$(wc -l < "${modsdir}/${modreq}-files.txt") -# # if file list is empty -# if [ "${modsfilelistsize}" -eq 0 ]; then -# fn_mod_required_fail_exist "${modreq}" -# fi -# else -# fn_mod_required_fail_exist "${modreq}" -# fi -# } - -# fn_mod_required_fail_exist() { -# modreq=$1 -# # requires one parameter, the mod -# fn_script_log_fatal "${modreq}-files.txt is empty: unable to find ${modreq} installed" -# echo -en "* Unable to find '${modreq}' which is required prior to installing this mod..." -# fn_print_fail_eol_nl -# core_exit.sh -# } - -# ## Database initialisation. - -# mods_list.sh -# fn_mods_available +# Builds list of installed Steam Workshop mods. +fn_workshop_installed_list() { + fn_workshop_count_installed + for f in ${workshopmodsdir}/*; do + if [ -d "$f" ]; 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 +} From 2c3b9dbe77b72ef627caac89fd8e983fdcc75bfa Mon Sep 17 00:00:00 2001 From: FliesWithWind Date: Mon, 13 Mar 2023 13:29:03 +0100 Subject: [PATCH 7/9] Remove arma from mods module --- lgsm/functions/core_getopt.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lgsm/functions/core_getopt.sh b/lgsm/functions/core_getopt.sh index 6064942c18..6ff8f2f1cb 100755 --- a/lgsm/functions/core_getopt.sh +++ b/lgsm/functions/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" ] || [ "${shortname}" == "realvirtuality" ]; then +if [ "${engine}" == "source" ] || [ "${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 From c81d339a925d2050014e7f7b38a6cdb577cec105 Mon Sep 17 00:00:00 2001 From: FliesWithWind Date: Wed, 15 Mar 2023 10:51:00 +0100 Subject: [PATCH 8/9] Cleanup and styleup --- lgsm/functions/command_workshop_install.sh | 4 +-- lgsm/functions/command_workshop_update.sh | 10 +++--- lgsm/functions/workshop_core.sh | 39 +++++++++++----------- 3 files changed, 27 insertions(+), 26 deletions(-) diff --git a/lgsm/functions/command_workshop_install.sh b/lgsm/functions/command_workshop_install.sh index ba2025afda..f047aaaddd 100644 --- a/lgsm/functions/command_workshop_install.sh +++ b/lgsm/functions/command_workshop_install.sh @@ -38,8 +38,8 @@ for modid in "${workshoplist[@]}"; do echo -e "" echo -e "Installing $(fn_workshop_get_mod_name ${modid})." echo -e "=================================" - fn_workshop_download $modid - fn_workshop_copy_destination $modid + fn_workshop_download "${modid}" + fn_workshop_copy_destination "${modid}"s done fn_workshop_lowercase diff --git a/lgsm/functions/command_workshop_update.sh b/lgsm/functions/command_workshop_update.sh index 489411e8de..a5b7814a84 100644 --- a/lgsm/functions/command_workshop_update.sh +++ b/lgsm/functions/command_workshop_update.sh @@ -22,13 +22,13 @@ 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 + 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 + fn_workshop_download "${modid}" + fn_workshop_copy_destination "${modid}" else - echo "Mod $modname is up to date." + echo "Mod ${modname} is up to date." fi done diff --git a/lgsm/functions/workshop_core.sh b/lgsm/functions/workshop_core.sh index 435d56b66f..d3f3d10c33 100644 --- a/lgsm/functions/workshop_core.sh +++ b/lgsm/functions/workshop_core.sh @@ -104,35 +104,35 @@ fn_workshop_download() { } fn_workshop_get_list() { - workshoplist=($(echo $workshopmods | tr ";" "\n")) + 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 + if [[ "${serverresp}" =~ \"hcontent_file\":[[:space:]]*([^,]*) ]]; then remupd="${BASH_REMATCH[1]}" fi - echo "$remupd" | tr -d '"' + 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 + if [[ "${serverresp}" =~ \"title\":[[:space:]]*([^,]*) ]]; then title="${BASH_REMATCH[1]}" fi - echo "$title" | tr -d '"' + 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 [ -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 @@ -144,8 +144,8 @@ fn_workshop_is_mod_copy_needed(){ 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 [ -z "${instmft}" ]; then return 0; fi + local remmft="$(grep "timestamp" ${modsrc}/meta.cpp)" if [[ -n "${remmft}" && "${instmft}" != "${remmft}" ]]; then return 0 # true fi @@ -225,31 +225,31 @@ fn_workshop_lowercase() { # # 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 + 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" + modsrc="${workshopmodsdldir}/steamapps/workshop/content/${gameappid}/${modid}" cp -fa ${modsrc} ${workshopmodsdir} if [ "${engine}" == "realvirtuality" ]; then - modkey="${workshopmodsdldir}/steamapps/workshop/content/${gameappid}/$modid/keys" + modkey="${workshopmodsdldir}/steamapps/workshop/content/${gameappid}/${modid}/keys" if ! [ -d "${modkey}" ]; then - modkey="$steamcmd/steamapps/workshop/content/${gameappid}/$modid/Keys" + modkey="$steamcmd/steamapps/workshop/content/${gameappid}/${modid}/Keys" fi if ! [ -d "${modkey}" ]; then - modkey="$steamcmd/steamapps/workshop/content/${gameappid}/$modid/key" + modkey="$steamcmd/steamapps/workshop/content/${gameappid}/${modid}/key" fi if ! [ -d "${modkey}" ]; then - modkey="$steamcmd/steamapps/workshop/content/${gameappid}/$modid/Key" + 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} + cp -fa ${modkey}/*.bikey ${keysdir} fi fi else @@ -328,8 +328,9 @@ fn_workshop_check_installed() { # Builds list of installed Steam Workshop mods. fn_workshop_installed_list() { fn_workshop_count_installed - for f in ${workshopmodsdir}/*; do - if [ -d "$f" ]; then + 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 From cbaf0af14f233ed9c94ddb6cd60815f2ca9ed39b Mon Sep 17 00:00:00 2001 From: FliesWithWind Date: Wed, 15 Mar 2023 11:24:18 +0100 Subject: [PATCH 9/9] Cleanup comments and add game check for mod name --- lgsm/functions/workshop_core.sh | 80 ++++++++++++--------------------- 1 file changed, 29 insertions(+), 51 deletions(-) diff --git a/lgsm/functions/workshop_core.sh b/lgsm/functions/workshop_core.sh index d3f3d10c33..6120345b3b 100644 --- a/lgsm/functions/workshop_core.sh +++ b/lgsm/functions/workshop_core.sh @@ -155,10 +155,15 @@ fn_workshop_is_mod_copy_needed(){ fn_workshop_get_mod_name(){ local modid="$1" - 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)" + # 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 @@ -179,45 +184,29 @@ fn_workshop_lowercase() { 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..." - # Works but not on folders - # while IFS= read -r -d '' file; do - # mv -b -- "$file" "${file,,}" 2>/dev/null - # done < <(find ${workshopmodsdir} -depth -name '*[A-Z]*' -print0) - # while IFS= read -r -d '' file; do - # mv -b -- "$file" "${file,,}" 2>/dev/null - # done < <(find ${workshopmodsdir}/ -depth -name '*[A-Z]*' -print0) - - # Works bu not on WSL? - # https://unix.stackexchange.com/questions/20222/change-entire-directory-tree-to-lower-case-names/20232#20232 # - find ${workshopmodsdir} -depth -exec sh -c ' - t=${0%/*}/$(printf %s "${0##*/}" | tr "[:upper:]" "[:lower:]"); - [ "$t" = "$0" ] || mv -i "$0" "$t" - ' {} \; - - # - # Coudln't get this to work. + # 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) + 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 } @@ -255,17 +244,6 @@ fn_workshop_copy_destination() { else echo "Mod ${modname} is already in mods folder." fi - # echo -en "copying ${modprettyname} to ${modinstalldir}..." - # fn_sleep_time - # cp -Rf "${extractdir}/." "${modinstalldir}/" - # local exitcode=$? - # if [ "${exitcode}" != 0 ]; then - # fn_print_fail_eol_nl - # fn_script_log_fatal "Copying ${modprettyname} to ${modinstalldir}" - # else - # fn_print_ok_eol_nl - # fn_script_log_pass "Copying ${modprettyname} to ${modinstalldir}" - # fi } # ## Directory management.