Преглед изворни кода

Major re-organise

This is a major sort out of the new functions. To simplify and make it easier to follow the code. All functionality remains.

Possible bugs in this that will be resolved after testing
Daniel Gibbs пре 9 година
родитељ
комит
f1dbdd6cc6

+ 103 - 57
lgsm/functions/command_mods_install.sh

@@ -9,67 +9,113 @@ local commandname="MODS"
 local commandaction="addons/mods"
 local function_selfname="$(basename $(readlink -f "${BASH_SOURCE[0]}"))"
 
-fn_mods_install_init(){
-	fn_print_header
-	# Display installed mods
-	fn_installed_mods_light_list
+check.sh
+mods_core.sh
+
+fn_print_header
+
+# exits if no mods installed
+fn_mods_check_installed
 
-	echo "Available addons/mods"
+# Displays a list of installed mods
+fn_mods_installed_list
+if [ ${installedmodscount} -gt 0 ]; then
+	echo "Installed addons/mods"
 	echo "================================="
-	# Display available mods from mods_list.sh
-	fn_mods_show_available
-	echo ""
-	# Keep prompting as long as the user input doesn't correspond to an available mod
-	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
+	# 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 " * \e[1m${green}${modcommand}${default}${default}"
+	((totalmodsinstalled++))
 	done
 	echo ""
-	echo "Installing ${modprettyname}"
-	echo "================================="
-	fn_script_log_info "${modprettyname} selected for install"
-	# Gives a pretty name to the user and get all mod info
-	currentmod="${usermodselect}"
-}
+fi
 
-# Run all required operation
-fn_mod_installation(){
-	# Get mod info
-	fn_mod_get_info_from_command
-	# Check if mod is already installed
-	fn_mod_already_installed
-	# Check and create required files
-	fn_mods_files
-	# Clear lgsm/tmp/mods dir if exists then recreate it
-	fn_clear_tmp_mods
-	fn_mods_tmpdir
-	# Download & extract mod
-	fn_install_mod_dl_extract
-	# Convert to lowercase if needed
-	fn_mod_lowercase
-	# Build a file list
-	fn_mod_fileslist
-	# Copying to destination
-	fn_mod_copy_destination
-	# Ending with installation routines
-	fn_mod_add_list
-	# Post install fixes
-	fn_postinstall_tasks
-	# Cleaning
-	fn_clear_tmp_mods
-	echo "${modprettyname} installed"
-	fn_script_log_pass "${modprettyname} installed."
-}
+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 "\e[1m${displayedmodname}${default} - ${displayedmoddescription} - ${displayedmodsite}"
+	echo -e " * ${cyan}${displayedmodcommand}${default}"
+	# Increment index from the amount of values we just displayed
+	let "compatiblemodslistindex+=4"
+	((totalmods++))
+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 "${totalmods} 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
+currentmod="${usermodselect}"
+
+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
+	fi
+fn_script_log_info "User selected to continue"
+fi
+
+## Installation
+
+fn_mod_get_info
+fn_mod_already_installed
+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."
 
-check.sh
-mods_core.sh
-fn_mods_install_init
-fn_mod_installation
 core_exit.sh

+ 112 - 103
lgsm/functions/command_mods_remove.sh

@@ -9,114 +9,123 @@ 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 "================================="
 
