mods_core.sh 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421
  1. #!/bin/bash
  2. # LGSM command_mods_install.sh function
  3. # Author: Daniel Gibbs
  4. # Contributor: UltimateByte
  5. # Website: https://gameservermanagers.com
  6. # Description: Core functions for mods list/install/update/remove
  7. local commandname="MODS"
  8. local commandaction="Core functions for mods"
  9. local function_selfname="$(basename $(readlink -f "${BASH_SOURCE[0]}"))"
  10. ## Useful variables
  11. # Files and Directories
  12. modstmpdir="${tmpdir}/mods"
  13. extractdir="${modstmpdir}/extracted"
  14. modsdatadir="${lgsmdir}/data/mods"
  15. modslockfile="installed-mods-listing"
  16. modslockfilefullpath="${modsdatadir}/${modslockfile}"
  17. # Database initialization
  18. mods_list.sh
  19. # Sets some gsm requirements
  20. fn_gsm_requirements(){
  21. # If tmpdir variable doesn't exist, LGSM is too old
  22. if [ -z "${tmpdir}" ]||[ -z "${lgsmdir}" ]; then
  23. fn_print_fail "Your LGSM version is too old."
  24. echo " * Please do a full update, including ${selfname} script."
  25. core_exit.sh
  26. fi
  27. }
  28. # Create mods directory if it doesn't exist
  29. # Assuming the game is already installed as mods_list.sh checked for it.
  30. fn_mods_dir(){
  31. if [ ! -d "${modinstalldir}" ]; then
  32. fn_script_log_info "Creating mods directory: ${modinstalldir}"
  33. fn_print_dots "Creating mods directory"
  34. sleep 1
  35. mkdir -p "${modinstalldir}"
  36. fn_print_ok "Created mods directory"
  37. fi
  38. }
  39. # Clear mod download directory so that there is only one file in it since we don't the file name and extention
  40. fn_clear_tmp_mods(){
  41. if [ -d "${modstmpdir}" ]; then
  42. rm -r "${modstmpdir}"
  43. fn_script_log "Clearing temp mod download directory: ${modstmpdir}"
  44. fi
  45. # Clear temp file list as well
  46. if [ -f "${modsdatadir}/.removedfiles.tmp" ]; then
  47. rm "${modsdatadir}/.removedfiles.tmp"
  48. fi
  49. }
  50. # Create tmp download mod directory
  51. fn_mods_tmpdir(){
  52. if [ ! -d "${modstmpdir}" ]; then
  53. mkdir -p "${modstmpdir}"
  54. fn_script_log "Creating temp mod download directory: ${modstmpdir}"
  55. fi
  56. }
  57. fn_mod_dl(){
  58. # fn_fetch_file "${fileurl}" "${filedir}" "${filename}" "${executecmd}" "${run}" "${force}" "${md5}"
  59. fileurl="${modurl}"
  60. filedir="${modstmpdir}"
  61. filename="${modfilename}"
  62. fn_script_log "Downloading mods to ${modstmpdir}"
  63. fn_fetch_file "${fileurl}" "${filedir}" "${filename}"
  64. # Check if variable is valid checking if file has been downloaded and exists
  65. if [ ! -f "${modstmpdir}/${modfilename}" ]; then
  66. fn_print_fail "An issue occurred upon downloading ${modprettyname}"
  67. core_exit.sh
  68. fi
  69. }
  70. fn_mod_extract(){
  71. # fn_dl_extract "${filedir}" "${filename}" "${extractdir}"
  72. filename="${modfilename}"
  73. if [ ! -d "${extractdir}" ]; then
  74. mkdir -p "${extractdir}"
  75. fi
  76. fn_script_log "Extracting ${modprettyname} to ${extractdir}"
  77. fn_dl_extract "${filedir}" "${filename}" "${extractdir}"
  78. }
  79. fn_mod_lowercase(){
  80. # Converting files to lowercase
  81. if [ "${modlowercase}" == "LowercaseOn" ]; then
  82. fn_print_dots "Converting ${modprettyname} files to lowercase"
  83. fn_script_log "Converting ${modprettyname} files to lowercase"
  84. find "${extractdir}" -depth -exec rename 's/(.*)\/([^\/]*)/$1\/\L$2/' {} \;
  85. fn_print_ok "Converting ${modprettyname} files to lowercase"
  86. sleep 1
  87. fi
  88. }
  89. fn_remove_cfg_files(){
  90. # Remove config file after extraction for updates set by ${modkeepfiles}
  91. if [ "${modkeepfiles}" != "OVERWRITE" ]&&[ "${modkeepfiles}" != "NOUPDATE" ]; then
  92. # Upon mods updates, config files should not be overwritten
  93. # We will just remove these files before copying the mod to the destination
  94. # Let's count how many files there are to remove
  95. fn_print_dots "Allow for preserving ${modprettyname} config files"
  96. sleep 0.5
  97. removefilesamount="$(echo "${modkeepfiles}" | awk -F ';' '{ print NF }')"
  98. # Test all subvalue of "modgames" using the ";" separator
  99. for ((removefilesindex=1; removefilesindex < ${removefilesamount}; removefilesindex++)); do
  100. # Put current file we're looking for into a variable
  101. filetoremove="$( echo "${modkeepfiles}" | awk -F ';' -v x=${removefilesindex} '{ print $x }' )"
  102. # If it matches an existing file that have been extracted
  103. if [ -f "${extractdir}/${filetoremove}" ]||[ -d "${extractdir}/${filetoremove}" ]; then
  104. # Then delete the file!
  105. rm -R "${extractdir}/${filetoremove}"
  106. # Write this file path in a tmp file, to rebuild a full file list
  107. if [ ! -f "${modsdatadir}/.removedfiles.tmp" ]; then
  108. touch "${modsdatadir}/.removedfiles.tmp"
  109. fi
  110. echo "${filetoremove}" >> "${modsdatadir}/.removedfiles.tmp"
  111. fi
  112. done
  113. fn_print_ok "Allow for preserving ${modprettyname} config files"
  114. fi
  115. }
  116. fn_mod_fileslist(){
  117. # Create lgsm/data/mods directory
  118. if [ ! -d "${modsdatadir}" ]; then
  119. mkdir -p "${modsdatadir}"
  120. fn_script_log "Created ${modsdatadir}"
  121. fi
  122. fn_print_dots "Building ${modcommand}-files.list"
  123. fn_script_log "Building ${modcommand}-files.list"
  124. # ${modsdatadir}/${modcommand}-files.list
  125. find "${extractdir}" -mindepth 1 -printf '%P\n' > ${modsdatadir}/${modcommand}-files.list
  126. fn_script_log "Writing file list: ${modsdatadir}/${modcommand}-files.list}"
  127. # Adding removed files if needed
  128. if [ -f "${modsdatadir}/.removedfiles.tmp" ]; then
  129. cat "${modsdatadir}/.removedfiles.tmp" >> ${modsdatadir}/${modcommand}-files.list
  130. fi
  131. fn_print_ok "Building ${modcommand}-files.list"
  132. }
  133. fn_mod_copy_destination(){
  134. # Destination directory: ${modinstalldir}
  135. fn_print_dots "Copying ${modprettyname} to ${modinstalldir}"
  136. fn_script_log "Copying ${modprettyname} to ${modinstalldir}"
  137. cp -Rf "${extractdir}/." "${modinstalldir}/"
  138. sleep 0.5
  139. fn_print_ok "Copying ${modprettyname} to ${modinstalldir}"
  140. }
  141. # Check if the mod is already installed and warn the user
  142. fn_mod_already_installed(){
  143. if [ -f "${modslockfilefullpath}" ]; then
  144. if [ -n "$(cat "${modslockfilefullpath}" | grep "${modcommand}")" ]; then
  145. fn_print_warning_nl "${modprettyname} has already been installed."
  146. echo " * Config files, if any, might be overwritten."
  147. echo " * Press ctrl + c to abort."
  148. sleep 4
  149. fi
  150. fn_script_log "${modprettyname} is already installed, overwriting any file."
  151. fi
  152. }
  153. # Add the mod to the installed mods list
  154. fn_mod_add_list(){
  155. # Create lgsm/data/mods directory
  156. if [ ! -d "${modsdatadir}" ]; then
  157. mkdir -p "${modsdatadir}"
  158. fn_script_log "Created ${modsdatadir}"
  159. fi
  160. # Create lgsm/data/${modslockfile}
  161. if [ ! -f "${modslockfilefullpath}" ]; then
  162. touch "${modslockfilefullpath}"
  163. fn_script_log "Created ${modslockfilefullpath}"
  164. fi
  165. # Input mod name to lockfile
  166. if [ ! -n "$(cat "${modslockfilefullpath}" | grep "${modcommand}")" ]; then
  167. echo "${modcommand}" >> "${modslockfilefullpath}"
  168. fn_script_log "${modcommand} added to ${modslockfile}"
  169. fi
  170. }
  171. fn_check_files_list(){
  172. # File list must exist and be valid before any operation on it
  173. if [ -f "${modsdatadir}/${modcommand}-files.list" ]; then
  174. # How many lines is the file list
  175. modsfilelistsize="$(cat "${modsdatadir}/${modcommand}-files.list" | wc -l)"
  176. # If file list is empty
  177. if [ $modsfilelistsize -eq 0 ]; then
  178. fn_print_error_nl "${modcommand}-files.list is empty"
  179. echo "Exiting."
  180. fn_scrip_log_fatal "${modcommand}-files.list is empty"
  181. exitcode="2"
  182. core_exit.sh
  183. fi
  184. else
  185. fn_print_error_nl "${modsdatadir}/${modcommand}-files.list don't exist"
  186. echo "Exiting."
  187. fn_scrip_log_fatal "${modsdatadir}/${modcommand}-files.list don't exist"
  188. exitcode="2"
  189. core_exit.sh
  190. fi
  191. }
  192. fn_postinstall_tasks(){
  193. # Prevent addons folder from being removed by clearing them in: ${modsdatadir}/${modcommand}-files.list
  194. # Check file validity
  195. fn_check_files_list
  196. # Output to the user
  197. fn_print_dots "Rearranging ${modcommand}-files.list"
  198. sleep 1
  199. fn_script_log_info "Rearranging ${modcommand}-files.list"
  200. # What lines/files to remove from file list
  201. removefromlist="cfg;addons;"
  202. # Loop through files to remove from file list,
  203. # that way these files won't get removed upon uninstall
  204. # How many elements to remove from list
  205. removefromlistamount="$(echo "${removefromlist}" | awk -F ';' '{ print NF }')"
  206. # Test all subvalue of "removefromlist" using the ";" separator
  207. for ((filesindex=1; filesindex < ${removefromlistamount}; filesindex++)); do
  208. # Put current file into test variable
  209. removefilevar="$( echo "${removefromlist}" | awk -F ';' -v x=${filesindex} '{ print $x }' )"
  210. # Then delete matching line(s)!
  211. sed -i "/^${removefilevar}$/d" "${modsdatadir}/${modcommand}-files.list"
  212. done
  213. fn_print_ok "Rearranging ${modcommand}-files.list"
  214. }
  215. ## mods_list.sh arrays
  216. # Define all variables from a mod at once when index is set to a separator
  217. fn_mod_info(){
  218. # If for some reason no index is set, none of this can work
  219. if [ -z "$index" ]; then
  220. fn_print_error "index variable not set. Please report an issue to LGSM Team."
  221. echo "* https://github.com/GameServerManagers/LinuxGSM/issues"
  222. core_exit.sh
  223. fi
  224. modcommand="${mods_global_array[index+1]}"
  225. modprettyname="${mods_global_array[index+2]}"
  226. modurl="${mods_global_array[index+3]}"
  227. modfilename="${mods_global_array[index+4]}"
  228. modsubdirs="${mods_global_array[index+5]}"
  229. modlowercase="${mods_global_array[index+6]}"
  230. modinstalldir="${mods_global_array[index+7]}"
  231. modkeepfiles="${mods_global_array[index+8]}"
  232. modengines="${mods_global_array[index+9]}"
  233. modgames="${mods_global_array[index+10]}"
  234. modexcludegames="${mods_global_array[index+11]}"
  235. modsite="${mods_global_array[index+12]}"
  236. moddescription="${mods_global_array[index+13]}"
  237. }
  238. # Find out if a game is compatible with a mod from a modgames (list of games supported by a mod) variable
  239. fn_compatible_mod_games(){
  240. # Reset test value
  241. modcompatiblegame="0"
  242. # If value is set to GAMES (ignore)
  243. if [ "${modgames}" != "GAMES" ]; then
  244. # How many games we need to test
  245. gamesamount="$(echo "${modgames}" | awk -F ';' '{ print NF }')"
  246. # Test all subvalue of "modgames" using the ";" separator
  247. for ((gamevarindex=1; gamevarindex < ${gamesamount}; gamevarindex++)); do
  248. # Put current game name into modtest variable
  249. gamemodtest="$( echo "${modgames}" | awk -F ';' -v x=${gamevarindex} '{ print $x }' )"
  250. # If game name matches
  251. if [ "${gamemodtest}" == "${gamename}" ]; then
  252. # Mod is compatible !
  253. modcompatiblegame="1"
  254. fi
  255. done
  256. fi
  257. }
  258. # Find out if an engine is compatible with a mod from a modengines (list of engines supported by a mod) variable
  259. fn_compatible_mod_engines(){
  260. # Reset test value
  261. modcompatibleengine="0"
  262. # If value is set to ENGINES (ignore)
  263. if [ "${modengines}" != "ENGINES" ]; then
  264. # How many engines we need to test
  265. enginesamount="$(echo "${modengines}" | awk -F ';' '{ print NF }')"
  266. # Test all subvalue of "modengines" using the ";" separator
  267. for ((gamevarindex=1; gamevarindex < ${enginesamount}; gamevarindex++)); do
  268. # Put current engine name into modtest variable
  269. enginemodtest="$( echo "${modengines}" | awk -F ';' -v x=${gamevarindex} '{ print $x }' )"
  270. # If engine name matches
  271. if [ "${enginemodtest}" == "${engine}" ]; then
  272. # Mod is compatible !
  273. modcompatibleengine="1"
  274. fi
  275. done
  276. fi
  277. }
  278. # Find out if a game is not compatible with a mod from a modnotgames (list of games not supported by a mod) variable
  279. fn_not_compatible_mod_games(){
  280. # Reset test value
  281. modeincompatiblegame="0"
  282. # If value is set to NOTGAMES (ignore)
  283. if [ "${modexcludegames}" != "NOTGAMES" ]; then
  284. # How many engines we need to test
  285. excludegamesamount="$(echo "${modexcludegames}" | awk -F ';' '{ print NF }')"
  286. # Test all subvalue of "modexcludegames" using the ";" separator
  287. for ((gamevarindex=1; gamevarindex < ${excludegamesamount}; gamevarindex++)); do
  288. # Put current engine name into modtest variable
  289. excludegamemodtest="$( echo "${modexcludegames}" | awk -F ';' -v x=${gamevarindex} '{ print $x }' )"
  290. # If engine name matches
  291. if [ "${excludegamemodtest}" == "${gamename}" ]; then
  292. # Mod is compatible !
  293. modeincompatiblegame="1"
  294. fi
  295. done
  296. fi
  297. }
  298. # Sums up if a mod is compatible or not with modcompatibility=0/1
  299. fn_mod_compatible_test(){
  300. # Test game and engine compatibility
  301. fn_compatible_mod_games
  302. fn_compatible_mod_engines
  303. fn_not_compatible_mod_games
  304. if [ "${modeincompatiblegame}" == "1" ]; then
  305. modcompatibility="0"
  306. elif [ "${modcompatibleengine}" == "1" ]||[ "${modcompatiblegame}" == "1" ]; then
  307. modcompatibility="1"
  308. else
  309. modcompatibility="0"
  310. fi
  311. }
  312. # Checks if a mod is compatibile for installation
  313. # Provides available mods for installation
  314. # Provides commands for mods installation
  315. fn_mods_available(){
  316. # First, reset variables
  317. compatiblemodslist=()
  318. availablemodscommands=()
  319. modprettynamemaxlength="0"
  320. modsitemaxlength="0"
  321. moddescriptionmaxlength="0"
  322. modcommandmaxlength="0"
  323. # Find compatible games
  324. # Find separators through the global array
  325. for ((index="0"; index <= ${#mods_global_array[@]}; index++)); do
  326. # If current value is a separator; then
  327. if [ "${mods_global_array[index]}" == "${modseparator}" ]; then
  328. # Set mod variables
  329. fn_mod_info
  330. # Test if game is compatible
  331. fn_mod_compatible_test
  332. # If game is compatible
  333. if [ "${modcompatibility}" == "1" ]; then
  334. # Put it into an array to prepare user output
  335. compatiblemodslist+=( "${modprettyname}" "${modcommand}" "${modsite}" "${moddescription}" )
  336. # Keep available commands in an array to make life easier
  337. availablemodscommands+=( "${modcommand}" )
  338. fi
  339. fi
  340. done
  341. }
  342. # Output available mods in a nice way to the user
  343. fn_mods_show_available(){
  344. # Set and reset vars
  345. compatiblemodslistindex=0
  346. spaces=" "
  347. # As long as we're within index values
  348. while [ "${compatiblemodslistindex}" -lt "${#compatiblemodslist[@]}" ]; do
  349. # Set values for convenience
  350. displayedmodname="${compatiblemodslist[compatiblemodslistindex]}"
  351. displayedmodcommand="${compatiblemodslist[compatiblemodslistindex+1]}"
  352. displayedmodsite="${compatiblemodslist[compatiblemodslistindex+2]}"
  353. displayedmoddescription="${compatiblemodslist[compatiblemodslistindex+3]}"
  354. # Output mods to the user
  355. echo -e "\e[1m${displayedmodname}\e[0m - ${displayedmoddescription} - ${displayedmodsite}"
  356. echo -e " * \e[36m${displayedmodcommand}\e[0m"
  357. # Increment index from the amount of values we just displayed
  358. let "compatiblemodslistindex+=4"
  359. done
  360. # If no mods are found
  361. if [ -z "${compatiblemodslist}" ]; then
  362. fn_print_fail "No mods are currently available for ${gamename}."
  363. core_exit.sh
  364. fi
  365. }
  366. # Get details of a mod any (relevant and unique, such as full mod name or install command) value
  367. fn_mod_get_info_from_command(){
  368. # Variable to know when job is done
  369. modinfocommand="0"
  370. # Find entry in global array
  371. for ((index=0; index <= ${#mods_global_array[@]}; index++)); do
  372. # When entry is found
  373. if [ "${mods_global_array[index]}" == "${currentmod}" ]; then
  374. # Go back to the previous "MOD" separator
  375. for ((index=index; index <= ${#mods_global_array[@]}; index--)); do
  376. # When "MOD" is found
  377. if [ "${mods_global_array[index]}" == "MOD" ]; then
  378. # Get info
  379. fn_mod_info
  380. modinfocommand="1"
  381. break
  382. fi
  383. done
  384. fi
  385. # Exit the loop if job is done
  386. if [ "${modinfocommand}" == "1" ]; then
  387. break
  388. fi
  389. done
  390. }
  391. fn_gsm_requirements
  392. fn_mods_scrape_urls
  393. fn_mods_info
  394. fn_mods_available