17 changed files with 989 additions and 19 deletions
@ -0,0 +1,18 @@ |
|||
#!/bin/bash |
|||
# LGSM check_system_dir.sh function |
|||
# Author: Daniel Gibbs |
|||
# Website: https://gameservermanagers.com |
|||
# Description: Checks if systemdir is accessible. |
|||
|
|||
local commandname="CHECK" |
|||
local function_selfname="$(basename $(readlink -f "${BASH_SOURCE[0]}"))" |
|||
|
|||
# Check if executable exists |
|||
if [ ! -f "${executabledir}/${execname}" ]; then |
|||
fn_script_log_warn "Expected executable not found: ${executabledir}/${execname}" |
|||
if [ -d "${scriptlogdir}" ]; then |
|||
fn_print_fail_nl "Executable ${execname} was not found" |
|||
fi |
|||
exitcode="1" |
|||
core_exit.sh |
|||
fi |
@ -0,0 +1,117 @@ |
|||
#!/bin/bash |
|||
# LGSM command_mods_install.sh function |
|||
# Author: Daniel Gibbs |
|||
# Contributor: UltimateByte |
|||
# Website: https://gameservermanagers.com |
|||
# Description: List and installs available mods along with mods_list.sh and mods_core.sh. |
|||
|
|||
local commandname="MODS" |
|||
local commandaction="addons/mods" |
|||
local function_selfname="$(basename $(readlink -f "${BASH_SOURCE[0]}"))" |
|||
|
|||
check.sh |
|||
mods_core.sh |
|||
|
|||
fn_print_header |
|||
|
|||
# Displays a list of installed mods |
|||
fn_mods_installed_list |
|||
if [ ${installedmodscount} -gt 0 ]; then |
|||
echo "Installed addons/mods" |
|||
echo "=================================" |
|||
# 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 "" |
|||
fi |
|||
|
|||
echo "Available addons/mods" |
|||
echo "=================================" |
|||
# 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 "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 "" |
|||
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 "" |
|||
echo "Installing ${modprettyname}" |
|||
echo "=================================" |
|||
fn_script_log_info "${modprettyname} selected for install" |
|||
|
|||
# Check if the mod is already installed and warn the user |
|||
if [ -f "${modsinstalledlistfullpath}" ]; then |
|||
if [ -n "$(sed -n "/^${modcommand}$/p" "${modsinstalledlistfullpath}")" ]; then |
|||
fn_print_warning_nl "${modprettyname} is already installed" |
|||
fn_script_log_warn "${modprettyname} is already installed" |
|||
sleep 1 |
|||
echo " * Any configs may be overwritten." |
|||
while true; do |
|||
read -e -i "y" -p "Continue? [Y/n]" yn |
|||
case $yn in |
|||
[Yy]* ) break;; |
|||
[Nn]* ) echo Exiting; core_exit.sh;; |
|||
* ) echo "Please answer yes or no.";; |
|||
esac |
|||
done |
|||
fn_script_log_info "User selected to continue" |
|||
fi |
|||
fi |
|||
|
|||
## Installation |
|||
|
|||
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 |
|||
echo "${modprettyname} installed" |
|||
fn_script_log_pass "${modprettyname} installed." |
|||
|
|||
core_exit.sh |
@ -0,0 +1,137 @@ |
|||
#!/bin/bash |
|||
# LGSM command_mods_uninstall.sh function |
|||
# Author: Daniel Gibbs |
|||
# Contributor: UltimateByte |
|||
# Website: https://gameservermanagers.com |
|||
# Description: Uninstall mods along with mods_list.sh and mods_core.sh. |
|||
|
|||
local commandname="MODS" |
|||
local commandaction="addons/mods" |
|||
local function_selfname="$(basename $(readlink -f "${BASH_SOURCE[0]}"))" |
|||
|
|||
check.sh |
|||
mods_core.sh |
|||
fn_mods_check_installed |
|||
|
|||
fn_print_header |
|||
echo "Remove addons/mods" |
|||
echo "=================================" |
|||
|
|||
## Displays list of installed mods |
|||
# Generates list to display to user |
|||
fn_mods_installed_list |
|||
for ((mlindex=0; mlindex < ${#installedmodslist[@]}; mlindex++)); do |
|||
# Current mod is the "mlindex" value of the array we are going through |
|||
currentmod="${installedmodslist[mlindex]}" |
|||
# Get mod info |
|||
fn_mod_get_info |
|||
# Display mod info to the user |
|||
echo -e "${red}${modcommand}${default} - ${modprettyname} - ${moddescription}" |
|||
done |
|||
|
|||
echo "" |
|||
# Keep prompting as long as the user input doesn't correspond to an available mod |
|||
while [[ ! " ${installedmodslist[@]} " =~ " ${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 |
|||
|
|||
fn_print_warning_nl "You are about to remove ${cyan}${usermodselect}${default}." |
|||
echo " * Any custom files/configuration will be removed." |
|||
while true; do |
|||
read -e -i "y" -p "Continue? [Y/n]" yn |
|||
case $yn in |
|||
[Yy]* ) break;; |
|||
[Nn]* ) echo Exiting; exit;; |
|||
* ) echo "Please answer yes or no.";; |
|||
esac |
|||
done |
|||
|
|||
currentmod="${usermodselect}" |
|||
fn_mod_get_info |
|||
fn_check_mod_files_list |
|||
|
|||
# Uninstall the mod |
|||
fn_script_log_info "Removing ${modsfilelistsize} files from ${modprettyname}" |
|||
echo -e "removing ${modprettyname}" |
|||
echo -e "* ${modsfilelistsize} files to be removed" |
|||
echo -e "* location: ${modinstalldir}" |
|||
sleep 1 |
|||
# Go through every file and remove it |
|||
modfileline="1" |
|||
tput sc |
|||
while [ "${modfileline}" -le "${modsfilelistsize}" ]; do |
|||
# Current line defines current file to remove |
|||
currentfileremove="$(sed "${modfileline}q;d" "${modsdir}/${modcommand}-files.txt")" |
|||
# If file or directory exists, then remove it |
|||
|
|||
if [ -f "${modinstalldir}/${currentfileremove}" ]||[ -d "${modinstalldir}/${currentfileremove}" ]; then |
|||
rm -rf "${modinstalldir}/${currentfileremove}" |
|||
((exitcode=$?)) |
|||
if [ ${exitcode} -ne 0 ]; then |
|||
fn_script_log_fatal "Removing ${modinstalldir}/${currentfileremove}" |
|||
break |
|||
else |
|||
fn_script_log_pass "Removing ${modinstalldir}/${currentfileremove}" |
|||
fi |
|||
fi |
|||
tput rc; tput el |
|||
printf "removing ${modprettyname} ${modfileline} / ${modsfilelistsize} : ${currentfileremove}..." |
|||
((modfileline++)) |
|||
done |
|||
if [ ${exitcode} -ne 0 ]; then |
|||
fn_print_fail_eol_nl |
|||
core_exit.sh |
|||
else |
|||
fn_print_ok_eol_nl |
|||
fi |
|||
sleep 0.5 |
|||
# Remove file list |
|||
echo -en "removing ${modcommand}-files.txt..." |
|||
sleep 0.5 |
|||
rm -rf "${modsdir}/${modcommand}-files.txt" |
|||
local exitcode=$? |
|||
if [ ${exitcode} -ne 0 ]; then |
|||
fn_script_log_fatal "Removing ${modsdir}/${modcommand}-files.txt" |
|||
fn_print_fail_eol_nl |
|||
core_exit.sh |
|||
else |
|||
fn_script_log_pass "Removing ${modsdir}/${modcommand}-files.txt" |
|||
fn_print_ok_eol_nl |
|||
fi |
|||
|
|||
# Remove mods from installed mods list |
|||
echo -en "removing ${modcommand} from ${modsinstalledlist}..." |
|||
sleep 0.5 |
|||
|
|||
sed -i "/^${modcommand}$/d" "${modsinstalledlistfullpath}" |
|||
local exitcode=$? |
|||
if [ ${exitcode} -ne 0 ]; then |
|||
fn_script_loga_fatal "Removing ${modcommand} from ${modsinstalledlist}" |
|||
fn_print_fail_eol_nl |
|||
core_exit.sh |
|||
else |
|||
fn_script_loga_pass "Removing ${modcommand} from ${modsinstalledlist}" |
|||
fn_print_ok_eol_nl |
|||
fi |
|||
|
|||
# Oxide fix |
|||
# Oxide replaces server files, so a validate is required after uninstall |
|||
if [ "${engine}" == "unity3d" ]&&[[ "${modprettyname}" == *"Oxide"* ]]; then |
|||
fn_print_information_nl "Validating to restore original ${gamename} files replaced by Oxide" |
|||
fn_script_log "Validating to restore original ${gamename} files replaced by Oxide" |
|||
exitbypass="1" |
|||
command_validate.sh |
|||
unset exitbypass |
|||
fi |
|||
echo "${modprettyname} removed" |
|||
fn_script_log "${modprettyname} removed" |
|||
|
|||
core_exit.sh |
@ -0,0 +1,110 @@ |
|||
#!/bin/bash |
|||
# LGSM command_mods_update.sh function |
|||
# Author: Daniel Gibbs |
|||
# Contributor: UltimateByte |
|||
# Website: https://gameservermanagers.com |
|||
# Description: Updates installed mods along with mods_list.sh and mods_core.sh. |
|||
|
|||
local commandname="MODS" |
|||
local commandaction="Mods Update" |
|||
local function_selfname="$(basename $(readlink -f "${BASH_SOURCE[0]}"))" |
|||
|
|||
check.sh |
|||
mods_core.sh |
|||
|
|||
# Prevents specific files being overwritten upon update (set by ${modkeepfiles}) |
|||
# For that matter, remove cfg files after extraction before copying them to destination |
|||
fn_remove_cfg_files(){ |
|||
if [ "${modkeepfiles}" != "OVERWRITE" ]&&[ "${modkeepfiles}" != "NOUPDATE" ]; then |
|||
echo -e "the following files/directories will be preserved:" |
|||
sleep 0.5 |
|||
# Count how many files there are to remove |
|||
filestopreserve="$(echo "${modkeepfiles}" | awk -F ';' '{ print NF }')" |
|||
# Test all subvalues of "modkeepfiles" using the ";" separator |
|||
for ((preservefilesindex=1; preservefilesindex < ${filestopreserve}; preservefilesindex++)); do |
|||
# Put the current file we are looking for into a variable |
|||
filetopreserve="$(echo "${modkeepfiles}" | awk -F ';' -v x=${preservefilesindex} '{ print $x }' )" |
|||
echo -e " * serverfiles/${filetopreserve}" |
|||
# If it matches an existing file that have been extracted delete the file |
|||
if [ -f "${extractdir}/${filetopreserve}" ]||[ -d "${extractdir}/${filetopreserve}" ]; then |
|||
rm -r "${extractdir}/${filetopreserve}" |
|||
# Write the file path in a tmp file, to rebuild a full file list as it is rebuilt upon update |
|||
if [ ! -f "${modsdir}/.removedfiles.tmp" ]; then |
|||
touch "${modsdir}/.removedfiles.tmp" |
|||
fi |
|||
echo "${filetopreserve}" >> "${modsdir}/.removedfiles.tmp" |
|||
fi |
|||
done |
|||
fi |
|||
} |
|||
|
|||
fn_print_dots "Update addons/mods" |
|||
sleep 0.5 |
|||
fn_mods_check_installed |
|||
fn_print_info_nl "Update addons/mods: ${installedmodscount} addons/mods will be updated" |
|||
fn_script_log_info "${installedmodscount} mods or addons will be updated" |
|||
fn_mods_installed_list |
|||
# Go through all available commands, get details and display them to the user |
|||
for ((ulindex=0; ulindex < ${#installedmodslist[@]}; ulindex++)); do |
|||
# Current mod is the "ulindex" value of the array we're going through |
|||
currentmod="${installedmodslist[ulindex]}" |
|||
fn_mod_get_info |
|||
# Display installed mods and the update policy |
|||
if [ -z "${modkeepfiles}" ]; then |
|||
# If modkeepfiles is not set for some reason, that's a problem |
|||
fn_script_log_error "Could not find update policy for ${modprettyname}" |
|||
fn_print_error_nl "Could not find update policy for ${modprettyname}" |
|||
exitcode="1" |
|||
core_exit.sh |
|||
# If the mod won't get updated |
|||
elif [ "${modkeepfiles}" == "NOUPDATE" ]; then |
|||
echo -e " * ${red}{modprettyname}${default} (won't be updated)" |
|||
# If the mode is just overwritten |
|||
elif [ "${modkeepfiles}" == "OVERWRITE" ]; then |
|||
echo -e " * ${modprettyname} (overwrite)" |
|||
else |
|||
echo -e " * ${yellow}${modprettyname}${default} (retain common custom files)" |
|||
fi |
|||
done |
|||
sleep 1 |
|||
|
|||
## Update |
|||
# List all installed mods and apply update |
|||
# Reset line value |
|||
installedmodsline="1" |
|||
while [ ${installedmodsline} -le ${installedmodscount} ]; do |
|||
currentmod="$(sed "${installedmodsline}q;d" "${modsinstalledlistfullpath}")" |
|||
if [ -n "${currentmod}" ]; then |
|||
fn_mod_get_info |
|||
# Don not update mod if the policy is set to "NOUPDATE" |
|||
if [ "${modkeepfiles}" == "NOUPDATE" ]; then |
|||
fn_print_info "${modprettyname} will not be updated to preserve custom files" |
|||
fn_script_log_info "${modprettyname} will not be updated to preserve custom files" |
|||
else |
|||
echo "" |
|||
echo "==> Updating ${modprettyname}" |
|||
fn_create_mods_dir |
|||
fn_mods_clear_tmp_dir |
|||
fn_mods_create_tmp_dir |
|||
fn_mod_install_files |
|||
fn_mod_lowercase |
|||
fn_remove_cfg_files |
|||
fn_mod_create_filelist |
|||
fn_mod_copy_destination |
|||
fn_mod_add_list |
|||
fn_mod_tidy_files_list |
|||
fn_mods_clear_tmp_dir |
|||
fi |
|||
((installedmodsline++)) |
|||
else |
|||
fn_print_fail "No mod was selected" |
|||
fn_script_log_fatal "No mod was selected" |
|||
exitcode="1" |
|||
core_exit.sh |
|||
fi |
|||
done |
|||
echo "" |
|||
fn_print_ok_nl "Mods update complete" |
|||
fn_script_log_info "Mods update complete" |
|||
|
|||
core_exit.sh |
@ -0,0 +1,455 @@ |
|||
#!/bin/bash |
|||
# LGSM command_mods_install.sh function |
|||
# Author: Daniel Gibbs |
|||
# Contributor: UltimateByte |
|||
# Website: https://gameservermanagers.com |
|||
# Description: Core functions for mods list/install/update/remove |
|||
|
|||
local commandname="MODS" |
|||
local commandaction="addons/mods" |
|||
local function_selfname="$(basename $(readlink -f "${BASH_SOURCE[0]}"))" |
|||
|
|||
# Files and Directories |
|||
modsdir="${lgsmdir}/mods" |
|||
modstmpdir="${modsdir}/tmp" |
|||
extractdir="${modstmpdir}/extract" |
|||
modsinstalledlist="installed-mods.txt" |
|||
modsinstalledlistfullpath="${modsdir}/${modsinstalledlist}" |
|||
|
|||
|
|||
|
|||
## Installation |
|||
|
|||
# Download management |
|||
fn_mod_install_files(){ |
|||
fn_fetch_file "${modurl}" "${modstmpdir}" "${modfilename}" |
|||
# Check if variable is valid checking if file has been downloaded and exists |
|||
if [ ! -f "${modstmpdir}/${modfilename}" ]; then |
|||
fn_print_failure "An issue occurred downloading ${modprettyname}" |
|||
fn_script_log_fatal "An issue occurred downloading ${modprettyname}" |
|||
core_exit.sh |
|||
fi |
|||
if [ ! -d "${extractdir}" ]; then |
|||
mkdir -p "${extractdir}" |
|||
fi |
|||
fn_dl_extract "${modstmpdir}" "${filename}" "${extractdir}" |
|||
} |
|||
|
|||
# Convert mod files to lowercase if needed |
|||
fn_mod_lowercase(){ |
|||
if [ "${modlowercase}" == "LowercaseOn" ]; then |
|||
|
|||
echo -ne "converting ${modprettyname} files to lowercase..." |
|||
sleep 0.5 |
|||
fn_script_log_info "Converting ${modprettyname} files to lowercase" |
|||
files=$(find "${extractdir}" -depth | wc -l) |
|||
echo -en "\r" |
|||
while read -r src; do |
|||
dst=`dirname "${src}"`/`basename "${src}" | tr '[A-Z]' '[a-z]'` |
|||
if [ "${src}" != "${dst}" ] |
|||
then |
|||
[ ! -e "${dst}" ] && mv -T "${src}" "${dst}" || echo "${src} was not renamed" |
|||
local exitcode=$? |
|||
((renamedwc++)) |
|||
fi |
|||
echo -ne "${renamedwc} / ${totalfileswc} / $files converting ${modprettyname} files to lowercase..." $'\r' |
|||
((totalfileswc++)) |
|||
done < <(find "${extractdir}" -depth) |
|||
echo -ne "${renamedwc} / ${totalfileswc} / $files converting ${modprettyname} files to lowercase..." |
|||
|
|||
if [ ${exitcode} -ne 0 ]; then |
|||
fn_print_fail_eol_nl |
|||
core_exit.sh |
|||
else |
|||
fn_print_ok_eol_nl |
|||
fi |
|||
sleep 0.5 |
|||
fi |
|||
} |
|||
|
|||
# Create ${modcommand}-files.txt containing the full extracted file/directory list |
|||
fn_mod_create_filelist(){ |
|||
echo -ne "building ${modcommand}-files.txt..." |
|||
sleep 0.5 |
|||
# ${modsdir}/${modcommand}-files.txt |
|||
find "${extractdir}" -mindepth 1 -printf '%P\n' > "${modsdir}/${modcommand}-files.txt" |
|||
local exitcode=$? |
|||
if [ ${exitcode} -ne 0 ]; then |
|||
fn_print_fail_eol_nl |
|||
fn_script_log_fatal "Building ${modsdir}/${modcommand}-files.txt" |
|||
core_exit.sh |
|||
else |
|||
fn_print_ok_eol_nl |
|||
fn_script_log_pass "Building ${modsdir}/${modcommand}-files.txt" |
|||
fi |
|||
# Adding removed files if needed |
|||
if [ -f "${modsdir}/.removedfiles.tmp" ]; then |
|||
cat "${modsdir}/.removedfiles.tmp" >> "${modsdir}/${modcommand}-files.txt" |
|||
fi |
|||
sleep 0.5 |
|||
} |
|||
|
|||
# Copy the mod into serverfiles |
|||
fn_mod_copy_destination(){ |
|||
echo -ne "copying ${modprettyname} to ${modinstalldir}..." |
|||
sleep 0.5 |
|||
cp -Rf "${extractdir}/." "${modinstalldir}/" |
|||
local exitcode=$? |
|||
if [ ${exitcode} -ne 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 |
|||
} |
|||
|
|||
# Add the mod to the installed-mods.txt |
|||
fn_mod_add_list(){ |
|||
if [ ! -n "$(sed -n "/^${modcommand}$/p" "${modsinstalledlistfullpath}")" ]; then |
|||
echo "${modcommand}" >> "${modsinstalledlistfullpath}" |
|||
fn_script_log_info "${modcommand} added to ${modsinstalledlist}" |
|||
fi |
|||
} |
|||
|
|||
# Prevent sensitive directories from being erased upon uninstall by removing them from: ${modcommand}-files.txt |
|||
fn_mod_tidy_files_list(){ |
|||
# Check file list validity |
|||
fn_check_mod_files_list |
|||
# Output to the user |
|||
echo -ne "tidy up ${modcommand}-files.txt..." |
|||
sleep 0.5 |
|||
fn_script_log_info "Tidy up ${modcommand}-files.txt" |
|||
# Lines/files to remove from file list (end with ";" separator) |
|||
removefromlist="cfg;addons;" |
|||
# Loop through files to remove from file list, |
|||
# generate elements to remove from list |
|||
removefromlistamount="$(echo "${removefromlist}" | awk -F ';' '{ print NF }')" |
|||
# Test all subvalue of "removefromlist" using the ";" separator |
|||
for ((filesindex=1; filesindex < removefromlistamount; filesindex++)); do |
|||
# Put current file into test variable |
|||
removefilevar="$(echo "${removefromlist}" | awk -F ';' -v x=${filesindex} '{ print $x }')" |
|||
# Delete line(s) matching exactly |
|||
sed -i "/^${removefilevar}$/d" "${modsdir}/${modcommand}-files.txt" |
|||
# Exit on error |
|||
local exitcode=$? |
|||
if [ ${exitcode} -ne 0 ]; then |
|||
fn_print_fail_eol_nl |
|||
fn_script_log_fatal "Error while tidying line: ${removefilevar} from: ${modsdir}/${modcommand}-files.txt" |
|||
core_exit.sh |
|||
break |
|||
fi |
|||
done |
|||
fn_print_ok_eol_nl |
|||
# Sourcemod fix |
|||
# Remove metamod from sourcemod fileslist |
|||
if [ "${modcommand}" == "sourcemod" ]; then |
|||
# Remove addons/metamod & addons/metamod/sourcemod.vdf from ${modcommand}-files.txt |
|||
sed -i "/^addons\/metamod$/d" "${modsdir}/${modcommand}-files.txt" |
|||
sed -i "/^addons\/metamod\/sourcemod.vdf$/d" "${modsdir}/${modcommand}-files.txt" |
|||
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}" |
|||
exitcode="1" |
|||
core_exit.sh |
|||
fi |
|||
} |
|||
|
|||
# Define all variables for a mod at once when index is set to a separator |
|||
fn_mods_define(){ |
|||
if [ -z "$index" ]; then |
|||
fn_script_log_fatal "index variable not set. Please report an issue." |
|||
fn_print_error "index variable not set. Please report an issue." |
|||
echo "* https://github.com/GameServerManagers/LinuxGSM/issues" |
|||
core_exit.sh |
|||
fi |
|||
modcommand="${mods_global_array[index+1]}" |
|||
modprettyname="${mods_global_array[index+2]}" |
|||
modurl="${mods_global_array[index+3]}" |
|||
modfilename="${mods_global_array[index+4]}" |
|||
modsubdirs="${mods_global_array[index+5]}" |
|||
modlowercase="${mods_global_array[index+6]}" |
|||
modinstalldir="${mods_global_array[index+7]}" |
|||
modkeepfiles="${mods_global_array[index+8]}" |
|||
modengines="${mods_global_array[index+9]}" |
|||
modgames="${mods_global_array[index+10]}" |
|||
modexcludegames="${mods_global_array[index+11]}" |
|||
modsite="${mods_global_array[index+12]}" |
|||
moddescription="${mods_global_array[index+13]}" |
|||
} |
|||
|
|||
# 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 [ -n "${installedmodscount}" ] ;then |
|||
fn_script_log_info "${installedmodscount} addons/mods are currently installed" |
|||
fi |
|||
} |
|||
|
|||
# Loops through mods_global_array to define available mods & provide available commands for mods installation |
|||
fn_mods_available(){ |
|||
# First, reset variables |
|||
compatiblemodslist=() |
|||
availablemodscommands=() |
|||
# Find compatible games |
|||
# Find separators through the global array |
|||
for ((index="0"; index <= ${#mods_global_array[@]}; index++)); do |
|||
# If current value is a separator; then |
|||
if [ "${mods_global_array[index]}" == "${modseparator}" ]; then |
|||
# Set mod variables |
|||
fn_mods_define |
|||
# Test if game is compatible |
|||
fn_mod_compatible_test |
|||
# If game is compatible |
|||
if [ "${modcompatibility}" == "1" ]; then |
|||
# Put it into an array to prepare user output |
|||
compatiblemodslist+=( "${modprettyname}" "${modcommand}" "${modsite}" "${moddescription}" ) |
|||
# Keep available commands in an array to make life easier |
|||
availablemodscommands+=( "${modcommand}" ) |
|||
fi |
|||
fi |
|||
done |
|||
} |
|||
|
|||
## Mod compatibility check |
|||
|
|||
# Find out if a game is compatible with a mod from a modgames (list of games supported by a mod) variable |
|||
fn_compatible_mod_games(){ |
|||
# Reset test value |
|||
modcompatiblegame="0" |
|||
# If value is set to GAMES (ignore) |
|||
if [ "${modgames}" != "GAMES" ]; then |
|||
# How many games we need to test |
|||
gamesamount="$(echo "${modgames}" | awk -F ';' '{ print NF }')" |
|||
# Test all subvalue of "modgames" using the ";" separator |
|||
for ((gamevarindex=1; gamevarindex < gamesamount; gamevarindex++)); do |
|||
# Put current game name into modtest variable |
|||
gamemodtest="$( echo "${modgames}" | awk -F ';' -v x=${gamevarindex} '{ print $x }' )" |
|||
# If game name matches |
|||
if [ "${gamemodtest}" == "${gamename}" ]; then |
|||
# Mod is compatible ! |
|||
modcompatiblegame="1" |
|||
fi |
|||
done |
|||
fi |
|||
} |
|||
|
|||
# Find out if an engine is compatible with a mod from a modengines (list of engines supported by a mod) variable |
|||
fn_compatible_mod_engines(){ |
|||
# Reset test value |
|||
modcompatibleengine="0" |
|||
# If value is set to ENGINES (ignore) |
|||
if [ "${modengines}" != "ENGINES" ]; then |
|||
# How many engines we need to test |
|||
enginesamount="$(echo "${modengines}" | awk -F ';' '{ print NF }')" |
|||
# Test all subvalue of "modengines" using the ";" separator |
|||
for ((gamevarindex=1; gamevarindex < ${enginesamount}; gamevarindex++)); do |
|||
# Put current engine name into modtest variable |
|||
enginemodtest="$( echo "${modengines}" | awk -F ';' -v x=${gamevarindex} '{ print $x }' )" |
|||
# If engine name matches |
|||
if [ "${enginemodtest}" == "${engine}" ]; then |
|||
# Mod is compatible! |
|||
modcompatibleengine="1" |
|||
fi |
|||
done |
|||
fi |
|||
} |
|||
|
|||
# Find out if a game is not compatible with a mod from a modnotgames (list of games not supported by a mod) variable |
|||
fn_not_compatible_mod_games(){ |
|||
# Reset test value |
|||
modeincompatiblegame="0" |
|||
# If value is set to NOTGAMES (ignore) |
|||
if [ "${modexcludegames}" != "NOTGAMES" ]; then |
|||
# How many engines we need to test |
|||
excludegamesamount="$(echo "${modexcludegames}" | awk -F ';' '{ print NF }')" |
|||
# Test all subvalue of "modexcludegames" using the ";" separator |
|||
for ((gamevarindex=1; gamevarindex < excludegamesamount; gamevarindex++)); do |
|||
# Put current engine name into modtest variable |
|||
excludegamemodtest="$( echo "${modexcludegames}" | awk -F ';' -v x=${gamevarindex} '{ print $x }' )" |
|||
# If engine name matches |
|||
if [ "${excludegamemodtest}" == "${gamename}" ]; then |
|||
# Mod is compatible! |
|||
modeincompatiblegame="1" |
|||
fi |
|||
done |
|||
fi |
|||
} |
|||
|
|||
# Sums up if a mod is compatible or not with modcompatibility=0/1 |
|||
fn_mod_compatible_test(){ |
|||
# Test game and engine compatibility |
|||
fn_compatible_mod_games |
|||
fn_compatible_mod_engines |
|||
fn_not_compatible_mod_games |
|||
if [ "${modeincompatiblegame}" == "1" ]; then |
|||
modcompatibility="0" |
|||
elif [ "${modcompatibleengine}" == "1" ]||[ "${modcompatiblegame}" == "1" ]; then |
|||
modcompatibility="1" |
|||
else |
|||
modcompatibility="0" |
|||
fi |
|||
} |
|||
|
|||
## Directory management |
|||
|
|||
# Create mods files and directories if it doesn't exist |
|||
fn_create_mods_dir(){ |
|||
# Create mod install directory |
|||
if [ ! -d "${modinstalldir}" ]; then |
|||
echo "creating mods install directory ${modinstalldir}..." |
|||
mkdir -p "${modinstalldir}" |
|||
exitcode=$? |
|||
if [ ${exitcode} -ne 0 ]; then |
|||
fn_print_fail_eol_nl |
|||
fn_script_log_fatal "Creating mod download dir ${modinstalldir}" |
|||
core_exit.sh |
|||
else |
|||
fn_print_ok_eol_nl |
|||
fn_script_log_pass "Creating mod download dir ${modinstalldir}" |
|||
fi |
|||
sleep 0.5 |
|||
fi |
|||
|
|||
# Create lgsm/data/${modsinstalledlist} |
|||
if [ ! -f "${modsinstalledlistfullpath}" ]; then |
|||
touch "${modsinstalledlistfullpath}" |
|||
fn_script_log_info "Created ${modsinstalledlistfullpath}" |
|||
fi |
|||
} |
|||
|
|||
# Create tmp download mod directory |
|||
fn_mods_create_tmp_dir(){ |
|||
if [ ! -d "${modstmpdir}" ]; then |
|||
mkdir -p "${modstmpdir}" |
|||
exitcode=$? |
|||
echo -ne "creating mod download directory ${modstmpdir}..." |
|||
if [ ${exitcode} -ne 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 -ne "clearing mod download directory ${modstmpdir}..." |
|||
rm -r "${modstmpdir}" |
|||
exitcode=$? |
|||
if [ ${exitcode} -ne 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 "${modsdir}/.removedfiles.tmp" |
|||
fi |
|||
} |
|||
|
|||
# Counts how many mods were installed |
|||
fn_mods_count_installed(){ |
|||
if [ -f "${modsinstalledlistfullpath}" ]; then |
|||
installedmodscount="$(wc -l < "${modsinstalledlistfullpath}")" |
|||
else |
|||
installedmodscount=0 |
|||
fi |
|||
} |
|||
|
|||
# Exits if no mods were installed |
|||
fn_mods_check_installed(){ |
|||
# Count installed mods |
|||
fn_mods_count_installed |
|||
# If no mods are found |
|||
if [ ${installedmodscount} -eq 0 ]; then |
|||
echo "" |
|||
fn_print_failure_nl "No installed mods or addons were found" |
|||
echo " * Install mods using LGSM first with: ./${selfname} mods-install" |
|||
fn_script_log_fail "No installed mods or addons were found." |
|||
core_exit.sh |
|||
fi |
|||
} |
|||
|
|||
# Checks that mod files list exists and isn't empty |
|||
fn_check_mod_files_list(){ |
|||
# File list must exist and be valid before any operation on it |
|||
if [ -f "${modsdir}/${modcommand}-files.txt" ]; then |
|||
# How many lines is the file list |
|||
modsfilelistsize="$(wc -l < "${modsdir}/${modcommand}-files.txt")" |
|||
# If file list is empty |
|||
if [ "${modsfilelistsize}" -eq 0 ]; then |
|||
fn_print_failure "${modcommand}-files.txt is empty" |
|||
echo "* Unable to remove ${modprettyname}" |
|||
fn_script_log_fatal "${modcommand}-files.txt is empty: Unable to remove ${modprettyname}." |
|||
core_exit.sh |
|||
fi |
|||
else |
|||
fn_print_failure "${modsdir}/${modcommand}-files.txt does not exist" |
|||
fn_script_log_fatal "${modsdir}/${modcommand}-files.txt does not exist: Unable to remove ${modprettyname}." |
|||
core_exit.sh |
|||
fi |
|||
} |
|||
|
|||
## Database initialisation |
|||
|
|||
mods_list.sh |
|||
fn_mods_available |
@ -0,0 +1,73 @@ |
|||
#!/bin/bash |
|||
# LGSM mods_list.sh function |
|||
# Author: Daniel Gibbs |
|||
# Contributor: UltimateByte |
|||
# Website: https://gameservermanagers.com |
|||
# Description: Lists and defines available mods for LGSM supported servers; works along with mods_core.sh. |
|||
# Usage: To add a mod, you need to add an array variable following the guide to set proper values; |
|||
# Usage: Then add this array to the mods_global_array. |
|||
# Usage: If needed, you can scrape the download URL first. |
|||
|
|||
local commandname="MODS" |
|||
local commandaction="List Mods" |
|||
local function_selfname="$(basename $(readlink -f "${BASH_SOURCE[0]}"))" |
|||
|
|||
# Get a proper URL for mods that don't provide a good one (optional) |
|||
fn_script_log_info "Retrieving latest mods URLs" |
|||
# Metamod |
|||
metamodscrapeurl="http://www.gsptalk.com/mirror/sourcemod" |
|||
metamodlatestfile="$(wget "${metamodscrapeurl}/?MD" -q -O -| grep "mmsource" | grep "\-linux" | head -n1 | awk -F '>' '{ print $3 }' | awk -F '<' '{ print $1}')" |
|||
metamoddownloadurl="http://cdn.probablyaserver.com/sourcemod/" |
|||
metamodurl="${metamoddownloadurl}/${metamodlatestfile}" |
|||
# Sourcemod |
|||
sourcemodmversion="1.8" |
|||
sourcemodscrapeurl="https://sm.alliedmods.net/smdrop/${sourcemodmversion}/sourcemod-latest-linux" |
|||
sourcemodlatestfile="$(wget "${sourcemodscrapeurl}" -q -O -)" |
|||
sourcemoddownloadurl="https://sm.alliedmods.net/smdrop/${sourcemodmversion}" |
|||
sourcemodurl="${sourcemoddownloadurl}/${sourcemodlatestfile}" |
|||
|
|||
# Define mods information (required) |
|||
|
|||
# Separator name |
|||
modseparator="MOD" |
|||
|
|||
# REQUIRED: mod_info_name=( MOD "modcommand" "Pretty Name" "URL" "filename" "modsubdirs" "LowercaseOn/Off" "/files/to/keep;" "/install/path" "ENGINES" "GAMES" "NOTGAMES" "AUTHOR_URL" "Short Description" ) |
|||
# Example 1) Well made mod: mod_info_name=( MOD "awesomemod" "This is an Awesome Mod" "https://awesomemod.com/latest.zip" "awesomemod.zip" "0" "LowercaseOff" "OVERWRITE" "${systemdir}/addons" "source;unity3d;" "GAMES" "NOTGAMES" "https://awesomemod.com/" "This mod knows that 42 is the answer" ) |
|||
# Example 2) Poorly made mod: mod_info_name=( MOD "stupidmod" "This is a stupid mod" "${crappymodurl}" "StupidMod.zip" "2" "LowercaseOn" "cfg;data/crappymod;" "${systemdir}" "source;" "GAMES" "Garry's mod;Counter-Strike: Source;" "This mod is dumber than dumb" ) |
|||
# None of those values can be empty |
|||
# index | Usage |
|||
# [0] | MOD: separator, all mods must begin with it |
|||
# [1] | "modcommand": the LGSM name and command to install the mod (must be unique and lowercase) |
|||
# [2] | "Pretty Name": the common name people use to call the mod that will be displayed to the user |
|||
# [3] | "URL": link to the mod archive file; can be a variable previously defined while scraping a URL |
|||
# [4] | "filename": the output filename |
|||
# [5] | "modsubdirs": in how many subdirectories is the mod (none is 0) (not used at release, but could be in the future) |
|||
# [6] | "LowercaseOn/Off": LowercaseOff or LowercaseOn: enable/disable converting extracted files and directories to lowercase (some games require it) |
|||
# [7] | "modinstalldir": the directory in which to install the mode ( use LGSM dir variables such as ${systemdir}) |
|||
# [8] | "/files/to/keep;", files & directories that should not be overwritten upon update, separated and ended with a semicolon; you can also use "OVERWRITE" value to ignore the value or "NOUPDATE" to disallow updating; for files to keep upon uninstall, see fn_mod_tidy_files_list from mods_core.sh |
|||
# [9] | "Supported Engines;": list them according to LGSM ${engine} variables, separated and ended with a semicolon, or use ENGINES to ignore the value |
|||
# [10] | "Supported Games;": list them according to LGSM ${gamename} variables, separated and ended with a semicolon, or use GAMES to ignore the value |
|||
# [11] | "Unsupported Games;": list them according to LGSM ${gamename} variables, separated and ended with a semicolon, or use NOTGAMES to ignore the value (useful to exclude a game when using Supported Engines) |
|||
# [12] | "AUTHOR_URL" is the author's website, displayed to the user when chosing mods to install |
|||
# [13] | "Short Description" a description showed to the user upon installation/removal |
|||
|
|||
# Source mods |
|||
mod_info_metamod=( MOD "metamod" "MetaMod" "${metamodurl}" "${metamodlatestfile}" "0" "LowercaseOff" "${systemdir}" "addons/metamod/metaplugins.ini;" "source;" "GAMES" "NOTGAMES" "https://www.sourcemm.net" "Plugins Framework" ) |
|||
mod_info_sourcemod=( MOD "sourcemod" "SourceMod" "${sourcemodurl}" "${sourcemodlatestfile}" "0" "LowercaseOff" "${systemdir}" "cfg;addons/sourcemod/configs;" "source;" "GAMES" "NOTGAMES" "http://www.sourcemod.net" "Admin Features (requires MetaMod)" ) |
|||
# Garry's Mod Addons |
|||
mod_info_ulib=( MOD "ulib" "ULib" "https://codeload.github.com/TeamUlysses/ulib/zip/master" "ulib-master.zip" "0" "LowercaseOff" "${systemdir}/addons" "OVERWRITE" "ENGINES" "Garry's Mod;" "NOTGAMES" "http://ulyssesmod.net" "Complete Framework" ) |
|||
mod_info_ulx=( MOD "ulx" "ULX" "https://codeload.github.com/TeamUlysses/ulx/zip/master" "ulx-master.zip" "0" "LowercaseOff" "${systemdir}/addons" "OVERWRITE" "ENGINES" "Garry's Mod;" "NOTGAMES" "http://ulyssesmod.net" "Admin Panel (requires ULib)" ) |
|||
mod_info_utime=( MOD "utime" "UTime" "https://github.com/TeamUlysses/utime/archive/master.zip" "utime-master.zip" "0" "LowercaseOff" "${systemdir}/addons" "OVERWRITE" "ENGINES" "Garry's Mod;" "NOTGAMES" "http://ulyssesmod.net" "Keep track of players play time" ) |
|||
mod_info_uclip=( MOD "uclip" "UClip" "https://github.com/TeamUlysses/uclip/archive/master.zip" "uclip-master.zip" "0" "LowercaseOff" "${systemdir}/addons" "OVERWRITE" "ENGINES" "Garry's Mod;" "NOTGAMES" "http://ulyssesmod.net" "An alternative to noclip" ) |
|||
mod_info_acf=( MOD "acf" "Armoured Combat Framework" "https://github.com/nrlulz/ACF/archive/master.zip" "acf-master.zip" "0" "LowercaseOn" "${systemdir}/addons" "acf-master/lua/acf/shared/guns;" "ENGINES" "Garry's Mod;" "NOTGAMES" "https://github.com/nrlulz/ACF" "Realistic Wepons & Engines" ) |
|||
mod_info_acf_missiles=( MOD "acfmissiles" "ACF Missiles" "https://github.com/Bubbus/ACF-Missiles/archive/master.zip" "acf-missiles-master.zip" "0" "LowercaseOn" "${systemdir}/addons" "OVERWRITE" "ENGINES" "Garry's Mod;" "NOTGAMES" "https://github.com/Bubbus/ACF-Missiles" "More missiles for ACF" ) |
|||
mod_info_acf_advdupe2=( MOD "advdupe2" "Advanced Duplicator 2" "https://github.com/wiremod/advdupe2/archive/master.zip" "advdupe2-master.zip" "0" "LowercaseOn" "${systemdir}/addons" "OVERWRITE" "ENGINES" "Garry's Mod;" "NOTGAMES" "http://www.wiremod.com" "Save your constructions" ) |
|||
mod_info_darkrp=( MOD "darkrp" "DarkRP" "https://github.com/FPtje/DarkRP/archive/master.zip" "darkrp-master.zip" "0" "LowercaseOn" "${systemdir}/addons" "OVERWRITE" "ENGINES" "Garry's Mod;" "NOTGAMES" "http://darkrp.com" "Most popular gamemode" ) |
|||
mod_info_darkrpmodification=( MOD "darkrpmodification" "DarkRP Modification" "https://github.com/FPtje/darkrpmodification/archive/master.zip" "darkrpmodification-master.zip" "0" "LowercaseOff" "${systemdir}/addons" "NOUPDATE" "ENGINES" "Garry's Mod;" "NOTGAMES" "http://darkrp.com" "Customize DarkRP settings" ) |
|||
# Oxidemod |
|||
mod_info_rustoxide=( MOD "rustoxide" "Oxide for Rust" "https://raw.githubusercontent.com/OxideMod/Snapshots/master/Oxide-Rust.zip" "Oxide-Rust_Linux.zip" "0" "LowercaseOff" "${systemdir}" "OVERWRITE" "ENGINES" "Rust;" "NOTGAMES" "http://oxidemod.org/downloads/oxide-for-rust.1659" "Allows for the use of plugins" ) |
|||
mod_info_hwoxide=( MOD "hwoxide" "Oxide for Hurtworld" "https://raw.githubusercontent.com/OxideMod/Snapshots/master/Oxide-Hurtworld.zip" "Oxide-Hurtworld_Linux.zip" "0" "LowercaseOff" "${systemdir}" "OVERWRITE" "ENGINES" "Hurtworld;" "NOTGAMES" "http://oxidemod.org/downloads/oxide-for-hurtworld.1332" "Allows for the use of plugins" ) |
|||
mod_info_sdtdoxide=( MOD "sdtdoxide" "Oxide for 7 Days To Die" "https://raw.githubusercontent.com/OxideMod/Snapshots/master/Oxide-7DaysToDie.zip" "Oxide-7DaysToDie_Linux.zip" "0" "LowercaseOff" "${systemdir}" "OVERWRITE" "ENGINES" "7 Days To Die;" "NOTGAMES" "http://oxidemod.org/downloads/oxide-for-7-days-to-die.813" "Allows for the use of plugins" ) |
|||
|
|||
# REQUIRED: Set all mods info into the global array |
|||
mods_global_array=( "${mod_info_metamod[@]}" "${mod_info_sourcemod[@]}" "${mod_info_ulib[@]}" "${mod_info_ulx[@]}" "${mod_info_utime[@]}" "${mod_info_uclip[@]}" "${mod_info_acf[@]}" "${mod_info_acf_missiles[@]}" "${mod_info_acf_sweps[@]}" "${mod_info_advdupe2[@]}" "${mod_info_darkrp[@]}" "${mod_info_darkrpmodification[@]}" "${mod_info_rustoxide[@]}" "${mod_info_hwoxide[@]}" "${mod_info_sdtdoxide[@]}" ) |
Loading…
Reference in new issue