-fn_mods_remove_init(){
-	fn_print_header
-	echo "Remove addons/mods"
-	echo "================================="
-	# A simple function to exit if no mods were installed
-	# Also returns ${installedmodscount} if mods were found
-	fn_mods_exit_if_not_installed
-	# Displays installed addons to the user
-	fn_installed_mods_medium_list
-	echo ""
-  	# Keep prompting as long as the user input doesn't correspond to an available mod
-	while [[ ! " ${installedmodslist[@]} " =~ " ${usermodselect} " ]]; do
-		echo -en "Enter a ${cyan}mod${default} to ${red}remove${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
-	# Gives a pretty name to the user and get all mod info
-	currentmod="${usermodselect}"
-	fn_mod_get_info_from_command
-	# Check file list in order to make sure we're able to remove the mod (returns ${modsfilelistsize})
-	fn_check_files_list
+## 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 "${cyan}${modcommand}${default} - \e[1m${modprettyname}${default} - ${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
 
-# Uninstall the mod
-fn_mod_remove_process(){
-	fn_script_log "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" "${modsdatadir}/${modcommand}-files.txt")"
-		# If file or directory exists, then remove it
-		fn_script_log "Removing: ${modinstalldir}/${currentfileremove}"
-		if [ -f "${modinstalldir}/${currentfileremove}" ]||[ -d "${modinstalldir}/${currentfileremove}" ]; then
-			rm -rf "${modinstalldir}/${currentfileremove}"
-			local exitcode=$?
-		fi
-		tput rc; tput el
-		printf  "removing ${modprettyname} ${totalfileswc} / ${modsfilelistsize} : ${currentfileremove}..."
+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
 
-		((totalfileswc++))
-		let modfileline=modfileline+1
-	done
-	tput rc; tput ed;
-	echo -ne "removing ${modprettyname} ${totalfileswc} / ${modsfilelistsize}..."
-	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
-	fn_script_log "Removing: ${modsdatadir}/${modcommand}-files.txt"
-	rm -rf "${modsdatadir}/${modcommand}-files.txt"
-	local exitcode=$?
-	if [ ${exitcode} -ne 0 ]; then
-		fn_print_fail_eol_nl
-		core_exit.sh
-	else
-		fn_print_ok_eol_nl
-	fi
-	# Remove from installed mods list
-	echo -en "removing ${modcommand} from ${modslockfile}..."
-	sleep 0.5
-	fn_script_log "Removing: ${modcommand} from ${modslockfilefullpath}"
-	sed -i "/^${modcommand}$/d" "${modslockfilefullpath}"
-	# Post install tasks to solve potential issues
-	local exitcode=$?
-	if [ ${exitcode} -ne 0 ]; then
-		fn_print_fail_eol_nl
-		core_exit.sh
-	else
-		fn_print_ok_eol_nl
+currentmod="${usermodselect}"
+fn_mod_get_info
+fn_check_mod_files_list
+
+# Uninstall the mod
+fn_script_log "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" "${modsdatadir}/${modcommand}-files.txt")"
+	# If file or directory exists, then remove it
+	fn_script_log "Removing: ${modinstalldir}/${currentfileremove}"
+	if [ -f "${modinstalldir}/${currentfileremove}" ]||[ -d "${modinstalldir}/${currentfileremove}" ]; then
+		rm -rf "${modinstalldir}/${currentfileremove}"
+		local exitcode=$?
 	fi
-	fn_postuninstall_tasks
-	echo "${modprettyname} removed"
-	fn_script_log "${modprettyname} removed"
-}
+	tput rc; tput el
+	printf  "removing ${modprettyname} ${modfileline} / ${modsfilelistsize} : ${currentfileremove}..."
+	((modfileline++))
+done
+tput rc; tput ed;
+echo -ne "removing ${modprettyname} ${modfileline} / ${modsfilelistsize}..."
+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
+fn_script_log "Removing: ${modsdatadir}/${modcommand}-files.txt"
+rm -rf "${modsdatadir}/${modcommand}-files.txt"
+local exitcode=$?
+if [ ${exitcode} -ne 0 ]; then
+	fn_print_fail_eol_nl
+	core_exit.sh
+else
+	fn_print_ok_eol_nl
+fi
+
+# Remove mods from installed mods list
+echo -en "removing ${modcommand} from ${modslockfile}..."
+sleep 0.5
+fn_script_log "Removing: ${modcommand} from ${modslockfilefullpath}"
+sed -i "/^${modcommand}$/d" "${modslockfilefullpath}"
+local exitcode=$?
+if [ ${exitcode} -ne 0 ]; then
+	fn_print_fail_eol_nl
+	core_exit.sh
+else
+	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"
 
-check.sh
-mods_core.sh
-fn_mods_remove_init
-fn_mod_remove_process
 core_exit.sh

