mods_core.sh 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822
  1. #!/bin/bash
  2. # LinuxGSM command_mods_install.sh module
  3. # Author: Daniel Gibbs
  4. # Contributors: https://linuxgsm.com/contrib
  5. # Website: https://linuxgsm.com
  6. # Description: Core modules for mods list/install/update/remove
  7. moduleselfname="$(basename "$(readlink -f "${BASH_SOURCE[0]}")")"
  8. # Files and Directories.
  9. modsdir="${lgsmdir}/mods"
  10. modstmpdir="${modsdir}/tmp"
  11. extractdest="${modstmpdir}/extract"
  12. modsinstalledlist="installed-mods.txt"
  13. modsinstalledlistfullpath="${modsdir}/${modsinstalledlist}"
  14. ## Installation.
  15. # Download management.
  16. fn_mod_install_files() {
  17. fn_fetch_file "${modurl}" "" "" "" "${modstmpdir}" "${modfilename}"
  18. # Check if variable is valid checking if file has been downloaded and exists.
  19. if [ ! -f "${modstmpdir}/${modfilename}" ]; then
  20. fn_print_failure "An issue occurred downloading ${modprettyname}"
  21. fn_script_log_fail "An issue occurred downloading ${modprettyname}"
  22. core_exit.sh
  23. fi
  24. if [ ! -d "${extractdest}" ]; then
  25. mkdir -p "${extractdest}"
  26. fi
  27. fn_dl_extract "${modstmpdir}" "${modfilename}" "${extractdest}"
  28. # If modsubdirs names a specific subfolder, use its contents as the install root.
  29. if [ "${modsubdirs}" != "0" ] && [ -d "${extractdest}/${modsubdirs}" ]; then
  30. local tmpsubdir
  31. tmpsubdir=$(mktemp -d)
  32. mv "${extractdest}/${modsubdirs}" "${tmpsubdir}/"
  33. rm -rf "${extractdest}"
  34. mv "${tmpsubdir}/${modsubdirs}" "${extractdest}"
  35. rm -rf "${tmpsubdir}"
  36. fi
  37. }
  38. # Convert mod files to lowercase if needed.
  39. fn_mod_lowercase() {
  40. # Checking lowercase settings from mods array definition
  41. if [ "${modlowercase}" == "LowercaseOn" ]; then
  42. echo -en "converting ${modprettyname} files to lowercase..."
  43. fn_sleep_time
  44. fn_script_log_info "Converting ${modprettyname} files to lowercase"
  45. # Total files and directories for the mod, to output to the user
  46. fileswc=$(find "${extractdest}" | wc -l)
  47. # Total uppercase files and directories for the mod, to output to the user
  48. filesupperwc=$(find "${extractdest}" -name '*[[:upper:]]*' | wc -l)
  49. fn_script_log_info "Found ${filesupperwc} uppercase files out of ${fileswc}, converting"
  50. echo -en "Found ${filesupperwc} uppercase files out of ${fileswc}, converting..."
  51. # Convert files and directories starting from the deepest to prevent issues (-depth argument)
  52. while read -r src; do
  53. # We have to convert only the last file from the path, otherwise we will fail to convert anything if a parent dir has any uppercase
  54. # therefore, we have to separate the end of the filename to only lowercase it rather than the whole line
  55. # Gather parent dir, filename lowercase filename, and set lowercase destination name
  56. latestparentdir=$(dirname "${src}")
  57. latestfilelc=$(basename "${src}" | tr '[:upper:]' '[:lower:]')
  58. dst="${latestparentdir}/${latestfilelc}"
  59. # Only convert if destination does not already exist for some reason
  60. if [ ! -e "${dst}" ]; then
  61. # Finally we can rename the file
  62. mv "${src}" "${dst}"
  63. # Exit if it fails for any reason
  64. exitcode=$?
  65. if [ "${exitcode}" -ne 0 ]; then
  66. fn_print_fail_eol_nl
  67. core_exit.sh
  68. fi
  69. fi
  70. done < <(find "${extractdest}" -depth -name '*[[:upper:]]*')
  71. fn_print_ok_eol_nl
  72. fi
  73. }
  74. # Create ${modcommand}-files.txt containing the full extracted file/directory list.
  75. fn_mod_create_filelist() {
  76. echo -en "building ${modcommand}-files.txt..."
  77. fn_sleep_time
  78. # ${modsdir}/${modcommand}-files.txt.
  79. find "${extractdest}" -mindepth 1 -printf '%P\n' > "${modsdir}/${modcommand}-files.txt"
  80. exitcode=$?
  81. if [ "${exitcode}" -ne 0 ]; then
  82. fn_print_fail_eol_nl
  83. fn_script_log_fail "Building ${modsdir}/${modcommand}-files.txt"
  84. core_exit.sh
  85. else
  86. fn_print_ok_eol_nl
  87. fn_script_log_pass "Building ${modsdir}/${modcommand}-files.txt"
  88. fi
  89. # Adding removed files if needed.
  90. if [ -f "${modsdir}/.removedfiles.tmp" ]; then
  91. cat "${modsdir}/.removedfiles.tmp" >> "${modsdir}/${modcommand}-files.txt"
  92. fi
  93. }
  94. # Copy the mod into serverfiles.
  95. fn_mod_copy_destination() {
  96. echo -en "copying ${modprettyname} to ${modinstalldir}..."
  97. fn_sleep_time
  98. cp -Rf "${extractdest}/." "${modinstalldir}/"
  99. exitcode=$?
  100. if [ "${exitcode}" -ne 0 ]; then
  101. fn_print_fail_eol_nl
  102. fn_script_log_fail "Copying ${modprettyname} to ${modinstalldir}"
  103. else
  104. fn_print_ok_eol_nl
  105. fn_script_log_pass "Copying ${modprettyname} to ${modinstalldir}"
  106. fi
  107. }
  108. # Add the mod to the installed-mods.txt.
  109. fn_mod_add_list() {
  110. if [ -z "$(sed -n "/^${modcommand}$/p" "${modsinstalledlistfullpath}")" ]; then
  111. echo -e "${modcommand}" >> "${modsinstalledlistfullpath}"
  112. fn_script_log_info "${modcommand} added to ${modsinstalledlist}"
  113. fi
  114. }
  115. # Prevent sensitive directories from being erased upon uninstall by removing them from: ${modcommand}-files.txt.
  116. fn_mod_tidy_files_list() {
  117. # Check file list validity.
  118. fn_check_mod_files_list
  119. # Output to the user
  120. echo -en "tidy up ${modcommand}-files.txt..."
  121. fn_sleep_time
  122. fn_script_log_info "Tidy up ${modcommand}-files.txt"
  123. # Lines/files to remove from file list (end with ";" separator).
  124. removefromlist="cfg;addons;RustDedicated_Data;RustDedicated_Data\/Managed;RustDedicated_Data\/Managed\/x86;RustDedicated_Data\/Managed\/x64;"
  125. # Loop through files to remove from file list,
  126. # generate elements to remove from list.
  127. removefromlistamount=$(echo -e "${removefromlist}" | awk -F ';' '{ print NF }')
  128. # Test all subvalue of "removefromlist" using the ";" separator.
  129. for ((filesindex = 1; filesindex < removefromlistamount; filesindex++)); do
  130. # Put current file into test variable.
  131. removefilevar=$(echo -e "${removefromlist}" | awk -F ';' -v x=${filesindex} '{ print $x }')
  132. # Delete line(s) matching exactly.
  133. sed -i "/^${removefilevar}$/d" "${modsdir}/${modcommand}-files.txt"
  134. # Exit on error.
  135. exitcode=$?
  136. if [ "${exitcode}" -ne 0 ]; then
  137. fn_print_fail_eol_nl
  138. fn_script_log_fail "Error while tidying line: ${removefilevar} from: ${modsdir}/${modcommand}-files.txt"
  139. core_exit.sh
  140. break
  141. fi
  142. done
  143. fn_print_ok_eol_nl
  144. # Sourcemod fix
  145. # Remove metamod from sourcemod fileslist.
  146. if [ "${modcommand}" == "sourcemod" ]; then
  147. # Remove addons/metamod & addons/metamod/sourcemod.vdf from ${modcommand}-files.txt.
  148. sed -i "/^addons\/metamod$/d" "${modsdir}/${modcommand}-files.txt"
  149. sed -i "/^addons\/metamod\/sourcemod.vdf$/d" "${modsdir}/${modcommand}-files.txt"
  150. fi
  151. # Keep Metamod:Source when removing CounterStrikeSharp, but remove its own VDF.
  152. if [ "${modcommand}" == "counterstrikesharp" ]; then
  153. sed -i "/^addons\/metamod$/d" "${modsdir}/${modcommand}-files.txt"
  154. fi
  155. # Remove common paths from deletion list (Add your sourcemod mod here)
  156. if [ "${modcommand}" == "gokz" ] || [ "${modcommand}" == "ttt" ] || [ "${modcommand}" == "steamworks" ] || [ "${modcommand}" == "get5" ]; then
  157. sed -i "/^addons\/sourcemod$/d" "${modsdir}/${modcommand}-files.txt"
  158. sed -i "/^addons\/sourcemod\/configs$/d" "${modsdir}/${modcommand}-files.txt"
  159. sed -i "/^addons\/sourcemod\/extensions$/d" "${modsdir}/${modcommand}-files.txt"
  160. sed -i "/^addons\/sourcemod\/logs$/d" "${modsdir}/${modcommand}-files.txt"
  161. sed -i "/^addons\/sourcemod\/plugins$/d" "${modsdir}/${modcommand}-files.txt"
  162. sed -i "/^addons\/sourcemod\/plugins\/disabled$/d" "${modsdir}/${modcommand}-files.txt"
  163. sed -i "/^addons\/sourcemod\/scripting$/d" "${modsdir}/${modcommand}-files.txt"
  164. sed -i "/^addons\/sourcemod\/scripting\/include$/d" "${modsdir}/${modcommand}-files.txt"
  165. sed -i "/^addons\/sourcemod\/translations$/d" "${modsdir}/${modcommand}-files.txt"
  166. # Don't delete directories of translations like 'fr', 'sv', 'de', etc
  167. sed -i "/^addons\/sourcemod\/translations\/[A-Za-z0-9_]*$/d" "${modsdir}/${modcommand}-files.txt"
  168. sed -i "/^cfg\/sourcemod$/d" "${modsdir}/${modcommand}-files.txt"
  169. sed -i "/^maps$/d" "${modsdir}/${modcommand}-files.txt"
  170. sed -i "/^materialss$/d" "${modsdir}/${modcommand}-files.txt"
  171. sed -i "/^materials\/models$/d" "${modsdir}/${modcommand}-files.txt"
  172. sed -i "/^materials\/models\/weapons$/d" "${modsdir}/${modcommand}-files.txt"
  173. sed -i "/^materials\/darkness$/d" "${modsdir}/${modcommand}-files.txt"
  174. sed -i "/^materials\/decals$/d" "${modsdir}/${modcommand}-files.txt"
  175. sed -i "/^materials\/overlays$/d" "${modsdir}/${modcommand}-files.txt"
  176. sed -i "/^models$/d" "${modsdir}/${modcommand}-files.txt"
  177. sed -i "/^models\/weapons$/d" "${modsdir}/${modcommand}-files.txt"
  178. sed -i "/^sound$/d" "${modsdir}/${modcommand}-files.txt"
  179. sed -i "/^sound\/weapons$/d" "${modsdir}/${modcommand}-files.txt"
  180. fi
  181. # Remove paths of specific mods from deletion list
  182. if [ "${modcommand}" == "gokz" ]; then
  183. sed -i "/^addons\/sourcemod\/scripting\/include\/smjansson.inc$/d" "${modsdir}/${modcommand}-files.txt"
  184. sed -i "/^addons\/sourcemod\/scripting\/include\/GlobalAPI-Core.inc$/d" "${modsdir}/${modcommand}-files.txt"
  185. sed -i "/^addons\/sourcemod\/scripting\/include\/sourcebanspp.inc$/d" "${modsdir}/${modcommand}-files.txt"
  186. sed -i "/^addons\/sourcemod\/scripting\/include\/autoexecconfig.inc$/d" "${modsdir}/${modcommand}-files.txt"
  187. sed -i "/^addons\/sourcemod\/scripting\/include\/colorvariables.inc$/d" "${modsdir}/${modcommand}-files.txt"
  188. sed -i "/^addons\/sourcemod\/scripting\/include\/movementapi.inc$/d" "${modsdir}/${modcommand}-files.txt"
  189. sed -i "/^addons\/sourcemod\/scripting\/include\/movement.inc$/d" "${modsdir}/${modcommand}-files.txt"
  190. sed -i "/^addons\/sourcemod\/scripting\/include\/dhooks.inc$/d" "${modsdir}/${modcommand}-files.txt"
  191. sed -i "/^addons\/sourcemod\/scripting\/include\/updater.inc$/d" "${modsdir}/${modcommand}-files.txt"
  192. fi
  193. }
  194. ## Information Gathering.
  195. # Get details of a mod any (relevant and unique, such as full mod name or install command) value.
  196. fn_mod_get_info() {
  197. # Variable to know when job is done.
  198. modinfocommand="0"
  199. # Find entry in global array.
  200. for ((index = 0; index < ${#mods_global_array[@]}; index++)); do
  201. # When entry is found.
  202. if [ "${mods_global_array[index]}" == "${currentmod}" ]; then
  203. # Go back to the previous "MOD" separator.
  204. for ((index_search = index; index_search >= 0; index_search--)); do
  205. # When "MOD" is found.
  206. if [ "${mods_global_array[index_search]}" == "MOD" ]; then
  207. # Get info.
  208. index=${index_search}
  209. fn_mods_define
  210. modinfocommand="1"
  211. break
  212. fi
  213. done
  214. fi
  215. # Exit the loop if job is done.
  216. if [ "${modinfocommand}" == "1" ]; then
  217. break
  218. fi
  219. done
  220. # What happens if mod is not found.
  221. if [ "${modinfocommand}" == "0" ]; then
  222. fn_script_log_error "Could not find information for ${currentmod}"
  223. fn_print_error_nl "Could not find information for ${currentmod}"
  224. core_exit.sh
  225. fi
  226. }
  227. # Define all variables for a mod at once when index is set to a separator.
  228. fn_mods_define() {
  229. if [ -z "$index" ]; then
  230. fn_script_log_fail "index variable not set. Please report an issue."
  231. fn_print_error "index variable not set. Please report an issue."
  232. echo -e "* https://github.com/GameServerManagers/LinuxGSM/issues"
  233. core_exit.sh
  234. fi
  235. modcommand="${mods_global_array[index + 1]}"
  236. modprettyname="${mods_global_array[index + 2]}"
  237. modurl="${mods_global_array[index + 3]}"
  238. modfilename="${mods_global_array[index + 4]}"
  239. modsubdirs="${mods_global_array[index + 5]}"
  240. modlowercase="${mods_global_array[index + 6]}"
  241. modinstalldir="${mods_global_array[index + 7]}"
  242. modkeepfiles="${mods_global_array[index + 8]}"
  243. modengines="${mods_global_array[index + 9]}"
  244. modgames="${mods_global_array[index + 10]}"
  245. modexcludegames="${mods_global_array[index + 11]}"
  246. modsite="${mods_global_array[index + 12]}"
  247. moddescription="${mods_global_array[index + 13]}"
  248. }
  249. # Builds list of installed mods.
  250. # using installed-mods.txt grabbing mod info from mods_list.sh.
  251. fn_mods_installed_list() {
  252. fn_mods_count_installed
  253. # Set/reset variables.
  254. installedmodsline="1"
  255. installedmodslist=()
  256. modprettynamemaxlength="0"
  257. modsitemaxlength="0"
  258. moddescriptionmaxlength="0"
  259. modcommandmaxlength="0"
  260. # Loop through every line of the installed mods list ${modsinstalledlistfullpath}.
  261. while [ "${installedmodsline}" -le "${installedmodscount}" ]; do
  262. currentmod=$(sed "${installedmodsline}q;d" "${modsinstalledlistfullpath}")
  263. # Get mod info to make sure mod exists.
  264. fn_mod_get_info
  265. # Add the mod to available commands.
  266. installedmodslist+=("${modcommand}")
  267. # Increment line check.
  268. ((installedmodsline++))
  269. done
  270. if [ "${installedmodscount}" ]; then
  271. fn_script_log_info "${installedmodscount} addons/mods are currently installed"
  272. fi
  273. }
  274. # Loops through mods_global_array to define available mods & provide available commands for mods installation.
  275. fn_mods_available() {
  276. # First, reset variables.
  277. compatiblemodslist=()
  278. availablemodscommands=()
  279. # Find compatible games.
  280. # Find separators through the global array.
  281. for ((index = "0"; index <= ${#mods_global_array[@]}; index++)); do
  282. # If current value is a separator; then.
  283. if [ "${mods_global_array[index]}" == "${modseparator}" ]; then
  284. # Set mod variables.
  285. fn_mods_define
  286. # Test if game is compatible.
  287. fn_mod_compatible_test
  288. # If game is compatible.
  289. if [ "${modcompatibility}" == "1" ]; then
  290. # Put it into an array to prepare user output.
  291. compatiblemodslist+=("${modprettyname}" "${modcommand}" "${modsite}" "${moddescription}")
  292. # Keep available commands in an array to make life easier.
  293. availablemodscommands+=("${modcommand}")
  294. fi
  295. fi
  296. done
  297. }
  298. ## Mod compatibility check.
  299. # Find out if a game is compatible with a mod from a modgames (list of games supported by a mod) variable.
  300. fn_compatible_mod_games() {
  301. # Reset test value.
  302. modcompatiblegame="0"
  303. # If value is set to GAMES (ignore).
  304. if [ "${modgames}" != "GAMES" ]; then
  305. # How many games we need to test.
  306. gamesamount=$(echo -e "${modgames}" | awk -F ';' '{ print NF }')
  307. # Test all subvalue of "modgames" using the ";" separator.
  308. for ((gamevarindex = 1; gamevarindex < gamesamount; gamevarindex++)); do
  309. # Put current game name into modtest variable.
  310. gamemodtest=$(echo -e "${modgames}" | awk -F ';' -v x=${gamevarindex} '{ print $x }')
  311. # If game name matches.
  312. if [ "${gamemodtest}" == "${gamename}" ]; then
  313. # Mod is compatible.
  314. modcompatiblegame="1"
  315. fi
  316. done
  317. fi
  318. }
  319. # Find out if an engine is compatible with a mod from a modengines (list of engines supported by a mod) variable.
  320. fn_compatible_mod_engines() {
  321. # Reset test value.
  322. modcompatibleengine="0"
  323. # If value is set to ENGINES (ignore).
  324. if [ "${modengines}" != "ENGINES" ]; then
  325. # How many engines we need to test.
  326. enginesamount=$(echo -e "${modengines}" | awk -F ';' '{ print NF }')
  327. # Test all subvalue of "modengines" using the ";" separator.
  328. for ((gamevarindex = 1; gamevarindex < enginesamount; gamevarindex++)); do
  329. # Put current engine name into modtest variable.
  330. enginemodtest=$(echo -e "${modengines}" | awk -F ';' -v x=${gamevarindex} '{ print $x }')
  331. # If engine name matches.
  332. if [ "${enginemodtest}" == "${engine}" ]; then
  333. # Mod is compatible.
  334. modcompatibleengine="1"
  335. fi
  336. done
  337. fi
  338. }
  339. # Find out if a game is not compatible with a mod from a modnotgames (list of games not supported by a mod) variable.
  340. fn_not_compatible_mod_games() {
  341. # Reset test value.
  342. modeincompatiblegame="0"
  343. # If value is set to NOTGAMES (ignore).
  344. if [ "${modexcludegames}" != "NOTGAMES" ]; then
  345. # How many engines we need to test.
  346. excludegamesamount=$(echo -e "${modexcludegames}" | awk -F ';' '{ print NF }')
  347. # Test all subvalue of "modexcludegames" using the ";" separator.
  348. for ((gamevarindex = 1; gamevarindex < excludegamesamount; gamevarindex++)); do
  349. # Put current engine name into modtest variable.
  350. excludegamemodtest=$(echo -e "${modexcludegames}" | awk -F ';' -v x=${gamevarindex} '{ print $x }')
  351. # If engine name matches.
  352. if [ "${excludegamemodtest}" == "${gamename}" ]; then
  353. # Mod is compatible.
  354. modeincompatiblegame="1"
  355. fi
  356. done
  357. fi
  358. }
  359. # Sums up if a mod is compatible or not with modcompatibility=0/1.
  360. fn_mod_compatible_test() {
  361. # Test game and engine compatibility.
  362. fn_compatible_mod_games
  363. fn_compatible_mod_engines
  364. fn_not_compatible_mod_games
  365. if [ "${modeincompatiblegame}" == "1" ]; then
  366. modcompatibility="0"
  367. elif [ "${modcompatibleengine}" == "1" ] || [ "${modcompatiblegame}" == "1" ]; then
  368. modcompatibility="1"
  369. else
  370. modcompatibility="0"
  371. fi
  372. }
  373. ## Directory management.
  374. # Create mods files and directories if it doesn't exist.
  375. fn_create_mods_dir() {
  376. # Create lgsm data modsdir.
  377. if [ ! -d "${modsdir}" ]; then
  378. echo -en "creating LinuxGSM mods data directory ${modsdir}..."
  379. mkdir -p "${modsdir}"
  380. exitcode=$?
  381. if [ "${exitcode}" -ne 0 ]; then
  382. fn_print_fail_eol_nl
  383. fn_script_log_fail "Creating mod download dir ${modsdir}"
  384. core_exit.sh
  385. else
  386. fn_print_ok_eol_nl
  387. fn_script_log_pass "Creating mod download dir ${modsdir}"
  388. fi
  389. fi
  390. # Create mod install directory.
  391. if [ ! -d "${modinstalldir}" ]; then
  392. echo -en "creating mods install directory ${modinstalldir}..."
  393. mkdir -p "${modinstalldir}"
  394. exitcode=$?
  395. if [ "${exitcode}" -ne 0 ]; then
  396. fn_print_fail_eol_nl
  397. fn_script_log_fail "Creating mod install directory ${modinstalldir}"
  398. core_exit.sh
  399. else
  400. fn_print_ok_eol_nl
  401. fn_script_log_pass "Creating mod install directory ${modinstalldir}"
  402. fi
  403. fi
  404. # Create ${datadir}/${modsinstalledlist}.
  405. if [ ! -f "${modsinstalledlistfullpath}" ]; then
  406. touch "${modsinstalledlistfullpath}"
  407. fn_script_log_info "Created ${modsinstalledlistfullpath}"
  408. fi
  409. }
  410. # Create tmp download mod directory.
  411. fn_mods_create_tmp_dir() {
  412. if [ ! -d "${modstmpdir}" ]; then
  413. mkdir -p "${modstmpdir}"
  414. exitcode=$?
  415. echo -en "creating mod download directory ${modstmpdir}..."
  416. if [ "${exitcode}" -ne 0 ]; then
  417. fn_print_fail_eol_nl
  418. fn_script_log_fail "Creating mod download directory ${modstmpdir}"
  419. core_exit.sh
  420. else
  421. fn_print_ok_eol_nl
  422. fn_script_log_pass "Creating mod download directory ${modstmpdir}"
  423. fi
  424. fi
  425. }
  426. # Remove the tmp mod download directory when finished.
  427. fn_mods_clear_tmp_dir() {
  428. if [ -d "${modstmpdir}" ]; then
  429. echo -en "clearing mod download directory ${modstmpdir}..."
  430. rm -rf "${modstmpdir:?}"
  431. exitcode=$?
  432. if [ "${exitcode}" -ne 0 ]; then
  433. fn_print_fail_eol_nl
  434. fn_script_log_fail "Clearing mod download directory ${modstmpdir}"
  435. core_exit.sh
  436. else
  437. fn_print_ok_eol_nl
  438. fn_script_log_pass "Clearing mod download directory ${modstmpdir}"
  439. fi
  440. fi
  441. # Clear temp file list as well.
  442. if [ -f "${modsdir}/.removedfiles.tmp" ]; then
  443. rm -f "${modsdir:?}/.removedfiles.tmp"
  444. fi
  445. }
  446. # Counts how many mods were installed.
  447. fn_mods_count_installed() {
  448. if [ -f "${modsinstalledlistfullpath}" ]; then
  449. installedmodscount=$(wc -l < "${modsinstalledlistfullpath}")
  450. else
  451. installedmodscount=0
  452. fi
  453. }
  454. # Exits if no mods were installed.
  455. fn_mods_check_installed() {
  456. # Count installed mods.
  457. fn_mods_count_installed
  458. # If no mods are found.
  459. if [ "${installedmodscount}" -eq 0 ]; then
  460. echo -e ""
  461. fn_print_failure_nl "No installed mods or addons were found"
  462. echo -e " * Install mods using LinuxGSM first with: ./${selfname} mods-install"
  463. fn_script_log_error "No installed mods or addons were found."
  464. core_exit.sh
  465. fi
  466. }
  467. # Checks that mod files list exists and isn't empty.
  468. fn_check_mod_files_list() {
  469. # File list must exist and be valid before any operation on it.
  470. if [ -f "${modsdir}/${modcommand}-files.txt" ]; then
  471. # How many lines is the file list.
  472. modsfilelistsize=$(wc -l < "${modsdir}/${modcommand}-files.txt")
  473. # If file list is empty.
  474. if [ "${modsfilelistsize}" -eq 0 ]; then
  475. fn_print_failure "${modcommand}-files.txt is empty"
  476. echo -e "* Unable to remove ${modprettyname}"
  477. fn_script_log_fail "${modcommand}-files.txt is empty: Unable to remove ${modprettyname}."
  478. core_exit.sh
  479. fi
  480. else
  481. fn_print_failure "${modsdir}/${modcommand}-files.txt does not exist"
  482. fn_script_log_fail "${modsdir}/${modcommand}-files.txt does not exist: Unable to remove ${modprettyname}."
  483. core_exit.sh
  484. fi
  485. }
  486. fn_mod_exist() {
  487. modreq=$1
  488. # requires one parameter, the mod
  489. if [ -f "${modsdir}/${modreq}-files.txt" ]; then
  490. # how many lines is the file list
  491. modsfilelistsize=$(wc -l < "${modsdir}/${modreq}-files.txt")
  492. # if file list is empty
  493. if [ "${modsfilelistsize}" -eq 0 ]; then
  494. fn_mod_required_fail_exist "${modreq}"
  495. fi
  496. else
  497. fn_mod_required_fail_exist "${modreq}"
  498. fi
  499. }
  500. fn_mod_required_fail_exist() {
  501. modreq=$1
  502. # requires one parameter, the mod
  503. fn_script_log_fail "${modreq}-files.txt is empty: unable to find ${modreq} installed"
  504. echo -en "* Unable to find '${modreq}' which is required prior to installing this mod..."
  505. fn_print_fail_eol_nl
  506. core_exit.sh
  507. }
  508. fn_mod_liblist_gam_filenames() {
  509. # clear variables just in case
  510. moddll=""
  511. modso=""
  512. moddylib=""
  513. # default libraries
  514. case ${gamename} in
  515. "Counter-Strike 1.6")
  516. moddll="mp.dll"
  517. modso="cs.so"
  518. moddylib="cs.dylib"
  519. ;;
  520. "Day of Defeat")
  521. moddll="dod.dll"
  522. modso="dod.so"
  523. moddylib="dod.dylib"
  524. ;;
  525. "Team Fortress Classic")
  526. moddll="tfc.dll"
  527. modso="tfc.so"
  528. moddylib="tfc.dylib"
  529. ;;
  530. "Natural Selection")
  531. moddll="ns.dll"
  532. modso="ns_i386.so"
  533. moddylib=""
  534. ;;
  535. "The Specialists")
  536. moddll="mp.dll"
  537. modso="ts_i386.so"
  538. moddylib=""
  539. ;;
  540. "Half-Life: Deathmatch")
  541. moddll="hl.dll"
  542. modso="hl.so"
  543. moddylib="hl.dylib"
  544. ;;
  545. esac
  546. }
  547. # modifiers for liblist.gam to add/remote metamod binaries
  548. fn_mod_install_liblist_gam_file() {
  549. fn_mod_liblist_gam_filenames
  550. if [ -f "${modinstalldir}/liblist.gam" ]; then
  551. # modify the liblist.gam file to initialize Metamod
  552. logentry="sed replace (dlls\\${moddll}) ${modinstalldir}/liblist.gam"
  553. echo -en "modifying gamedll in liblist.gam..."
  554. rpldll="s/dlls\\\\${moddll}/addons\/metamod\/dlls\/metamod.dll/g"
  555. sed -i $rpldll "${modinstalldir}/liblist.gam"
  556. grep -q "addons/metamod/dlls/metamod.dll" "${modinstalldir}/liblist.gam"
  557. exitcode=$?
  558. # if replacement back didn't happen, error out.
  559. if [ "${exitcode}" -ne 0 ]; then
  560. fn_script_log_fail "${logentry}"
  561. fn_print_fail_eol_nl
  562. else
  563. fn_script_log_pass "${logentry}"
  564. fn_print_ok_eol_nl
  565. fi
  566. # modify the liblist.gam file to initialize metamod
  567. logentry="sed replace (dlls\\${modso}) ${modinstalldir}/liblist.gam"
  568. echo -en "modifying gamedll_linux in liblist.gam..."
  569. rplso="s/dlls\/${modso}/addons\/metamod\/dlls\/metamod.so/g"
  570. sed -i $rplso "${modinstalldir}/liblist.gam"
  571. grep -q "addons/metamod/dlls/metamod.so" "${modinstalldir}/liblist.gam"
  572. exitcode=$?
  573. # if replacement back didn't happen, error out
  574. if [ "${exitcode}" -ne 0 ]; then
  575. fn_script_log_fail "${logentry}"
  576. fn_print_fail_eol_nl
  577. else
  578. fn_script_log_pass "${logentry}"
  579. fn_print_ok_eol_nl
  580. fi
  581. # mac os needs to be checked not all mods support mac os
  582. if [ -n "${moddylib}" ]; then
  583. # modify the liblist.gam file to initialize metamod
  584. logentry="sed replace (dlls\\${moddylib}) ${modinstalldir}/liblist.gam"
  585. echo -en "modifying gamedll_osx in liblist.gam..."
  586. rpldylib="s/dlls\/${moddylib}/addons\/metamod\/dlls\/metamod.dylib/g"
  587. sed -i $rpldylib "${modinstalldir}/liblist.gam"
  588. grep -q "addons/metamod/dlls/metamod.dylib" "${modinstalldir}/liblist.gam"
  589. exitcode=$?
  590. # if replacement back didn't happen, error out.
  591. if [ "${exitcode}" -ne 0 ]; then
  592. fn_script_log_fail "${logentry}"
  593. fn_print_fail_eol_nl
  594. else
  595. fn_script_log_pass "${logentry}"
  596. fn_print_ok_eol_nl
  597. fi
  598. fi
  599. fi
  600. }
  601. fn_mod_remove_liblist_gam_file() {
  602. fn_mod_liblist_gam_filenames
  603. if [ -f "${modinstalldir}/liblist.gam" ]; then
  604. # modify the liblist.gam file back to defaults
  605. logentry="sed replace (addons/metamod/dlls/metamod.dll) ${modinstalldir}/liblist.gam"
  606. echo -en "modifying gamedll in liblist.gam..."
  607. rpldll="s/addons\/metamod\/dlls\/metamod.dll/dlls\\\\${moddll}/g"
  608. sed -i $rpldll "${modinstalldir}/liblist.gam"
  609. grep -q "${moddll}" "${modinstalldir}/liblist.gam"
  610. exitcode=$?
  611. # if replacement back didn't happen, error out.
  612. if [ "${exitcode}" -ne 0 ]; then
  613. fn_script_log_fail "${logentry}"
  614. fn_print_fail_eol_nl
  615. else
  616. fn_script_log_pass "${logentry}"
  617. fn_print_ok_eol_nl
  618. fi
  619. # modify the liblist.gam file back to defaults
  620. logentry="sed replace (addons/metamod/dlls/metamod.so) ${modinstalldir}/liblist.gam"
  621. echo -en "modifying gamedll_linux in liblist.gam..."
  622. rplso="s/addons\/metamod\/dlls\/metamod.so/dlls\/${modso}/g"
  623. sed -i $rplso "${modinstalldir}/liblist.gam"
  624. grep -q "${modso}" "${modinstalldir}/liblist.gam"
  625. exitcode=$?
  626. # if replacement back didn't happen, error out
  627. if [ "${exitcode}" -ne 0 ]; then
  628. fn_script_log_fail "${logentry}"
  629. fn_print_fail_eol_nl
  630. else
  631. fn_script_log_pass "${logentry}"
  632. fn_print_ok_eol_nl
  633. fi
  634. # mac os needs to be checked not all mods support mac os
  635. if [ -n "${moddylib}" ]; then
  636. # modify the liblist.gam file back to defaults
  637. logentry="sed replace (addons/metamod/dlls/metamod.dylib) ${modinstalldir}/liblist.gam"
  638. echo -en "modifying gamedll_osx in liblist.gam..."
  639. rpldylib="s/addons\/metamod\/dlls\/metamod.dylib/dlls\/${moddylib}/g"
  640. sed -i $rpldylib "${modinstalldir}/liblist.gam"
  641. grep -q "${moddylib}" "${modinstalldir}/liblist.gam"
  642. # if replacement back didn't happen, error out.
  643. exitcode=$?
  644. if [ "${exitcode}" -ne 0 ]; then
  645. fn_script_log_fail "${logentry}"
  646. fn_print_fail_eol_nl
  647. else
  648. fn_script_log_pass "${logentry}"
  649. fn_print_ok_eol_nl
  650. fi
  651. fi
  652. fi
  653. }
  654. # modifiers for gameinfo.gi to add/remove the Metamod:Source search path
  655. # Counter-Strike 2 only: the csgo paths below are specific to that game.
  656. fn_mod_install_gameinfo_gi_file() {
  657. local gameinfofile="${modinstalldir}/gameinfo.gi"
  658. local metamodpattern='^[[:space:]]*"?Game"?[[:space:]]+"?csgo/addons/metamod"?[[:space:]]*(//.*)?$'
  659. local lowviolencepattern='^[[:space:]]*"?Game_LowViolence"?[[:space:]]+"?csgo_lv"?[[:space:]]*(//.*)?$'
  660. if [ -f "${gameinfofile}" ]; then
  661. # the search path survives a mod update, only add it when it is missing
  662. if grep -Eq "${metamodpattern}" "${gameinfofile}"; then
  663. fn_script_log_info "Metamod:Source search path already set in ${gameinfofile}"
  664. else
  665. # insert the search path below Game_LowViolence as documented by Metamod:Source
  666. logentry="line (Game csgo/addons/metamod) inserted into ${gameinfofile}"
  667. echo -en "adding Metamod:Source search path in gameinfo.gi..."
  668. sed -i -E "\\@${lowviolencepattern}@a\\\\t\\t\\tGame\\tcsgo/addons/metamod" "${gameinfofile}"
  669. grep -Eq "${metamodpattern}" "${gameinfofile}"
  670. exitcode=$?
  671. # if the insert didn't happen, error out
  672. if [ "${exitcode}" -ne 0 ]; then
  673. fn_script_log_fail "${logentry}"
  674. fn_print_fail_eol_nl
  675. core_exit.sh
  676. else
  677. fn_script_log_pass "${logentry}"
  678. fn_print_ok_eol_nl
  679. fi
  680. fi
  681. else
  682. fn_script_log_fail "Unable to find ${gameinfofile}"
  683. fn_print_fail_nl "Unable to find ${gameinfofile}"
  684. core_exit.sh
  685. fi
  686. }
  687. # Unlike the install counterpart this does not call core_exit.sh on failure:
  688. # command_mods_remove.sh ends with fn_script_log, which leaves exitcode alone,
  689. # while command_mods_install.sh ends with fn_script_log_pass, which resets it to 0.
  690. fn_mod_remove_gameinfo_gi_file() {
  691. local gameinfofile="${modinstalldir}/gameinfo.gi"
  692. local metamodpattern='^[[:space:]]*"?Game"?[[:space:]]+"?csgo/addons/metamod"?[[:space:]]*(//.*)?$'
  693. if [ -f "${gameinfofile}" ]; then
  694. # is the search path found? If so remove it and keep the rest of the file
  695. if grep -Eq "${metamodpattern}" "${gameinfofile}"; then
  696. logentry="line (Game csgo/addons/metamod) removed from ${gameinfofile}"
  697. echo -en "removing Metamod:Source search path in gameinfo.gi..."
  698. # delete the line we inserted
  699. sed -i -E "\\@${metamodpattern}@d" "${gameinfofile}"
  700. if grep -Eq "${metamodpattern}" "${gameinfofile}"; then
  701. fn_script_log_fail "${logentry}"
  702. fn_print_fail_eol_nl
  703. else
  704. fn_script_log_pass "${logentry}"
  705. fn_print_ok_eol_nl
  706. fi
  707. fi
  708. fi
  709. }
  710. fn_mod_install_amxmodx_file() {
  711. # does plugins.ini exist?
  712. if [ -f "${modinstalldir}/addons/metamod/plugins.ini" ]; then
  713. # since it does exist, is the entry already in plugins.ini
  714. logentry="line (linux addons/amxmodx/dlls/amxmodx_mm_i386.so) inserted into ${modinstalldir}/addons/metamod/plugins.ini"
  715. echo -en "adding amxmodx_mm_i386.so in plugins.ini..."
  716. if ! grep -q "amxmodx_mm_i386.so" "${modinstalldir}/addons/metamod/plugins.ini"; then
  717. # file exists but the entry does not, let's add it
  718. if ! echo "linux addons/amxmodx/dlls/amxmodx_mm_i386.so" >> "${modinstalldir}/addons/metamod/plugins.ini"; then
  719. fn_script_log_fail "${logentry}"
  720. fn_print_fail_eol_nl
  721. else
  722. fn_script_log_pass "${logentry}"
  723. fn_print_ok_eol_nl
  724. fi
  725. fi
  726. else
  727. # create new file and add the mod to it
  728. if ! echo "linux addons/amxmodx/dlls/amxmodx_mm_i386.so" > "${modinstalldir}/addons/metamod/plugins.ini"; then
  729. fn_script_log_fail "${logentry}"
  730. fn_print_fail_eol_nl
  731. core_exit.sh
  732. else
  733. fn_script_log_pass "${logentry}"
  734. fn_print_ok_eol_nl
  735. fi
  736. fi
  737. }
  738. fn_mod_remove_amxmodx_file() {
  739. if [ -f "${modinstalldir}/addons/metamod/plugins.ini" ]; then
  740. # since it does exist, is the entry already in plugins.ini
  741. logentry="line (linux addons/amxmodx/dlls/amxmodx_mm_i386.so) removed from ${modinstalldir}/addons/metamod/plugins.ini"
  742. echo -en "removing amxmodx_mm_i386.so in plugins.ini..."
  743. # is it found? If so remove it and clean up
  744. if grep -q "linux addons/amxmodx/dlls/amxmodx_mm_i386.so" "${modinstalldir}/addons/metamod/plugins.ini"; then
  745. # delete the line we inserted
  746. sed -i '/linux addons\/amxmodx\/dlls\/amxmodx_mm_i386.so/d' "${modinstalldir}/addons/metamod/plugins.ini"
  747. # remove empty lines
  748. sed -i '/^$/d' "${modinstalldir}/addons/metamod/plugins.ini"
  749. exitcode=$?
  750. if [ "${exitcode}" -ne 0 ]; then
  751. fn_script_log_fail "${logentry}"
  752. fn_print_fail_eol_nl
  753. else
  754. fn_script_log_pass "${logentry}"
  755. fn_print_ok_eol_nl
  756. fi
  757. # if file is empty, remove it.
  758. if [ -f "${modinstalldir}/addons/metamod/plugins.ini" ]; then
  759. rm -f "${modinstalldir}/addons/metamod/plugins.ini"
  760. fn_script_log_pass "file removed ${modinstalldir}/addons/metamod/plugins.ini because it was empty"
  761. fi
  762. fi
  763. fi
  764. }
  765. ## Database initialisation.
  766. mods_list.sh
  767. fn_mods_available