From 3dc76a2434c1d980ddf5bccacc2f9f5938690c62 Mon Sep 17 00:00:00 2001 From: FliesWithWind Date: Sun, 12 Mar 2023 19:48:52 +0100 Subject: [PATCH] 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 7c4619c17..50fcee6dc 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 000000000..48449b24f --- /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 000000000..a0b409eda --- /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 05b52e243..fada688c7 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 fdd66ab3f..6064942c1 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 000000000..0ccc7c490 --- /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