+ 97 - 71
lgsm/functions/command_mods_update.sh

@@ -9,81 +9,107 @@ local commandname="MODS"
 local commandaction="Mods Update"
 local function_selfname="$(basename $(readlink -f "${BASH_SOURCE[0]}"))"
 
+check.sh
+mods_core.sh
 
-fn_mods_update_init(){
-	fn_script_log "Entering mods & addons update"
-	echo "================================="
-	echo "${gamename} mods & addons update"
-	# A simple function to exit if no mods were installed
-	# Also returns ${installedmodscount} if mods were found
-	fn_mods_exit_if_not_installed
-	echo ""
-	fn_print_information_nl "${installedmodscount} mods or addons will be updated:"
-	fn_script_log_info "${installedmodscount} mods or addons will be updated"
-	# Display a list of installed addons
-	fn_installed_mods_update_list
-}
+fn_print_header
 
-# Recursively list all installed mods and apply update
-fn_mods_update_loop(){
-	# Reset line value
-	installedmodsline="1"
-	while [ $installedmodsline -le $installedmodscount ]; do
-		# Current line defines current mod command
-		currentmod="$(sed "${installedmodsline}q;d" "${modslockfilefullpath}")"
-		if [ -n "${currentmod}" ]; then
-			# Get mod info
-			fn_mod_get_info_from_command
-			# Don't update the mod if it's policy is to "NOUPDATE"
-			if [ "${modkeepfiles}" == "NOUPDATE" ]; then
-				fn_print_info "${modprettyname} won't be updated to preserve custom files"
-				fn_script_log "${modprettyname} won't be updated to preserve custom files."
-				let installedmodsline=installedmodsline+1
-			else
-				echo ""
-				fn_print_dots_nl "Updating ${modprettyname}"
-				fn_script_log "Updating ${modprettyname}."
-				# Check and create required files
-				fn_mods_files
-				# Clear lgsm/tmp/mods dir if exists then recreate it
-				fn_clear_tmp_mods
-				fn_mods_tmpdir
-				# Download mod
-				fn_mod_dl
-				# Extract the mod
-				fn_mod_extract
-				# Convert to lowercase if needed
-				fn_mod_lowercase
-				# Remove files that should not be erased
-				fn_remove_cfg_files
-				# Build a file list
-				fn_mod_fileslist
-				# Copying to destination
-				fn_mod_copy_destination
-				# Ending with installation routines
-				fn_mod_add_list
-				# Post install fixes
-				fn_postinstall_tasks
-				# Cleaning
-				fn_clear_tmp_mods
-				fn_print_ok "${modprettyname} updated"
-				fn_script_log "${modprettyname} updated."
-				let installedmodsline=installedmodsline+1
-			fi
+echo "Update addons/mods"
+echo "================================="
+fn_mods_check_installed
+fn_print_information_nl "${installedmodscount} addons/mods will be updated"
+fn_script_log_info "${installedmodscount} mods or addons will be updated"
+fn_mods_installed_list
+echo ""
+echo "Installed addons/mods"
+echo "================================="
+# 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 "Couldn't find update policy for ${modprettyname}"
+		fn_print_error_nl "Couldn't find update policy for ${modprettyname}"
+		exitcode="1"
+		core_exit.sh
+	# If the mod won't get updated
+	elif [ "${modkeepfiles}" == "NOUPDATE" ]; then
+		echo -e " * \e[31m${modprettyname}${default} (won't be updated)"
+	# If the mode is just overwritten
+	elif [ "${modkeepfiles}" == "OVERWRITE" ]; then
+		echo -e " * \e[1m${modprettyname}${default} (overwrite)"
+	else
+		echo -e " * ${yellow}${modprettyname}${default} (common custom files remain untouched)"
+	fi
+done
+
+## Update
+# List all installed mods and apply update
+# Reset line value
+installedmodsline="1"
+while [ ${installedmodsline} -le ${installedmodscount} ]; do
+	currentmod="$(sed "${installedmodsline}q;d" "${modslockfilefullpath}")"
+	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
-			fn_print_fail "No mod was selected"
-			fn_script_log_fail "No mod was selected."
-			exitcode="1"
-			core_exit.sh
+			echo ""
+			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
-	done
-	echo ""
-	fn_print_ok_nl "Mods update complete"
-	fn_script_log "Mods update complete."
+		((installedmodsline++))
+	else
+		fn_print_fail "No mod was selected"
+		fn_script_log_fail "No mod was selected"
+		exitcode="1"
+		core_exit.sh
+	fi
+done
+echo ""
+fn_print_ok_nl "Mods update complete"
+fn_script_log "Mods update complete"
+
+# 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
+		fn_print_dots "Preventing overwriting of ${modprettyname} config files"
+		fn_script_log "Preventing overwriting of ${modprettyname} config files"
+		sleep 0.5
+		# Count how many files there are to remove
+		removefilesamount="$(echo "${modkeepfiles}" | awk -F ';' '{ print NF }')"
+		# Test all subvalues of "modkeepfiles" using the ";" separator
+		for ((removefilesindex=1; removefilesindex < ${removefilesamount}; removefilesindex++)); do
+			# Put the current file we are looking for into a variable
+			filetoremove="$( echo "${modkeepfiles}" | awk -F ';' -v x=${removefilesindex} '{ print $x }' )"
+			# If it matches an existing file that have been extracted delete the file
+			if [ -f "${extractdir}/${filetoremove}" ]||[ -d "${extractdir}/${filetoremove}" ]; then
+				rm -r "${extractdir}/${filetoremove}"
+				# 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 "${filetoremove}" >> "${modsdir}/.removedfiles.tmp"
+			fi
+		done
+		fn_print_ok "Preventing overwriting of ${modprettyname} config files"
+		sleep 0.5
+	fi
 }
 
