mods_core.sh 15 KB

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