-check.sh
-mods_core.sh
-fn_mods_update_init
-fn_mods_update_loop
 core_exit.sh

+ 206 - 407
lgsm/functions/mods_core.sh

@@ -16,82 +16,17 @@ extractdir="${modstmpdir}/extract"
 modsinstalledlist="installed-mods.txt"
 modsinstalledlistfullpath="${modsdir}/${modsinstalledlist}"
 
-# Database initialisation
-mods_list.sh
-
-## Directory management
-
-# Create mods files and directories if it doesn't exist
-# Assuming the game is already installed as mods_list.sh checked for it.
-fn_mods_files(){
-	# 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 ${modstmpdir}"
-			core_exit.sh
-		else
-			fn_print_ok_eol_nl
-			fn_script_log_pass "Creating mod download dir ${modstmpdir}"
-		fi
-		sleep 0.5
-	fi
-
-	# Create lgsm/data/${modsinstalledlist}
-	if [ ! -f "${modsinstalledlistfullpath}" ]; then
-		touch "${modsinstalledlistfullpath}"
-		fn_script_log "Created ${modsinstalledlistfullpath}"
-	fi
-}
-
-# Create tmp download mod directory
-fn_mods_tmpdir(){
-	if [ ! -d "${modstmpdir}" ]; then
-		mkdir -p "${modstmpdir}"
-		exitcode=$?
-		echo -ne "creating mod download dir ${modstmpdir}..."
-		if [ ${exitcode} -ne 0 ]; then
-			fn_print_fail_eol_nl
-			fn_script_log_fatal "Creating mod download dir ${modstmpdir}"
-			core_exit.sh
-		else
-			fn_print_ok_eol_nl
-			fn_script_log_pass "Creating mod download dir ${modstmpdir}"
-		fi
-	fi
-}
 
-# Clear contents of mod download directory when finished
-fn_clear_tmp_mods(){
-	if [ -d "${modstmpdir}" ]; then
-		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
-}
 
+## Installation
 
-## Download management
-fn_install_mod_dl_extract(){
+# 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 upon downloading ${modprettyname}"
+		fn_print_failure "An issue occurred downloading ${modprettyname}"
+		fn_script_log_fail "An issue occurred downloading ${modprettyname}"
 		core_exit.sh
 	fi
 	if [ ! -d "${extractdir}" ]; then
@@ -132,60 +67,29 @@ fn_mod_lowercase(){
 	fi
 }
 
-# Don't overwrite specified files 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
-		fn_print_dots "Allow for not overwriting ${modprettyname} config files"
-		fn_script_log "Allow for not overwriting ${modprettyname} config files"
-		sleep 0.5
-		# Let's count how many files there are to remove
-		removefilesamount="$(echo "${modkeepfiles}" | awk -F ';' '{ print NF }')"
-		# Test all subvalue of "modkeepfiles" using the ";" separator
-		for ((removefilesindex=1; removefilesindex < ${removefilesamount}; removefilesindex++)); do
-			# Put current file we're looking for into a variable
-			filetoremove="$( echo "${modkeepfiles}" | awk -F ';' -v x=${removefilesindex} '{ print $x }' )"
-			# If it matches an existing file that have been extracted
-			if [ -f "${extractdir}/${filetoremove}" ]||[ -d "${extractdir}/${filetoremove}" ]; then
-				# Then delete the file!
-				rm -r "${extractdir}/${filetoremove}"
-				# Write this file path in a tmp file, to rebuild a full file list since it is rebuilt upon update
-				if [ ! -f "${modsdir}/.removedfiles.tmp" ]; then
-					touch "${modsdir}/.removedfiles.tmp"
-				fi
-					echo "${filetoremove}" >> "${modsdir}/.removedfiles.tmp"
-			fi
-		done
-		fn_print_ok "Allow for preserving ${modprettyname} config files"
-		sleep 0.5
-	fi
-}
-
 # Create ${modcommand}-files.txt containing the full extracted file/directory list
-fn_mod_fileslist(){
+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
+	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 ${modcommand}-files.txt"
+		fn_script_log_fatal "Building ${modsdir}/${modcommand}-files.txt"
 		core_exit.sh
 	else
 		fn_print_ok_eol_nl
-		fn_script_log_pass "Building ${modcommand}-files.txt"
+		fn_script_log_pass "Building ${modsdir}/${modcommand}-files.txt"
 	fi
-	fn_script_log "Writing file list ${modsdir}/${modcommand}-files.txt"
 	# Adding removed files if needed
 	if [ -f "${modsdir}/.removedfiles.tmp" ]; then
-		cat "${modsdir}/.removedfiles.tmp" >> "${modsdir}"/${modcommand}-files.txt
+		cat "${modsdir}/.removedfiles.tmp" >> "${modsdir}/${modcommand}-files.txt"
 	fi
 	sleep 0.5
 }
 
-# Copy the mod to the destination ${modinstalldir}
+# Copy the mod into serverfiles
 fn_mod_copy_destination(){
 	echo -ne "copying ${modprettyname} to ${modinstalldir}..."
 	sleep 0.5
@@ -200,75 +104,32 @@ fn_mod_copy_destination(){
 	fi
 }
 
-# Check if the mod is already installed and warn the user
-fn_mod_already_installed(){
-	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
-		fi
-	fn_script_log_info "User selected to continue"
-	fi
-}
-
-# Add the mod to the installed mods list
+# Add the mod to the installed-mods.txt
 fn_mod_add_list(){
-	# Append modname to lockfile if it's not already in it
 	if [ ! -n "$(sed -n "/^${modcommand}$/p" "${modsinstalledlistfullpath}")" ]; then
 		echo "${modcommand}" >> "${modsinstalledlistfullpath}"
 		fn_script_log_info "${modcommand} added to ${modsinstalledlist}"
 	fi
 }
 
-fn_check_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="$(cat "${modsdir}/${modcommand}-files.txt" | wc -l)"
-		# 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
-}
-
-# Apply some post-install fixes to make sure everything will be fine
-fn_postinstall_tasks(){
-	# Prevent sensitive directories from being erased upon uninstall by removing them from: ${modsdir}/${modcommand}-files.txt
+fn_mod_tidy_files_list(){
+	# Prevent sensitive directories from being erased by removing them from: ${modcommand}-files.txt
 	# Check file validity
-	fn_check_files_list
+	fn_check_mod_files_list
 	# Output to the user
 	echo -ne "tidy up ${modcommand}-files.txt..."
 	sleep 0.5
-	fn_script_log_info "Rearranging ${modcommand}-files.txt"
-	# What lines/files to remove from file list (end var with a ";" separator)
+	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,
-	# that way these files won't get removed upon uninstall
-	# How many elements to remove from 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 }' )"
-		# Then delete matching line(s)!
+		removefilevar="$(echo "${removefromlist}" | awk -F ';' -v x=${filesindex} '{ print $x }')"
+		# Delete matching line(s)
 		sed -i "/^${removefilevar}$/d" "${modsdir}/${modcommand}-files.txt"
 		local exitcode=$?
 		if [ ${exitcode} -ne 0 ]; then
@@ -290,47 +151,112 @@ fn_postinstall_tasks(){
 	fi
 }
 
-# Apply some post-uninstall fixes to make sure everything will be fine
-fn_postuninstall_tasks(){
-	# 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
+## 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
+					if [ -z "$index" ]; then
+						fn_print_error "index variable not set. Please report an issue."
+						echo "* https://github.com/GameServerManagers/LinuxGSM/issues"
+						exitcode="1"
+						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]}"
+					fi
+					modinfocommand="1"
+					break
+				fi
+				((totalmods++))
+			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
 }
 
-#########################
-## mods_list.sh arrays ##
-#########################
-
-## Define info for a mod
-
-# Define all variables from a mod at once when index is set to a separator
-fn_mod_info(){
-# If for some reason no index is set, none of this can work
-if [ -z "$index" ]; then
-	fn_print_error "index variable not set. Please report an issue to LGSM Team."
-	echo "* https://github.com/GameServerManagers/LinuxGSM/issues"
-	exitcode="1"
-	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(){
+	# Set/reset variables
+	installedmodsline="1"
+	installedmodslist=()
+	# 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 "${totalmods}" ] ;then
+		fn_script_log_info "${totalmods} addons/mods are already installed"
+	fi
+}
+
+# Checks if a mod is compatible for installation
+# Provides available mods for installation
+# Provides commands for mods installation
+fn_mods_available(){
+	# First, reset variables
+	compatiblemodslist=()
+	availablemodscommands=()
+	modprettynamemaxlength="0"
+	modsitemaxlength="0"
+	moddescriptionmaxlength="0"
+	modcommandmaxlength="0"
+	# 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
@@ -413,80 +339,82 @@ fn_mod_compatible_test(){
 	fi
 }
 
-# Checks if a mod is compatible for installation
-# Provides available mods for installation
-# Provides commands for mods installation
-fn_mods_available(){
-	# First, reset variables
-	compatiblemodslist=()
-	availablemodscommands=()
-	modprettynamemaxlength="0"
-	modsitemaxlength="0"
-	moddescriptionmaxlength="0"
-	modcommandmaxlength="0"
-	# 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_mod_info
-			# 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
+## 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
-	done
+		sleep 0.5
+	fi
+
+	# Create lgsm/data/${modsinstalledlist}
+	if [ ! -f "${modsinstalledlistfullpath}" ]; then
+		touch "${modsinstalledlistfullpath}"
+		fn_script_log_info "Created ${modsinstalledlistfullpath}"
+	fi
 }
 
-# Output available mods in a nice way to the user
-fn_mods_show_available(){
-	# 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 "\e[1m${displayedmodname}${default} - ${displayedmoddescription} - ${displayedmodsite}"
-		echo -e " * ${cyan}${displayedmodcommand}${default}"
-		# Increment index from the amount of values we just displayed
-		let "compatiblemodslistindex+=4"
-		((totalmods++))
-	done
-	# If no mods are found
-	if [ -z "${compatiblemodslist}" ]; then
-		fn_print_fail "No mods are currently available for ${gamename}."
-		core_exit.sh
+# Create tmp download mod directory
+fn_mods_create_tmp_dir(){
+	if [ ! -d "${modstmpdir}" ]; then
+		mkdir -p "${modstmpdir}"
+		exitcode=$?
+		echo -ne "creating mod download dir ${modstmpdir}..."
+		if [ ${exitcode} -ne 0 ]; then
+			fn_print_fail_eol_nl
+			fn_script_log_fatal "Creating mod download dir ${modstmpdir}"
+			core_exit.sh
+		else
+			fn_print_ok_eol_nl
+			fn_script_log_pass "Creating mod download dir ${modstmpdir}"
+		fi
 	fi
-	fn_script_log_info "${totalmods} addons/mods are available for install"
 }
 
-# Checks if mods have been installed
-# Also returns ${installedmodscount} if mods were found
-fn_check_installed_mods(){
+# Remove the tmp mod download directory when finished
+fn_mods_clear_tmp_dir(){
+	if [ -d "${modstmpdir}" ]; then
+		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
+}
+
+
+# Exit if no mods were installed
+fn_mods_check_installed(){
 	# Count installed mods
 	if [ -f "${modsinstalledlistfullpath}" ]; then
 		installedmodscount="$(cat "${modsinstalledlistfullpath}" | wc -l)"
+	else
+		installedmodscount=0
 	fi
-}
-
-# A simple function to exit if no mods were installed
-# Also returns ${installedmodscount} if mods were found
-fn_mods_exit_if_not_installed(){
-	# Checks if mods have been installed
-	# Also returns ${installedmodscount} if mods were found
-	fn_check_installed_mods
-	# If no mods lockfile is found or if it is empty
-	if [ ! -f "${modsinstalledlistfullpath}" ]||[ -z "${installedmodscount}" ]||[ ${installedmodscount} -le 0 ]; then
+	# If no mods are found
+	if [ ${installedmodscount} -eq 0 ]; then
 		fn_print_information_nl "No installed mods or addons were found"
 		echo " * Install mods using LGSM first with: ./${selfname} mods-install"
 		fn_script_log_info "No installed mods or addons were found."
@@ -494,155 +422,26 @@ fn_mods_exit_if_not_installed(){
 	fi
 }
 
-# Builds installed mods list and sets available commands according to installed mods
-# (requires ${installedmodscount} from fn_check_installed_mods)
-fn_mods_available_commands_from_installed(){
-	# Set/reset variables
-	installedmodsline="1"
-	installedmodslist=()
-	# 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_from_command
-		# Add the mod to available commands
-		installedmodslist+=( "${modcommand}" )
-		# Increment line check
-		let installedmodsline=installedmodsline+1
-	done
-	if [ -n "${totalmods}" ] ;then
-		fn_script_log_info "${totalmods} addons/mods are already installed"
-	fi
-}
-
-# Displays a detailed list of installed mods
-# Requires fn_check_installed_mods and fn_mods_available_commands_from_installed to run
-fn_installed_mods_detailed_list(){
-	fn_check_installed_mods
-	fn_mods_available_commands_from_installed
-	# Were now based on ${installedmodslist} array's values
-	# We're gonna go through all available commands, get details and display them to the user
-	for ((dlindex=0; dlindex < ${#installedmodslist[@]}; dlindex++)); do
-		# Current mod is the "dlindex" value of the array we're going through
-		currentmod="${installedmodslist[dlindex]}"
-		# Get mod info
-		fn_mod_get_info_from_command
-		# Display mod info to the user
-		echo -e "\e[1m${modprettyname}${default} - ${moddescription} - ${modsite}"
-		echo -e " * ${cyan}${modcommand}${default}"
-	done
-}
-
-# Displays a detailed list of installed mods
-# Requires fn_check_installed_mods and fn_mods_available_commands_from_installed to run
-fn_installed_mods_medium_list(){
-	fn_check_installed_mods
-	fn_mods_available_commands_from_installed
-	# Were now based on ${installedmodslist} array's values
-	# We're gonna go through all available commands, get details and display them to the user
-	for ((mlindex=0; mlindex < ${#installedmodslist[@]}; mlindex++)); do
-		# Current mod is the "mlindex" value of the array we're going through
-		currentmod="${installedmodslist[mlindex]}"
-		# Get mod info
-		fn_mod_get_info_from_command
-		# Display mod info to the user
-		echo -e "${cyan}${modcommand}${default} - \e[1m${modprettyname}${default} - ${moddescription}"
-	done
-}
-
-# Displays a simple list of installed mods
-# Requires fn_check_installed_mods and fn_mods_available_commands_from_installed to run
-# This list is only displayed when some mods are installed
-fn_installed_mods_light_list(){
-	fn_check_installed_mods
-	fn_mods_available_commands_from_installed
-	if [ "${installedmodscount}" -gt 0 ]; then
-		echo "Installed addons/mods"
-		echo "================================="
-		# Were now based on ${installedmodslist} array's values
-		# We're gonna 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]}"
-			# Get mod info
-			fn_mod_get_info_from_command
-			# Display simple mod info to the user
-			echo -e " * \e[1m${green}${modcommand}${default}${default}"
-		((totalmodsinstalled++))
-		done
-		echo ""
-	fi
-}
-
-# Displays a simple list of installed mods for mods-update command
-# Requires fn_check_installed_mods and fn_mods_available_commands_from_installed to run
-fn_installed_mods_update_list(){
-	fn_check_installed_mods
-	fn_mods_available_commands_from_installed
-	echo "================================="
-	echo "Installed addons/mods"
-	# Were now based on ${installedmodslist} array's values
-	# We're gonna 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]}"
-		# Get mod info
-		fn_mod_get_info_from_command
-		# Display simple mod info to the user according to the update policy
-		# If modkeepfiles is not set for some reason, that's a problem
-		if [ -z "${modkeepfiles}" ]; then
-			fn_script_log_error "Couldn't find update policy for ${modprettyname}"
-			fn_print_error_nl "Couldn't find update policy for ${modprettyname}"
-			exitcode="1"
+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="$(cat "${modsdir}/${modcommand}-files.txt" | wc -l)"
+		# 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
-		# If the mod won't get updated
-		elif [ "${modkeepfiles}" == "NOUPDATE" ]; then
-			echo -e " * \e[31m${modprettyname}${default} (won't be updated)"
-		# If the mode is just overwritten
-		elif [ "${modkeepfiles}" == "OVERWRITE" ]; then
-			echo -e " * \e[1m${modprettyname}${default} (overwrite)"
-		else
-			echo -e " * ${yellow}${modprettyname}${default} (common custom files remain untouched)"
-		fi
-	done
-}
-
-# Get details of a mod any (relevant and unique, such as full mod name or install command) value
-fn_mod_get_info_from_command(){
-	# 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_mod_info
-					modinfocommand="1"
-					break
-				fi
-				((totalmods++))
-			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"
+	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
 }
 
-fn_mods_scrape_urls
-fn_mods_info
-fn_mods_available
+# Database initialisation
+mods_list.sh
+mods_dir.sh
+fn_mods_available

+ 50 - 54
lgsm/functions/mods_list.sh

@@ -17,61 +17,57 @@ local function_selfname="$(basename $(readlink -f "${BASH_SOURCE[0]}"))"
 modseparator="MOD"
 
 # Define mods information (required)
-fn_mods_info(){
-	# 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 file; can be a variable defined in fn_mods_nasty_urls (make sure curl can download it)
-	# [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" to ignore the value or "NOUPDATE" to disallow updating
-	# [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
+# 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 file; can be a variable defined in fn_mods_nasty_urls (make sure curl can download it)
+# [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" to ignore the value or "NOUPDATE" to disallow updating
+# [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
 
-	# 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" "OVERWRITE" "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" )
+# 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" "OVERWRITE" "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 one array for convenience
-	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[@]}" )
-}
+# REQUIRED: Set all mods info into one array for convenience
+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[@]}" )
 
 # Get a proper URL for mods that don't provide a good one (optional)
-fn_mods_scrape_urls(){
-	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}"
-}
+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}"