Bladeren bron

fix (alerts): Alerts on update uses the old game server version not the new one (#4854)

* feat: refactor update comparison output for consistency and clarity

- Replaced direct echo statements with fn_print functions for uniformity in output formatting across multiple update scripts.
- Ensured lockfile creation uses the correct syntax for variable expansion.
- Moved lock file to the same location to ensure monitor doesnt reboot at the wrong time
- Updated remote build information display to enhance readability and maintain consistency in logging.
- Removed unnecessary echo commands to streamline the output process.

* Refactor remote build version handling across multiple modules

- Updated variable names from 'remotebuildversion' to 'remotebuild' for consistency.
- Adjusted logic to check for remote build availability using the new variable name.
- Modified output messages to reflect the change in variable naming.
- Ensured all modules (update_mc.sh, update_mcb.sh, update_mta.sh, update_pmc.sh, update_ts3.sh, update_ut99.sh, update_vints.sh, update_xnt.sh) are aligned with the new naming convention for better readability and maintainability.

* fix(alert): resolve issue with servername not always being listed in title

* Moved `info_distro.sh`, `info_game.sh`, and `info_messages.sh` calls to the top of the `fn_alert_log` function for better clarity.
* Updated `alerticon` assignment to maintain consistency in alert information handling.

* fix(alert_discord): remove "More info" field from Discord alert JSON

* Eliminated the "More info" field to streamline the alert message.
* This change enhances the clarity of the alert by focusing on essential information.

* fix(alert): improve update alert messaging for clarity

* Updated alert messages in `fn_alert_update` and `fn_alert_update_failed` for better readability.
* Changed alert action from `update-request` to `update-restart-request` in `fn_monitor_check_update_source`.

* remove inline

* fix(alert): Correct grammar in update alert message

* Changed "an LinuxGSM update" to "a LinuxGSM update" for grammatical accuracy.

* typo

* fix(alert_discord): Add inline property to "Is my Game Server Online?" field

* Ensures proper formatting of the Discord alert message.
* Improves the display of the server status information.

* fix(pd): increase timeout for termbin.com connection

* fix(alert_discord): reorder fields in Discord alert JSON

* Changed the order of fields in the Discord alert JSON structure.
* Updated the "More info" and "Is my Game Server Online?" fields for better clarity.

* revert back to factorio.com

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Standardizes alert messages across platforms

Ensures consistency in alert messages across Discord, NTFY,
Pushover, Rocketchat, Slack, and Telegram.

Updates Discord alerts to include server hostname and time,
removes redundant formatting.

Standardizes plain-text alert formatting for NTFY.

Refactors Pushover messages to use consistent HTML formatting.

Streamlines Rocketchat and Slack messages by removing duplicate
server info and adding optional link support.

* Removes Hostname from alert messages

Removes the Hostname field from various alert messages (Discord, Gotify, IFTTT, ntfy, Pushbullet, Pushover, Rocketchat, Slack, Telegram).

The hostname was deemed redundant or unnecessary in the context of these alerts.

Relates to #4696

* Configures shellcheckrc filename

Configures the Super-Linter action to use `.shellcheckrc` as the
BASH_FILE_NAME. This ensures that shellcheck uses the correct
configuration file for bash script linting.

Fixes #4696

* Disables shellcheck errors and removes variable

Disables specific shellcheck errors to allow certain coding
patterns and removes an unused variable from the super-linter
workflow. This improves the linter's signal-to-noise ratio
and reduces unnecessary checks.

Relates to #4696

* Fixes and improves server list validation scripts

Addresses issues in the server list validation scripts:

- Fixes potential issues with parsing curl custom arguments in telegram alerts.
- Corrects the shortname array generation.
- Implements more robust checks for validating game icons.
- Ensures the consistency of server counts across different CSV files.

* Fixes glibc check and mod selection logic

Corrects glibc version comparison to properly handle version strings.

Improves mod installation and removal by validating user input
against available options, providing a more robust selection process.
This prevents errors caused by invalid mod names and enhances the
user experience.

Updates arithmetic expression syntax for better compatibility.

* Fixes cache control for dev-debug mode

Updates the handling of cache control headers in dev-debug mode.
The `nocache` variable is changed to an array to correctly pass multiple headers to `curl`.
This resolves issues with cached versions of files being used when dev-debug is enabled, ensuring that the latest versions are always fetched.

Fixes #4696

* Allows spaces in steamcmdcommand variable

Parses steamcmdcommand as an array to allow spaces in the
variable.

This prevents issues when the user wants to pass arguments
with spaces to the steamcmd executable.

* Addresses various script improvements

Addresses multiple improvements across various scripts:

- Fixes Valheim unstripped_corlib override by commenting out the lines in the config files.
- Improves process identification for source and goldsrc engines using `pgrep`.
- Enhances backup file identification using `find` with `-maxdepth 1` and `-type f`.
- Fixes glibc version comparison logic in multiple files.
- Improves UT2K4 key installation script by using printf for writing the key to the file.
- Corrects the mod info extraction logic to correctly identify mod entries.
- Improves amxmodx file installation/removal logic to prevent duplicate entries.
- Fixes server info retrieval to handle spaces in the server list.

Relates to #4696

* Fixes mono repo install exit code check

Corrects the mono repo install exit code check to use the dedicated monorepoexitcode variable, ensuring accurate error detection.

Updates the exit trap to preserve the original exit status, preventing potential loss of information when handling script termination.

* Refactors and reorders core modules

Improves module loading by reordering and refactoring the core modules.

This change addresses inconsistencies and improves the overall structure
of how core modules are handled within the system.
Some fix scripts were renamed to match the module name.

* Makes scripts executable

Changes file permissions to make shell scripts executable.
This ensures that the scripts can be run directly.

Addresses a pre-existing issue.
Related to #4696

* Adds explicit permissions to workflows

Specifies explicit permissions for GitHub Actions workflows to enhance security and control access to resources.

This ensures that each workflow only has the necessary permissions, following the principle of least privilege.

* Fixes output redirection and URL parsing

Corrects output redirection in GitHub Actions workflows by enclosing the $GITHUB_OUTPUT variable in quotes, preventing potential issues with variable expansion.

Ensures proper URL parsing in workflows by enclosing the URL within quotes, addressing potential parsing errors.

Fixes #4696

* Applies code formatting for consistency

Applies Prettier formatting to the codebase for improved
readability and consistency.

Addresses minor code style inconsistencies across several files.

* Fixes minor formatting and logic issues

Addresses various minor issues including:

- Standardizes indentation in `.editorconfig` for different file types.
- Simplifies Prettier configuration.
- Updates image links in `README.md`.
- Ensures newline character at end of `.csv` files.
- Corrects a conditional statement in `command_fastdl.sh`.
- Corrects a conditional statement in `info_messages.sh`.
- Updates server query protocols in `query_gsquery.py`.

* Configures and disables linters

Adds YAML linting configuration and disables unnecessary
linters to streamline the CI/CD process and reduce
noise from irrelevant checks.

* Improves documentation and linting

Updates documentation links to be enclosed in angle brackets, preventing markdown rendering issues.

Configures markdownlint to align with repository standards and avoid common false positives.

The updated links in the documentation ensure they are correctly interpreted by markdown parsers, improving user experience.

The markdownlint configuration fine-tunes linting rules to better match the project's existing style and conventions, reducing noise from irrelevant warnings.

* Fixes typos and improves code consistency

Addresses various typos and inconsistencies across multiple files,
enhancing code readability and maintainability.

Adds codespell and flake8 configurations for linting.

Relates to #4696

* Excludes workflow files from Prettier formatting

Prevents Prettier from formatting workflow files due to GitHub token restrictions, as the token used by the Prettier auto-commit action lacks permissions to update files within the `.github/workflows/` directory.

* chore(prettier): format code

* Updates Super-Linter configuration

Improves Super-Linter's reliability by switching to linting the entire codebase instead of relying on git history. This change also addresses potential transient fetch failures from GitHub.

Additionally, this commit expands the ignored paths in codespell and disables some linters to improve performance and reduce false positives.

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: dgibbs64 <dgibbs64@users.noreply.github.com>
Daniel Gibbs 2 maanden geleden
bovenliggende
commit
fef128fb7d
98 gewijzigde bestanden met toevoegingen van 1155 en 1097 verwijderingen
  1. 28 28
      .devcontainer/devcontainer.json
  2. 16 1
      .editorconfig
  3. 11 0
      .github/linters/.codespellrc
  4. 2 0
      .github/linters/.flake8
  5. 23 0
      .github/linters/.markdown-lint.yml
  6. 1 0
      .github/linters/.shellcheckrc
  7. 25 0
      .github/linters/.yaml-lint.yml
  8. 15 15
      .github/pull_request_template.md
  9. 5 3
      .github/workflows/action-super-linter.yml
  10. 2 0
      .github/workflows/add-to-project.yml
  11. 6 4
      .github/workflows/details-check-generate-matrix.sh
  12. 5 2
      .github/workflows/details-check.yml
  13. 2 0
      .github/workflows/git-sync.yml
  14. 4 0
      .github/workflows/potential-duplicates.yml
  15. 8 4
      .github/workflows/serverlist-validate-game-icons.sh
  16. 6 3
      .github/workflows/serverlist-validate.sh
  17. 3 0
      .github/workflows/serverlist-validate.yml
  18. 2 0
      .github/workflows/trigger-docker-build.yml
  19. 3 1
      .github/workflows/update-check.yml
  20. 4 0
      .github/workflows/update-copyright-years-in-license-file.yml
  21. 3 0
      .github/workflows/version-check.sh
  22. 1 1
      .prettierrc
  23. 1 1
      .prettierrc.json
  24. 1 1
      .shellcheckrc
  25. 10 10
      .vscode/extensions.json
  26. 15 15
      CODE_OF_CONDUCT.md
  27. 66 67
      CONTRIBUTING.md
  28. 16 16
      README.md
  29. 1 1
      lgsm/config-default/config-lgsm/armarserver/_default.cfg
  30. 1 1
      lgsm/config-default/config-lgsm/necserver/_default.cfg
  31. 1 1
      lgsm/config-default/config-lgsm/ns2cserver/_default.cfg
  32. 1 1
      lgsm/config-default/config-lgsm/ns2server/_default.cfg
  33. 1 1
      lgsm/config-default/config-lgsm/pwserver/_default.cfg
  34. 1 1
      lgsm/data/name-left.csv
  35. 1 1
      lgsm/data/name-right.csv
  36. 9 9
      lgsm/modules/README.md
  37. 41 20
      lgsm/modules/alert.sh
  38. 10 11
      lgsm/modules/alert_discord.sh
  39. 1 1
      lgsm/modules/alert_email.sh
  40. 1 1
      lgsm/modules/alert_ifttt.sh
  41. 17 9
      lgsm/modules/alert_ntfy.sh
  42. 1 1
      lgsm/modules/alert_pushbullet.sh
  43. 2 2
      lgsm/modules/alert_pushover.sh
  44. 6 60
      lgsm/modules/alert_rocketchat.sh
  45. 6 90
      lgsm/modules/alert_slack.sh
  46. 8 2
      lgsm/modules/alert_telegram.sh
  47. 3 3
      lgsm/modules/check.sh
  48. 1 1
      lgsm/modules/check_executable.sh
  49. 1 0
      lgsm/modules/check_ip.sh
  50. 1 1
      lgsm/modules/check_logs.sh
  51. 1 1
      lgsm/modules/check_root.sh
  52. 1 1
      lgsm/modules/check_tmuxception.sh
  53. 1 1
      lgsm/modules/command_details.sh
  54. 1 1
      lgsm/modules/command_dev_clear_modules.sh
  55. 4 4
      lgsm/modules/command_dev_detect_ldd.sh
  56. 1 1
      lgsm/modules/command_dev_ui.sh
  57. 18 5
      lgsm/modules/command_install.sh
  58. 17 4
      lgsm/modules/command_mods_remove.sh
  59. 2 2
      lgsm/modules/command_mods_update.sh
  60. 2 2
      lgsm/modules/command_postdetails.sh
  61. 2 2
      lgsm/modules/command_restart.sh
  62. 2 2
      lgsm/modules/command_start.sh
  63. 20 19
      lgsm/modules/command_test_alert.sh
  64. 25 13
      lgsm/modules/command_validate.sh
  65. 1 1
      lgsm/modules/core_exit.sh
  66. 1 1
      lgsm/modules/core_logs.sh
  67. 98 108
      lgsm/modules/core_modules.sh
  68. 11 11
      lgsm/modules/core_steamcmd.sh
  69. 4 2
      lgsm/modules/core_trap.sh
  70. 2 2
      lgsm/modules/fix.sh
  71. 1 1
      lgsm/modules/fix_arma3.sh
  72. 1 1
      lgsm/modules/fix_hw.sh
  73. 1 1
      lgsm/modules/fix_pvr.sh
  74. 1 1
      lgsm/modules/fix_rw.sh
  75. 1 1
      lgsm/modules/fix_squad.sh
  76. 1 1
      lgsm/modules/fix_steamcmd.sh
  77. 3 3
      lgsm/modules/fix_ut.sh
  78. 7 7
      lgsm/modules/fix_wurm.sh
  79. 3 3
      lgsm/modules/info_game.sh
  80. 3 3
      lgsm/modules/info_messages.sh
  81. 2 2
      lgsm/modules/info_stats.sh
  82. 1 1
      lgsm/modules/install_dst_token.sh
  83. 13 20
      lgsm/modules/mods_core.sh
  84. 3 3
      lgsm/modules/mods_list.sh
  85. 1 1
      lgsm/modules/query_gamedig.sh
  86. 118 66
      lgsm/modules/query_gsquery.py
  87. 63 37
      lgsm/modules/update_fctr.sh
  88. 31 37
      lgsm/modules/update_jk2.sh
  89. 35 41
      lgsm/modules/update_mc.sh
  90. 35 41
      lgsm/modules/update_mcb.sh
  91. 31 37
      lgsm/modules/update_mta.sh
  92. 32 38
      lgsm/modules/update_pmc.sh
  93. 31 37
      lgsm/modules/update_steamcmd.sh
  94. 32 38
      lgsm/modules/update_ut99.sh
  95. 34 39
      lgsm/modules/update_vints.sh
  96. 31 38
      lgsm/modules/update_xnt.sh
  97. 2 1
      linuxgsm.sh
  98. 25 25
      package.json

+ 28 - 28
.devcontainer/devcontainer.json

@@ -1,30 +1,30 @@
 {
-  "name": "BASH Dev Container",
-  "image": "mcr.microsoft.com/devcontainers/base:ubuntu",
-  "features": {
-    "ghcr.io/devcontainers-community/npm-features/prettier:1": {
-      "plugins": "prettier-plugin-sh"
-    },
-    "ghcr.io/devcontainers-extra/features/actionlint:1": {},
-    "ghcr.io/devcontainers-extra/features/checkov:1": {},
-    "ghcr.io/devcontainers-extra/features/markdownlint-cli:1": {},
-    "ghcr.io/devcontainers-extra/features/shellcheck:1": {},
-    "ghcr.io/devcontainers-extra/features/yamllint:2": {},
-    "ghcr.io/devcontainers/features/github-cli:1": {}
-  },
-  "customizations": {
-    "vscode": {
-      "extensions": [
-        "DavidAnson.vscode-markdownlint",
-        "editorconfig.editorconfig",
-        "esbenp.prettier-vscode",
-        "github.vscode-github-actions",
-        "GitHub.vscode-pull-request-github",
-        "redhat.vscode-yaml",
-        "timonwong.shellcheck",
-        "yzhang.markdown-all-in-one"
-      ]
-    }
-  },
-  "postCreateCommand": "npm init -y >/dev/null 2>&1 || true && npm install --no-save prettier prettier-plugin-sh prettier-plugin-jinja-template"
+	"name": "BASH Dev Container",
+	"image": "mcr.microsoft.com/devcontainers/base:ubuntu",
+	"features": {
+		"ghcr.io/devcontainers-community/npm-features/prettier:1": {
+			"plugins": "prettier-plugin-sh"
+		},
+		"ghcr.io/devcontainers-extra/features/actionlint:1": {},
+		"ghcr.io/devcontainers-extra/features/checkov:1": {},
+		"ghcr.io/devcontainers-extra/features/markdownlint-cli:1": {},
+		"ghcr.io/devcontainers-extra/features/shellcheck:1": {},
+		"ghcr.io/devcontainers-extra/features/yamllint:2": {},
+		"ghcr.io/devcontainers/features/github-cli:1": {}
+	},
+	"customizations": {
+		"vscode": {
+			"extensions": [
+				"DavidAnson.vscode-markdownlint",
+				"editorconfig.editorconfig",
+				"esbenp.prettier-vscode",
+				"github.vscode-github-actions",
+				"GitHub.vscode-pull-request-github",
+				"redhat.vscode-yaml",
+				"timonwong.shellcheck",
+				"yzhang.markdown-all-in-one"
+			]
+		}
+	},
+	"postCreateCommand": "npm init -y >/dev/null 2>&1 || true && npm install --no-save prettier prettier-plugin-sh prettier-plugin-jinja-template"
 }

+ 16 - 1
.editorconfig

@@ -12,6 +12,21 @@ insert_final_newline = true
 trim_trailing_whitespace = true
 
 # BASH Files
-[*.{.sh}]
+[*.sh]
 indent_size = 4
 indent_style = tab
+
+# JSON Files (Biome formatting)
+[*.json]
+indent_style = tab
+indent_size = 2
+
+# Steam appmanifest files (Valve ACF format)
+[*.acf]
+indent_style = tab
+indent_size = 4
+
+# Python
+[*.py]
+indent_style = space
+indent_size = 4

+ 11 - 0
.github/linters/.codespellrc

@@ -0,0 +1,11 @@
+[codespell]
+# Skip data tables that contain many short server identifiers (e.g. "fof", "nd")
+skip =
+	lgsm/data/*.csv,
+	package-lock.json,
+	*/package-lock.json,
+	node_modules,
+	*/node_modules/*
+
+# Ignore common identifiers/acronyms and extensions used throughout LinuxGSM
+ignore-words-list = distroname,fof,nd,sav,parms,ThirdParty

+ 2 - 0
.github/linters/.flake8

@@ -0,0 +1,2 @@
+[flake8]
+max-line-length = 120

+ 23 - 0
.github/linters/.markdown-lint.yml

@@ -0,0 +1,23 @@
+# Configuration for markdownlint (used by Super Linter)
+
+# MD041: README starts with HTML badges in this repo.
+MD041: false
+
+# MD051: GitHub heading anchor generation can differ (emoji, punctuation).
+MD051: false
+
+# MD013: The project documentation frequently contains long URLs/commands.
+MD013: false
+
+# MD033: The main README uses inline HTML for badges.
+MD033: false
+
+# Match existing list formatting in this repo.
+MD007:
+  indent: 4
+
+MD030:
+  ul_single: 3
+  ol_single: 2
+  ul_multi: 3
+  ol_multi: 2

+ 1 - 0
.github/linters/.shellcheckrc

@@ -0,0 +1 @@
+disable=SC2154,SC2034

+ 25 - 0
.github/linters/.yaml-lint.yml

@@ -0,0 +1,25 @@
+extends: default
+
+rules:
+  document-start: disable
+  truthy: disable
+
+  line-length:
+    max: 200
+    level: warning
+    allow-non-breakable-words: true
+    allow-non-breakable-inline-mappings: true
+
+  braces:
+    min-spaces-inside: 0
+    max-spaces-inside: 1
+    min-spaces-inside-empty: 0
+    max-spaces-inside-empty: 0
+
+  empty-lines:
+    max: 2
+    max-start: 0
+    max-end: 0
+
+  comments:
+    min-spaces-from-content: 1

+ 15 - 15
.github/pull_request_template.md

@@ -6,30 +6,30 @@ Fixes #[issue]
 
 ## Type of change
 
--   [ ] Bug fix (a change which fixes an issue).
--   [ ] New feature (a change which adds functionality).
--   [ ] New Server (new server added).
--   [ ] Refactor (restructures existing code).
--   [ ] Comment update (typo, spelling, explanation, examples, etc).
+- [ ] Bug fix (a change which fixes an issue).
+- [ ] New feature (a change which adds functionality).
+- [ ] New Server (new server added).
+- [ ] Refactor (restructures existing code).
+- [ ] Comment update (typo, spelling, explanation, examples, etc).
 
 ## Checklist
 
 PR will not be merged until all steps are complete.
 
--   [ ] This pull request links to an issue.
--   [ ] This pull request uses the `develop` branch as its base.
--   [ ] This pull request subject follows the Conventional Commits standard.
--   [ ] This code follows the style guidelines of this project.
--   [ ] I have performed a self-review of my code.
--   [ ] I have checked that this code is commented where required.
--   [ ] I have provided a detailed enough description of this PR.
--   [ ] I have checked if documentation needs updating.
+- [ ] This pull request links to an issue.
+- [ ] This pull request uses the `develop` branch as its base.
+- [ ] This pull request subject follows the Conventional Commits standard.
+- [ ] This code follows the style guidelines of this project.
+- [ ] I have performed a self-review of my code.
+- [ ] I have checked that this code is commented where required.
+- [ ] I have provided a detailed enough description of this PR.
+- [ ] I have checked if documentation needs updating.
 
 ## Documentation
 
 If documentation does need updating either update it by creating a PR (preferred) or request a documentation update.
 
--   User docs: https://github.com/GameServerManagers/LinuxGSM-Docs
--   Dev docs: https://github.com/GameServerManagers/LinuxGSM-Dev-Docs
+- User docs: <https://github.com/GameServerManagers/LinuxGSM-Docs>
+- Dev docs: <https://github.com/GameServerManagers/LinuxGSM-Dev-Docs>
 
 **Thank you for your Pull Request!**

+ 5 - 3
.github/workflows/action-super-linter.yml

@@ -27,9 +27,10 @@ jobs:
       - name: Checkout code
         uses: actions/checkout@v6
         with:
-          # super-linter needs the full git history to get the
-          # list of files that changed across commits
-          fetch-depth: 0
+          # Shallow clone reduces transient fetch failures (HTTP 500) from GitHub.
+          # We lint the whole codebase instead of relying on git history.
+          fetch-depth: 1
+          fetch-tags: false
           persist-credentials: false
 
       - name: Install Prettier plugins (for summary formatting)
@@ -48,6 +49,7 @@ jobs:
           VALIDATE_JSON_PRETTIER: false
           VALIDATE_MARKDOWN_PRETTIER: false
           VALIDATE_NATURAL_LANGUAGE: false
+          VALIDATE_PYTHON_RUFF_FORMAT: false
           VALIDATE_SHELL_SHFMT: false
           VALIDATE_TRIVY: false
           VALIDATE_YAML_PRETTIER: false

+ 2 - 0
.github/workflows/add-to-project.yml

@@ -5,6 +5,8 @@ on:
       - opened
       - labeled
 
+permissions: {}
+
 jobs:
   add-to-project:
     if: github.repository_owner == 'GameServerManagers'

+ 6 - 4
.github/workflows/details-check-generate-matrix.sh

@@ -14,10 +14,12 @@ while read -r line; do
 	export gamename
 	distro=$(echo "$line" | awk -F, '{ print $4 }')
 	export distro
-	echo -n "{" >> "shortnamearray.json"
-	echo -n "\"shortname\":" >> "shortnamearray.json"
-	echo -n "\"${shortname}\"" >> "shortnamearray.json"
-	echo -n "}," >> "shortnamearray.json"
+	{
+		echo -n "{";
+		echo -n "\"shortname\":";
+		echo -n "\"${shortname}\"";
+		echo -n "},";
+	} >> "shortnamearray.json"
 done < <(tail -n +2 serverlist.csv)
 sed -i '$ s/.$//' "shortnamearray.json"
 echo -n "]" >> "shortnamearray.json"

+ 5 - 2
.github/workflows/details-check.yml

@@ -6,6 +6,9 @@ on:
     branches:
       - develop
 
+permissions:
+  contents: read
+
 concurrency:
   group: details-check-${{ github.ref_name }}
   cancel-in-progress: true
@@ -28,7 +31,7 @@ jobs:
         run: |
           shortnamearray=$(cat shortnamearray.json)
           echo "${shortnamearray}"
-          echo -n "matrix=${shortnamearray}" >> $GITHUB_OUTPUT
+          echo -n "matrix=${shortnamearray}" >> "$GITHUB_OUTPUT"
 
   details-check:
     if: github.repository_owner == 'GameServerManagers'
@@ -41,7 +44,7 @@ jobs:
 
     steps:
       - name: Download linuxgsm.sh
-        run: wget https://raw.githubusercontent.com/GameServerManagers/LinuxGSM/${GITHUB_REF#refs/heads/}/linuxgsm.sh; chmod +x linuxgsm.sh
+        run: wget "https://raw.githubusercontent.com/GameServerManagers/LinuxGSM/${GITHUB_REF#refs/heads/}/linuxgsm.sh"; chmod +x linuxgsm.sh
 
       - name: Install dependencies
         run: sudo apt-get install libxml2-utils jq

+ 2 - 0
.github/workflows/git-sync.yml

@@ -7,6 +7,8 @@ on:
       - master
       - develop
 
+permissions: {}
+
 jobs:
   gitHub-to-bitbucket:
     if: github.repository_owner == 'GameServerManagers'

+ 4 - 0
.github/workflows/potential-duplicates.yml

@@ -3,6 +3,10 @@ on:
   issues:
     types:
       - opened
+
+permissions:
+  issues: write
+
 jobs:
   potential-duplicates:
     if: github.repository_owner == 'GameServerManagers'

+ 8 - 4
.github/workflows/serverlist-validate-game-icons.sh

@@ -2,6 +2,8 @@
 
 cd "${datadir}" || exit
 
+exitcode=0
+
 echo ""
 echo "Checking that all the game servers listed in serverlist.csv have a shortname-icon.png file"
 for shortname in $(tail -n +2 serverlist.csv | cut -d ',' -f1); do
@@ -16,9 +18,11 @@ done
 
 echo ""
 echo "Checking if an unexpected gameicon exists"
-for gameicon in $(ls -1 gameicons); do
+shopt -s nullglob
+for gameiconpath in gameicons/*; do
+	gameicon="$(basename "${gameiconpath}")"
 	# check if $gameicon is in serverlist.csv
-	if ! grep -q "${gameicon%-icon.png}" serverlist.csv; then
+	if ! grep -q -F "${gameicon%-icon.png}" serverlist.csv; then
 		echo "ERROR: gameicon ${gameicon} is not in serverlist.csv"
 		exitcode=1
 	else
@@ -28,7 +32,7 @@ done
 
 echo ""
 echo "Checking that the number of gameicons matches the number of servers in serverlist.csv"
-gameiconcount="$(ls -1 gameicons | wc -l)"
+gameiconcount="$(find gameicons -mindepth 1 -maxdepth 1 -type f | wc -l)"
 serverlistcount="$(tail -n +2 serverlist.csv | wc -l)"
 if [ "${gameiconcount}" -ne "${serverlistcount}" ]; then
 	echo "ERROR: game icons (${gameiconcount}) does not match serverlist.csv ($serverlistcount)"
@@ -37,4 +41,4 @@ else
 	echo "OK: gameiconcount ($gameiconcount) matches serverlistcount ($serverlistcount)"
 fi
 
-exit ${exitcode}
+exit "${exitcode}"

+ 6 - 3
.github/workflows/serverlist-validate.sh

@@ -3,12 +3,15 @@ echo "Checking that all the game servers are listed in all csv files"
 echo "this check will ensure serverlist.csv has the same number of lines (-2 lines) as the other csv files"
 # count the number of lines in the serverlist.csv
 cd "${datadir}" || exit
+
+exitcode=0
 serverlistcount="$(tail -n +2 serverlist.csv | wc -l)"
 echo "serverlistcount: $serverlistcount"
 # get list of all csv files starting with ubunutu debian centos
-csvlist="$(ls -1 | grep -E '^(ubuntu|debian|centos|rhel|almalinux|rocky).*\.csv$')"
+shopt -s nullglob
+csvlist=(ubuntu*.csv debian*.csv centos*.csv rhel*.csv almalinux*.csv rocky*.csv)
 # loop though each csv file and make sure the number of lines is the same as the serverlistcount
-for csv in $csvlist; do
+for csv in "${csvlist[@]}"; do
 	csvcount="$(wc -l < "${csv}")"
 	csvcount=$((csvcount - 2))
 	if [ "$csvcount" -ne "$serverlistcount" ]; then
@@ -35,4 +38,4 @@ for shortname in $(tail -n +2 serverlist.csv | cut -d ',' -f1); do
 	fi
 done
 
-exit ${exitcode}
+exit "${exitcode}"

+ 3 - 0
.github/workflows/serverlist-validate.yml

@@ -3,6 +3,9 @@ on:
   workflow_dispatch:
   push:
 
+permissions:
+  contents: read
+
 jobs:
   serverlist-validate:
     if: github.repository_owner == 'GameServerManagers'

+ 2 - 0
.github/workflows/trigger-docker-build.yml

@@ -6,6 +6,8 @@ on:
     types:
       - published
 
+permissions: {}
+
 jobs:
   trigger_build_docker-linuxgsm:
     if: github.repository_owner == 'GameServerManagers'

+ 3 - 1
.github/workflows/update-check.yml

@@ -6,6 +6,8 @@ on:
     branches:
       - develop
 
+permissions: {}
+
 concurrency:
   group: update-check-${{ github.ref_name }}
   cancel-in-progress: true
@@ -22,7 +24,7 @@ jobs:
 
     steps:
       - name: Download linuxgsm.sh
-        run: wget https://raw.githubusercontent.com/GameServerManagers/LinuxGSM/${GITHUB_REF#refs/heads/}/linuxgsm.sh; chmod +x linuxgsm.sh
+        run: wget "https://raw.githubusercontent.com/GameServerManagers/LinuxGSM/${GITHUB_REF#refs/heads/}/linuxgsm.sh"; chmod +x linuxgsm.sh
 
       - name: Install dependencies
         run: sudo dpkg --add-architecture i386; sudo apt-get update;

+ 4 - 0
.github/workflows/update-copyright-years-in-license-file.yml

@@ -4,6 +4,10 @@ on:
   schedule:
     - cron: "0 3 1 1 *" # 03:00 AM on January 1
 
+permissions:
+  contents: write
+  pull-requests: write
+
 jobs:
   update-license-year:
     if: github.repository_owner == 'GameServerManagers'

+ 3 - 0
.github/workflows/version-check.sh

@@ -0,0 +1,3 @@
+# Prettier auto-commit runs with GITHUB_TOKEN (GitHub App).
+# GitHub blocks that token from creating/updating anything under .github/workflows.
+.github/workflows/**

+ 1 - 1
.prettierrc

@@ -1,3 +1,3 @@
 {
-	"plugins": ["prettier-plugin-sh"]
+  "plugins": ["prettier-plugin-sh"]
 }

+ 1 - 1
.prettierrc.json

@@ -1,3 +1,3 @@
 {
-  "plugins": ["prettier-plugin-sh"]
+	"plugins": ["prettier-plugin-sh"]
 }

+ 1 - 1
.shellcheckrc

@@ -1 +1 @@
-disable=SC2154
+disable=SC2154,SC2034

+ 10 - 10
.vscode/extensions.json

@@ -1,12 +1,12 @@
 {
-  "recommendations": [
-    "DavidAnson.vscode-markdownlint",
-    "editorconfig.editorconfig",
-    "esbenp.prettier-vscode",
-    "github.vscode-github-actions",
-    "GitHub.vscode-pull-request-github",
-    "redhat.vscode-yaml",
-    "timonwong.shellcheck",
-    "yzhang.markdown-all-in-one"
-  ]
+	"recommendations": [
+		"DavidAnson.vscode-markdownlint",
+		"editorconfig.editorconfig",
+		"esbenp.prettier-vscode",
+		"github.vscode-github-actions",
+		"GitHub.vscode-pull-request-github",
+		"redhat.vscode-yaml",
+		"timonwong.shellcheck",
+		"yzhang.markdown-all-in-one"
+	]
 }

+ 15 - 15
CODE_OF_CONDUCT.md

@@ -17,24 +17,24 @@ diverse, inclusive, and healthy community.
 Examples of behavior that contributes to a positive environment for our
 community include:
 
--   Demonstrating empathy and kindness toward other people
--   Being respectful of differing opinions, viewpoints, and experiences
--   Giving and gracefully accepting constructive feedback
--   Accepting responsibility and apologizing to those affected by our mistakes,
-    and learning from the experience
--   Focusing on what is best not just for us as individuals, but for the
-    overall community
+- Demonstrating empathy and kindness toward other people
+- Being respectful of differing opinions, viewpoints, and experiences
+- Giving and gracefully accepting constructive feedback
+- Accepting responsibility and apologizing to those affected by our mistakes,
+  and learning from the experience
+- Focusing on what is best not just for us as individuals, but for the
+  overall community
 
 Examples of unacceptable behavior include:
 
--   The use of sexualized language or imagery, and sexual attention or
-    advances of any kind
--   Trolling, insulting or derogatory comments, and personal or political attacks
--   Public or private harassment
--   Publishing others' private information, such as a physical or email
-    address, without their explicit permission
--   Other conduct which could reasonably be considered inappropriate in a
-    professional setting
+- The use of sexualized language or imagery, and sexual attention or
+  advances of any kind
+- Trolling, insulting or derogatory comments, and personal or political attacks
+- Public or private harassment
+- Publishing others' private information, such as a physical or email
+  address, without their explicit permission
+- Other conduct which could reasonably be considered inappropriate in a
+  professional setting
 
 ## Enforcement Responsibilities
 

+ 66 - 67
CONTRIBUTING.md

@@ -8,31 +8,31 @@ The following is a set of guidelines for contributing to LinuxGSM, which are hos
 
 [Contributing to LinuxGSM](#contributing-to-linuxgsm)
 
--   [Table of Contents](#table-of-contents)
--   [Code of Conduct](#code-of-conduct)
--   [🎉 Bug/Enhancement Contributions 🐛](#bug-enhancement-contributions)
-    -   [🐛Reporting Bugs](#reporting-bugs)
-        -   [Before Submitting A Bug Report](#before-submitting-a-bug-report)
-        -   [How Do I Submit A (Good) Bug Report?](#how-do-i-submit-a--good--bug-report-)
-    -   [🎉Suggesting Features](#suggesting-features)
-        -   [Before Submitting An Feature Suggestion](#before-submitting-an-feature-suggestion)
-        -   [How Do I Submit A (Good) Feature Suggestion?](#how-do-i-submit-a--good--feature-suggestion-)
-    -   [🎮 Game Server Requests](#game-server-requests)
-        -   [Before Submitting a Game Server Request](#before-submitting-a-game-server-request)
-        -   [How Do I Submit A (Good) Game Server Request?](#how-do-i-submit-a--good--game-server-request-)
-    -   [🎮 Game Server Specific Issues](#game-server-specific-issues)
--   [💻 Code Contributions](#code-contributions)
-    -   [Pull Requests](#pull-requests)
-        -   [Pull Request naming convention](#pull-request-naming-convention)
-    -   [Testing](#testing)
-        -   [Pull Request Status Checks](#pull-request-status-checks)
-        -   [Test Environment](#test-environment)
-    -   [:wine_glass: Styleguides](#-wine-glass--styleguides)
-        -   [Git Commit Messages](#git-commit-messages)
-        -   [BASH Styleguide](#bash-styleguide)
--   [:blue_book: Document Contributions](#-blue-book--document-contributions)
-    -   [Documentation Styleguide](#documentation-styleguide)
--   [Issue and Pull Request Labels](#issue-and-pull-request-labels)
+- [Table of Contents](#table-of-contents)
+- [Code of Conduct](#code-of-conduct)
+- [🎉 Bug/Enhancement Contributions 🐛](#bug-enhancement-contributions)
+  - [🐛Reporting Bugs](#reporting-bugs)
+    - [Before Submitting A Bug Report](#before-submitting-a-bug-report)
+    - [How Do I Submit A (Good) Bug Report?](#how-do-i-submit-a--good--bug-report-)
+  - [🎉Suggesting Features](#suggesting-features)
+    - [Before Submitting An Feature Suggestion](#before-submitting-an-feature-suggestion)
+    - [How Do I Submit A (Good) Feature Suggestion?](#how-do-i-submit-a--good--feature-suggestion-)
+  - [🎮 Game Server Requests](#game-server-requests)
+    - [Before Submitting a Game Server Request](#before-submitting-a-game-server-request)
+    - [How Do I Submit A (Good) Game Server Request?](#how-do-i-submit-a--good--game-server-request-)
+  - [🎮 Game Server Specific Issues](#game-server-specific-issues)
+- [💻 Code Contributions](#code-contributions)
+  - [Pull Requests](#pull-requests)
+    - [Pull Request naming convention](#pull-request-naming-convention)
+  - [Testing](#testing)
+    - [Pull Request Status Checks](#pull-request-status-checks)
+    - [Test Environment](#test-environment)
+  - [:wine_glass: Styleguides](#-wine-glass--styleguides)
+    - [Git Commit Messages](#git-commit-messages)
+    - [BASH Styleguide](#bash-styleguide)
+- [:blue_book: Document Contributions](#-blue-book--document-contributions)
+  - [Documentation Styleguide](#documentation-styleguide)
+- [Issue and Pull Request Labels](#issue-and-pull-request-labels)
 
 ## Code of Conduct
 
@@ -48,20 +48,20 @@ Before creating bug reports, please check [this list](https://github.com/GameSer
 
 #### Before Submitting A Bug Report
 
--   **Check the [documentation](https://docs.linuxgsm.com).** You might be able to find the cause of the problem and fix things yourself.
--   **Check the** [**support page**](https://linuxgsm.com/support) for links to other support options.
--   **Perform a** [**cursory search**](https://github.com/search?q=org:GameServerManagers%20type:issues&type=Issues) to see if the problem has already been reported. If it has **and the issue is still open**, add a comment to the existing issue and give it a thumbs up instead of opening a new one.
+- **Check the [documentation](https://docs.linuxgsm.com).** You might be able to find the cause of the problem and fix things yourself.
+- **Check the** [**support page**](https://linuxgsm.com/support) for links to other support options.
+- **Perform a** [**cursory search**](https://github.com/search?q=org:GameServerManagers%20type:issues&type=Issues) to see if the problem has already been reported. If it has **and the issue is still open**, add a comment to the existing issue and give it a thumbs up instead of opening a new one.
 
 #### How Do I Submit A (Good) Bug Report?
 
 Bugs are tracked as [GitHub issues](https://guides.github.com/features/issues/). Create an issue and provide the following information by filling in [the issues form](https://github.com/GameServerManagers/LinuxGSM/issues/new/choose).
 
--   **Use a clear and descriptive title** for the issue to identify the problem.
--   **Complete the user story** to give a summary of the issue.
--   **Provide basic info** to help us understand the context of the issue.
--   **Provide further info** to give specifics and more detail.
--   **Give steps to reproduce** the issue, allowing developers to follow steps that lead to the issue.
--   **Explain what you expect** to happen, so we know what you think should occur.
+- **Use a clear and descriptive title** for the issue to identify the problem.
+- **Complete the user story** to give a summary of the issue.
+- **Provide basic info** to help us understand the context of the issue.
+- **Provide further info** to give specifics and more detail.
+- **Give steps to reproduce** the issue, allowing developers to follow steps that lead to the issue.
+- **Explain what you expect** to happen, so we know what you think should occur.
 
 ### 🎉Suggesting Features
 
@@ -69,19 +69,19 @@ This section guides you through submitting a feature suggestion for LinuxGSM, in
 
 #### Before Submitting An Feature Suggestion
 
--   **Check the** [**documentation**](<https://docs.linuxgsm.com/%5D(https://docs.linuxgsm.com/)>) to confirm that the enhancement doesn’t already exist.
--   **Check your** [**LinuxGSM version**](https://docs.linuxgsm.com/commands/update-lgsm)**.** A newer version of LinuxGSM may already have your enhancement.
--   **Perform a** [**cursory search**](https://github.com/search?q=org:GameServerManagers%20type:issues&type=Issues) to see if the enhancement has already been suggested. If it has **and the enhancement is still open**, add a comment to the existing issue and give it a thumbs up instead of opening a new one.
+- **Check the** [**documentation**](<https://docs.linuxgsm.com/%5D(https://docs.linuxgsm.com/)>) to confirm that the enhancement doesn’t already exist.
+- **Check your** [**LinuxGSM version**](https://docs.linuxgsm.com/commands/update-lgsm)**.** A newer version of LinuxGSM may already have your enhancement.
+- **Perform a** [**cursory search**](https://github.com/search?q=org:GameServerManagers%20type:issues&type=Issues) to see if the enhancement has already been suggested. If it has **and the enhancement is still open**, add a comment to the existing issue and give it a thumbs up instead of opening a new one.
 
 #### How Do I Submit A (Good) Feature Suggestion?
 
 Features are tracked as [GitHub issues](https://guides.github.com/features/issues/). Create an issue and provide the following information by filling in [the issues form](https://github.com/GameServerManagers/LinuxGSM/issues/new/choose).
 
--   **Use a clear and descriptive title** for the issue to identify the problem.
--   **Complete the user story** to give a summary of the issue.
--   **Provide basic info** to help us understand the context of the enhancement.
--   **Provide further info** to give specifics and more detail.
--   **Provide any further reading** materials that might assist in developing the enhancement.
+- **Use a clear and descriptive title** for the issue to identify the problem.
+- **Complete the user story** to give a summary of the issue.
+- **Provide basic info** to help us understand the context of the enhancement.
+- **Provide further info** to give specifics and more detail.
+- **Provide any further reading** materials that might assist in developing the enhancement.
 
 ### 🎮 Game Server Requests
 
@@ -89,14 +89,14 @@ This section guides you through submitting a game server request for LinuxGSM, F
 
 #### Before Submitting a Game Server Request
 
--   **Check for existing** [**game server requests**](https://github.com/GameServerManagers/LinuxGSM/labels/type%3A%20game%20server%20request) to see if the new game server has already been suggested. If it has **and if the new game server is still open**, give it a thumbs up.
--   **Check the game server is supported on Linux**, this does not include Wine servers which we do not support.
+- **Check for existing** [**game server requests**](https://github.com/GameServerManagers/LinuxGSM/labels/type%3A%20game%20server%20request) to see if the new game server has already been suggested. If it has **and if the new game server is still open**, give it a thumbs up.
+- **Check the game server is supported on Linux**, this does not include Wine servers which we do not support.
 
 #### How Do I Submit A (Good) Game Server Request?
 
--   The title should be as follows: **[Server Request] Game Name**
--   **Provide Steam App ID** if applicable
--   **Supply any documentation/how-to guides** for the game server.
+- The title should be as follows: **[Server Request] Game Name**
+- **Provide Steam App ID** if applicable
+- **Supply any documentation/how-to guides** for the game server.
 
 ### 🎮 Game Server Specific Issues
 
@@ -114,10 +114,10 @@ A [list](https://docs.linuxgsm.com/support/game-server) of known game developer
 
 The process described here has several goals:
 
--   Maintain LinuxGSM quality.
--   Fix problems that are important to users.
--   Engage the community in working toward the best possible LinuxGSM.
--   Enable a sustainable system for LinuxGSM maintainers to review contributions.
+- Maintain LinuxGSM quality.
+- Fix problems that are important to users.
+- Engage the community in working toward the best possible LinuxGSM.
+- Enable a sustainable system for LinuxGSM maintainers to review contributions.
 
 Please follow these steps to have your contribution considered by the maintainers:
 
@@ -139,24 +139,23 @@ If applied, this commit will _your subject line here_
 
 For example:
 
--   If applied, this commit will **refactor subsystem X for readability**
--   If applied, this commit will **update getting started documentation**
--   If applied, this commit will **remove deprecated methods**
--   If applied, this commit will **release version 1.0.0**
--   If applied, this commit will **merge pull request #123 from user/branch**
+- If applied, this commit will **refactor subsystem X for readability**
+- If applied, this commit will **update getting started documentation**
+- If applied, this commit will **remove deprecated methods**
+- If applied, this commit will **release version 1.0.0**
+- If applied, this commit will **merge pull request #123 from user/branch**
 
 Notice how this doesn’t work for the other non-imperative forms:
 
--   If applied, this commit will **fixed bug with Y**
--   If applied, this commit will **change the behaviour of X**
--   If applied, this commit will **more fixes for broken stuff**
--   If applied, this commit will **sweet new API methods**
+- If applied, this commit will **fixed bug with Y**
+- If applied, this commit will **change the behaviour of X**
+- If applied, this commit will **more fixes for broken stuff**
+- If applied, this commit will **sweet new API methods**
 
 Below is an example of the subject line for a pull request:
 
-**feat(alerts): add slack support to alerts**
-
-**fix(csgoserver): remove SteamCMD auth requirement 32-bit workaround**
+- feat(alerts): add slack support to alerts
+- fix(csgoserver): remove SteamCMD auth requirement 32-bit workaround
 
 ### Testing
 
@@ -211,10 +210,10 @@ Labels to help pinpoint what the issue or PR relates to.
 
 variants:
 
--   _distro_
--   _engine_
--   _game_
--   _info_
+- _distro_
+- _engine_
+- _game_
+- _info_
 
 **outcome** Labels
 Labels that identify why an issue was closed.

+ 16 - 16
README.md

@@ -1,10 +1,10 @@
 <p align="center">
-	<a href="https://linuxgsm.com"><img src="https://i.imgur.com/Eoh1jsi.jpg" alt="LinuxGSM">
-	<a href="https://www.codacy.com/gh/GameServerManagers/LinuxGSM/dashboard"><img src="https://img.shields.io/codacy/grade/d19c5234dc3743d8a8a14093711ca52d?style=flat-square&logo=codacy&logoColor=white" alt="Codacy grade"></a>
-	<a href="https://bitbucket.org/GameServerManagers/linuxgsm"><img alt="GitHub Workflow Status" src="https://img.shields.io/github/actions/workflow/status/GameServerManagers/LinuxGSM/git-sync.yml?color=0052CC&logo=bitbucket&style=flat-square"></a>
-	<a href="https://linuxgsm.com/discord"><img alt="Discord" src="https://img.shields.io/discord/127498813903601664?color=5865F2&label=%20&logo=discord&logoColor=ffffff&style=flat-square"></a>
-	<a href="https://developer.valvesoftware.com/wiki/SteamCMD"><img src="https://img.shields.io/badge/SteamCMD-000000?style=flat-square&amp;logo=Steam&amp;logoColor=white" alt="SteamCMD"></a>
-	<a href="https://github.com/GameServerManagers/LinuxGSM/blob/master/LICENSE.md"><img src="https://img.shields.io/github/license/gameservermanagers/LinuxGSM?style=flat-square" alt="MIT License"></a>
+  <a href="https://linuxgsm.com"><img src="https://i.imgur.com/Eoh1jsi.jpg" alt="LinuxGSM">
+  <a href="https://www.codacy.com/gh/GameServerManagers/LinuxGSM/dashboard"><img src="https://img.shields.io/codacy/grade/d19c5234dc3743d8a8a14093711ca52d?style=flat-square&logo=codacy&logoColor=white" alt="Codacy grade"></a>
+  <a href="https://bitbucket.org/GameServerManagers/linuxgsm"><img alt="GitHub Workflow Status" src="https://img.shields.io/github/actions/workflow/status/GameServerManagers/LinuxGSM/git-sync.yml?color=0052CC&logo=bitbucket&style=flat-square"></a>
+  <a href="https://linuxgsm.com/discord"><img alt="Discord" src="https://img.shields.io/discord/127498813903601664?color=5865F2&label=%20&logo=discord&logoColor=ffffff&style=flat-square"></a>
+  <a href="https://developer.valvesoftware.com/wiki/SteamCMD"><img src="https://img.shields.io/badge/SteamCMD-000000?style=flat-square&amp;logo=Steam&amp;logoColor=white" alt="SteamCMD"></a>
+  <a href="https://github.com/GameServerManagers/LinuxGSM/blob/master/LICENSE.md"><img src="https://img.shields.io/github/license/gameservermanagers/LinuxGSM?style=flat-square" alt="MIT License"></a>
 </p>
 
 [LinuxGSM](https://linuxgsm.com) is the command-line tool for quick, simple deployment and management of Linux dedicated game servers.
@@ -17,21 +17,21 @@ Traditionally game servers are not easy to manage yourself. Admins often have to
 
 100+ game servers supported
 
--   :truck: Installer
--   :mag: Monitor
--   :phone: Alerts
--   :cloud: Updater
--   :blue_book: Server Details
--   :floppy_disk: Backup
--   :computer: Console
+- :truck: Installer
+- :mag: Monitor
+- :phone: Alerts
+- :cloud: Updater
+- :blue_book: Server Details
+- :floppy_disk: Backup
+- :computer: Console
 
 ## :penguin: Compatibility
 
 LinuxGSM will run on popular distros as long as the minimum requirements are met.
 
--   Ubuntu
--   Debian
--   CentOS
+- Ubuntu
+- Debian
+- CentOS
 
 Other distros are likely to work but are not fully tested.
 

+ 1 - 1
lgsm/config-default/config-lgsm/armarserver/_default.cfg

@@ -9,7 +9,7 @@
 #### Game Server Settings ####
 
 # https://community.bistudio.com/wiki/Arma_Reforger:Server_Hosting
-# MaxFPS to limit the used Server resouces
+# MaxFPS to limit the used Server resources
 maxfps="60"
 
 # Profile Name

+ 1 - 1
lgsm/config-default/config-lgsm/necserver/_default.cfg

@@ -8,7 +8,7 @@
 
 #### Game Server Settings ####
 
-## Pre-defined Paramters | https://docs.linuxgsm.com/configuration/start-parameters#predefined-parameters
+## Pre-defined Parameters | https://docs.linuxgsm.com/configuration/start-parameters#predefined-parameters
 worldname="MyWorld"
 
 ## Server Parameters | https://docs.linuxgsm.com/configuration/start-parameters#additional-parameters

+ 1 - 1
lgsm/config-default/config-lgsm/ns2cserver/_default.cfg

@@ -19,7 +19,7 @@ httppassword="CHANGE_ME"
 httpport="8080"
 mods=""
 serverpassword=""
-# Add the following line to the parms if you want a private server. Ensuring
+# Add the following line to the params if you want a private server. Ensuring
 # that the password variable above is not left empty.
 # -password \"${serverpassword}\"
 

+ 1 - 1
lgsm/config-default/config-lgsm/ns2server/_default.cfg

@@ -20,7 +20,7 @@ httppassword="CHANGE_ME"
 httpport="8080"
 modserverport="27031"
 serverpassword=""
-# Add the following line to the parms if you want a private server. Ensuring
+# Add the following line to the params if you want a private server. Ensuring
 # that the password variable above is not left empty.
 # -password '${serverpassword}'
 

+ 1 - 1
lgsm/config-default/config-lgsm/pwserver/_default.cfg

@@ -11,7 +11,7 @@
 ## Predefined Parameters | https://docs.linuxgsm.com/configuration/start-parameters
 servername="LinuxGSM"
 
-# For community servers (serverlist) you need to change these settings (publicip & publicport) in the gameserver config file aswell
+# For community servers (serverlist) you need to change these settings (publicip & publicport) in the gameserver config file as well
 port="8211"
 steamport="27015"
 

+ 1 - 1
lgsm/data/name-left.csv

@@ -105,4 +105,4 @@ wonderful
 xenodochial
 youthful
 zealous
-zen
+zen

+ 1 - 1
lgsm/data/name-right.csv

@@ -234,4 +234,4 @@ wright
 wu
 yalow
 yonath
-zhukovsky
+zhukovsky

+ 9 - 9
lgsm/modules/README.md

@@ -6,12 +6,12 @@ These modules are scripts that are called upon by the primary script linuxgsm.sh
 
 Modules have been named to give an idea of what the function does.
 
--   core: Essential modules that will always run first.
--   command: Primary command function.
--   check: Runs checks that will either halt on or fix an issue.
--   dev: development modules.
--   fix: Applies a game server specific fix.
--   info: retrieves information from a source such as config file or the OS.
--   install: modules related to the installer.
--   monitor: modules related to monitor.
--   update: modules that update the game server.
+- core: Essential modules that will always run first.
+- command: Primary command function.
+- check: Runs checks that will either halt on or fix an issue.
+- dev: development modules.
+- fix: Applies a game server specific fix.
+- info: retrieves information from a source such as config file or the OS.
+- install: modules related to the installer.
+- monitor: modules related to monitor.
+- update: modules that update the game server.

+ 41 - 20
lgsm/modules/alert.sh

@@ -10,13 +10,9 @@ moduleselfname="$(basename "$(readlink -f "${BASH_SOURCE[0]}")")"
 # Generates alert log of the details at the time of the alert.
 # Used with email alerts.
 fn_alert_log() {
-	info_distro.sh
-	info_game.sh
-	info_messages.sh
 	if [ -f "${alertlog}" ]; then
 		rm -f "${alertlog:?}"
 	fi
-
 	{
 		fn_info_messages_head
 		fn_info_messages_distro
@@ -24,7 +20,7 @@ fn_alert_log() {
 		fn_info_messages_gameserver_resource
 		fn_info_messages_gameserver
 		fn_info_logs
-	} | sed -r "s/\x1B\[([0-9]{1,2}(;[0-9]{1,2})?)?[m|K]//g" | tee -a "${alertlog}" >/dev/null 2>&1
+	} | sed -r "s/\x1B\[([0-9]{1,2}(;[0-9]{1,2})?)?[m|K]//g" | tee -a "${alertlog}" > /dev/null 2>&1
 }
 
 fn_alert_test() {
@@ -97,45 +93,66 @@ fn_alert_monitor_query() {
 
 # Update alerts
 fn_alert_update() {
-	fn_script_log_info "Sending alert: ${selfname} has received a game server update: ${localbuild}"
+	# If previousbuild is set show transition, else fallback to single version.
+	if [ -n "${previousbuild:-}" ] && [ -n "${localbuild:-}" ]; then
+		fn_script_log_info "Sending alert: ${selfname} updated: ${previousbuild} -> ${localbuild}"
+		alertmessage="${selfname} updated: ${previousbuild} -> ${localbuild}."
+	else
+		fn_script_log_info "Sending alert: ${selfname} updated to ${localbuild}"
+		alertmessage="${selfname} updated to ${localbuild}."
+	fi
 	alertaction="Updated"
 	alertemoji="🎉"
 	alertsound="1"
-	alertmessage="${selfname} has received a game server update: ${localbuild}."
 	# Green
 	alertcolourhex="#00cd00"
 	alertcolourdec="52480"
 }
 
-fn_alert_update_request() {
-	fn_script_log_info "Sending alert: ${selfname} has requested an update and needs to be restarted."
-	alertaction="Updating"
+# Update failure alert
+fn_alert_update_failed() {
+	# Expect updatefailureexpected (target version) and updatefailuregot (actual localbuild) if set
+	local updateexpected="${updatefailureexpected:-${remotebuild:-unknown}}"
+	local updategot="${updatefailuregot:-${localbuild:-unknown}}"
+	fn_script_log_error "Sending alert: ${selfname} update failed: expected ${updateexpected}, got ${updategot}"
+	alertaction="Update Failed"
+	alertemoji="❌"
+	alertsound="2"
+	alertmessage="${selfname} update failed: expected ${updateexpected}, got ${updategot}. Manual intervention required."
+	# Red
+	alertcolourhex="#cd0000"
+	alertcolourdec="13434880"
+}
+
+fn_alert_update_restart_request() {
+	fn_script_log_info "Sending alert: ${selfname} restart requested"
+	alertaction="Restart Requested"
 	alertemoji="🎉"
 	alertsound="1"
-	alertmessage="${selfname} has requested an update and needs to be restarted."
+	alertmessage="${selfname} has requested a restart for an update to be applied. Restarting now."
 	# Blue
 	alertcolourhex="#1e90ff"
 	alertcolourdec="2003199"
 }
 
 fn_alert_check_update() {
-	fn_script_log_info "Sending alert: ${gamename} update available: ${remotebuildversion}"
-	alertaction="Update available"
+	fn_script_log_info "Sending alert: ${gamename} update available: ${localbuild} -> ${remotebuild}"
+	alertaction="Update Available"
 	alertemoji="🎉"
 	alertsound="1"
-	alertmessage="${gamename} update available: ${remotebuildversion}"
+	alertmessage="${gamename} update available: ${localbuild} -> ${remotebuild}"
 	# Blue
 	alertcolourhex="#1e90ff"
 	alertcolourdec="2003199"
 }
 
 fn_alert_update_linuxgsm() {
-	fn_script_log_info "Sending alert: ${selfname} has received an LinuxGSM update"
+	fn_script_log_info "Sending alert: ${selfname} has received a LinuxGSM update"
 	alertaction="Updated"
 	alertemoji="🎉"
 	alertsound="1"
 	alertbody="${gamename} update available"
-	alertmessage="${selfname} has received an LinuxGSM update and been restarted."
+	alertmessage="${selfname} has received a LinuxGSM update and been restarted."
 	# Green
 	alertcolourhex="#00cd00"
 	alertcolourdec="52480"
@@ -197,8 +214,9 @@ fn_alert_info() {
 	alertcolourdec="2003199"
 }
 
-# Images
-alerticon="https://raw.githubusercontent.com/${githubuser}/${githubrepo}/${githubbranch}/lgsm/data/gameicons/${shortname}-icon.png"
+info_distro.sh
+info_game.sh
+info_messages.sh
 
 if [ "${alert}" == "permissions" ]; then
 	fn_alert_permissions
@@ -210,8 +228,10 @@ elif [ "${alert}" == "test" ]; then
 	fn_alert_test
 elif [ "${alert}" == "update" ]; then
 	fn_alert_update
-elif [ "${alert}" == "update-request" ]; then
-	fn_alert_update_request
+elif [ "${alert}" == "update-failed" ]; then
+	fn_alert_update_failed
+elif [ "${alert}" == "update-restart-request" ]; then
+	fn_alert_update_restart_request
 elif [ "${alert}" == "check-update" ]; then
 	fn_alert_check_update
 elif [ "${alert}" == "config" ]; then
@@ -237,6 +257,7 @@ else
 fi
 
 alerttitle="${alertemoji} ${alertaction} - ${servername} ${alertemoji}"
+alerticon="https://raw.githubusercontent.com/${githubuser}/${githubrepo}/${githubbranch}/lgsm/data/gameicons/${shortname}-icon.png"
 
 # Generate alert log.
 fn_alert_log

+ 10 - 11
lgsm/modules/alert_discord.sh

@@ -43,39 +43,38 @@ json=$(
 					"inline": true
 				},
 				{
-					"name": "Server Time",
-					"value": "$(date)",
+					"name": "Server IP",
+					"value": "\`${alertip}:${port}\`",
 					"inline": true
 				},
 				{
-					"name": "More info",
-					"value": "${alerturl}",
+					"name": "Server Time",
+					"value": "$(date)",
 					"inline": true
 				}
 EOF
 )
 
-if [ -n "${querytype}" ]; then
+if [ -n "${alerturl}" ]; then
 	json+=$(
 		cat << EOF
 				,
 				{
-					"name": "Is my Game Server Online?",
-					"value": "https://ismygameserver.online/${imgsoquerytype}/${alertip}:${queryport}",
+					"name": "More info",
+					"value": "${alerturl}",
 					"inline": true
 				}
 EOF
 	)
 fi
 
-if [ -n "${alerturl}" ]; then
+if [ -n "${querytype}" ]; then
 	json+=$(
 		cat << EOF
 				,
 				{
-					"name": "More info",
-					"value": "${alerturl}",
-					"inline": true
+					"name": "Is my Game Server Online?",
+					"value": "https://ismygameserver.online/${imgsoquerytype}/${alertip}:${queryport}"
 				}
 EOF
 	)

+ 1 - 1
lgsm/modules/alert_email.sh

@@ -11,7 +11,7 @@ json=$(
 	cat << EOF
 {
 	"title": "${alerttitle}",
-	"message": "Server Name\n${servername}\n\nInformation\n${alertmessage}\n\nGame\n${gamename}\n\nServer IP\n${alertip}:${port}\n\nHostname\n${HOSTNAME}\n\n
+	"message": "Server Name\n${servername}\n\nInformation\n${alertmessage}\n\nGame\n${gamename}\n\nServer IP\n${alertip}:${port}\n\n
 EOF
 )
 

+ 1 - 1
lgsm/modules/alert_ifttt.sh

@@ -12,7 +12,7 @@ json=$(
 {
 	"value1": "${selfname}",
 	"value2": "${alerttitle}",
-	"value3": "Server Name\n${servername}\n\nInformation\n${alertmessage}\n\nGame\n${gamename}\n\nServer IP\n${alertip}:${port}\n\nHostname\n${HOSTNAME}\n\n
+	"value3": "Server Name\n${servername}\n\nInformation\n${alertmessage}\n\nGame\n${gamename}\n\nServer IP\n${alertip}:${port}\n\n
 EOF
 )
 

+ 17 - 9
lgsm/modules/alert_ntfy.sh

@@ -35,23 +35,31 @@ else
 	tags="${alertemoji}"
 fi
 
-# Construct the message body
-message="Server Name: ${servername}
-Information: ${alertmessage}
-Game: ${gamename}
-Server IP: ${alertip}:${port}
-Hostname: ${HOSTNAME}
-Server Time: $(date)"
+# Construct the message body (keep formatting consistent with other plain-text alerts)
+message="Server Name
+${servername}
+
+Information
+${alertmessage}
+
+Game
+${gamename}
+
+Server IP
+${alertip}:${port}
+
+Server Time
+$(date)"
 
 # Add optional links if available
 if [ -n "${querytype}" ]; then
-	message+="\nIs my Game Server Online?: https://ismygameserver.online/${imgsoquerytype}/${alertip}:${queryport}"
+	message+="\n\nIs my Game Server Online?\nhttps://ismygameserver.online/${imgsoquerytype}/${alertip}:${queryport}"
 fi
 
 # Use alerturl for the click action if available
 clickurl=""
 if [ -n "${alerturl}" ]; then
-	message+="\nMore info: ${alerturl}"
+	message+="\n\nMore info\n${alerturl}"
 	clickurl="${alerturl}"
 fi
 

+ 1 - 1
lgsm/modules/alert_pushbullet.sh

@@ -13,7 +13,7 @@ json=$(
 	"channel_tag": "${channeltag}",
 	"type": "note",
 	"title": "${alerttitle}",
-	"body": "Server Name\n${servername}\n\nInformation\n${alertmessage}\n\nGame\n${gamename}\n\nServer IP\n${alertip}:${port}\n\nHostname\n${HOSTNAME}\n\n
+	"body": "Server Name\n${servername}\n\nInformation\n${alertmessage}\n\nGame\n${gamename}\n\nServer IP\n${alertip}:${port}\n\n
 EOF
 )
 

+ 2 - 2
lgsm/modules/alert_pushover.sh

@@ -22,7 +22,7 @@ else
 	alertpriority="0"
 fi
 
-message=" <b>Server name</b><br>${servername}<br><br><b>Information</b><br>${alertmessage}<br><br><b>Game</b><br>${gamename}<br><br><b>Server IP</b><br>${alertip}:${port}<br><br><b>Hostname</b><br>${HOSTNAME}<br><br>"
+message=" <b>Server Name</b><br>${servername}<br><br><b>Information</b><br>${alertmessage}<br><br><b>Game</b><br>${gamename}<br><br><b>Server IP</b><br>${alertip}:${port}<br><br>"
 
 if [ -n "${querytype}" ]; then
 	message+="<b>Is my Game Server Online?</b><br><a href='https://ismygameserver.online/${imgsoquerytype}/${alertip}:${queryport}'>Check here</a><br><br>"
@@ -32,7 +32,7 @@ if [ -n "${alerturl}" ]; then
 	message+="<b>More info</b><br><a href='${alerturl}'>${alerturl}</a><br><br>"
 fi
 
-message+="Server Time<br>$(date)"
+message+="<b>Server Time</b><br>$(date)"
 
 pushoversend=$(curl --connect-timeout 3 -sS \
 	-F token="${pushovertoken}" \

+ 6 - 60
lgsm/modules/alert_rocketchat.sh

@@ -40,38 +40,20 @@ json=$(
 				{
 					"short": false,
 					"title": "Server IP",
-					"value": "${alertip}:${port}"
-				},
-				{
-					"short": false,
-					"title": "Hostname",
-					"value": "${HOSTNAME}"
-				},
-				{
-					"short": false,
-					"title": "More info",
-					"value": "${alerturl}"
-				},
-				{
-					"short": false,
-					"title": "Server Time",
-					"value": "$(date)"
+					"value": "\`${alertip}:${port}\`"
 				}
-			]
-		}
-	]
-}
 EOF
 )
 
 if [ -n "${querytype}" ]; then
 	json+=$(
 		cat << EOF
+				,
 				{
 					"short": false,
 					"title": "Is my Game Server Online?",
 					"value": "<https://ismygameserver.online/${imgsoquerytype}/${alertip}:${queryport}|Check here>"
-				},
+				}
 EOF
 	)
 fi
@@ -79,55 +61,19 @@ fi
 if [ -n "${alerturl}" ]; then
 	json+=$(
 		cat << EOF
+				,
 				{
 					"short": false,
 					"title": "More info",
 					"value": "${alerturl}"
-				},
+				}
 EOF
 	)
 fi
 
 json+=$(
 	cat << EOF
-{
-	"alias": "LinuxGSM",
-	"text": "*${alerttitle}*",
-	"attachments": [
-		{
-			"title": "",
-			"color": "${alertcolourhex}",
-			"author_name": "LinuxGSM Alert",
-			"author_link": "https://linuxgsm.com",
-			"author_icon": "https://raw.githubusercontent.com/${githubuser}/${githubrepo}/${githubbranch}/lgsm/data/alert_discord_logo.jpg",
-			"thumb_url": "${alerticon}",
-			"text": "",
-			"fields": [
-				{
-					"short": false,
-					"title": "Server Name",
-					"value": "${servername}"
-				},
-				{
-					"short": false,
-					"title": "Information",
-					"value": "${alertmessage}"
-				},
-				{
-					"short": false,
-					"title": "Game",
-					"value": "${gamename}"
-				},
-				{
-					"short": false,
-					"title": "Server IP",
-					"value": "${alertip}:${port}"
-				},
-				{
-					"short": false,
-					"title": "Hostname",
-					"value": "${HOSTNAME}"
-				},
+				,
 				{
 					"short": false,
 					"title": "Server Time",

+ 6 - 90
lgsm/modules/alert_slack.sh

@@ -50,10 +50,6 @@ json=$(
 							"type": "mrkdwn",
 							"text": "*Server IP*\n\`${alertip}:${port}\`"
 						},
-						{
-							"type": "mrkdwn",
-							"text": "*Hostname*\n${HOSTNAME}"
-						},
 						{
 							"type": "mrkdwn",
 							"text": "*Server Time*\n$(date)"
@@ -62,41 +58,22 @@ json=$(
 					"accessory": {
 						"type": "image",
 						"image_url": "${alerticon}",
-						"alt_text": "cute cat"
+						"alt_text": "LinuxGSM game icon"
 					}
-				},
-				{
-					"type": "context",
-					"elements": [
-						{
-							"type": "image",
-							"image_url": "https://raw.githubusercontent.com/${githubuser}/${githubrepo}/${githubbranch}/lgsm/data/alert_discord_logo.jpg",
-							"alt_text": "LinuxGSM icon"
-						},
-						{
-							"type": "plain_text",
-							"text": "Sent by LinuxGSM ${version}",
-							"emoji": true
-						}
-					]
-				}
-			]
-		}
-	]
-}
 EOF
 )
 
 if [ -n "${querytype}" ]; then
 	json+=$(
 		cat << EOF
+				,
 				{
 					"type": "section",
 					"text": {
 						"type": "mrkdwn",
 						"text": "*Is my Game Server Online?*\n<https://ismygameserver.online/${imgsoquerytype}/${alertip}:${queryport}|Check here>"
 					}
-				},
+				}
 EOF
 	)
 fi
@@ -104,82 +81,21 @@ fi
 if [ -n "${alerturl}" ]; then
 	json+=$(
 		cat << EOF
+				,
 				{
 					"type": "section",
 					"text": {
 						"type": "mrkdwn",
 						"text": "*More info*\n<${alerturl}|${alerturl}>"
 					}
-				},
+				}
 EOF
 	)
 fi
 
 json+=$(
 	cat << EOF
-{
-	"attachments": [
-		{
-			"color": "${alertcolourhex}",
-			"blocks": [
-				{
-					"type": "header",
-					"text": {
-						"type": "mrkdwn",
-						"text": "${alerttitle}",
-						"emoji": true
-					}
-				},
-				{
-					"type": "divider"
-				},
-				{
-					"type": "section",
-					"text": {
-						"type": "mrkdwn",
-						"text": "*Server Name*\n${servername}"
-					}
-				},
-				{
-					"type": "section",
-					"text": {
-						"type": "mrkdwn",
-						"text": "*Information*\n${alertmessage}"
-					}
-				},
-				{
-					"type": "section",
-					"fields": [
-						{
-							"type": "mrkdwn",
-							"text": "*Game*\n${gamename}"
-						},
-						{
-							"type": "mrkdwn",
-							"text": "*Server IP*\n\`${alertip}:${port}\`"
-						},
-						{
-							"type": "mrkdwn",
-							"text": "*Hostname*\n${HOSTNAME}"
-						},
-						{
-							"type": "mrkdwn",
-							"text": "*Server Time*\n$(date)"
-						}
-					],
-					"accessory": {
-						"type": "image",
-						"image_url": "${alerticon}",
-						"alt_text": "cute cat"
-					}
-				},
-				{
-					"type": "section",
-					"text": {
-						"type": "mrkdwn",
-						"text": "*Server Time*\n${alertmessage}"
-					}
-				},
+				,
 				{
 					"type": "context",
 					"elements": [

+ 8 - 2
lgsm/modules/alert_telegram.sh

@@ -14,7 +14,7 @@ json=$(
 	"message_thread_id": "${telegramthreadid}",
 	"parse_mode": "HTML",
 	"disable_notification": "${telegramdisablenotification}",
-	"text": "<b>${alerttitle}</b>\n\n<b>Server name</b>\n${servername}\n\n<b>Information</b>\n${alertmessage}\n\n<b>Game</b>\n${gamename}\n\n<b>Server IP</b>\n${alertip}:${port}\n\n<b>Hostname</b>\n${HOSTNAME}\n\n
+	"text": "<b>${alerttitle}</b>\n\n<b>Server Name</b>\n${servername}\n\n<b>Information</b>\n${alertmessage}\n\n<b>Game</b>\n${gamename}\n\n<b>Server IP</b>\n${alertip}:${port}\n\n
 EOF
 )
 
@@ -43,7 +43,13 @@ EOF
 )
 
 fn_print_dots "Sending Telegram alert"
-telegramsend=$(curl --connect-timeout 3 -sSL -H "Content-Type: application/json" -X POST -d "$(echo -n "${json}" | jq -c .)" ${curlcustomstring} "https://${telegramapi}/bot${telegramtoken}/sendMessage" | grep "error_code")
+
+curlcustomargs=()
+if [ -n "${curlcustomstring}" ]; then
+	read -r -a curlcustomargs <<< "${curlcustomstring}"
+fi
+
+telegramsend=$(curl --connect-timeout 3 -sSL -H "Content-Type: application/json" -X POST -d "$(echo -n "${json}" | jq -c .)" "${curlcustomargs[@]}" "https://${telegramapi}/bot${telegramtoken}/sendMessage" | grep "error_code")
 
 if [ -n "${telegramsend}" ]; then
 	fn_print_fail_nl "Sending Telegram alert: ${telegramsend}"

+ 3 - 3
lgsm/modules/check.sh

@@ -75,11 +75,11 @@ fn_install_mono_repo() {
 
 		# Run the mono repo install.
 		eval "${cmd}"
+		monorepoexitcode=$?
 
 		# Did Mono repo install correctly?
 		if [ "${monoautoinstall}" != "1" ]; then
-			exitcode=$?
-			if [ "${exitcode}" -ne 0 ]; then
+			if [ "${monorepoexitcode}" -ne 0 ]; then
 				fn_print_failure_nl "Unable to install Mono repository."
 				fn_script_log_fail "Unable to install Mono repository."
 			else
@@ -234,7 +234,7 @@ fn_install_missing_deps() {
 }
 
 fn_check_loop() {
-	# Loop though required depenencies checking if they are installed.
+	# Loop though required dependencies checking if they are installed.
 	for deptocheck in "${array_deps_required[@]}"; do
 		fn_deps_detector
 	done

+ 1 - 1
lgsm/modules/check_executable.sh

@@ -17,7 +17,7 @@ elif [ -z "${glibc}" ]; then
 	fn_print_error_nl "Checking glibc: requirement unknown"
 	fn_script_log_error "Checking glibc: requirement unknown"
 	fn_sleep_time_5
-elif [ "$(printf '%s\n'${glibc}'\n' "${glibcversion}" | sort -V | head -n 1)" != "${glibc}" ]; then
+elif [ "$(printf '%s\n' "${glibc}" "${glibcversion}" | sort -V | head -n 1)" != "${glibc}" ]; then
 	fn_print_dots "Checking glibc"
 	fn_print_error_nl "Checking glibc: requirements not met"
 	fn_script_log_error "Checking glibc: requirements not met"

+ 1 - 0
lgsm/modules/check_ip.sh

@@ -11,6 +11,7 @@ moduleselfname="$(basename "$(readlink -f "${BASH_SOURCE[0]}")")"
 if [ -f "${lockdir}/${selfname}-last-started.lock" ]; then
 	laststart=$(cat "${lockdir}/${selfname}-last-started.lock")
 fi
+
 if [ -f "${lockdir}/last-updated.lock" ]; then
 	lastupdate=$(cat "${lockdir}/last-updated.lock")
 fi

+ 1 - 1
lgsm/modules/check_logs.sh

@@ -249,7 +249,7 @@ fn_sys_perm_error_process() {
 	fi
 }
 
-## Run permisions checks when not root.
+## Run permissions checks when not root.
 if [ "$(whoami)" != "root" ]; then
 	fn_check_ownership
 	fn_check_permissions

+ 1 - 1
lgsm/modules/check_root.sh

@@ -71,7 +71,7 @@ fi
 if [ "${ramrequirementgb}" ]; then
 	if (($(echo "${physmemtotalgb} < ${ramrequirementgb}" | bc -l))); then
 		fn_print_dots "Checking RAM"
-		fn_print_warn_nl "Checking RAM: Minumum RAM requirements not met"
+		fn_print_warn_nl "Checking RAM: Minimum RAM requirements not met"
 		fn_print_nl "* ${ramrequirementgb}G is required, but only ${physmemtotal} is available."
 		fn_print_nl "* ${gamename} server may fail to run or experience poor performance."
 		fn_sleep_time_5

+ 1 - 1
lgsm/modules/check_tmuxception.sh

@@ -49,7 +49,7 @@ if [ -n "${glibc}" ]; then
 		:
 	elif [ -z "${glibc}" ]; then
 		echo -e "${lightblue}glibc required:\t${red}UNKNOWN${default}"
-	elif [ "$(printf '%s\n'${glibc}'\n' ${glibcversion} | sort -V | head -n 1)" != "${glibc}" ]; then
+	elif [ "$(printf '%s\n' "${glibc}" "${glibcversion}" | sort -V | head -n 1)" != "${glibc}" ]; then
 		echo -e "${lightblue}glibc required:\t${red}${glibc} ${default}(${red}distro glibc ${glibcversion} too old${default})"
 	else
 		echo -e "${lightblue}glibc required:\t${green}${glibc}${default}"

+ 1 - 1
lgsm/modules/command_details.sh

@@ -29,7 +29,7 @@ fn_info_messages_gameserver_resource
 fn_info_messages_gameserver
 fn_info_messages_script
 fn_info_messages_backup
-# Some game servers do not have parms.
+# Some game servers do not have params.
 if [ "${shortname}" != "jc2" ] && [ "${shortname}" != "dst" ] && [ "${shortname}" != "pz" ] && [ "${engine}" != "renderware" ]; then
 	fn_info_messages_commandlineparms
 fi

+ 1 - 1
lgsm/modules/command_dev_clear_modules.sh

@@ -63,7 +63,7 @@ for glibc_check_var in "${glibc_check_dir_array[@]}"; do
 			cat "${tmpdir}/detect_glibc_${glibc_check_var}.tmp" | sort | uniq | sort -r --version-sort | head -1 | tee -a "${tmpdir}/detect_glibc_highest.tmp"
 			echo -e ""
 			echo -e "Files requiring GLIBC"
-			echo -e "Highest verion required: filename"
+			echo -e "Highest version required: filename"
 			cat "${tmpdir}/detect_glibc_files_${glibc_check_var}.tmp"
 			echo -e ""
 			echo -e "All required GLIBC versions"

+ 4 - 4
lgsm/modules/command_dev_detect_ldd.sh

@@ -249,9 +249,9 @@ echo -e "${bold}${lightyellow}Query Port (${queryport}) - TCP Output${default}"
 fn_messages_separator
 echo -e ""
 for queryip in "${queryips[@]}"; do
-	echo -e "${italic}bash -c 'exec 3<> /dev/tcp/'${queryip}'/'${queryport}''${default}"
+	echo -e "${italic}bash -c 'exec 3<> /dev/tcp/'\"${queryip}\"'/'\"${queryport}\"''${default}"
 	echo -e ""
-	timeout 3 bash -c 'exec 3<> /dev/tcp/'${queryip}'/'${queryport}''
+	timeout 3 bash -c 'exec 3<> /dev/tcp/'"${queryip}"'/'"${queryport}"''
 	querystatus="$?"
 	echo -e ""
 	if [ "${querystatus}" == "0" ]; then
@@ -268,9 +268,9 @@ echo -e "${lightgreen}TCP Raw Output${default}"
 fn_messages_separator
 echo -e ""
 for queryip in "${queryips[@]}"; do
-	echo -e "${italic}bash -c 'exec 3<> /dev/tcp/'${queryip}'/'${port}''${default}"
+	echo -e "${italic}bash -c 'exec 3<> /dev/tcp/'\"${queryip}\"'/'\"${port}\"''${default}"
 	echo -e ""
-	timeout 3 bash -c 'exec 3<> /dev/tcp/'${queryip}'/'${port}''
+	timeout 3 bash -c 'exec 3<> /dev/tcp/'"${queryip}"'/'"${port}"''
 	querystatus="$?"
 	echo -e ""
 	if [ "${querystatus}" == "0" ]; then

+ 1 - 1
lgsm/modules/command_dev_ui.sh

@@ -219,7 +219,7 @@ fn_fastdl_preview() {
 		core_exit.sh
 	fi
 
-  if [ "${engine}" == "source" ]; then
+	if [ "${engine}" == "source" ]; then
 		echo -e "about to compress ${totalfiles} files, total size $(fn_human_readable_file_size "${filesizetotal}" 0)"
 	elif [ "${engine}" == "goldsrc" ]; then
 		echo -e "about to copy ${totalfiles} files, total size $(fn_human_readable_file_size "${filesizetotal}" 0)"

+ 18 - 5
lgsm/modules/command_install.sh

@@ -47,7 +47,7 @@ while [ "${compatiblemodslistindex}" -lt "${#compatiblemodslist[@]}" ]; do
 	echo -e "${displayedmodname} - ${displayedmoddescription} - ${displayedmodsite}"
 	echo -e " * ${cyan}${displayedmodcommand}${default}"
 	# Increment index from the amount of values we just displayed.
-	let "compatiblemodslistindex+=4"
+	((compatiblemodslistindex += 4))
 	((totalmodsavailable++))
 done
 
@@ -61,16 +61,29 @@ fn_script_log_info "${totalmodsavailable} addons/mods are available for install"
 
 ## User selects a mod.
 echo -e ""
-while [[ ! " ${availablemodscommands[@]} " =~ " ${usermodselect} " ]]; do
+
+while :; 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
+
+	validselection=0
+	for availablemodcommand in "${availablemodscommands[@]}"; do
+		if [ "${availablemodcommand}" == "${usermodselect}" ]; then
+			validselection=1
+			break
+		fi
+	done
+
+	if [ "${validselection}" -eq 1 ]; then
+		break
+	fi
+
+	# Supplementary output upon invalid user input.
+	fn_print_error2_nl "${usermodselect} is not a valid addon/mod."
 done
 # Get mod info.
 currentmod="${usermodselect}"

+ 17 - 4
lgsm/modules/command_mods_remove.sh

@@ -32,16 +32,29 @@ done
 
 echo -e ""
 # Keep prompting as long as the user input doesn't correspond to an available mod.
-while [[ ! " ${installedmodslist[@]} " =~ " ${usermodselect} " ]]; do
+
+while :; do
 	echo -en "Enter an ${cyan}addon/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
+
+	validselection=0
+	for installedmodcommand in "${installedmodslist[@]}"; do
+		if [ "${installedmodcommand}" == "${usermodselect}" ]; then
+			validselection=1
+			break
+		fi
+	done
+
+	if [ "${validselection}" -eq 1 ]; then
+		break
+	fi
+
+	# Supplementary output upon invalid user input.
+	fn_print_error2_nl "${usermodselect} is not a valid addon/mod."
 done
 
 fn_print_warning_nl "You are about to remove ${cyan}${usermodselect}${default}."

+ 2 - 2
lgsm/modules/command_mods_update.sh

@@ -164,8 +164,8 @@ fn_monitor_check_update_source() {
 			fn_script_log_info "Checking update: CHECKING"
 			fn_print_ok "Checking update"
 			fn_print_ok_eol_nl
-			fn_script_log_info "Checking update: ${selfname} has requested an update and needs to be restarted"
-			alert="update-request"
+			fn_script_log_info "Checking update: ${selfname} has requested a restart for an update to be applied"
+			alert="update-restart-request"
 			alert.sh
 			command_restart.sh
 			core_exit.sh

+ 2 - 2
lgsm/modules/command_postdetails.sh

@@ -46,7 +46,7 @@ else
 		fn_info_messages_gameserver
 		fn_info_messages_script
 		fn_info_messages_backup
-		# Some game servers do not have parms.
+		# Some game servers do not have params.
 		if [ "${shortname}" != "jc2" ] && [ "${shortname}" != "jc3" ] && [ "${shortname}" != "dst" ] && [ "${shortname}" != "pz" ] && [ "${engine}" != "renderware" ]; then
 			fn_info_messages_commandlineparms
 		fi
@@ -59,7 +59,7 @@ fi
 
 fn_print_dots "termbin.com"
 link=$(cat "${postdetailslog}" | {
-	nc -w 3 termbin.com 9999
+	nc -w 10 termbin.com 9999
 	echo $? > /tmp/nc_exit_status
 } | tr -d '\n\0')
 nc_exit_status=$(cat /tmp/nc_exit_status)

+ 2 - 2
lgsm/modules/command_restart.sh

@@ -3,7 +3,7 @@
 # Author: Daniel Gibbs
 # Contributors: https://linuxgsm.com/contrib
 # Website: https://linuxgsm.com
-# Description: Creates an copy of a game servers directorys.
+# Description: Creates an copy of a game servers directories.
 
 commandname="SKELETON"
 commandaction="Skeleton"
@@ -13,7 +13,7 @@ fn_firstcommand_set
 fn_print_dots "Creating skeleton directory"
 check.sh
 
-# Find all directorys and create them in the skel directory
+# Find all directories and create them in the skel directory
 find "${rootdir}" -type d -not \( -path ./skel -prune \) | cpio -pdvm skel 2> /dev/null
 exitcode=$?
 if [ "${exitcode}" -ne 0 ]; then

+ 2 - 2
lgsm/modules/command_start.sh

@@ -16,7 +16,7 @@ fn_stop_graceful_ctrlc() {
 	fn_script_log_info "Graceful: CTRL+c"
 	# Sends CTRL+c.
 	tmux -L "${socketname}" send-keys -t "${sessionname}" C-c > /dev/null 2>&1
-	# Waits up to 30 seconds giving the server time to shutdown gracefuly.
+	# Waits up to 30 seconds giving the server time to shutdown gracefully.
 	for seconds in {1..30}; do
 		check_status.sh
 		if [ "${status}" == "0" ]; then
@@ -293,7 +293,7 @@ fn_stop_graceful_avorion() {
 	fn_sleep_time_5
 	# Sends /quit.
 	tmux -L "${socketname}" send-keys -t "${sessionname}" /stop ENTER > /dev/null 2>&1
-	# Waits up to 30 seconds giving the server time to shutdown gracefuly.
+	# Waits up to 30 seconds giving the server time to shutdown gracefully.
 	for seconds in {1..30}; do
 		check_status.sh
 		if [ "${status}" == "0" ]; then

+ 20 - 19
lgsm/modules/command_test_alert.sh

@@ -16,8 +16,9 @@ info_distro.sh
 info_game.sh
 
 # Prevent github from using a cached version of the file if dev-debug is enabled.
+nocache=()
 if [ -f "${rootdir}/.dev-debug" ]; then
-	nocache="-H \"Cache-Control: no-cache\" -H \"Pragma: no-cache\""
+	nocache=(-H "Cache-Control: no-cache" -H "Pragma: no-cache")
 fi
 
 fn_script_log_info "Updating LinuxGSM"
@@ -26,10 +27,10 @@ fn_print_dots "Selecting repo"
 fn_script_log_info "Selecting repo"
 # Select remotereponame
 
-curl ${nocache} --connect-timeout 3 -IsfL "https://raw.githubusercontent.com/${githubuser}/${githubrepo}/${githubbranch}/linuxgsm.sh" 1> /dev/null
+curl "${nocache[@]}" --connect-timeout 3 -IsfL "https://raw.githubusercontent.com/${githubuser}/${githubrepo}/${githubbranch}/linuxgsm.sh" 1> /dev/null
 exitcode=$?
 if [ "${exitcode}" -ne "0" ]; then
-	curl ${nocache} --connect-timeout 3 -IsfL "https://bitbucket.org/${githubuser}/${githubrepo}/raw/${githubbranch}/linuxgsm.sh" 1> /dev/null
+	curl "${nocache[@]}" --connect-timeout 3 -IsfL "https://bitbucket.org/${githubuser}/${githubrepo}/raw/${githubbranch}/linuxgsm.sh" 1> /dev/null
 	exitcode=$?
 	if [ "${exitcode}" -ne "0" ]; then
 		fn_print_fail_nl "Selecting repo: Unable to to access GitHub or Bitbucket repositories"
@@ -47,9 +48,9 @@ fi
 # Check linuxsm.sh
 echo -en "checking ${remotereponame} script [ ${italic}linuxgsm.sh${default} ]\c"
 if [ "${remotereponame}" == "GitHub" ]; then
-	curl ${nocache} --connect-timeout 3 -IsfL "https://raw.githubusercontent.com/${githubuser}/${githubrepo}/${githubbranch}/linuxgsm.sh" 1> /dev/null
+	curl "${nocache[@]}" --connect-timeout 3 -IsfL "https://raw.githubusercontent.com/${githubuser}/${githubrepo}/${githubbranch}/linuxgsm.sh" 1> /dev/null
 else
-	curl ${nocache} --connect-timeout 3 -IsfL "https://bitbucket.org/${githubuser}/${githubrepo}/raw/${githubbranch}/linuxgsm.sh" 1> /dev/null
+	curl "${nocache[@]}" --connect-timeout 3 -IsfL "https://bitbucket.org/${githubuser}/${githubrepo}/raw/${githubbranch}/linuxgsm.sh" 1> /dev/null
 fi
 exitcode=$?
 if [ "${exitcode}" -ne 0 ]; then
@@ -60,9 +61,9 @@ if [ "${exitcode}" -ne 0 ]; then
 fi
 
 if [ "${remotereponame}" == "GitHub" ]; then
-	tmp_script_diff=$(diff "${tmpdir}/linuxgsm.sh" <(curl ${nocache} --connect-timeout 3 -s "https://raw.githubusercontent.com/${githubuser}/${githubrepo}/${githubbranch}/linuxgsm.sh"))
+	tmp_script_diff=$(diff "${tmpdir}/linuxgsm.sh" <(curl "${nocache[@]}" --connect-timeout 3 -s "https://raw.githubusercontent.com/${githubuser}/${githubrepo}/${githubbranch}/linuxgsm.sh"))
 else
-	tmp_script_diff=$(diff "${tmpdir}/linuxgsm.sh" <(curl ${nocache} --connect-timeout 3 -s "https://bitbucket.org/${githubuser}/${githubrepo}/raw/${githubbranch}/linuxgsm.sh"))
+	tmp_script_diff=$(diff "${tmpdir}/linuxgsm.sh" <(curl "${nocache[@]}" --connect-timeout 3 -s "https://bitbucket.org/${githubuser}/${githubrepo}/raw/${githubbranch}/linuxgsm.sh"))
 fi
 
 if [ "${tmp_script_diff}" != "" ]; then
@@ -130,9 +131,9 @@ fi
 echo -en "checking ${remotereponame} config [ ${italic}_default.cfg${default} ]\c"
 fn_script_log_info "Checking ${remotereponame} config _default.cfg"
 if [ "${remotereponame}" == "GitHub" ]; then
-	curl ${nocache} --connect-timeout 3 -IsfL "https://raw.githubusercontent.com/${githubuser}/${githubrepo}/${githubbranch}/lgsm/config-default/config-lgsm/${gameservername}/_default.cfg" 1> /dev/null
+	curl "${nocache[@]}" --connect-timeout 3 -IsfL "https://raw.githubusercontent.com/${githubuser}/${githubrepo}/${githubbranch}/lgsm/config-default/config-lgsm/${gameservername}/_default.cfg" 1> /dev/null
 else
-	curl ${nocache} --connect-timeout 3 -IsfL "https://bitbucket.org/${githubuser}/${githubrepo}/raw/${githubbranch}/lgsm/config-default/config-lgsm/${gameservername}/_default.cfg" 1> /dev/null
+	curl "${nocache[@]}" --connect-timeout 3 -IsfL "https://bitbucket.org/${githubuser}/${githubrepo}/raw/${githubbranch}/lgsm/config-default/config-lgsm/${gameservername}/_default.cfg" 1> /dev/null
 fi
 exitcode=$?
 if [ "${exitcode}" -ne 0 ]; then
@@ -143,9 +144,9 @@ if [ "${exitcode}" -ne 0 ]; then
 fi
 
 if [ "${remotereponame}" == "GitHub" ]; then
-	config_file_diff=$(diff "${configdirdefault}/config-lgsm/${gameservername}/_default.cfg" <(curl ${nocache} --connect-timeout 3 -s "https://raw.githubusercontent.com/${githubuser}/${githubrepo}/${githubbranch}/lgsm/config-default/config-lgsm/${gameservername}/_default.cfg"))
+	config_file_diff=$(diff "${configdirdefault}/config-lgsm/${gameservername}/_default.cfg" <(curl "${nocache[@]}" --connect-timeout 3 -s "https://raw.githubusercontent.com/${githubuser}/${githubrepo}/${githubbranch}/lgsm/config-default/config-lgsm/${gameservername}/_default.cfg"))
 else
-	config_file_diff=$(diff "${configdirdefault}/config-lgsm/${gameservername}/_default.cfg" <(curl ${nocache} --connect-timeout 3 -s "https://bitbucket.org/${githubuser}/${githubrepo}/raw/${githubbranch}/lgsm/config-default/config-lgsm/${gameservername}/_default.cfg"))
+	config_file_diff=$(diff "${configdirdefault}/config-lgsm/${gameservername}/_default.cfg" <(curl "${nocache[@]}" --connect-timeout 3 -s "https://bitbucket.org/${githubuser}/${githubrepo}/raw/${githubbranch}/lgsm/config-default/config-lgsm/${gameservername}/_default.cfg"))
 fi
 
 if [ "${config_file_diff}" != "" ]; then
@@ -165,9 +166,9 @@ if [ -f "${datadir}/${distroid}-${distroversioncsv}.csv" ]; then
 	echo -en "checking ${remotereponame} config [ ${italic}${distroid}-${distroversioncsv}.csv${default} ]\c"
 	fn_script_log_info "Checking ${remotereponame} ${distroid}-${distroversioncsv}.csv"
 	if [ "${remotereponame}" == "GitHub" ]; then
-		curl ${nocache} --connect-timeout 3 -IsfL "https://raw.githubusercontent.com/${githubuser}/${githubrepo}/${githubbranch}/lgsm/data/${distroid}-${distroversioncsv}.csv" 1> /dev/null
+		curl "${nocache[@]}" --connect-timeout 3 -IsfL "https://raw.githubusercontent.com/${githubuser}/${githubrepo}/${githubbranch}/lgsm/data/${distroid}-${distroversioncsv}.csv" 1> /dev/null
 	else
-		curl ${nocache} --connect-timeout 3 -IsfL "https://bitbucket.org/${githubuser}/${githubrepo}/raw/${githubbranch}/lgsm/data/${distroid}-${distroversioncsv}.csv" 1> /dev/null
+		curl "${nocache[@]}" --connect-timeout 3 -IsfL "https://bitbucket.org/${githubuser}/${githubrepo}/raw/${githubbranch}/lgsm/data/${distroid}-${distroversioncsv}.csv" 1> /dev/null
 	fi
 	exitcode=$?
 	if [ "${exitcode}" -ne 0 ]; then
@@ -178,9 +179,9 @@ if [ -f "${datadir}/${distroid}-${distroversioncsv}.csv" ]; then
 	fi
 
 	if [ "${remotereponame}" == "GitHub" ]; then
-		config_file_diff=$(diff "${datadir}/${distroid}-${distroversioncsv}.csv" <(curl ${nocache} --connect-timeout 3 -s "https://raw.githubusercontent.com/${githubuser}/${githubrepo}/${githubbranch}/lgsm/data/${distroid}-${distroversioncsv}.csv"))
+		config_file_diff=$(diff "${datadir}/${distroid}-${distroversioncsv}.csv" <(curl "${nocache[@]}" --connect-timeout 3 -s "https://raw.githubusercontent.com/${githubuser}/${githubrepo}/${githubbranch}/lgsm/data/${distroid}-${distroversioncsv}.csv"))
 	else
-		config_file_diff=$(diff "${datadir}/${distroid}-${distroversioncsv}.csv" <(curl ${nocache} --connect-timeout 3 -s "https://bitbucket.org/${githubuser}/${githubrepo}/raw/${githubbranch}/lgsm/data/${distroid}-${distroversioncsv}.csv"))
+		config_file_diff=$(diff "${datadir}/${distroid}-${distroversioncsv}.csv" <(curl "${nocache[@]}" --connect-timeout 3 -s "https://bitbucket.org/${githubuser}/${githubrepo}/raw/${githubbranch}/lgsm/data/${distroid}-${distroversioncsv}.csv"))
 	fi
 
 	if [ "${config_file_diff}" != "" ]; then
@@ -204,9 +205,9 @@ if [ -n "${modulesdir}" ]; then
 				echo -en "checking ${remotereponame} module [ ${italic}${modulefile}${default} ]\c"
 				github_file_url_dir="lgsm/modules"
 				if [ "${remotereponame}" == "GitHub" ]; then
-					curl ${nocache} --connect-timeout 3 -IsfL "https://raw.githubusercontent.com/${githubuser}/${githubrepo}/${githubbranch}/${github_file_url_dir}/${modulefile}" 1> /dev/null
+					curl "${nocache[@]}" --connect-timeout 3 -IsfL "https://raw.githubusercontent.com/${githubuser}/${githubrepo}/${githubbranch}/${github_file_url_dir}/${modulefile}" 1> /dev/null
 				else
-					curl ${nocache} --connect-timeout 3 -IsfL "https://bitbucket.org/${githubuser}/${githubrepo}/raw/${githubbranch}/${github_file_url_dir}/${modulefile}" 1> /dev/null
+					curl "${nocache[@]}" --connect-timeout 3 -IsfL "https://bitbucket.org/${githubuser}/${githubrepo}/raw/${githubbranch}/${github_file_url_dir}/${modulefile}" 1> /dev/null
 				fi
 				exitcode=$?
 				if [ "${exitcode}" -ne 0 ]; then
@@ -224,9 +225,9 @@ if [ -n "${modulesdir}" ]; then
 				else
 					# compare file
 					if [ "${remotereponame}" == "GitHub" ]; then
-						module_file_diff=$(diff "${modulesdir}/${modulefile}" <(curl ${nocache} --connect-timeout 3 -s "https://raw.githubusercontent.com/${githubuser}/${githubrepo}/${githubbranch}/${github_file_url_dir}/${modulefile}"))
+						module_file_diff=$(diff "${modulesdir}/${modulefile}" <(curl "${nocache[@]}" --connect-timeout 3 -s "https://raw.githubusercontent.com/${githubuser}/${githubrepo}/${githubbranch}/${github_file_url_dir}/${modulefile}"))
 					else
-						module_file_diff=$(diff "${modulesdir}/${modulefile}" <(curl ${nocache} --connect-timeout 3 -s "https://bitbucket.org/${githubuser}/${githubrepo}/raw/${githubbranch}/${github_file_url_dir}/${modulefile}"))
+						module_file_diff=$(diff "${modulesdir}/${modulefile}" <(curl "${nocache[@]}" --connect-timeout 3 -s "https://bitbucket.org/${githubuser}/${githubrepo}/raw/${githubbranch}/${github_file_url_dir}/${modulefile}"))
 					fi
 
 					# results

+ 25 - 13
lgsm/modules/command_validate.sh

@@ -46,6 +46,18 @@ fn_dl_steamcmd() {
 		validate="validate"
 	fi
 
+	# steamcmdcommand can contain multiple arguments; treat it as an argv array.
+	steamcmdcommandarray=()
+	read -r -a steamcmdcommandarray <<< "${steamcmdcommand}"
+	unbuffercommand=()
+	if [ -n "${unbuffer}" ]; then
+		unbuffercommand=("${unbuffer}")
+	fi
+	validateparam=()
+	if [ -n "${validate}" ]; then
+		validateparam=("${validate}")
+	fi
+
 	# To do error checking for SteamCMD the output of steamcmd will be saved to a log.
 	steamcmdlog="${lgsmlogdir}/${selfname}-steamcmd.log"
 
@@ -61,29 +73,29 @@ fn_dl_steamcmd() {
 		if [ "${appid}" == "90" ]; then
 			# If using a specific branch.
 			if [ -n "${branch}" ] && [ -n "${betapassword}" ]; then
-				${unbuffer} ${steamcmdcommand} +force_install_dir "${serverfiles}" +login "${steamuser}" "${steampass}" +app_set_config 90 mod "${appidmod}" +app_update "${appid}" -beta "${branch}" -betapassword "${betapassword}" ${validate} +quit | uniq | tee -a "${lgsmlog}" "${steamcmdlog}"
+				"${unbuffercommand[@]}" "${steamcmdcommandarray[@]}" +force_install_dir "${serverfiles}" +login "${steamuser}" "${steampass}" +app_set_config 90 mod "${appidmod}" +app_update "${appid}" -beta "${branch}" -betapassword "${betapassword}" "${validateparam[@]}" +quit | uniq | tee -a "${lgsmlog}" "${steamcmdlog}"
 			elif [ -n "${branch}" ]; then
-				${unbuffer} ${steamcmdcommand} +force_install_dir "${serverfiles}" +login "${steamuser}" "${steampass}" +app_set_config 90 mod "${appidmod}" +app_update "${appid}" -beta "${branch}" ${validate} +quit | uniq | tee -a "${lgsmlog}" "${steamcmdlog}"
+				"${unbuffercommand[@]}" "${steamcmdcommandarray[@]}" +force_install_dir "${serverfiles}" +login "${steamuser}" "${steampass}" +app_set_config 90 mod "${appidmod}" +app_update "${appid}" -beta "${branch}" "${validateparam[@]}" +quit | uniq | tee -a "${lgsmlog}" "${steamcmdlog}"
 			else
-				${unbuffer} ${steamcmdcommand} +force_install_dir "${serverfiles}" +login "${steamuser}" "${steampass}" +app_set_config 90 mod "${appidmod}" +app_update "${appid}" ${validate} +quit | uniq | tee -a "${lgsmlog}" "${steamcmdlog}"
+				"${unbuffercommand[@]}" "${steamcmdcommandarray[@]}" +force_install_dir "${serverfiles}" +login "${steamuser}" "${steampass}" +app_set_config 90 mod "${appidmod}" +app_update "${appid}" "${validateparam[@]}" +quit | uniq | tee -a "${lgsmlog}" "${steamcmdlog}"
 			fi
 		# Force Windows Platform type.
 		elif [ "${steamcmdforcewindows}" == "yes" ]; then
 			if [ -n "${branch}" ] && [ -n "${betapassword}" ]; then
-				${unbuffer} ${steamcmdcommand} +@sSteamCmdForcePlatformType windows +force_install_dir "${serverfiles}" +login "${steamuser}" "${steampass}" +app_update "${appid}" -beta "${branch}" -betapassword "${betapassword}" ${validate} +quit | uniq | tee -a "${lgsmlog}" "${steamcmdlog}"
+				"${unbuffercommand[@]}" "${steamcmdcommandarray[@]}" +@sSteamCmdForcePlatformType windows +force_install_dir "${serverfiles}" +login "${steamuser}" "${steampass}" +app_update "${appid}" -beta "${branch}" -betapassword "${betapassword}" "${validateparam[@]}" +quit | uniq | tee -a "${lgsmlog}" "${steamcmdlog}"
 			elif [ -n "${branch}" ]; then
-				${unbuffer} ${steamcmdcommand} +@sSteamCmdForcePlatformType windows +force_install_dir "${serverfiles}" +login "${steamuser}" "${steampass}" +app_update "${appid}" -beta "${branch}" ${validate} +quit | uniq | tee -a "${lgsmlog}" "${steamcmdlog}"
+				"${unbuffercommand[@]}" "${steamcmdcommandarray[@]}" +@sSteamCmdForcePlatformType windows +force_install_dir "${serverfiles}" +login "${steamuser}" "${steampass}" +app_update "${appid}" -beta "${branch}" "${validateparam[@]}" +quit | uniq | tee -a "${lgsmlog}" "${steamcmdlog}"
 			else
-				${unbuffer} ${steamcmdcommand} +@sSteamCmdForcePlatformType windows +force_install_dir "${serverfiles}" +login "${steamuser}" "${steampass}" +app_update "${appid}" ${validate} +quit | uniq | tee -a "${lgsmlog}" "${steamcmdlog}"
+				"${unbuffercommand[@]}" "${steamcmdcommandarray[@]}" +@sSteamCmdForcePlatformType windows +force_install_dir "${serverfiles}" +login "${steamuser}" "${steampass}" +app_update "${appid}" "${validateparam[@]}" +quit | uniq | tee -a "${lgsmlog}" "${steamcmdlog}"
 			fi
 		# All other servers.
 		else
 			if [ -n "${branch}" ] && [ -n "${betapassword}" ]; then
-				${unbuffer} ${steamcmdcommand} +force_install_dir "${serverfiles}" +login "${steamuser}" "${steampass}" +app_update "${appid}" -beta "${branch}" -betapassword "${betapassword}" ${validate} +quit | uniq | tee -a "${lgsmlog}" "${steamcmdlog}"
+				"${unbuffercommand[@]}" "${steamcmdcommandarray[@]}" +force_install_dir "${serverfiles}" +login "${steamuser}" "${steampass}" +app_update "${appid}" -beta "${branch}" -betapassword "${betapassword}" "${validateparam[@]}" +quit | uniq | tee -a "${lgsmlog}" "${steamcmdlog}"
 			elif [ -n "${branch}" ]; then
-				${unbuffer} ${steamcmdcommand} +force_install_dir "${serverfiles}" +login "${steamuser}" "${steampass}" +app_update "${appid}" -beta "${branch}" ${validate} +quit | uniq | tee -a "${lgsmlog}" "${steamcmdlog}"
+				"${unbuffercommand[@]}" "${steamcmdcommandarray[@]}" +force_install_dir "${serverfiles}" +login "${steamuser}" "${steampass}" +app_update "${appid}" -beta "${branch}" "${validateparam[@]}" +quit | uniq | tee -a "${lgsmlog}" "${steamcmdlog}"
 			else
-				${unbuffer} ${steamcmdcommand} +force_install_dir "${serverfiles}" +login "${steamuser}" "${steampass}" +app_update "${appid}" ${validate} +quit | uniq | tee -a "${lgsmlog}" "${steamcmdlog}"
+				"${unbuffercommand[@]}" "${steamcmdcommandarray[@]}" +force_install_dir "${serverfiles}" +login "${steamuser}" "${steampass}" +app_update "${appid}" "${validateparam[@]}" +quit | uniq | tee -a "${lgsmlog}" "${steamcmdlog}"
 			fi
 		fi
 
@@ -132,9 +144,9 @@ fn_dl_steamcmd() {
 				fn_print_error2_nl "${commandaction} ${selfname}: ${remotelocation}: Corrupt update files"
 				fn_script_log_error "${commandaction} ${selfname}: ${remotelocation}: Corrupt update files"
 			else
-				fn_print_error2_nl "${commandaction} ${selfname}: ${remotelocation}: Unknown error occured"
+				fn_print_error2_nl "${commandaction} ${selfname}: ${remotelocation}: Unknown error occurred"
 				fn_print_nl "Please provide content log to LinuxGSM developers https://linuxgsm.com/steamcmd-error"
-				fn_script_log_error "${commandaction} ${selfname}: ${remotelocation}: Unknown error occured"
+				fn_script_log_error "${commandaction} ${selfname}: ${remotelocation}: Unknown error occurred"
 			fi
 		elif [ "${exitcode}" -ne 0 ]; then
 			fn_print_error2_nl "${commandaction} ${selfname}: ${remotelocation}: Exit code: ${exitcode}"
@@ -188,8 +200,8 @@ fn_dl_hash() {
 			hashbin="sha512sum"
 			hashtype="SHA512"
 		else
-			fn_script_log_error "hash lengh not known for hash type"
-			fn_print_error_nl "hash lengh not known for hash type"
+			fn_script_log_error "hash length not known for hash type"
+			fn_print_error_nl "hash length not known for hash type"
 			core_exit.sh
 		fi
 		echo -en "verifying ${local_filename} with ${hashtype}..."

+ 1 - 1
lgsm/modules/core_exit.sh

@@ -3,7 +3,7 @@
 # Author: Daniel Gibbs
 # Contributors: https://linuxgsm.com/contrib
 # Website: https://linuxgsm.com
-# Description: Code for backwards compatability with older versions of LinuxGSM.
+# Description: Code for backwards compatibility with older versions of LinuxGSM.
 
 moduleselfname="$(basename "$(readlink -f "${BASH_SOURCE[0]}")")"
 

+ 1 - 1
lgsm/modules/core_logs.sh

@@ -560,7 +560,7 @@ fn_print_restart_warning() {
 }
 
 # Functions below are used to ensure that logs and UI correctly reflect the command it is actually running.
-# Useful when a command has to call upon another command causing the other command to overrite commandname variables
+# Useful when a command has to call upon another command causing the other command to overwrite commandname variables
 
 # Used to remember the command that ran first.
 fn_firstcommand_set() {

+ 98 - 108
lgsm/modules/core_modules.sh

@@ -14,31 +14,13 @@ modulesversion="v25.2.0"
 
 core_dl.sh() {
 	modulefile="${FUNCNAME[0]}"
-	if [ "$(type fn_fetch_core_dl 2>/dev/null)" ]; then
+	if [ "$(type fn_fetch_core_dl 2> /dev/null)" ]; then
 		fn_fetch_core_dl "lgsm/modules" "core_dl.sh" "${modulesdir}" "chmodx" "run" "noforcedl" "nohash"
 	else
 		fn_bootstrap_fetch_file_github "lgsm/modules" "core_dl.sh" "${modulesdir}" "chmodx" "run" "noforcedl" "nohash"
 	fi
 }
 
-core_messages.sh() {
-	modulefile="${FUNCNAME[0]}"
-	if [ "$(type fn_fetch_core_dl 2>/dev/null)" ]; then
-		fn_fetch_core_dl "lgsm/modules" "core_messages.sh" "${modulesdir}" "chmodx" "run" "noforcedl" "nohash"
-	else
-		fn_bootstrap_fetch_file_github "lgsm/modules" "core_messages.sh" "${modulesdir}" "chmodx" "run" "noforcedl" "nohash"
-	fi
-}
-
-core_legacy.sh() {
-	modulefile="${FUNCNAME[0]}"
-	if [ "$(type fn_fetch_core_dl 2>/dev/null)" ]; then
-		fn_fetch_core_dl "lgsm/modules" "core_legacy.sh" "${modulesdir}" "chmodx" "run" "noforcedl" "nohash"
-	else
-		fn_bootstrap_fetch_file_github "lgsm/modules" "core_legacy.sh" "${modulesdir}" "chmodx" "run" "noforcedl" "nohash"
-	fi
-}
-
 core_exit.sh() {
 	modulefile="${FUNCNAME[0]}"
 	fn_fetch_module
@@ -54,17 +36,35 @@ core_getopt.sh() {
 	fn_fetch_module
 }
 
-core_trap.sh() {
+core_github.sh() {
 	modulefile="${FUNCNAME[0]}"
 	fn_fetch_module
 }
 
+core_legacy.sh() {
+	modulefile="${FUNCNAME[0]}"
+	if [ "$(type fn_fetch_core_dl 2> /dev/null)" ]; then
+		fn_fetch_core_dl "lgsm/modules" "core_legacy.sh" "${modulesdir}" "chmodx" "run" "noforcedl" "nohash"
+	else
+		fn_bootstrap_fetch_file_github "lgsm/modules" "core_legacy.sh" "${modulesdir}" "chmodx" "run" "noforcedl" "nohash"
+	fi
+}
+
+core_messages.sh() {
+	modulefile="${FUNCNAME[0]}"
+	if [ "$(type fn_fetch_core_dl 2> /dev/null)" ]; then
+		fn_fetch_core_dl "lgsm/modules" "core_messages.sh" "${modulesdir}" "chmodx" "run" "noforcedl" "nohash"
+	else
+		fn_bootstrap_fetch_file_github "lgsm/modules" "core_messages.sh" "${modulesdir}" "chmodx" "run" "noforcedl" "nohash"
+	fi
+}
+
 core_steamcmd.sh() {
 	modulefile="${FUNCNAME[0]}"
 	fn_fetch_module
 }
 
-core_github.sh() {
+core_trap.sh() {
 	modulefile="${FUNCNAME[0]}"
 	fn_fetch_module
 }
@@ -91,87 +91,87 @@ command_details.sh() {
 	fn_fetch_module
 }
 
-command_sponsor.sh() {
+command_fastdl.sh() {
 	modulefile="${FUNCNAME[0]}"
 	fn_fetch_module
 }
 
-command_postdetails.sh() {
+command_install.sh() {
 	modulefile="${FUNCNAME[0]}"
 	fn_fetch_module
 }
 
-command_test_alert.sh() {
+command_install_resources_mta.sh() {
 	modulefile="${FUNCNAME[0]}"
 	fn_fetch_module
 }
 
-command_monitor.sh() {
+command_mods_install.sh() {
 	modulefile="${FUNCNAME[0]}"
 	fn_fetch_module
 }
 
-command_start.sh() {
+command_mods_remove.sh() {
 	modulefile="${FUNCNAME[0]}"
 	fn_fetch_module
 }
 
-command_stop.sh() {
+command_mods_update.sh() {
 	modulefile="${FUNCNAME[0]}"
 	fn_fetch_module
 }
 
-command_validate.sh() {
+command_monitor.sh() {
 	modulefile="${FUNCNAME[0]}"
 	fn_fetch_module
 }
 
-command_install.sh() {
+command_postdetails.sh() {
 	modulefile="${FUNCNAME[0]}"
 	fn_fetch_module
 }
 
-command_install_resources_mta.sh() {
+command_restart.sh() {
 	modulefile="${FUNCNAME[0]}"
 	fn_fetch_module
 }
 
-install_squad_license.sh() {
+command_send.sh() {
 	modulefile="${FUNCNAME[0]}"
 	fn_fetch_module
 }
 
-command_mods_install.sh() {
+command_skeleton.sh() {
 	modulefile="${FUNCNAME[0]}"
 	fn_fetch_module
 }
 
-command_mods_update.sh() {
+command_sponsor.sh() {
 	modulefile="${FUNCNAME[0]}"
 	fn_fetch_module
 }
 
-command_mods_remove.sh() {
+command_start.sh() {
 	modulefile="${FUNCNAME[0]}"
 	fn_fetch_module
 }
 
-command_fastdl.sh() {
+command_stop.sh() {
 	modulefile="${FUNCNAME[0]}"
 	fn_fetch_module
 }
 
-command_ts3_server_pass.sh() {
+command_test_alert.sh() {
 	modulefile="${FUNCNAME[0]}"
 	fn_fetch_module
 }
 
-command_restart.sh() {
+command_ts3_server_pass.sh() {
 	modulefile="${FUNCNAME[0]}"
 	fn_fetch_module
 }
 
-command_skeleton.sh() {
+command_validate.sh() {
 	modulefile="${FUNCNAME[0]}"
 	fn_fetch_module
 }
@@ -181,7 +181,7 @@ command_wipe.sh() {
 	fn_fetch_module
 }
 
-command_send.sh() {
+install_squad_license.sh() {
 	modulefile="${FUNCNAME[0]}"
 	fn_fetch_module
 }
@@ -277,12 +277,12 @@ compress_unreal2_maps.sh() {
 
 # Mods
 
-mods_list.sh() {
+mods_core.sh() {
 	modulefile="${FUNCNAME[0]}"
 	fn_fetch_module
 }
 
-mods_core.sh() {
+mods_list.sh() {
 	modulefile="${FUNCNAME[0]}"
 	fn_fetch_module
 }
@@ -299,37 +299,37 @@ command_dev_debug.sh() {
 	fn_fetch_module
 }
 
-command_dev_parse_game_details.sh() {
+command_dev_detect_deps.sh() {
 	modulefile="${FUNCNAME[0]}"
 	fn_fetch_module
 }
 
-command_dev_parse_distro_details.sh() {
+command_dev_detect_glibc.sh() {
 	modulefile="${FUNCNAME[0]}"
 	fn_fetch_module
 }
 
-command_dev_detect_deps.sh() {
+command_dev_detect_ldd.sh() {
 	modulefile="${FUNCNAME[0]}"
 	fn_fetch_module
 }
 
-command_dev_detect_glibc.sh() {
+command_dev_parse_distro_details.sh() {
 	modulefile="${FUNCNAME[0]}"
 	fn_fetch_module
 }
 
-command_dev_detect_ldd.sh() {
+command_dev_parse_game_details.sh() {
 	modulefile="${FUNCNAME[0]}"
 	fn_fetch_module
 }
 
-command_dev_ui.sh() {
+command_dev_query_raw.sh() {
 	modulefile="${FUNCNAME[0]}"
 	fn_fetch_module
 }
 
-command_dev_query_raw.sh() {
+command_dev_ui.sh() {
 	modulefile="${FUNCNAME[0]}"
 	fn_fetch_module
 }
@@ -346,27 +346,27 @@ fix_ark.sh() {
 	fn_fetch_module
 }
 
-fix_av.sh() {
+fix_arma3.sh() {
 	modulefile="${FUNCNAME[0]}"
 	fn_fetch_module
 }
 
-fix_arma3.sh() {
+fix_armar.sh() {
 	modulefile="${FUNCNAME[0]}"
 	fn_fetch_module
 }
 
-fix_armar.sh() {
+fix_av.sh() {
 	modulefile="${FUNCNAME[0]}"
 	fn_fetch_module
 }
 
-fix_bt.sh() {
+fix_bo.sh() {
 	modulefile="${FUNCNAME[0]}"
 	fn_fetch_module
 }
 
-fix_bo.sh() {
+fix_bt.sh() {
 	modulefile="${FUNCNAME[0]}"
 	fn_fetch_module
 }
@@ -446,67 +446,62 @@ fix_rw.sh() {
 	fn_fetch_module
 }
 
-fix_sfc.sh() {
-	modulefile="${FUNCNAME[0]}"
-	fn_fetch_module
-}
-
-fix_sm.sh() {
+fix_samp.sh() {
 	modulefile="${FUNCNAME[0]}"
 	fn_fetch_module
 }
 
-fix_st.sh() {
+fix_sfc.sh() {
 	modulefile="${FUNCNAME[0]}"
 	fn_fetch_module
 }
 
-fix_steamcmd.sh() {
+fix_sm.sh() {
 	modulefile="${FUNCNAME[0]}"
 	fn_fetch_module
 }
 
-fix_terraria.sh() {
+fix_sof2.sh() {
 	modulefile="${FUNCNAME[0]}"
 	fn_fetch_module
 }
 
-fix_tf2.sh() {
+fix_squad.sh() {
 	modulefile="${FUNCNAME[0]}"
 	fn_fetch_module
 }
 
-fix_ut3.sh() {
+fix_st.sh() {
 	modulefile="${FUNCNAME[0]}"
 	fn_fetch_module
 }
 
-fix_rust.sh() {
+fix_steamcmd.sh() {
 	modulefile="${FUNCNAME[0]}"
 	fn_fetch_module
 }
 
-fix_samp.sh() {
+fix_terraria.sh() {
 	modulefile="${FUNCNAME[0]}"
 	fn_fetch_module
 }
 
-fix_sdtd.sh() {
+fix_tf2.sh() {
 	modulefile="${FUNCNAME[0]}"
 	fn_fetch_module
 }
 
-fix_sof2.sh() {
+fix_ts3.sh() {
 	modulefile="${FUNCNAME[0]}"
 	fn_fetch_module
 }
 
-fix_squad.sh() {
+fix_unt.sh() {
 	modulefile="${FUNCNAME[0]}"
 	fn_fetch_module
 }
 
-fix_ts3.sh() {
+fix_ut.sh() {
 	modulefile="${FUNCNAME[0]}"
 	fn_fetch_module
 }
@@ -516,12 +511,7 @@ fix_ut2k4.sh() {
 	fn_fetch_module
 }
 
-fix_ut.sh() {
-	modulefile="${FUNCNAME[0]}"
-	fn_fetch_module
-}
-
-fix_unt.sh() {
+fix_ut3.sh() {
 	modulefile="${FUNCNAME[0]}"
 	fn_fetch_module
 }
@@ -585,27 +575,27 @@ alert_email.sh() {
 	fn_fetch_module
 }
 
-alert_ifttt.sh() {
+alert_gotify.sh() {
 	modulefile="${FUNCNAME[0]}"
 	fn_fetch_module
 }
 
-alert_pushbullet.sh() {
+alert_ifttt.sh() {
 	modulefile="${FUNCNAME[0]}"
 	fn_fetch_module
 }
 
-alert_pushover.sh() {
+alert_ntfy.sh() {
 	modulefile="${FUNCNAME[0]}"
 	fn_fetch_module
 }
 
-alert_gotify.sh() {
+alert_pushbullet.sh() {
 	modulefile="${FUNCNAME[0]}"
 	fn_fetch_module
 }
 
-alert_telegram.sh() {
+alert_pushover.sh() {
 	modulefile="${FUNCNAME[0]}"
 	fn_fetch_module
 }
@@ -620,10 +610,11 @@ alert_slack.sh() {
 	fn_fetch_module
 }
 
-alert_ntfy.sh() {
+alert_telegram.sh() {
 	modulefile="${FUNCNAME[0]}"
 	fn_fetch_module
 }
+
 # Logs
 
 core_logs.sh() {
@@ -639,58 +630,57 @@ query_gamedig.sh() {
 }
 
 # Update
-
-command_update_modules.sh() {
+command_check_update.sh() {
 	modulefile="${FUNCNAME[0]}"
 	fn_fetch_module
 }
 
-command_update_linuxgsm.sh() {
+command_update.sh() {
 	modulefile="${FUNCNAME[0]}"
 	fn_fetch_module
 }
 
-command_update.sh() {
+command_update_linuxgsm.sh() {
 	modulefile="${FUNCNAME[0]}"
 	fn_fetch_module
 }
 
-command_check_update.sh() {
+command_update_modules.sh() {
 	modulefile="${FUNCNAME[0]}"
 	fn_fetch_module
 }
 
-update_ts3.sh() {
+fn_update_modules.sh() {
 	modulefile="${FUNCNAME[0]}"
 	fn_fetch_module
 }
 
-update_mc.sh() {
+update_fctr.sh() {
 	modulefile="${FUNCNAME[0]}"
 	fn_fetch_module
 }
 
-update_mcb.sh() {
+update_jk2.sh() {
 	modulefile="${FUNCNAME[0]}"
 	fn_fetch_module
 }
 
-update_pmc.sh() {
+update_mc.sh() {
 	modulefile="${FUNCNAME[0]}"
 	fn_fetch_module
 }
 
-update_mta.sh() {
+update_mcb.sh() {
 	modulefile="${FUNCNAME[0]}"
 	fn_fetch_module
 }
 
-update_fctr.sh() {
+update_mta.sh() {
 	modulefile="${FUNCNAME[0]}"
 	fn_fetch_module
 }
 
-update_jk2.sh() {
+update_pmc.sh() {
 	modulefile="${FUNCNAME[0]}"
 	fn_fetch_module
 }
@@ -700,7 +690,7 @@ update_steamcmd.sh() {
 	fn_fetch_module
 }
 
-update_vints.sh() {
+update_ts3.sh() {
 	modulefile="${FUNCNAME[0]}"
 	fn_fetch_module
 }
@@ -710,12 +700,12 @@ update_ut99.sh() {
 	fn_fetch_module
 }
 
-update_xnt.sh() {
+update_vints.sh() {
 	modulefile="${FUNCNAME[0]}"
 	fn_fetch_module
 }
 
-fn_update_modules.sh() {
+update_xnt.sh() {
 	modulefile="${FUNCNAME[0]}"
 	fn_fetch_module
 }
@@ -723,6 +713,10 @@ fn_update_modules.sh() {
 #
 ## Installer modules
 #
+check_gamedig.sh() {
+	modulefile="${FUNCNAME[0]}"
+	fn_fetch_module
+}
 
 fn_autoinstall() {
 	autoinstall=1
@@ -739,32 +733,32 @@ install_config.sh() {
 	fn_fetch_module
 }
 
-install_factorio_save.sh() {
+install_dl_ut2k4.sh() {
 	modulefile="${FUNCNAME[0]}"
 	fn_fetch_module
 }
 
-check_gamedig.sh() {
+install_dst_token.sh() {
 	modulefile="${FUNCNAME[0]}"
 	fn_fetch_module
 }
 
-install_dst_token.sh() {
+install_eula.sh() {
 	modulefile="${FUNCNAME[0]}"
 	fn_fetch_module
 }
 
-install_eula.sh() {
+install_factorio_save.sh() {
 	modulefile="${FUNCNAME[0]}"
 	fn_fetch_module
 }
 
-install_gsquery.sh() {
+install_gslt.sh() {
 	modulefile="${FUNCNAME[0]}"
 	fn_fetch_module
 }
 
-install_gslt.sh() {
+install_gsquery.sh() {
 	modulefile="${FUNCNAME[0]}"
 	fn_fetch_module
 }
@@ -788,6 +782,7 @@ install_server_dir.sh() {
 	modulefile="${FUNCNAME[0]}"
 	fn_fetch_module
 }
+
 install_server_files.sh() {
 	modulefile="${FUNCNAME[0]}"
 	fn_fetch_module
@@ -818,11 +813,6 @@ install_ut2k4.sh() {
 	fn_fetch_module
 }
 
-install_dl_ut2k4.sh() {
-	modulefile="${FUNCNAME[0]}"
-	fn_fetch_module
-}
-
 install_ut2k4_key.sh() {
 	modulefile="${FUNCNAME[0]}"
 	fn_fetch_module

+ 11 - 11
lgsm/modules/core_steamcmd.sh

@@ -185,12 +185,12 @@ fn_update_steamcmd_remotebuild() {
 	fi
 
 	# password for branch not needed to check the buildid
-	remotebuildversion=$(${steamcmdcommand} +login "${steamuser}" "${steampass}" +app_info_request "${appid}" +login "${steamuser}" "${steampass}" +app_info_update 1 +app_info_print "${appid}" +quit | sed -e '/"branches"/,/^}/!d' | sed -n "/\"${branch}\"/,/}/p" | grep -m 1 buildid | tr -cd '[:digit:]')
+	remotebuild=$(${steamcmdcommand} +login "${steamuser}" "${steampass}" +app_info_request "${appid}" +login "${steamuser}" "${steampass}" +app_info_update 1 +app_info_print "${appid}" +quit | sed -e '/"branches"/,/^}/!d' | sed -n "/\"${branch}\"/,/}/p" | grep -m 1 buildid | tr -cd '[:digit:]')
 
 	if [ "${firstcommandname}" != "INSTALL" ]; then
 		fn_print_dots "Checking remote build: ${remotelocation}"
-		# Checks if remotebuildversion variable has been set.
-		if [ -z "${remotebuildversion}" ] || [ "${remotebuildversion}" == "null" ]; then
+		# Checks if remotebuild variable has been set.
+		if [ -z "${remotebuild}" ] || [ "${remotebuild}" == "null" ]; then
 			fn_print_fail "Checking remote build: ${remotelocation}"
 			fn_script_log_fail "Checking remote build"
 			core_exit.sh
@@ -200,7 +200,7 @@ fn_update_steamcmd_remotebuild() {
 		fi
 	else
 		# Checks if remotebuild variable has been set.
-		if [ -z "${remotebuildversion}" ] || [ "${remotebuildversion}" == "null" ]; then
+		if [ -z "${remotebuild}" ] || [ "${remotebuild}" == "null" ]; then
 			fn_print_failure "Unable to get remote build"
 			fn_script_log_fail "Unable to get remote build"
 			core_exit.sh
@@ -211,14 +211,14 @@ fn_update_steamcmd_remotebuild() {
 fn_update_steamcmd_compare() {
 	fn_print_dots "Checking for update: ${remotelocation}"
 	# Update has been found or force update.
-	if [ "${localbuild}" != "${remotebuildversion}" ] || [ "${forceupdate}" == "1" ]; then
+	if [ "${localbuild}" != "${remotebuild}" ] || [ "${forceupdate}" == "1" ]; then
 		# Create update lockfile.
 		date '+%s' > "${lockdir:?}/update.lock"
 		fn_print_ok_nl "Checking for update: ${remotelocation}"
 		fn_print "\n"
 		fn_print_nl "${bold}${underline}Update${default} available"
 		fn_print_nl "* Local build: ${red}${localbuild}${default}"
-		fn_print_nl "* Remote build: ${green}${remotebuildversion}${default}"
+		fn_print_nl "* Remote build: ${green}${remotebuild}${default}"
 		if [ -n "${branch}" ]; then
 			fn_print_nl "* Branch: ${branch}"
 		fi
@@ -229,16 +229,17 @@ fn_update_steamcmd_compare() {
 		fn_print "\n"
 		fn_script_log_info "Update available"
 		fn_script_log_info "Local build: ${localbuild}"
-		fn_script_log_info "Remote build: ${remotebuildversion}"
+		fn_script_log_info "Remote build: ${remotebuild}"
 		if [ -n "${branch}" ]; then
 			fn_script_log_info "Branch: ${branch}"
 		fi
 		if [ -n "${betapassword}" ]; then
 			fn_script_log_info "Branch password: ${betapassword}"
 		fi
-		fn_script_log_info "${localbuild} > ${remotebuildversion}"
+		fn_script_log_info "${localbuild} > ${remotebuild}"
 
 		if [ "${commandname}" == "UPDATE" ]; then
+			date +%s > "${lockdir:?}/last-updated.lock"
 			unset updateonstart
 			check_status.sh
 			# If server stopped.
@@ -257,7 +258,6 @@ fn_update_steamcmd_compare() {
 				fn_firstcommand_reset
 			fi
 			unset exitbypass
-			date +%s > "${lockdir:?}/last-updated.lock"
 			alert="update"
 		elif [ "${commandname}" == "CHECK-UPDATE" ]; then
 			alert="check-update"
@@ -268,7 +268,7 @@ fn_update_steamcmd_compare() {
 		fn_print "\n"
 		fn_print_nl "${bold}${underline}No update${default} available"
 		fn_print_nl "* Local build: ${green}${localbuild}${default}"
-		fn_print_nl "* Remote build: ${green}${remotebuildversion}${default}"
+		fn_print_nl "* Remote build: ${green}${remotebuild}${default}"
 		if [ -n "${branch}" ]; then
 			fn_print_nl "* Branch: ${branch}"
 		fi
@@ -279,7 +279,7 @@ fn_update_steamcmd_compare() {
 		fn_print "\n"
 		fn_script_log_info "No update available"
 		fn_script_log_info "Local build: ${localbuild}"
-		fn_script_log_info "Remote build: ${remotebuildversion}"
+		fn_script_log_info "Remote build: ${remotebuild}"
 		if [ -n "${branch}" ]; then
 			fn_script_log_info "Branch: ${branch}"
 		fi

+ 4 - 2
lgsm/modules/core_trap.sh

@@ -8,10 +8,12 @@
 moduleselfname="$(basename "$(readlink -f "${BASH_SOURCE[0]}")")"
 
 fn_exit_trap() {
+	local saved_exit_status=$?
+	echo -e ""
 	if [ -z "${exitcode}" ]; then
-		exitcode=$?
+		exitcode=${saved_exit_status}
 	fi
-	echo -e ""
+
 	if [ -z "${exitcode}" ]; then
 		exitcode=0
 	fi

+ 2 - 2
lgsm/modules/fix.sh

@@ -7,7 +7,7 @@
 
 moduleselfname="$(basename "$(readlink -f "${BASH_SOURCE[0]}")")"
 
-# removes mulitple appworkshop_346110.acf if found.
+# removes multiple appworkshop_346110.acf if found.
 steamappsfilewc="$(find "${HOME}" -name appworkshop_346110.acf | wc -l)"
 if [ "${steamappsfilewc}" -gt "1" ]; then
 	fixname="multiple appworkshop acf files"
@@ -15,7 +15,7 @@ if [ "${steamappsfilewc}" -gt "1" ]; then
 	find "${HOME}" -name appworkshop_346110.acf -exec rm -f {} \;
 	fn_fix_msg_end
 elif [ "${steamappsfilewc}" -eq "1" ]; then
-	# Steam mods directory selecter
+	# Steam mods directory selector
 	# This allows LinxuGSM to select either ~/.steam or ~/Steam. depending on what is being used
 	steamappsfile=$(find "${HOME}" -name appworkshop_346110.acf)
 	steamappsdir=$(dirname "${steamappsfile}")

+ 1 - 1
lgsm/modules/fix_arma3.sh

@@ -8,7 +8,7 @@
 moduleselfname="$(basename "$(readlink -f "${BASH_SOURCE[0]}")")"
 
 # Fixes: ./dontstarve_dedicated_server_nullrenderer: ./lib32/libcurl-gnutls.so.4: no version information available (required by ./dontstarve_dedicated_server_nullrenderer).
-# Issue only occures on CentOS as libcurl-gnutls.so.4 is called libcurl.so.4 on CentOS.
+# Issue only occurs on CentOS as libcurl-gnutls.so.4 is called libcurl.so.4 on CentOS.
 if [ -f "/etc/redhat-release" ] && [ ! -f "${serverfiles}/bin/lib32/libcurl-gnutls.so.4" ]; then
 	fixname="libcurl-gnutls.so.4"
 	fn_fix_msg_start

+ 1 - 1
lgsm/modules/fix_hw.sh

@@ -10,7 +10,7 @@ moduleselfname="$(basename "$(readlink -f "${BASH_SOURCE[0]}")")"
 export LD_LIBRARY_PATH="$LD_LIBRARY_PATH:${serverfiles}"
 
 # Fixes: Failed loading "mariadb": libmariadbclient.so.18: cannot open shared object file: No such file or directory
-# Issue only occures on CentOS as libmariadbclient.so.18 is called libmariadb.so.3 on CentOS.
+# Issue only occurs on CentOS as libmariadbclient.so.18 is called libmariadb.so.3 on CentOS.
 if [ -f "/etc/redhat-release" ] && [ ! -f "${serverfiles}/libmariadbclient.so.18" ] && [ -f "/usr/lib64/libmariadb.so.3" ]; then
 	fixname="libmariadbclient.so.18"
 	fn_fix_msg_start

+ 1 - 1
lgsm/modules/fix_pvr.sh

@@ -23,7 +23,7 @@ if [ -z "${seed}" ] || [ "${seed}" == "0" ]; then
 	randomseed=1
 fi
 
-# If Carbon mod is installed, run enviroment.sh
+# If Carbon mod is installed, run environment.sh
 if [ -f "${serverfiles}/carbon/tools/environment.sh" ]; then
 	fn_print_info_nl "Running Carbon environment.sh"
 	fn_script_log_info "Running Carbon environment.sh"

+ 1 - 1
lgsm/modules/fix_rw.sh

@@ -1,5 +1,5 @@
 #!/bin/bash
-# LinuxGSM fix_rust.sh module
+# LinuxGSM fix_sof2.sh module
 # Author: Daniel Gibbs
 # Contributors: https://linuxgsm.com/contrib
 # Website: https://linuxgsm.com

+ 1 - 1
lgsm/modules/fix_squad.sh

@@ -1,5 +1,5 @@
 #!/bin/bash
-# LinuxGSM fix_rust.sh module
+# LinuxGSM fix_ts.sh module
 # Author: Daniel Gibbs
 # Contributors: https://linuxgsm.com/contrib
 # Website: https://linuxgsm.com

+ 1 - 1
lgsm/modules/fix_steamcmd.sh

@@ -1,5 +1,5 @@
 #!/bin/bash
-# LinuxGSM fix_rust.sh module
+# LinuxGSM fix_unt.sh module
 # Author: Daniel Gibbs
 # Contributors: https://linuxgsm.com/contrib
 # Website: https://linuxgsm.com

+ 3 - 3
lgsm/modules/fix_ut.sh

@@ -1,5 +1,5 @@
 #!/bin/bash
-# LinuxGSM fix_rust.sh module
+# LinuxGSM fix_vh.sh module
 # Author: Alasdair Haig
 # Website: https://linuxgsm.com
 # Description: Resolves issues with Valheim.
@@ -21,8 +21,8 @@ if [ -f "${modsinstalledlistfullpath}" ]; then
 			rm -rf "${serverfiles}/unstripped_corlib"
 		fi
 		sed -i "s/^dllSearchPathOverride=unstripped_corlib/# &/" "${serverfiles}/doorstop_config.ini"
-		sed -i "s/^export DOORSTOP_CORLIB_OVERRIDE_PATH="$BASEDIR\/unstripped_corlib"/# &/" "${serverfiles}/start_game_bepinex.sh"
-		sed -i "s/^export DOORSTOP_CORLIB_OVERRIDE_PATH="${VALHEIM_PLUS_PATH}\/unstripped_corlib"/# &/" "${serverfiles}/start_server_bepinex.sh"
+		sed -i "s|^export DOORSTOP_CORLIB_OVERRIDE_PATH=\"\\\$BASEDIR/unstripped_corlib\"|# &|" "${serverfiles}/start_game_bepinex.sh"
+		sed -i "s|^export DOORSTOP_CORLIB_OVERRIDE_PATH=\"\\\${VALHEIM_PLUS_PATH}/unstripped_corlib\"|# &|" "${serverfiles}/start_server_bepinex.sh"
 	fi
 	# special exports for BepInEx if installed
 	if grep -qE "^bepinexvh" "${modsinstalledlistfullpath}"; then

+ 7 - 7
lgsm/modules/fix_wurm.sh

@@ -3,7 +3,7 @@
 # Author: Daniel Gibbs
 # Contributors: https://linuxgsm.com/contrib
 # Website: https://linuxgsm.com
-# Description: Variables providing useful info on the Operating System such as disk and performace info.
+# Description: Variables providing useful info on the Operating System such as disk and performance info.
 # Used for command_details.sh, command_debug.sh and alert.sh.
 # !Note: When adding variables to this script, ensure that they are also added to the command_dev_parse_distro_details.sh script.
 
@@ -13,9 +13,9 @@ moduleselfname="$(basename "$(readlink -f "${BASH_SOURCE[0]}")")"
 if [ "${status}" == "1" ]; then
 	gameserverpid="$(tmux -L "${socketname}" list-sessions -F "#{session_name} #{pane_pid}" | grep "^${sessionname} " | awk '{print $NF}')"
 	if [ "${engine}" == "source" ]; then
-		srcdslinuxpid="$(ps -ef | grep -v grep | grep "${gameserverpid}" | grep srcds_linux | awk '{print $2}')"
+		srcdslinuxpid="$(pgrep -P "${gameserverpid}" -x srcds_linux 2> /dev/null | head -n 1)"
 	elif [ "${engine}" == "goldsrc" ]; then
-		hldslinuxpid="$(ps -ef | grep -v grep | grep "${gameserverpid}" | grep hlds_linux | awk '{print $2}')"
+		hldslinuxpid="$(pgrep -P "${gameserverpid}" -x hlds_linux 2> /dev/null | head -n 1)"
 	fi
 fi
 ### Distro information
@@ -252,11 +252,11 @@ if [ -d "${backupdir}" ]; then
 	backupcount=0
 
 	# If there are backups in backup dir.
-	if [ "$(find "${backupdir}" -name "*.tar.*" | wc -l)" -ne "0" ]; then
+	if [ "$(find "${backupdir}" -maxdepth 1 -type f -name "*.tar.*" | wc -l)" -ne "0" ]; then
 		# number of backups.
-		backupcount="$(find "${backupdir}"/*.tar.* | wc -l)" # integer
+		backupcount="$(find "${backupdir}" -maxdepth 1 -type f -name "*.tar.*" | wc -l)" # integer
 		# most recent backup.
-		lastbackup="$(ls -1t "${backupdir}"/*.tar.* | head -1)" # string
+		lastbackup="$(find "${backupdir}" -maxdepth 1 -type f -name "*.tar.*" -printf '%T@ %p\n' 2> /dev/null | sort -nr | head -n 1 | cut -d' ' -f2-)" # string
 		# date of most recent backup.
 		lastbackupdate="$(date -r "${lastbackup}")" # string
 		# no of days since last backup.
@@ -272,7 +272,7 @@ netlink=$(${ethtoolcommand} "${netint}" 2> /dev/null | grep Speed | awk '{print
 
 # Sets the SteamCMD glibc requirement if the game server requirement is less or not required.
 if [ "${appid}" ]; then
-	if [ "${glibc}" = "null" ] || [ -z "${glibc}" ] || [ "$(printf '%s\n'${glibc}'\n' "2.14" | sort -V | head -n 1)" != "2.14" ]; then
+	if [ "${glibc}" = "null" ] || [ -z "${glibc}" ] || [ "$(printf '%s\n' "${glibc}" "2.14" | sort -V | head -n 1)" != "2.14" ]; then
 		glibc="2.14"
 	fi
 fi

+ 3 - 3
lgsm/modules/info_game.sh

@@ -350,7 +350,7 @@ fn_info_game_av() {
 	rconenabled="${rconenabled:-"false"}"
 	rconpassword="${rconpassword:-"NOT SET"}"
 	rconport="${rconport:-"0"}"
-	# queryport doesnt respond to any queries, using session only.
+	# queryport doesn't respond to any queries, using session only.
 	queryport=""$((port + 3))""
 	servername="${servername:-"NOT SET"}"
 	serverpassword="${serverpassword:-"NOT SET"}"
@@ -2514,7 +2514,7 @@ if [ ! -f "${tmpdir}/publicip.json" ] || [ "$(find "${tmpdir}/publicip.json" -mm
 	ipresponse=$(curl -s --max-time 3 "${apiurl}") # Attempt to query ip-api.com with a 3 second timeout
 	exitcode=$?
 
-	# Check if the first request was successfull
+	# Check if the first request was successful
 	if [ "${exitcode}" -eq 0 ]; then
 		fn_script_log_pass "Queried ${apiurl} for public IP address"
 
@@ -2532,7 +2532,7 @@ if [ ! -f "${tmpdir}/publicip.json" ] || [ "$(find "${tmpdir}/publicip.json" -mm
 		ipresponse=$(curl -s --max-time 3 "${apiurl}") # Attempt to query myip.wtf with a 3 second timeout as a backup
 		exitcode=$?
 
-		# Check if the backup request was successfull
+		# Check if the backup request was successful
 		if [ "${exitcode}" -eq 0 ]; then
 			fn_script_log_pass "Queried ${apiurl} for public IP address"
 

+ 3 - 3
lgsm/modules/info_messages.sh

@@ -369,7 +369,7 @@ fn_info_messages_gameserver() {
 			fi
 		fi
 
-		# Reverved Slots
+		# Reserved Slots
 		if [ -n "${statspassword}" ]; then
 			echo -e "${lightblue}Reserved Slots:\t${default}${reservedslots}"
 		fi
@@ -578,7 +578,7 @@ fn_info_messages_script() {
 				:
 			elif [ -z "${glibc}" ]; then
 				echo -e "${lightblue}glibc required:\t${red}UNKNOWN${default}"
-			elif [ "$(printf '%s\n'${glibc}'\n' ${glibcversion} | sort -V | head -n 1)" != "${glibc}" ]; then
+			elif [ "$(printf '%s\n' "${glibc}" "${glibcversion}" | sort -V | head -n 1)" != "${glibc}" ]; then
 				echo -e "${lightblue}glibc required:\t${red}${glibc} ${default}(${red}distro glibc ${glibcversion} too old${default})"
 			else
 				echo -e "${lightblue}glibc required:\t${green}${glibc}${default}"
@@ -598,7 +598,7 @@ fn_info_messages_script() {
 			echo -e "${lightblue}Gotify alert:\t${default}${gotifyalert}"
 		fi
 		# IFTTT alert
-    if [ "${iftttalert}" == "on" ]; then
+		if [ "${iftttalert}" == "on" ]; then
 			echo -e "${lightblue}IFTTT alert:\t${default}${iftttalert}"
 		fi
 		# Pushbullet alert

+ 2 - 2
lgsm/modules/info_stats.sh

@@ -16,7 +16,7 @@ fn_check_cfgdir() {
 	fi
 }
 
-# Copys default configs from Game-Server-Configs repo to server config location.
+# Copies default configs from Game-Server-Configs repo to server config location.
 fn_default_config_remote() {
 	echo -e ""
 	echo -e "${bold}${lightyellow}Downloading ${gamename} Configs${default}"
@@ -88,7 +88,7 @@ fn_default_config_remote() {
 	done
 }
 
-# Copys local default config to server config location.
+# Copies local default config to server config location.
 fn_default_config_local() {
 	echo -e ""
 	echo -e "${bold}${lightyellow}Copying ${gamename} Configs${default}"

+ 1 - 1
lgsm/modules/install_dst_token.sh

@@ -18,7 +18,7 @@ if [ -z "${autoinstall}" ]; then
 	echo -e "Once you have the key enter it below"
 	echo -n "KEY: "
 	read -r CODE
-	echo -e ""\""CDKey"\""="\""${CODE}"\""" > "${systemdir}/cdkey"
+	printf '"CDKey"="%s"\n' "${CODE}" > "${systemdir}/cdkey"
 	if [ -f "${systemdir}/cdkey" ]; then
 		fn_script_log_info "UT2K4 Server CD Key created"
 	fi

+ 13 - 20
lgsm/modules/mods_core.sh

@@ -197,14 +197,15 @@ 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
+	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
+			for ((index_search = index; index_search >= 0; index_search--)); do
 				# When "MOD" is found.
-				if [ "${mods_global_array[index]}" == "MOD" ]; then
+				if [ "${mods_global_array[index_search]}" == "MOD" ]; then
 					# Get info.
+					index=${index_search}
 					fn_mods_define
 					modinfocommand="1"
 					break
@@ -249,7 +250,7 @@ fn_mods_define() {
 }
 
 # Builds list of installed mods.
-# using installed-mods.txt grabing mod info from mods_list.sh.
+# using installed-mods.txt grabbing mod info from mods_list.sh.
 fn_mods_installed_list() {
 	fn_mods_count_installed
 	# Set/reset variables.
@@ -331,7 +332,7 @@ fn_compatible_mod_engines() {
 		# How many engines we need to test.
 		enginesamount=$(echo -e "${modengines}" | awk -F ';' '{ print NF }')
 		# Test all subvalue of "modengines" using the ";" separator.
-		for ((gamevarindex = 1; gamevarindex < ${enginesamount}; gamevarindex++)); do
+		for ((gamevarindex = 1; gamevarindex < enginesamount; gamevarindex++)); do
 			# Put current engine name into modtest variable.
 			enginemodtest=$(echo -e "${modengines}" | awk -F ';' -v x=${gamevarindex} '{ print $x }')
 			# If engine name matches.
@@ -472,7 +473,7 @@ fn_mods_check_installed() {
 	# Count installed mods.
 	fn_mods_count_installed
 	# If no mods are found.
-	if [ ${installedmodscount} -eq 0 ]; then
+	if [ "${installedmodscount}" -eq 0 ]; then
 		echo -e ""
 		fn_print_failure_nl "No installed mods or addons were found"
 		echo -e " * Install mods using LinuxGSM first with: ./${selfname} mods-install"
@@ -566,7 +567,7 @@ fn_mod_liblist_gam_filenames() {
 	esac
 }
 
-# modifers for liblist.gam to add/remote metamod binaries
+# modifiers for liblist.gam to add/remote metamod binaries
 fn_mod_install_liblist_gam_file() {
 
 	fn_mod_liblist_gam_filenames
@@ -689,13 +690,9 @@ fn_mod_install_amxmodx_file() {
 		# since it does exist, is the entry already in plugins.ini
 		logentry="line (linux addons/amxmodx/dlls/amxmodx_mm_i386.so) inserted into ${modinstalldir}/addons/metamod/plugins.ini"
 		echo -en "adding amxmodx_mm_i386.so in plugins.ini..."
-		grep -q "amxmodx_mm_i386.so" "${modinstalldir}/addons/metamod/plugins.ini"
-		exitcode=$?
-		if [ "${exitcode}" -ne 0 ]; then
+		if ! grep -q "amxmodx_mm_i386.so" "${modinstalldir}/addons/metamod/plugins.ini"; then
 			# file exists but the entry does not, let's add it
-			echo "linux addons/amxmodx/dlls/amxmodx_mm_i386.so" >> "${modinstalldir}/addons/metamod/plugins.ini"
-			exitcode=$?
-			if [ "${exitcode}" -ne 0 ]; then
+			if ! echo "linux addons/amxmodx/dlls/amxmodx_mm_i386.so" >> "${modinstalldir}/addons/metamod/plugins.ini"; then
 				fn_script_log_fail "${logentry}"
 				fn_print_fail_eol_nl
 			else
@@ -705,9 +702,7 @@ fn_mod_install_amxmodx_file() {
 		fi
 	else
 		# create new file and add the mod to it
-		echo "linux addons/amxmodx/dlls/amxmodx_mm_i386.so" > "${modinstalldir}/addons/metamod/plugins.ini"
-		exitcode=$?
-		if [ "${exitcode}" -ne 0 ]; then
+		if ! echo "linux addons/amxmodx/dlls/amxmodx_mm_i386.so" > "${modinstalldir}/addons/metamod/plugins.ini"; then
 			fn_script_log_fail "${logentry}"
 			fn_print_fail_eol_nl
 			core_exit.sh
@@ -723,10 +718,8 @@ fn_mod_remove_amxmodx_file() {
 		# since it does exist, is the entry already in plugins.ini
 		logentry="line (linux addons/amxmodx/dlls/amxmodx_mm_i386.so) removed from ${modinstalldir}/addons/metamod/plugins.ini"
 		echo -en "removing amxmodx_mm_i386.so in plugins.ini..."
-		grep -q "linux addons/amxmodx/dlls/amxmodx_mm_i386.so" "${modinstalldir}/addons/metamod/plugins.ini"
-		# iIs it found? If so remove it and clean up
-		exitcode=$?
-		if [ "${exitcode}" -eq 0 ]; then
+		# is it found? If so remove it and clean up
+		if grep -q "linux addons/amxmodx/dlls/amxmodx_mm_i386.so" "${modinstalldir}/addons/metamod/plugins.ini"; then
 			# delete the line we inserted
 			sed -i '/linux addons\/amxmodx\/dlls\/amxmodx_mm_i386.so/d' "${modinstalldir}/addons/metamod/plugins.ini"
 			# remove empty lines

+ 3 - 3
lgsm/modules/mods_list.sh

@@ -129,7 +129,7 @@ modseparator="MOD"
 # [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
+# [12]	| "AUTHOR_URL" is the author's website, displayed to the user when choosing mods to install
 # [13]	| "Short Description" a description showed to the user upon installation/removal
 
 # Half-life 1 Engine Mods
@@ -172,7 +172,7 @@ mod_info_ulib=(MOD "ulib" "ULib" "https://codeload.github.com/TeamUlysses/ulib/z
 mod_info_ulx=(MOD "ulx" "ULX" "https://codeload.github.com/TeamUlysses/ulx/zip/master" "ulx-master.zip" "0" "LowercaseOff" "${systemdir}/addons" "OVERWRITE" "ENGINES" "Garry's Mod;" "NOTGAMES" "http://ulyssesmod.net" "Admin Panel (requires ULib)")
 mod_info_utime=(MOD "utime" "UTime" "https://github.com/TeamUlysses/utime/archive/master.zip" "utime-master.zip" "0" "LowercaseOff" "${systemdir}/addons" "OVERWRITE" "ENGINES" "Garry's Mod;" "NOTGAMES" "http://ulyssesmod.net" "Keep track of players play time")
 mod_info_uclip=(MOD "uclip" "UClip" "https://github.com/TeamUlysses/uclip/archive/master.zip" "uclip-master.zip" "0" "LowercaseOff" "${systemdir}/addons" "OVERWRITE" "ENGINES" "Garry's Mod;" "NOTGAMES" "http://ulyssesmod.net" "An alternative to noclip")
-mod_info_acf=(MOD "acf" "Armoured Combat Framework" "https://github.com/nrlulz/ACF/archive/master.zip" "acf-master.zip" "0" "LowercaseOn" "${systemdir}/addons" "acf-master/lua/acf/shared/guns;" "ENGINES" "Garry's Mod;" "NOTGAMES" "https://github.com/nrlulz/ACF" "Realistic Wepons & Engines")
+mod_info_acf=(MOD "acf" "Armoured Combat Framework" "https://github.com/nrlulz/ACF/archive/master.zip" "acf-master.zip" "0" "LowercaseOn" "${systemdir}/addons" "acf-master/lua/acf/shared/guns;" "ENGINES" "Garry's Mod;" "NOTGAMES" "https://github.com/nrlulz/ACF" "Realistic Weapons & 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_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. Second version")
 mod_info_pac3=(MOD "pac3" "PAC3" "https://github.com/CapsAdmin/pac3/archive/master.zip" "pac3-master.zip" "0" "LowercaseOff" "${systemdir}/addons" "OVERWRITE" "ENGINES" "Garry's Mod;" "NOTGAMES" "https://github.com/CapsAdmin/pac3" "Advanced player model customization")
@@ -191,7 +191,7 @@ mod_info_magneticdipole=(MOD "magneticdipole" "Magnetic Dipole" "https://github.
 mod_info_environmentorganizer=(MOD "environmentorganizer" "Environment Organizer" "https://github.com/dvdvideo1234/environmentorganizer/archive/master.zip" "environmentorganizer-master.zip" "0" "LowercaseOn" "${systemdir}/addons" "OVERWRITE" "ENGINES" "Garry's Mod;" "NOTGAMES" "https://github.com/dvdvideo1234/EnvironmentOrganizer" "Installs routines designed for server settings adjustment")
 mod_info_improved_stacker=(MOD "improved-stacker" "Improved Stacker" "https://github.com/Mista-Tea/improved-stacker/archive/master.zip" "improved-stacker-master.zip" "0" "LowercaseOn" "${systemdir}/addons" "OVERWRITE" "ENGINES" "Garry's Mod;" "NOTGAMES" "https://github.com/Mista-Tea/improved-stacker" "Stacks entities in the direction chosen")
 mod_info_improved_weight=(MOD "improved-weight" "Improved Weight" "https://github.com/Mista-Tea/improved-weight/archive/master.zip" "improved-weight-master.zip" "0" "LowercaseOn" "${systemdir}/addons" "OVERWRITE" "ENGINES" "Garry's Mod;" "NOTGAMES" "https://github.com/Mista-Tea/improved-weight" "Weight tool but with more features")
-mod_info_improved_antinoclip=(MOD "improved-antinoclip" "Improved Antinoclip" "https://github.com/Mista-Tea/improved-antinoclip/archive/master.zip" "improved-antinoclip-master.zip" "0" "LowercaseOn" "${systemdir}/addons" "OVERWRITE" "ENGINES" "Garry's Mod;" "NOTGAMES" "https://github.com/Mista-Tea/improved-antinoclip" "Controls clipping trough an object")
+mod_info_improved_antinoclip=(MOD "improved-antinoclip" "Improved Antinoclip" "https://github.com/Mista-Tea/improved-antinoclip/archive/master.zip" "improved-antinoclip-master.zip" "0" "LowercaseOn" "${systemdir}/addons" "OVERWRITE" "ENGINES" "Garry's Mod;" "NOTGAMES" "https://github.com/Mista-Tea/improved-antinoclip" "Controls clipping through an object")
 mod_info_darkrp=(MOD "darkrp" "DarkRP" "https://github.com/FPtje/DarkRP/archive/master.zip" "darkrp-master.zip" "0" "LowercaseOn" "${systemdir}/gamemodes" "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")
 mod_info_laserstool=(MOD "laserstool" "Laser STool" "https://github.com/dvdvideo1234/laserstool/archive/main.zip" "laserstool-main.zip" "0" "LowercaseOn" "${systemdir}/addons" "OVERWRITE" "ENGINES" "Garry's Mod;" "NOTGAMES" "https://github.com/dvdvideo1234/LaserSTool" "Scripted tool that spawns laser entities, simulates light rays and even kill players")

+ 1 - 1
lgsm/modules/query_gamedig.sh

@@ -3,7 +3,7 @@
 # Author: Daniel Gibbs
 # Contributors: https://linuxgsm.com/contrib
 # Website: https://linuxgsm.com
-# Description: Querys a gameserver using node-gamedig.
+# Description: Queries a gameserver using node-gamedig.
 # https://github.com/gamedig/node-gamedig
 
 moduleselfname="$(basename "$(readlink -f "${BASH_SOURCE[0]}")")"

+ 118 - 66
lgsm/modules/query_gsquery.py

@@ -6,154 +6,206 @@
 # Website: https://linuxgsm.com
 # Description: Allows querying of various game servers.
 
+"""Query game servers using a set of lightweight UDP protocols."""
+
 import argparse
 import socket
 import sys
 
-engine_types = ('protocol-valve', 'protocol-quake2', 'protocol-quake3', 'protocol-gamespy1',
-                'protocol-unreal2', 'ut3', 'minecraft', 'minecraftbe', 'jc2m', 'mumbleping', 'soldat', 'teeworlds')
+engine_types = (
+    "protocol-valve",
+    "protocol-quake2",
+    "protocol-quake3",
+    "protocol-gamespy1",
+    "protocol-unreal2",
+    "ut3",
+    "minecraft",
+    "minecraftbe",
+    "jc2m",
+    "mumbleping",
+    "soldat",
+    "teeworlds",
+)
+
 
+class GSQuery:
+    """Game server query dispatcher."""
 
-class gsquery:
     server_response_timeout = 2
     default_buffer_length = 1024
-    sourcequery = ('protocol-valve', 'avalanche3.0', 'barotrauma', 'madness', 'quakelive', 'realvirtuality',
-                   'refractor', 'source', 'goldsrc', 'spark', 'starbound', 'unity3d', 'unreal4', 'wurm')
-    idtech2query = ('protocol-quake2', 'idtech2', 'quake', 'iw2.0')
-    idtech3query = ('protocol-quake3', 'iw3.0', 'ioquake3', 'qfusion')
-    minecraftquery = ('minecraft', 'lwjgl2')
-    minecraftbequery = ('minecraftbe')
-    jc2mquery = ('jc2m')
-    mumblequery = ('mumbleping')
-    soldatquery = ('soldat')
-    twquery = ('teeworlds')
-    unrealquery = ('protocol-gamespy1', 'unreal')
-    unreal2query = ('protocol-unreal2', 'unreal2')
-    unreal3query = ('ut3', 'unreal3')
+    sourcequery = (
+        "protocol-valve",
+        "avalanche3.0",
+        "barotrauma",
+        "madness",
+        "quakelive",
+        "realvirtuality",
+        "refractor",
+        "source",
+        "goldsrc",
+        "spark",
+        "starbound",
+        "unity3d",
+        "unreal4",
+        "wurm",
+    )
+    idtech2query = ("protocol-quake2", "idtech2", "quake", "iw2.0")
+    idtech3query = ("protocol-quake3", "iw3.0", "ioquake3", "qfusion")
+    minecraftquery = ("minecraft", "lwjgl2")
+    minecraftbequery = ("minecraftbe",)
+    jc2mquery = ("jc2m",)
+    mumblequery = ("mumbleping",)
+    soldatquery = ("soldat",)
+    twquery = ("teeworlds",)
+    unrealquery = ("protocol-gamespy1", "unreal")
+    unreal2query = ("protocol-unreal2", "unreal2")
+    unreal3query = ("ut3", "unreal3")
 
     def __init__(self, arguments):
+        """Create a query instance from parsed CLI args."""
+
         self.argument = arguments
         #
         if self.argument.engine in self.sourcequery:
-            self.query_prompt_string = b'\xFF\xFF\xFF\xFFTSource Engine Query\0'
+            self.query_prompt_string = b"\xff\xff\xff\xffTSource Engine Query\0"
         elif self.argument.engine in self.idtech2query:
-            self.query_prompt_string = b'\xff\xff\xff\xffstatus\x00'
+            self.query_prompt_string = b"\xff\xff\xff\xffstatus\x00"
         elif self.argument.engine in self.idtech3query:
-            self.query_prompt_string = b'\xff\xff\xff\xffgetstatus'
+            self.query_prompt_string = b"\xff\xff\xff\xffgetstatus"
         elif self.argument.engine in self.jc2mquery:
-            self.query_prompt_string = b'\xFE\xFD\x09\x10\x20\x30\x40'
+            self.query_prompt_string = b"\xfe\xfd\x09\x10\x20\x30\x40"
         elif self.argument.engine in self.minecraftquery:
-            self.query_prompt_string = b'\xFE\xFD\x09\x3d\x54\x1f\x93'
+            self.query_prompt_string = b"\xfe\xfd\x09\x3d\x54\x1f\x93"
         elif self.argument.engine in self.minecraftbequery:
-            self.query_prompt_string = b'\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\x00\xfe\xfe\xfe\xfe\xfd\xfd\xfd\xfd\x12\x34\x56\x78\x00\x00\x00\x00\x00\x00\x00\x00'
+            self.query_prompt_string = (
+                b"\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\x00"
+                b"\xfe\xfe\xfe\xfe\xfd\xfd\xfd\xfd\x12\x34\x56\x78"
+                b"\x00\x00\x00\x00\x00\x00\x00\x00"
+            )
         elif self.argument.engine in self.mumblequery:
-            self.query_prompt_string = b'\x00\x00\x00\x00\x01\x02\x03\x04\x05\x06\x07\x08'
+            self.query_prompt_string = (
+                b"\x00\x00\x00\x00\x01\x02\x03\x04\x05\x06\x07\x08"
+            )
         elif self.argument.engine in self.soldatquery:
-            self.query_prompt_string = b'\x69\x00'
+            self.query_prompt_string = b"\x69\x00"
         elif self.argument.engine in self.twquery:
-            self.query_prompt_string = b'\x04\x00\x00\xff\xff\xff\xff\x05' + \
-                bytearray(511)
+            self.query_prompt_string = b"\x04\x00\x00\xff\xff\xff\xff\x05" + bytearray(
+                511
+            )
         elif self.argument.engine in self.unrealquery:
-            self.query_prompt_string = b'\x5C\x69\x6E\x66\x6F\x5C'
+            self.query_prompt_string = b"\x5c\x69\x6e\x66\x6f\x5c"
         elif self.argument.engine in self.unreal2query:
-            self.query_prompt_string = b'\x79\x00\x00\x00\x00'
+            self.query_prompt_string = b"\x79\x00\x00\x00\x00"
         elif self.argument.engine in self.unreal3query:
-            self.query_prompt_string = b'\xFE\xFD\x09\x00\x00\x00\x00'
+            self.query_prompt_string = b"\xfe\xfd\x09\x00\x00\x00\x00"
 
         self.connected = False
         self.response = None
 
     @staticmethod
     def fatal_error(error_message, error_code=1):
-        sys.stderr.write('ERROR: ' + str(error_message) + '\n')
+        """Write an error message to stderr and exit."""
+
+        sys.stderr.write("ERROR: " + str(error_message) + "\n")
         sys.exit(error_code)
 
     @staticmethod
-    def exit_success(success_message=''):
-        sys.stdout.write('OK: ' + str(success_message) + '\n')
+    def exit_success(success_message=""):
+        """Write a success message to stdout and exit."""
+
+        sys.stdout.write("OK: " + str(success_message) + "\n")
         sys.exit(0)
 
     def responding(self):
+        """Send a single UDP query and print the response."""
+
         # Connect.
         connection = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
         connection.settimeout(self.server_response_timeout)
         try:
             self.connected = connection.connect(
-                (self.argument.address, int(self.argument.port)))
+                (self.argument.address, int(self.argument.port))
+            )
         except socket.timeout:
-            self.fatal_error('Request timed out', 1)
-        except Exception:
-            self.fatal_error('Unable to connect', 1)
+            self.fatal_error("Request timed out", 1)
+        except OSError:
+            self.fatal_error("Unable to connect", 1)
         # Send.
         connection.send(self.query_prompt_string)
         # Receive.
         try:
             self.response = connection.recv(self.default_buffer_length)
         except socket.error:
-            self.fatal_error('Unable to receive', 2)
+            self.fatal_error("Unable to receive", 2)
         connection.close()
         # Response.
         if self.response is None:
-            self.fatal_error('No response', 3)
+            self.fatal_error("No response", 3)
         if len(self.response) < 5:
-            sys.exit('Short response.', 3)
+            sys.exit("Short response.", 3)
         else:
             self.exit_success(str(self.response))
 
 
 def parse_args():
+    """Parse command-line arguments."""
+
     parser = argparse.ArgumentParser(
-        description='Allows querying of various game servers.',
-        usage='usage: python3 %(prog)s [options]',
-        add_help=False
+        description="Allows querying of various game servers.",
+        usage="usage: python3 %(prog)s [options]",
+        add_help=False,
     )
     parser.add_argument(
-        '-a', '--address',
+        "-a",
+        "--address",
         type=str,
         required=True,
-        help='The IPv4 address of the server.'
+        help="The IPv4 address of the server.",
     )
     parser.add_argument(
-        '-p', '--port',
+        "-p",
+        "--port",
         type=int,
         required=True,
-        help='The IPv4 port of the server.'
+        help="The IPv4 port of the server.",
     )
     parser.add_argument(
-        '-e', '--engine',
-        metavar='ENGINE',
+        "-e",
+        "--engine",
+        metavar="ENGINE",
         choices=engine_types,
-        help='Engine type: ' + ' '.join(engine_types)
+        help="Engine type: " + " ".join(engine_types),
     )
     parser.add_argument(
-        '-v', '--verbose',
-        action='store_true',
-        help='Display verbose output.'
+        "-v",
+        "--verbose",
+        action="store_true",
+        help="Display verbose output.",
     )
     parser.add_argument(
-        '-d', '--debug',
-        action='store_true',
-        help='Display debugging output.'
+        "-d",
+        "--debug",
+        action="store_true",
+        help="Display debugging output.",
     )
     parser.add_argument(
-        '-V', '--version',
-        action='version',
-        version='%(prog)s 0.0.1',
-        help='Display version and exit.'
-    )
-    parser.add_argument(
-        '-h', '--help',
-        action='help',
-        help='Display help and exit.'
+        "-V",
+        "--version",
+        action="version",
+        version="%(prog)s 0.0.1",
+        help="Display version and exit.",
     )
+    parser.add_argument("-h", "--help", action="help", help="Display help and exit.")
     return parser.parse_args()
 
 
 def main():
+    """CLI entrypoint."""
+
     arguments = parse_args()
-    server = gsquery(arguments)
+    server = GSQuery(arguments)
     server.responding()
 
 
-if __name__ == '__main__':
+if __name__ == "__main__":
     main()

+ 63 - 37
lgsm/modules/update_fctr.sh

@@ -10,25 +10,32 @@ moduleselfname="$(basename "$(readlink -f "${BASH_SOURCE[0]}")")"
 fn_update_dl() {
 	# Download and extract files to serverfiles.
 	fn_fetch_file "${remotebuildurl}" "" "" "" "${tmpdir}" "${remotebuildfilename}" "nochmodx" "norun" "force" "nohash"
-	fn_dl_extract "${tmpdir}" "factorio_headless_${factorioarch}-${remotebuildversion}.tar.xz" "${serverfiles}" "factorio"
+	fn_dl_extract "${tmpdir}" "factorio_headless_${factorioarch}-${remotebuild}.tar.xz" "${serverfiles}" "factorio"
 	fn_clear_tmp
 }
 
 fn_update_localbuild() {
-	# Gets local build info.
-	fn_print_dots "Checking local build: ${remotelocation}"
+	# Optional arg1: 'silent' to suppress user-facing output
+	local mode="${1:-}"
+	if [ "${mode}" != "silent" ]; then
+		fn_print_dots "Checking local build: ${remotelocation}"
+	fi
 	# Uses executable to get local build.
 	if [ -d "${executabledir}" ]; then
 		cd "${executabledir}" || exit
 		localbuild=$(${executable} --version | grep -m 1 "Version:" | awk '{print $2}')
 	fi
 	if [ -z "${localbuild}" ]; then
-		fn_print_error "Checking local build: ${remotelocation}: missing local build info"
+		if [ "${mode}" != "silent" ]; then
+			fn_print_error "Checking local build: ${remotelocation}: missing local build info"
+		fi
 		fn_script_log_error "Missing local build info"
 		fn_script_log_error "Set localbuild to 0"
 		localbuild="0"
 	else
-		fn_print_ok "Checking local build: ${remotelocation}"
+		if [ "${mode}" != "silent" ]; then
+			fn_print_ok "Checking local build: ${remotelocation}"
+		fi
 		fn_script_log_pass "Checking local build"
 	fi
 }
@@ -37,14 +44,14 @@ fn_update_remotebuild() {
 	# Gets remote build info.
 	apiurl="https://factorio.com/get-download/${branch}/headless/${factorioarch}"
 	remotebuildresponse=$(curl -s "${apiurl}")
-	remotebuildversion=$(echo "${remotebuildresponse}" | grep -o '[0-9]\.[0-9]\{1,\}\.[0-9]\{1,\}' | head -1)
+	remotebuild=$(echo "${remotebuildresponse}" | grep -o '[0-9]\.[0-9]\{1,\}\.[0-9]\{1,\}' | head -1)
 	remotebuildurl="https://factorio.com/get-download/${branch}/headless/${factorioarch}"
-	remotebuildfilename="factorio_headless_${factorioarch}-${remotebuildversion}.tar.xz"
+	remotebuildfilename="factorio_headless_${factorioarch}-${remotebuild}.tar.xz"
 
 	if [ "${firstcommandname}" != "INSTALL" ]; then
 		fn_print_dots "Checking remote build: ${remotelocation}"
-		# Checks if remotebuildversion variable has been set.
-		if [ -z "${remotebuildversion}" ] || [ "${remotebuildversion}" == "null" ]; then
+		# Checks if remotebuild variable has been set.
+		if [ -z "${remotebuild}" ] || [ "${remotebuild}" == "null" ]; then
 			fn_print_fail "Checking remote build: ${remotelocation}"
 			fn_script_log_fail "Checking remote build"
 			core_exit.sh
@@ -54,7 +61,7 @@ fn_update_remotebuild() {
 		fi
 	else
 		# Checks if remotebuild variable has been set.
-		if [ -z "${remotebuildversion}" ] || [ "${remotebuildversion}" == "null" ]; then
+		if [ -z "${remotebuild}" ] || [ "${remotebuild}" == "null" ]; then
 			fn_print_failure "Unable to get remote build"
 			fn_script_log_fail "Unable to get remote build"
 			core_exit.sh
@@ -65,35 +72,37 @@ fn_update_remotebuild() {
 fn_update_compare() {
 	fn_print_dots "Checking for update: ${remotelocation}"
 	# Update has been found or force update.
-	if [ "${localbuild}" != "${remotebuildversion}" ] || [ "${forceupdate}" == "1" ]; then
+	if [ "${localbuild}" != "${remotebuild}" ] || [ "${forceupdate}" == "1" ]; then
 		# Create update lockfile.
 		date '+%s' > "${lockdir:?}/update.lock"
 		fn_print_ok_nl "Checking for update: ${remotelocation}"
-		echo -en "\n"
-		echo -e "Update available"
-		echo -e "* Local build: ${red}${localbuild} ${factorioarch}${default}"
-		echo -e "* Remote build: ${green}${remotebuildversion} ${factorioarch}${default}"
+		fn_print "\n"
+		fn_print_nl "${bold}${underline}Update${default} available"
+		fn_print_nl "* Local build: ${red}${localbuild}${default}"
+		fn_print_nl "* Remote build: ${green}${remotebuild}${default}"
 		if [ -n "${branch}" ]; then
-			echo -e "* Branch: ${branch}"
+			fn_print_nl "* Branch: ${branch}"
 		fi
 		if [ -f "${rootdir}/.dev-debug" ]; then
-			echo -e "Remote build info"
-			echo -e "* apiurl: ${apiurl}"
-			echo -e "* remotebuildfilename: ${remotebuildfilename}"
-			echo -e "* remotebuildurl: ${remotebuildurl}"
-			echo -e "* remotebuildversion: ${remotebuildversion}"
+			fn_print_nl "Remote build info"
+			fn_print_nl "* apiurl: ${apiurl}"
+			fn_print_nl "* remotebuildfilename: ${remotebuildfilename}"
+			fn_print_nl "* remotebuildurl: ${remotebuildurl}"
+			fn_print_nl "* remotebuild: ${remotebuild}"
 		fi
-		echo -en "\n"
+		fn_print "\n"
 		fn_script_log_info "Update available"
 		fn_script_log_info "Local build: ${localbuild} ${factorioarch}"
-		fn_script_log_info "Remote build: ${remotebuildversion} ${factorioarch}"
+		fn_script_log_info "Remote build: ${remotebuild} ${factorioarch}"
 		if [ -n "${branch}" ]; then
 			fn_script_log_info "Branch: ${branch}"
 		fi
-		fn_script_log_info "${localbuild} > ${remotebuildversion}"
+		fn_script_log_info "${localbuild} > ${remotebuild}"
 
 		if [ "${commandname}" == "UPDATE" ]; then
-			date +%s > "${lockdir}/last-updated.lock"
+			# Keep track of the build before updating for alert purposes.
+			previousbuild="${localbuild}"
+			date +%s > "${lockdir:?}/last-updated.lock"
 			unset updateonstart
 			check_status.sh
 			# If server stopped.
@@ -120,6 +129,23 @@ fn_update_compare() {
 				command_start.sh
 				fn_firstcommand_reset
 			fi
+			# Refresh local build value after update (silent) so alerts show new version.
+			fn_update_localbuild silent
+			# Verify the update applied correctly unless forced update to same version.
+			if [ "${localbuild}" != "${remotebuild}" ]; then
+				# If forced update and version unchanged treat as acceptable; otherwise failure.
+				if [ "${forceupdate}" != "1" ] || [ "${previousbuild}" = "${localbuild}" ]; then
+					fn_script_log_error "Update verification failed: expected ${remotebuild}, got ${localbuild}"
+					fn_print_fail_nl "Update verification failed: expected ${remotebuild}, got ${localbuild}"
+					updatefailureexpected="${remotebuild}"
+					updatefailuregot="${localbuild}"
+					alert="update-failed"
+					alert.sh
+					core_exit.sh
+				fi
+			else
+				fn_script_log_pass "Update verification success: ${previousbuild} -> ${localbuild}"
+			fi
 			unset exitbypass
 			alert="update"
 		elif [ "${commandname}" == "CHECK-UPDATE" ]; then
@@ -128,26 +154,26 @@ fn_update_compare() {
 		alert.sh
 	else
 		fn_print_ok_nl "Checking for update: ${remotelocation}"
-		echo -en "\n"
-		echo -e "No update available"
-		echo -e "* Local build: ${green}${localbuild} ${factorioarch}${default}"
-		echo -e "* Remote build: ${green}${remotebuildversion} ${factorioarch}${default}"
+		fn_print "\n"
+		fn_print_nl "${bold}${underline}No update${default} available"
+		fn_print_nl "* Local build: ${green}${localbuild}${default}"
+		fn_print_nl "* Remote build: ${green}${remotebuild}${default}"
 		if [ -n "${branch}" ]; then
-			echo -e "* Branch: ${branch}"
+			fn_print_nl "* Branch: ${branch}"
 		fi
-		echo -en "\n"
+		fn_print "\n"
 		fn_script_log_info "No update available"
 		fn_script_log_info "Local build: ${localbuild} ${factorioarch}"
-		fn_script_log_info "Remote build: ${remotebuildversion} ${factorioarch}"
+		fn_script_log_info "Remote build: ${remotebuild} ${factorioarch}"
 		if [ -n "${branch}" ]; then
 			fn_script_log_info "Branch: ${branch}"
 		fi
 		if [ -f "${rootdir}/.dev-debug" ]; then
-			echo -e "Remote build info"
-			echo -e "* apiurl: ${apiurl}"
-			echo -e "* remotebuildfilename: ${remotebuildfilename}"
-			echo -e "* remotebuildurl: ${remotebuildurl}"
-			echo -e "* remotebuildversion: ${remotebuildversion}"
+			fn_print_nl "Remote build info"
+			fn_print_nl "* apiurl: ${apiurl}"
+			fn_print_nl "* remotebuildfilename: ${remotebuildfilename}"
+			fn_print_nl "* remotebuildurl: ${remotebuildurl}"
+			fn_print_nl "* remotebuild: ${remotebuild}"
 		fi
 	fi
 }

+ 31 - 37
lgsm/modules/update_jk2.sh

@@ -36,12 +36,12 @@ fn_update_remotebuild() {
 	remotebuildresponse=$(curl -s "${apiurl}")
 	remotebuildfilename=$(echo "${remotebuildresponse}" | jq -r '.assets[]|select(.browser_download_url | contains("dedicated.zip")) | .name')
 	remotebuildurl=$(echo "${remotebuildresponse}" | jq -r '.assets[]|select(.browser_download_url | contains("dedicated.zip")) | .browser_download_url')
-	remotebuildversion=$(echo "${remotebuildresponse}" | jq -r '.tag_name')
+	remotebuild=$(echo "${remotebuildresponse}" | jq -r '.tag_name')
 
 	if [ "${firstcommandname}" != "INSTALL" ]; then
 		fn_print_dots "Checking remote build: ${remotelocation}"
-		# Checks if remotebuildversion variable has been set.
-		if [ -z "${remotebuildversion}" ] || [ "${remotebuildversion}" == "null" ]; then
+		# Checks if remotebuild variable has been set.
+		if [ -z "${remotebuild}" ] || [ "${remotebuild}" == "null" ]; then
 			fn_print_fail "Checking remote build: ${remotelocation}"
 			fn_script_log_fail "Checking remote build"
 			core_exit.sh
@@ -51,7 +51,7 @@ fn_update_remotebuild() {
 		fi
 	else
 		# Checks if remotebuild variable has been set.
-		if [ -z "${remotebuildversion}" ] || [ "${remotebuildversion}" == "null" ]; then
+		if [ -z "${remotebuild}" ] || [ "${remotebuild}" == "null" ]; then
 			fn_print_failure "Unable to get remote build"
 			fn_script_log_fail "Unable to get remote build"
 			core_exit.sh
@@ -62,34 +62,35 @@ fn_update_remotebuild() {
 fn_update_compare() {
 	fn_print_dots "Checking for update: ${remotelocation}"
 	# Update has been found or force update.
-	if [ "${localbuild}" != "${remotebuildversion}" ] || [ "${forceupdate}" == "1" ]; then
+	if [ "${localbuild}" != "${remotebuild}" ] || [ "${forceupdate}" == "1" ]; then
 		# Create update lockfile.
 		date '+%s' > "${lockdir:?}/update.lock"
 		fn_print_ok_nl "Checking for update: ${remotelocation}"
-		echo -en "\n"
-		echo -e "Update available"
-		echo -e "* Local build: ${red}${localbuild}${default}"
-		echo -e "* Remote build: ${green}${remotebuildversion}${default}"
+		fn_print "\n"
+		fn_print_nl "${bold}${underline}Update${default} available"
+		fn_print_nl "* Local build: ${red}${localbuild}${default}"
+		fn_print_nl "* Remote build: ${green}${remotebuild}${default}"
 		if [ -n "${branch}" ]; then
-			echo -e "* Branch: ${branch}"
+			fn_print_nl "* Branch: ${branch}"
 		fi
 		if [ -f "${rootdir}/.dev-debug" ]; then
-			echo -e "Remote build info"
-			echo -e "* apiurl: ${apiurl}"
-			echo -e "* remotebuildfilename: ${remotebuildfilename}"
-			echo -e "* remotebuildurl: ${remotebuildurl}"
-			echo -e "* remotebuildversion: ${remotebuildversion}"
+			fn_print_nl "Remote build info"
+			fn_print_nl "* apiurl: ${apiurl}"
+			fn_print_nl "* remotebuildfilename: ${remotebuildfilename}"
+			fn_print_nl "* remotebuildurl: ${remotebuildurl}"
+			fn_print_nl "* remotebuild: ${remotebuild}"
 		fi
-		echo -en "\n"
+		fn_print "\n"
 		fn_script_log_info "Update available"
 		fn_script_log_info "Local build: ${localbuild}"
-		fn_script_log_info "Remote build: ${remotebuildversion}"
+		fn_script_log_info "Remote build: ${remotebuild}"
 		if [ -n "${branch}" ]; then
 			fn_script_log_info "Branch: ${branch}"
 		fi
-		fn_script_log_info "${localbuild} > ${remotebuildversion}"
+		fn_script_log_info "${localbuild} > ${remotebuild}"
 
 		if [ "${commandname}" == "UPDATE" ]; then
+			date +%s > "${lockdir:?}/last-updated.lock"
 			unset updateonstart
 			check_status.sh
 			# If server stopped.
@@ -117,7 +118,6 @@ fn_update_compare() {
 				fn_firstcommand_reset
 			fi
 			unset exitbypass
-			date +%s > "${lockdir}/last-updated.lock"
 			alert="update"
 		elif [ "${commandname}" == "CHECK-UPDATE" ]; then
 			alert="check-update"
@@ -125,26 +125,26 @@ fn_update_compare() {
 		alert.sh
 	else
 		fn_print_ok_nl "Checking for update: ${remotelocation}"
-		echo -en "\n"
-		echo -e "No update available"
-		echo -e "* Local build: ${green}${localbuild}${default}"
-		echo -e "* Remote build: ${green}${remotebuildversion}${default}"
+		fn_print "\n"
+		fn_print_nl "${bold}${underline}No update${default} available"
+		fn_print_nl "* Local build: ${green}${localbuild}${default}"
+		fn_print_nl "* Remote build: ${green}${remotebuild}${default}"
 		if [ -n "${branch}" ]; then
-			echo -e "* Branch: ${branch}"
+			fn_print_nl "* Branch: ${branch}"
 		fi
-		echo -en "\n"
+		fn_print "\n"
 		fn_script_log_info "No update available"
 		fn_script_log_info "Local build: ${localbuild}"
-		fn_script_log_info "Remote build: ${remotebuildversion}"
+		fn_script_log_info "Remote build: ${remotebuild}"
 		if [ -n "${branch}" ]; then
 			fn_script_log_info "Branch: ${branch}"
 		fi
 		if [ -f "${rootdir}/.dev-debug" ]; then
-			echo -e "Remote build info"
-			echo -e "* apiurl: ${apiurl}"
-			echo -e "* remotebuildfilename: ${remotebuildfilename}"
-			echo -e "* remotebuildurl: ${remotebuildurl}"
-			echo -e "* remotebuildversion: ${remotebuildversion}"
+			fn_print_nl "Remote build info"
+			fn_print_nl "* apiurl: ${apiurl}"
+			fn_print_nl "* remotebuildfilename: ${remotebuildfilename}"
+			fn_print_nl "* remotebuildurl: ${remotebuildurl}"
+			fn_print_nl "* remotebuild: ${remotebuild}"
 		fi
 	fi
 }
@@ -152,12 +152,6 @@ fn_update_compare() {
 # The location where the builds are checked and downloaded.
 remotelocation="github.com"
 
-if [ ! "$(command -v jq 2> /dev/null)" ]; then
-	fn_print_fail_nl "jq is not installed"
-	fn_script_log_fail "jq is not installed"
-	core_exit.sh
-fi
-
 if [ "${firstcommandname}" == "INSTALL" ]; then
 	fn_update_remotebuild
 	fn_update_dl

+ 35 - 41
lgsm/modules/update_mc.sh

@@ -39,24 +39,24 @@ fn_update_remotebuild() {
 	remotebuildresponse=$(curl -s "${apiurl}")
 	# Latest release.
 	if [ "${branch}" == "release" ] && [ "${mcversion}" == "latest" ]; then
-		remotebuildversion=$(echo "${remotebuildresponse}" | jq -r '.latest.release')
+		remotebuild=$(echo "${remotebuildresponse}" | jq -r '.latest.release')
 	# Latest snapshot.
 	elif [ "${branch}" == "snapshot" ] && [ "${mcversion}" == "latest" ]; then
-		remotebuildversion=$(echo "${remotebuildresponse}" | jq -r '.latest.snapshot')
+		remotebuild=$(echo "${remotebuildresponse}" | jq -r '.latest.snapshot')
 	# Specific release/snapshot.
 	else
-		remotebuildversion=$(echo "${remotebuildresponse}" | jq -r --arg branch "${branch}" --arg mcversion "${mcversion}" '.versions | .[] | select(.type==$branch and .id==$mcversion) | .id')
+		remotebuild=$(echo "${remotebuildresponse}" | jq -r --arg branch "${branch}" --arg mcversion "${mcversion}" '.versions | .[] | select(.type==$branch and .id==$mcversion) | .id')
 	fi
-	remotebuildfilename="minecraft_server.${remotebuildversion}.jar"
+	remotebuildfilename="minecraft_server.${remotebuild}.jar"
 	# Generate link to version manifest json.
-	remotebuildmanifest=$(echo "${remotebuildresponse}" | jq -r --arg branch "${branch}" --arg mcversion "${remotebuildversion}" '.versions | .[] | select(.type==$branch and .id==$mcversion) | .url')
+	remotebuildmanifest=$(echo "${remotebuildresponse}" | jq -r --arg branch "${branch}" --arg mcversion "${remotebuild}" '.versions | .[] | select(.type==$branch and .id==$mcversion) | .url')
 	# Generate link to server.jar
 	remotebuildurl=$(curl -s "${remotebuildmanifest}" | jq -r '.downloads.server.url')
 
 	if [ "${firstcommandname}" != "INSTALL" ]; then
 		fn_print_dots "Checking remote build: ${remotelocation}"
-		# Checks if remotebuildversion variable has been set.
-		if [ -z "${remotebuildversion}" ] || [ "${remotebuildversion}" == "null" ]; then
+		# Checks if remotebuild variable has been set.
+		if [ -z "${remotebuild}" ] || [ "${remotebuild}" == "null" ]; then
 			fn_print_fail "Checking remote build: ${remotelocation}"
 			fn_script_log_fail "Checking remote build"
 			core_exit.sh
@@ -66,7 +66,7 @@ fn_update_remotebuild() {
 		fi
 	else
 		# Checks if remotebuild variable has been set.
-		if [ -z "${remotebuildversion}" ] || [ "${remotebuildversion}" == "null" ]; then
+		if [ -z "${remotebuild}" ] || [ "${remotebuild}" == "null" ]; then
 			fn_print_failure "Unable to get remote build"
 			fn_script_log_fail "Unable to get remote build"
 			core_exit.sh
@@ -77,35 +77,35 @@ fn_update_remotebuild() {
 fn_update_compare() {
 	fn_print_dots "Checking for update: ${remotelocation}"
 	# Update has been found or force update.
-	if [ "${localbuild}" != "${remotebuildversion}" ] || [ "${forceupdate}" == "1" ]; then
+	if [ "${localbuild}" != "${remotebuild}" ] || [ "${forceupdate}" == "1" ]; then
 		# Create update lockfile.
 		date '+%s' > "${lockdir:?}/update.lock"
 		fn_print_ok_nl "Checking for update: ${remotelocation}"
-		echo -en "\n"
-		echo -e "Update available"
-		echo -e "* Local build: ${red}${localbuild}${default}"
-		echo -e "* Remote build: ${green}${remotebuildversion}${default}"
+		fn_print "\n"
+		fn_print_nl "${bold}${underline}Update${default} available"
+		fn_print_nl "* Local build: ${red}${localbuild}${default}"
+		fn_print_nl "* Remote build: ${green}${remotebuild}${default}"
 		if [ -n "${branch}" ]; then
-			echo -e "* Branch: ${branch}"
+			fn_print_nl "* Branch: ${branch}"
 		fi
 		if [ -f "${rootdir}/.dev-debug" ]; then
-			echo -e "Remote build info"
-			echo -e "* apiurl: ${apiurl}"
-			echo -e "* remotebuildfilename: ${remotebuildfilename}"
-			echo -e "* remotebuildurl: ${remotebuildurl}"
-			echo -e "* remotebuildversion: ${remotebuildversion}"
+			fn_print_nl "Remote build info"
+			fn_print_nl "* apiurl: ${apiurl}"
+			fn_print_nl "* remotebuildfilename: ${remotebuildfilename}"
+			fn_print_nl "* remotebuildurl: ${remotebuildurl}"
+			fn_print_nl "* remotebuild: ${remotebuild}"
 		fi
-		echo -en "\n"
+		fn_print "\n"
 		fn_script_log_info "Update available"
 		fn_script_log_info "Local build: ${localbuild}"
-		fn_script_log_info "Remote build: ${remotebuildversion}"
+		fn_script_log_info "Remote build: ${remotebuild}"
 		if [ -n "${branch}" ]; then
 			fn_script_log_info "Branch: ${branch}"
 		fi
-		fn_script_log_info "${localbuild} > ${remotebuildversion}"
+		fn_script_log_info "${localbuild} > ${remotebuild}"
 
 		if [ "${commandname}" == "UPDATE" ]; then
-			date +%s > "${lockdir}/last-updated.lock"
+			date +%s > "${lockdir:?}/last-updated.lock"
 			unset updateonstart
 			check_status.sh
 			# If server stopped.
@@ -140,26 +140,26 @@ fn_update_compare() {
 		alert.sh
 	else
 		fn_print_ok_nl "Checking for update: ${remotelocation}"
-		echo -en "\n"
-		echo -e "No update available"
-		echo -e "* Local build: ${green}${localbuild}${default}"
-		echo -e "* Remote build: ${green}${remotebuildversion}${default}"
+		fn_print "\n"
+		fn_print_nl "${bold}${underline}No update${default} available"
+		fn_print_nl "* Local build: ${green}${localbuild}${default}"
+		fn_print_nl "* Remote build: ${green}${remotebuild}${default}"
 		if [ -n "${branch}" ]; then
-			echo -e "* Branch: ${branch}"
+			fn_print_nl "* Branch: ${branch}"
 		fi
-		echo -en "\n"
+		fn_print "\n"
 		fn_script_log_info "No update available"
 		fn_script_log_info "Local build: ${localbuild}"
-		fn_script_log_info "Remote build: ${remotebuildversion}"
+		fn_script_log_info "Remote build: ${remotebuild}"
 		if [ -n "${branch}" ]; then
 			fn_script_log_info "Branch: ${branch}"
 		fi
 		if [ -f "${rootdir}/.dev-debug" ]; then
-			echo -e "Remote build info"
-			echo -e "* apiurl: ${apiurl}"
-			echo -e "* remotebuildfilename: ${remotebuildfilename}"
-			echo -e "* remotebuildurl: ${remotebuildurl}"
-			echo -e "* remotebuildversion: ${remotebuildversion}"
+			fn_print_nl "Remote build info"
+			fn_print_nl "* apiurl: ${apiurl}"
+			fn_print_nl "* remotebuildfilename: ${remotebuildfilename}"
+			fn_print_nl "* remotebuildurl: ${remotebuildurl}"
+			fn_print_nl "* remotebuild: ${remotebuild}"
 		fi
 	fi
 }
@@ -167,12 +167,6 @@ fn_update_compare() {
 # The location where the builds are checked and downloaded.
 remotelocation="mojang.com"
 
-if [ ! "$(command -v jq 2> /dev/null)" ]; then
-	fn_print_fail_nl "jq is not installed"
-	fn_script_log_fail "jq is not installed"
-	core_exit.sh
-fi
-
 if [ "${firstcommandname}" == "INSTALL" ]; then
 	fn_update_remotebuild
 	fn_update_dl

+ 35 - 41
lgsm/modules/update_mcb.sh

@@ -8,12 +8,12 @@
 moduleselfname="$(basename "$(readlink -f "${BASH_SOURCE[0]}")")"
 
 fn_update_dl() {
-	fn_fetch_file "${remotebuildurl}" "" "" "" "${tmpdir}" "bedrock_server.${remotebuildversion}.zip" "nochmodx" "norun" "noforce" "nohash"
+	fn_fetch_file "${remotebuildurl}" "" "" "" "${tmpdir}" "bedrock_server.${remotebuild}.zip" "nochmodx" "norun" "noforce" "nohash"
 	echo -e "Extracting to ${serverfiles}...\c"
 	if [ "${firstcommandname}" == "INSTALL" ]; then
-		unzip -oq "${tmpdir}/bedrock_server.${remotebuildversion}.zip" -x "server.properties" -d "${serverfiles}"
+		unzip -oq "${tmpdir}/bedrock_server.${remotebuild}.zip" -x "server.properties" -d "${serverfiles}"
 	else
-		unzip -oq "${tmpdir}/bedrock_server.${remotebuildversion}.zip" -x "permissions.json" "server.properties" "allowlist.json" -d "${serverfiles}"
+		unzip -oq "${tmpdir}/bedrock_server.${remotebuild}.zip" -x "permissions.json" "server.properties" "allowlist.json" -d "${serverfiles}"
 	fi
 	exitcode=$?
 	if [ "${exitcode}" -ne 0 ]; then
@@ -61,13 +61,13 @@ fn_update_remotebuild() {
 	else
 		remotebuildurl=$(echo "${remotebuildresponse}" | jq -r 'select(.downloadType == "serverBedrockLinux") | .downloadUrl')
 	fi
-	remotebuildversion=$(echo "${remotebuildurl}" | grep -Eo "[.0-9]+[0-9]")
-	remotebuildfilename="bedrock-server-${remotebuildversion}.zip"
+	remotebuild=$(echo "${remotebuildurl}" | grep -Eo "[.0-9]+[0-9]")
+	remotebuildfilename="bedrock-server-${remotebuild}.zip"
 
 	if [ "${firstcommandname}" != "INSTALL" ]; then
 		fn_print_dots "Checking remote build: ${remotelocation}"
-		# Checks if remotebuildversion variable has been set.
-		if [ -z "${remotebuildversion}" ] || [ "${remotebuildversion}" == "null" ]; then
+		# Checks if remotebuild variable has been set.
+		if [ -z "${remotebuild}" ] || [ "${remotebuild}" == "null" ]; then
 			fn_print_fail "Checking remote build: ${remotelocation}"
 			fn_script_log_fail "Checking remote build"
 			core_exit.sh
@@ -77,7 +77,7 @@ fn_update_remotebuild() {
 		fi
 	else
 		# Checks if remotebuild variable has been set.
-		if [ -z "${remotebuildversion}" ] || [ "${remotebuildversion}" == "null" ]; then
+		if [ -z "${remotebuild}" ] || [ "${remotebuild}" == "null" ]; then
 			fn_print_failure "Unable to get remote build"
 			fn_script_log_fail "Unable to get remote build"
 			core_exit.sh
@@ -88,35 +88,35 @@ fn_update_remotebuild() {
 fn_update_compare() {
 	fn_print_dots "Checking for update: ${remotelocation}"
 	# Update has been found or force update.
-	if [ "${localbuild}" != "${remotebuildversion}" ] || [ "${forceupdate}" == "1" ]; then
+	if [ "${localbuild}" != "${remotebuild}" ] || [ "${forceupdate}" == "1" ]; then
 		# Create update lockfile.
 		date '+%s' > "${lockdir:?}/update.lock"
 		fn_print_ok_nl "Checking for update: ${remotelocation}"
-		echo -en "\n"
-		echo -e "Update available"
-		echo -e "* Local build: ${red}${localbuild}${default}"
-		echo -e "* Remote build: ${green}${remotebuildversion}${default}"
+		fn_print "\n"
+		fn_print_nl "${bold}${underline}Update${default} available"
+		fn_print_nl "* Local build: ${red}${localbuild}${default}"
+		fn_print_nl "* Remote build: ${green}${remotebuild}${default}"
 		if [ -n "${branch}" ]; then
-			echo -e "* Branch: ${branch}"
+			fn_print_nl "* Branch: ${branch}"
 		fi
 		if [ -f "${rootdir}/.dev-debug" ]; then
-			echo -e "Remote build info"
-			echo -e "* apiurl: ${apiurl}"
-			echo -e "* remotebuildfilename: ${remotebuildfilename}"
-			echo -e "* remotebuildurl: ${remotebuildurl}"
-			echo -e "* remotebuildversion: ${remotebuildversion}"
+			fn_print_nl "Remote build info"
+			fn_print_nl "* apiurl: ${apiurl}"
+			fn_print_nl "* remotebuildfilename: ${remotebuildfilename}"
+			fn_print_nl "* remotebuildurl: ${remotebuildurl}"
+			fn_print_nl "* remotebuild: ${remotebuild}"
 		fi
-		echo -en "\n"
+		fn_print "\n"
 		fn_script_log_info "Update available"
 		fn_script_log_info "Local build: ${localbuild}"
-		fn_script_log_info "Remote build: ${remotebuildversion}"
+		fn_script_log_info "Remote build: ${remotebuild}"
 		if [ -n "${branch}" ]; then
 			fn_script_log_info "Branch: ${branch}"
 		fi
-		fn_script_log_info "${localbuild} > ${remotebuildversion}"
+		fn_script_log_info "${localbuild} > ${remotebuild}"
 
 		if [ "${commandname}" == "UPDATE" ]; then
-			date +%s > "${lockdir}/last-updated.lock"
+			date +%s > "${lockdir:?}/last-updated.lock"
 			unset updateonstart
 			check_status.sh
 			# If server stopped.
@@ -151,26 +151,26 @@ fn_update_compare() {
 		alert.sh
 	else
 		fn_print_ok_nl "Checking for update: ${remotelocation}"
-		echo -en "\n"
-		echo -e "No update available"
-		echo -e "* Local build: ${green}${localbuild}${default}"
-		echo -e "* Remote build: ${green}${remotebuildversion}${default}"
+		fn_print "\n"
+		fn_print_nl "${bold}${underline}No update${default} available"
+		fn_print_nl "* Local build: ${green}${localbuild}${default}"
+		fn_print_nl "* Remote build: ${green}${remotebuild}${default}"
 		if [ -n "${branch}" ]; then
-			echo -e "* Branch: ${branch}"
+			fn_print_nl "* Branch: ${branch}"
 		fi
-		echo -en "\n"
+		fn_print "\n"
 		fn_script_log_info "No update available"
 		fn_script_log_info "Local build: ${localbuild}"
-		fn_script_log_info "Remote build: ${remotebuildversion}"
+		fn_script_log_info "Remote build: ${remotebuild}"
 		if [ -n "${branch}" ]; then
 			fn_script_log_info "Branch: ${branch}"
 		fi
 		if [ -f "${rootdir}/.dev-debug" ]; then
-			echo -e "Remote build info"
-			echo -e "* apiurl: ${apiurl}"
-			echo -e "* remotebuildfilename: ${remotebuildfilename}"
-			echo -e "* remotebuildurl: ${remotebuildurl}"
-			echo -e "* remotebuildversion: ${remotebuildversion}"
+			fn_print_nl "Remote build info"
+			fn_print_nl "* apiurl: ${apiurl}"
+			fn_print_nl "* remotebuildfilename: ${remotebuildfilename}"
+			fn_print_nl "* remotebuildurl: ${remotebuildurl}"
+			fn_print_nl "* remotebuild: ${remotebuild}"
 		fi
 	fi
 }
@@ -178,12 +178,6 @@ fn_update_compare() {
 # The location where the builds are checked and downloaded.
 remotelocation="minecraft.net"
 
-if [ ! "$(command -v jq 2> /dev/null)" ]; then
-	fn_print_fail_nl "jq is not installed"
-	fn_script_log_fail "jq is not installed"
-	core_exit.sh
-fi
-
 if [ "${firstcommandname}" == "INSTALL" ]; then
 	fn_update_remotebuild
 	fn_update_dl

+ 31 - 37
lgsm/modules/update_mta.sh

@@ -39,11 +39,11 @@ fn_update_remotebuild() {
 	remotebuildresponse=$(curl -s "${apiurl}")
 	remotebuildfilename="multitheftauto_linux_x64.tar.gz"
 	remotebuildurl="http://linux.mtasa.com/dl/multitheftauto_linux_x64.tar.gz"
-	remotebuildversion=$(echo "${remotebuildresponse}")
+	remotebuild="${remotebuildresponse}"
 	if [ "${firstcommandname}" != "INSTALL" ]; then
 		fn_print_dots "Checking remote build: ${remotelocation}"
-		# Checks if remotebuildversion variable has been set.
-		if [ -z "${remotebuildversion}" ] || [ "${remotebuildversion}" == "null" ]; then
+		# Checks if remotebuild variable has been set.
+		if [ -z "${remotebuild}" ] || [ "${remotebuild}" == "null" ]; then
 			fn_print_fail "Checking remote build: ${remotelocation}"
 			fn_script_log_fail "Checking remote build"
 			core_exit.sh
@@ -53,7 +53,7 @@ fn_update_remotebuild() {
 		fi
 	else
 		# Checks if remotebuild variable has been set.
-		if [ -z "${remotebuildversion}" ] || [ "${remotebuildversion}" == "null" ]; then
+		if [ -z "${remotebuild}" ] || [ "${remotebuild}" == "null" ]; then
 			fn_print_failure "Unable to get remote build"
 			fn_script_log_fail "Unable to get remote build"
 			core_exit.sh
@@ -64,7 +64,7 @@ fn_update_remotebuild() {
 fn_update_compare() {
 	fn_print_dots "Checking for update: ${remotelocation}"
 	# Update has been found or force update.
-	if [ "${localbuild}" != "${remotebuildversion}" ] || [ "${forceupdate}" == "1" ]; then
+	if [ "${localbuild}" != "${remotebuild}" ] || [ "${forceupdate}" == "1" ]; then
 		# Create update lockfile.
 		date '+%s' > "${lockdir:?}/update.lock"
 		if [ "${forceupdate}" == "1" ]; then
@@ -74,30 +74,31 @@ fn_update_compare() {
 			mtaupdatestatus="available"
 		fi
 		fn_print_ok_nl "Checking for update: ${remotelocation}"
-		echo -en "\n"
-		echo -e "Update available"
-		echo -e "* Local build: ${red}${localbuild}${default}"
-		echo -e "* Remote build: ${green}${remotebuildversion}${default}"
+		fn_print "\n"
+		fn_print_nl "${bold}${underline}Update${default} available"
+		fn_print_nl "* Local build: ${red}${localbuild}${default}"
+		fn_print_nl "* Remote build: ${green}${remotebuild}${default}"
 		if [ -n "${branch}" ]; then
-			echo -e "* Branch: ${branch}"
+			fn_print_nl "* Branch: ${branch}"
 		fi
 		if [ -f "${rootdir}/.dev-debug" ]; then
-			echo -e "Remote build info"
-			echo -e "* apiurl: ${apiurl}"
-			echo -e "* remotebuildfilename: ${remotebuildfilename}"
-			echo -e "* remotebuildurl: ${remotebuildurl}"
-			echo -e "* remotebuildversion: ${remotebuildversion}"
+			fn_print_nl "Remote build info"
+			fn_print_nl "* apiurl: ${apiurl}"
+			fn_print_nl "* remotebuildfilename: ${remotebuildfilename}"
+			fn_print_nl "* remotebuildurl: ${remotebuildurl}"
+			fn_print_nl "* remotebuild: ${remotebuild}"
 		fi
-		echo -en "\n"
+		fn_print "\n"
 		fn_script_log_info "Update available"
 		fn_script_log_info "Local build: ${localbuild}"
-		fn_script_log_info "Remote build: ${remotebuildversion}"
+		fn_script_log_info "Remote build: ${remotebuild}"
 		if [ -n "${branch}" ]; then
 			fn_script_log_info "Branch: ${branch}"
 		fi
-		fn_script_log_info "${localbuild} > ${remotebuildversion}"
+		fn_script_log_info "${localbuild} > ${remotebuild}"
 
 		if [ "${commandname}" == "UPDATE" ]; then
+			date +%s > "${lockdir:?}/last-updated.lock"
 			unset updateonstart
 			check_status.sh
 			# If server stopped.
@@ -125,7 +126,6 @@ fn_update_compare() {
 				fn_firstcommand_reset
 			fi
 			unset exitbypass
-			date +%s > "${lockdir}/last-updated.lock"
 			alert="update"
 		elif [ "${commandname}" == "CHECK-UPDATE" ]; then
 			alert="check-update"
@@ -133,26 +133,26 @@ fn_update_compare() {
 		alert.sh
 	else
 		fn_print_ok_nl "Checking for update: ${remotelocation}"
-		echo -en "\n"
-		echo -e "No update available"
-		echo -e "* Local build: ${green}${localbuild}${default}"
-		echo -e "* Remote build: ${green}${remotebuildversion}${default}"
+		fn_print "\n"
+		fn_print_nl "${bold}${underline}No update${default} available"
+		fn_print_nl "* Local build: ${green}${localbuild}${default}"
+		fn_print_nl "* Remote build: ${green}${remotebuild}${default}"
 		if [ -n "${branch}" ]; then
-			echo -e "* Branch: ${branch}"
+			fn_print_nl "* Branch: ${branch}"
 		fi
-		echo -en "\n"
+		fn_print "\n"
 		fn_script_log_info "No update available"
 		fn_script_log_info "Local build: ${localbuild}"
-		fn_script_log_info "Remote build: ${remotebuildversion}"
+		fn_script_log_info "Remote build: ${remotebuild}"
 		if [ -n "${branch}" ]; then
 			fn_script_log_info "Branch: ${branch}"
 		fi
 		if [ -f "${rootdir}/.dev-debug" ]; then
-			echo -e "Remote build info"
-			echo -e "* apiurl: ${apiurl}"
-			echo -e "* remotebuildfilename: ${remotebuildfilename}"
-			echo -e "* remotebuildurl: ${remotebuildurl}"
-			echo -e "* remotebuildversion: ${remotebuildversion}"
+			fn_print_nl "Remote build info"
+			fn_print_nl "* apiurl: ${apiurl}"
+			fn_print_nl "* remotebuildfilename: ${remotebuildfilename}"
+			fn_print_nl "* remotebuildurl: ${remotebuildurl}"
+			fn_print_nl "* remotebuild: ${remotebuild}"
 		fi
 	fi
 }
@@ -160,12 +160,6 @@ fn_update_compare() {
 # The location where the builds are checked and downloaded.
 remotelocation="linux.mtasa.com"
 
-if [ ! "$(command -v jq 2> /dev/null)" ]; then
-	fn_print_fail_nl "jq is not installed"
-	fn_script_log_fail "jq is not installed"
-	core_exit.sh
-fi
-
 if [ "${firstcommandname}" == "INSTALL" ]; then
 	fn_update_remotebuild
 	fn_update_dl

+ 32 - 38
lgsm/modules/update_pmc.sh

@@ -11,7 +11,7 @@ fn_update_dl() {
 	# Download and extract files to serverfiles.
 	fn_fetch_file "${remotebuildurl}" "" "" "" "${tmpdir}" "${remotebuildfilename}" "chmodx" "norun" "force" "${remotebuildhash}"
 	cp -f "${tmpdir}/${remotebuildfilename}" "${serverfiles}/${executable#./}"
-	echo "${remotebuildversion}" > "${serverfiles}/build.txt"
+	echo "${remotebuild}" > "${serverfiles}/build.txt"
 	fn_clear_tmp
 }
 
@@ -61,12 +61,12 @@ fn_update_remotebuild() {
 	remotebuildhash=$(echo "${remotebuildresponseversion}" | jq -r '.downloads.application.sha256')
 	remotebuildurl="${apiurl}/${paperproject}/versions/${remotebuildmcversion}/builds/${remotebuildpaperversion}/downloads/${remotebuildfilename}"
 	# Combines Minecraft: Java Edition version and paper build. e.g 1.16.5-456
-	remotebuildversion="${remotebuildmcversion}-${remotebuildpaperversion}"
+	remotebuild="${remotebuildmcversion}-${remotebuildpaperversion}"
 
 	if [ "${firstcommandname}" != "INSTALL" ]; then
 		fn_print_dots "Checking remote build: ${remotelocation}"
-		# Checks if remotebuildversion variable has been set.
-		if [ -z "${remotebuildversion}" ] || [ "${remotebuildversion}" == "null" ]; then
+		# Checks if remotebuild variable has been set.
+		if [ -z "${remotebuild}" ] || [ "${remotebuild}" == "null" ]; then
 			fn_print_fail "Checking remote build: ${remotelocation}"
 			fn_script_log_fail "Checking remote build"
 			core_exit.sh
@@ -76,7 +76,7 @@ fn_update_remotebuild() {
 		fi
 	else
 		# Checks if remotebuild variable has been set.
-		if [ -z "${remotebuildversion}" ] || [ "${remotebuildversion}" == "null" ]; then
+		if [ -z "${remotebuild}" ] || [ "${remotebuild}" == "null" ]; then
 			fn_print_failure "Unable to get remote build"
 			fn_script_log_fail "Unable to get remote build"
 			core_exit.sh
@@ -87,35 +87,35 @@ fn_update_remotebuild() {
 fn_update_compare() {
 	fn_print_dots "Checking for update: ${remotelocation}"
 	# Update has been found or force update.
-	if [ "${localbuild}" != "${remotebuildversion}" ] || [ "${forceupdate}" == "1" ]; then
+	if [ "${localbuild}" != "${remotebuild}" ] || [ "${forceupdate}" == "1" ]; then
 		# Create update lockfile.
 		date '+%s' > "${lockdir:?}/update.lock"
 		fn_print_ok_nl "Checking for update: ${remotelocation}"
-		echo -en "\n"
-		echo -e "Update available"
-		echo -e "* Local build: ${red}${localbuild}${default}"
-		echo -e "* Remote build: ${green}${remotebuildversion}${default}"
+		fn_print "\n"
+		fn_print_nl "${bold}${underline}Update${default} available"
+		fn_print_nl "* Local build: ${red}${localbuild}${default}"
+		fn_print_nl "* Remote build: ${green}${remotebuild}${default}"
 		if [ -n "${branch}" ]; then
-			echo -e "* Branch: ${branch}"
+			fn_print_nl "* Branch: ${branch}"
 		fi
 		if [ -f "${rootdir}/.dev-debug" ]; then
-			echo -e "Remote build info"
-			echo -e "* apiurl: ${apiurl}"
-			echo -e "* remotebuildfilename: ${remotebuildfilename}"
-			echo -e "* remotebuildurl: ${remotebuildurl}"
-			echo -e "* remotebuildversion: ${remotebuildversion}"
+			fn_print_nl "Remote build info"
+			fn_print_nl "* apiurl: ${apiurl}"
+			fn_print_nl "* remotebuildfilename: ${remotebuildfilename}"
+			fn_print_nl "* remotebuildurl: ${remotebuildurl}"
+			fn_print_nl "* remotebuild: ${remotebuild}"
 		fi
-		echo -en "\n"
+		fn_print "\n"
 		fn_script_log_info "Update available"
 		fn_script_log_info "Local build: ${localbuild}"
-		fn_script_log_info "Remote build: ${remotebuildversion}"
+		fn_script_log_info "Remote build: ${remotebuild}"
 		if [ -n "${branch}" ]; then
 			fn_script_log_info "Branch: ${branch}"
 		fi
-		fn_script_log_info "${localbuild} > ${remotebuildversion}"
+		fn_script_log_info "${localbuild} > ${remotebuild}"
 
 		if [ "${commandname}" == "UPDATE" ]; then
-			date +%s > "${lockdir}/last-updated.lock"
+			date +%s > "${lockdir:?}/last-updated.lock"
 			unset updateonstart
 			check_status.sh
 			# If server stopped.
@@ -150,26 +150,26 @@ fn_update_compare() {
 		alert.sh
 	else
 		fn_print_ok_nl "Checking for update: ${remotelocation}"
-		echo -en "\n"
-		echo -e "No update available"
-		echo -e "* Local build: ${green}${localbuild}${default}"
-		echo -e "* Remote build: ${green}${remotebuildversion}${default}"
+		fn_print "\n"
+		fn_print_nl "${bold}${underline}No update${default} available"
+		fn_print_nl "* Local build: ${green}${localbuild}${default}"
+		fn_print_nl "* Remote build: ${green}${remotebuild}${default}"
 		if [ -n "${branch}" ]; then
-			echo -e "* Branch: ${branch}"
+			fn_print_nl "* Branch: ${branch}"
 		fi
-		echo -en "\n"
+		fn_print "\n"
 		fn_script_log_info "No update available"
 		fn_script_log_info "Local build: ${localbuild}"
-		fn_script_log_info "Remote build: ${remotebuildversion}"
+		fn_script_log_info "Remote build: ${remotebuild}"
 		if [ -n "${branch}" ]; then
 			fn_script_log_info "Branch: ${branch}"
 		fi
 		if [ -f "${rootdir}/.dev-debug" ]; then
-			echo -e "Remote build info"
-			echo -e "* apiurl: ${apiurl}"
-			echo -e "* remotebuildfilename: ${remotebuildfilename}"
-			echo -e "* remotebuildurl: ${remotebuildurl}"
-			echo -e "* remotebuildversion: ${remotebuildversion}"
+			fn_print_nl "Remote build info"
+			fn_print_nl "* apiurl: ${apiurl}"
+			fn_print_nl "* remotebuildfilename: ${remotebuildfilename}"
+			fn_print_nl "* remotebuildurl: ${remotebuildurl}"
+			fn_print_nl "* remotebuild: ${remotebuild}"
 		fi
 	fi
 }
@@ -177,12 +177,6 @@ fn_update_compare() {
 # The location where the builds are checked and downloaded.
 remotelocation="papermc.io"
 
-if [ ! "$(command -v jq 2> /dev/null)" ]; then
-	fn_print_fail_nl "jq is not installed"
-	fn_script_log_fail "jq is not installed"
-	core_exit.sh
-fi
-
 if [ "${shortname}" == "pmc" ]; then
 	paperproject="paper"
 elif [ "${shortname}" == "vpmc" ]; then

+ 31 - 37
lgsm/modules/update_steamcmd.sh

@@ -43,12 +43,12 @@ fn_update_remotebuild() {
 		remotebuildhash=$(echo -e "${remotebuildresponse}" | jq -r '.linux.x86.checksum')
 	fi
 	remotebuildfilename=$(basename "${remotebuildurl}")
-	remotebuildversion=$(echo -e "${remotebuildresponse}" | jq -r '.linux.x86_64.version')
+	remotebuild=$(echo -e "${remotebuildresponse}" | jq -r '.linux.x86_64.version')
 
 	if [ "${firstcommandname}" != "INSTALL" ]; then
 		fn_print_dots "Checking remote build: ${remotelocation}"
-		# Checks if remotebuildversion variable has been set.
-		if [ -z "${remotebuildversion}" ] || [ "${remotebuildversion}" == "null" ]; then
+		# Checks if remotebuild variable has been set.
+		if [ -z "${remotebuild}" ] || [ "${remotebuild}" == "null" ]; then
 			fn_print_fail "Checking remote build: ${remotelocation}"
 			fn_script_log_fail "Checking remote build"
 			core_exit.sh
@@ -58,7 +58,7 @@ fn_update_remotebuild() {
 		fi
 	else
 		# Checks if remotebuild variable has been set.
-		if [ -z "${remotebuildversion}" ] || [ "${remotebuildversion}" == "null" ]; then
+		if [ -z "${remotebuild}" ] || [ "${remotebuild}" == "null" ]; then
 			fn_print_failure "Unable to get remote build"
 			fn_script_log_fail "Unable to get remote build"
 			core_exit.sh
@@ -69,35 +69,35 @@ fn_update_remotebuild() {
 fn_update_compare() {
 	fn_print_dots "Checking for update: ${remotelocation}"
 	# Update has been found or force update.
-	if [ "${localbuild}" != "${remotebuildversion}" ] || [ "${forceupdate}" == "1" ]; then
+	if [ "${localbuild}" != "${remotebuild}" ] || [ "${forceupdate}" == "1" ]; then
 		# Create update lockfile.
 		date '+%s' > "${lockdir:?}/update.lock"
 		fn_print_ok_nl "Checking for update: ${remotelocation}"
-		echo -en "\n"
-		echo -e "Update available"
-		echo -e "* Local build: ${red}${localbuild}${default}"
-		echo -e "* Remote build: ${green}${remotebuildversion}${default}"
+		fn_print "\n"
+		fn_print_nl "${bold}${underline}Update${default} available"
+		fn_print_nl "* Local build: ${red}${localbuild}${default}"
+		fn_print_nl "* Remote build: ${green}${remotebuild}${default}"
 		if [ -n "${branch}" ]; then
-			echo -e "* Branch: ${branch}"
+			fn_print_nl "* Branch: ${branch}"
 		fi
 		if [ -f "${rootdir}/.dev-debug" ]; then
-			echo -e "Remote build info"
-			echo -e "* apiurl: ${apiurl}"
-			echo -e "* remotebuildfilename: ${remotebuildfilename}"
-			echo -e "* remotebuildurl: ${remotebuildurl}"
-			echo -e "* remotebuildversion: ${remotebuildversion}"
+			fn_print_nl "Remote build info"
+			fn_print_nl "* apiurl: ${apiurl}"
+			fn_print_nl "* remotebuildfilename: ${remotebuildfilename}"
+			fn_print_nl "* remotebuildurl: ${remotebuildurl}"
+			fn_print_nl "* remotebuild: ${remotebuild}"
 		fi
-		echo -en "\n"
+		fn_print "\n"
 		fn_script_log_info "Update available"
 		fn_script_log_info "Local build: ${localbuild}"
-		fn_script_log_info "Remote build: ${remotebuildversion}"
+		fn_script_log_info "Remote build: ${remotebuild}"
 		if [ -n "${branch}" ]; then
 			fn_script_log_info "Branch: ${branch}"
 		fi
-		fn_script_log_info "${localbuild} > ${remotebuildversion}"
+		fn_script_log_info "${localbuild} > ${remotebuild}"
 
 		if [ "${commandname}" == "UPDATE" ]; then
-			date +%s > "${lockdir}/last-updated.lock"
+			date +%s > "${lockdir:?}/last-updated.lock"
 			unset updateonstart
 			check_status.sh
 			# If server stopped.
@@ -132,26 +132,26 @@ fn_update_compare() {
 		alert.sh
 	else
 		fn_print_ok_nl "Checking for update: ${remotelocation}"
-		echo -en "\n"
-		echo -e "No update available"
-		echo -e "* Local build: ${green}${localbuild}${default}"
-		echo -e "* Remote build: ${green}${remotebuildversion}${default}"
+		fn_print "\n"
+		fn_print_nl "${bold}${underline}No update${default} available"
+		fn_print_nl "* Local build: ${green}${localbuild}${default}"
+		fn_print_nl "* Remote build: ${green}${remotebuild}${default}"
 		if [ -n "${branch}" ]; then
-			echo -e "* Branch: ${branch}"
+			fn_print_nl "* Branch: ${branch}"
 		fi
-		echo -en "\n"
+		fn_print "\n"
 		fn_script_log_info "No update available"
 		fn_script_log_info "Local build: ${localbuild}"
-		fn_script_log_info "Remote build: ${remotebuildversion}"
+		fn_script_log_info "Remote build: ${remotebuild}"
 		if [ -n "${branch}" ]; then
 			fn_script_log_info "Branch: ${branch}"
 		fi
 		if [ -f "${rootdir}/.dev-debug" ]; then
-			echo -e "Remote build info"
-			echo -e "* apiurl: ${apiurl}"
-			echo -e "* remotebuildfilename: ${remotebuildfilename}"
-			echo -e "* remotebuildurl: ${remotebuildurl}"
-			echo -e "* remotebuildversion: ${remotebuildversion}"
+			fn_print_nl "Remote build info"
+			fn_print_nl "* apiurl: ${apiurl}"
+			fn_print_nl "* remotebuildfilename: ${remotebuildfilename}"
+			fn_print_nl "* remotebuildurl: ${remotebuildurl}"
+			fn_print_nl "* remotebuild: ${remotebuild}"
 		fi
 	fi
 }
@@ -171,12 +171,6 @@ fi
 # The location where the builds are checked and downloaded.
 remotelocation="teamspeak.com"
 
-if [ ! "$(command -v jq 2> /dev/null)" ]; then
-	fn_print_fail_nl "jq is not installed"
-	fn_script_log_fail "jq is not installed"
-	core_exit.sh
-fi
-
 if [ "${firstcommandname}" == "INSTALL" ]; then
 	fn_update_remotebuild
 	fn_update_dl

+ 32 - 38
lgsm/modules/update_ut99.sh

@@ -11,7 +11,7 @@ fn_update_dl() {
 	# Download and extract files to serverfiles.
 	fn_fetch_file "${remotebuildurl}" "" "" "" "${tmpdir}" "${remotebuildfilename}" "nochmodx" "norun" "force" "nohash"
 	fn_dl_extract "${tmpdir}" "${remotebuildfilename}" "${serverfiles}"
-	echo "${remotebuildversion}" > "${serverfiles}/build.txt"
+	echo "${remotebuild}" > "${serverfiles}/build.txt"
 	fn_clear_tmp
 }
 
@@ -37,12 +37,12 @@ fn_update_remotebuild() {
 	remotebuildresponse=$(curl -s "${apiurl}")
 	remotebuildfilename=$(echo "${remotebuildresponse}" | jq -r '.assets[]|select(.browser_download_url | contains("Linux-amd64")) | .name')
 	remotebuildurl=$(echo "${remotebuildresponse}" | jq -r '.assets[]|select(.browser_download_url | contains("Linux-amd64")) | .browser_download_url')
-	remotebuildversion=$(echo "${remotebuildresponse}" | jq -r '.tag_name')
+	remotebuild=$(echo "${remotebuildresponse}" | jq -r '.tag_name')
 
 	if [ "${firstcommandname}" != "INSTALL" ]; then
 		fn_print_dots "Checking remote build: ${remotelocation}"
-		# Checks if remotebuildversion variable has been set.
-		if [ -z "${remotebuildversion}" ] || [ "${remotebuildversion}" == "null" ]; then
+		# Checks if remotebuild variable has been set.
+		if [ -z "${remotebuild}" ] || [ "${remotebuild}" == "null" ]; then
 			fn_print_fail "Checking remote build: ${remotelocation}"
 			fn_script_log_fail "Checking remote build"
 			core_exit.sh
@@ -52,7 +52,7 @@ fn_update_remotebuild() {
 		fi
 	else
 		# Checks if remotebuild variable has been set.
-		if [ -z "${remotebuildversion}" ] || [ "${remotebuildversion}" == "null" ]; then
+		if [ -z "${remotebuild}" ] || [ "${remotebuild}" == "null" ]; then
 			fn_print_failure "Unable to get remote build"
 			fn_script_log_fail "Unable to get remote build"
 			core_exit.sh
@@ -63,35 +63,35 @@ fn_update_remotebuild() {
 fn_update_compare() {
 	fn_print_dots "Checking for update: ${remotelocation}"
 	# Update has been found or force update.
-	if [ "${localbuild}" != "${remotebuildversion}" ] || [ "${forceupdate}" == "1" ]; then
+	if [ "${localbuild}" != "${remotebuild}" ] || [ "${forceupdate}" == "1" ]; then
 		# Create update lockfile.
 		date '+%s' > "${lockdir:?}/update.lock"
 		fn_print_ok_nl "Checking for update: ${remotelocation}"
-		echo -en "\n"
-		echo -e "Update available"
-		echo -e "* Local build: ${red}${localbuild}${default}"
-		echo -e "* Remote build: ${green}${remotebuildversion}${default}"
+		fn_print "\n"
+		fn_print_nl "${bold}${underline}Update${default} available"
+		fn_print_nl "* Local build: ${red}${localbuild}${default}"
+		fn_print_nl "* Remote build: ${green}${remotebuild}${default}"
 		if [ -n "${branch}" ]; then
-			echo -e "* Branch: ${branch}"
+			fn_print_nl "* Branch: ${branch}"
 		fi
 		if [ -f "${rootdir}/.dev-debug" ]; then
-			echo -e "Remote build info"
-			echo -e "* apiurl: ${apiurl}"
-			echo -e "* remotebuildfilename: ${remotebuildfilename}"
-			echo -e "* remotebuildurl: ${remotebuildurl}"
-			echo -e "* remotebuildversion: ${remotebuildversion}"
+			fn_print_nl "Remote build info"
+			fn_print_nl "* apiurl: ${apiurl}"
+			fn_print_nl "* remotebuildfilename: ${remotebuildfilename}"
+			fn_print_nl "* remotebuildurl: ${remotebuildurl}"
+			fn_print_nl "* remotebuild: ${remotebuild}"
 		fi
-		echo -en "\n"
+		fn_print "\n"
 		fn_script_log_info "Update available"
 		fn_script_log_info "Local build: ${localbuild}"
-		fn_script_log_info "Remote build: ${remotebuildversion}"
+		fn_script_log_info "Remote build: ${remotebuild}"
 		if [ -n "${branch}" ]; then
 			fn_script_log_info "Branch: ${branch}"
 		fi
-		fn_script_log_info "${localbuild} > ${remotebuildversion}"
+		fn_script_log_info "${localbuild} > ${remotebuild}"
 
 		if [ "${commandname}" == "UPDATE" ]; then
-			date +%s > "${lockdir}/last-updated.lock"
+			date +%s > "${lockdir:?}/last-updated.lock"
 			unset updateonstart
 			check_status.sh
 			# If server stopped.
@@ -126,26 +126,26 @@ fn_update_compare() {
 		alert.sh
 	else
 		fn_print_ok_nl "Checking for update: ${remotelocation}"
-		echo -en "\n"
-		echo -e "No update available"
-		echo -e "* Local build: ${green}${localbuild}${default}"
-		echo -e "* Remote build: ${green}${remotebuildversion}${default}"
+		fn_print "\n"
+		fn_print_nl "${bold}${underline}No update${default} available"
+		fn_print_nl "* Local build: ${green}${localbuild}${default}"
+		fn_print_nl "* Remote build: ${green}${remotebuild}${default}"
 		if [ -n "${branch}" ]; then
-			echo -e "* Branch: ${branch}"
+			fn_print_nl "* Branch: ${branch}"
 		fi
-		echo -en "\n"
+		fn_print "\n"
 		fn_script_log_info "No update available"
 		fn_script_log_info "Local build: ${localbuild}"
-		fn_script_log_info "Remote build: ${remotebuildversion}"
+		fn_script_log_info "Remote build: ${remotebuild}"
 		if [ -n "${branch}" ]; then
 			fn_script_log_info "Branch: ${branch}"
 		fi
 		if [ -f "${rootdir}/.dev-debug" ]; then
-			echo -e "Remote build info"
-			echo -e "* apiurl: ${apiurl}"
-			echo -e "* remotebuildfilename: ${remotebuildfilename}"
-			echo -e "* remotebuildurl: ${remotebuildurl}"
-			echo -e "* remotebuildversion: ${remotebuildversion}"
+			fn_print_nl "Remote build info"
+			fn_print_nl "* apiurl: ${apiurl}"
+			fn_print_nl "* remotebuildfilename: ${remotebuildfilename}"
+			fn_print_nl "* remotebuildurl: ${remotebuildurl}"
+			fn_print_nl "* remotebuild: ${remotebuild}"
 		fi
 	fi
 }
@@ -153,12 +153,6 @@ fn_update_compare() {
 # The location where the builds are checked and downloaded.
 remotelocation="github.com"
 
-if [ ! "$(command -v jq 2> /dev/null)" ]; then
-	fn_print_fail_nl "jq is not installed"
-	fn_script_log_fail "jq is not installed"
-	core_exit.sh
-fi
-
 if [ "${firstcommandname}" == "INSTALL" ]; then
 	fn_update_remotebuild
 	fn_update_dl

+ 34 - 39
lgsm/modules/update_vints.sh

@@ -20,6 +20,7 @@ fn_update_localbuild() {
 	# Uses executable to get local build.
 	if [ -d "${executabledir}" ]; then
 		cd "${executabledir}" || exit
+		# shellcheck disable=SC2086 # Intentional: preexecutable may be empty; unquoted to drop it without producing an empty arg.
 		localbuild="$(${preexecutable} ${executable} --version 2> /dev/null | sed '/^[[:space:]]*$/d')"
 	fi
 	if [ -z "${localbuild}" ]; then
@@ -44,14 +45,14 @@ fn_update_remotebuild() {
 	else
 		remotebuildversion="${branch}"
 	fi
-	remotebuildfilename=$(echo "${remotebuildresponse}" | jq --arg remotebuildversion "${remotebuildversion}" -r '.[$remotebuildversion].linuxserver.filename')
-	remotebuildurl=$(echo "${remotebuildresponse}" | jq --arg remotebuildversion "${remotebuildversion}" -r '.[$remotebuildversion].linuxserver.urls.cdn')
-	remotebuildhash=$(echo "${remotebuildresponse}" | jq --arg remotebuildversion "${remotebuildversion}" -r '.[$remotebuildversion].linuxserver.md5')
+	remotebuildfilename=$(echo "${remotebuildresponse}" | jq --arg remotebuild "${remotebuild}" -r '.[$remotebuild].linuxserver.filename')
+	remotebuildurl=$(echo "${remotebuildresponse}" | jq --arg remotebuild "${remotebuild}" -r '.[$remotebuild].linuxserver.urls.cdn')
+	remotebuildhash=$(echo "${remotebuildresponse}" | jq --arg remotebuild "${remotebuild}" -r '.[$remotebuild].linuxserver.md5')
 
 	if [ "${firstcommandname}" != "INSTALL" ]; then
 		fn_print_dots "Checking remote build: ${remotelocation}"
-		# Checks if remotebuildversion variable has been set.
-		if [ -z "${remotebuildversion}" ] || [ "${remotebuildversion}" == "null" ]; then
+		# Checks if remotebuild variable has been set.
+		if [ -z "${remotebuild}" ] || [ "${remotebuild}" == "null" ]; then
 			fn_print_fail "Checking remote build: ${remotelocation}"
 			fn_script_log_fail "Checking remote build"
 			core_exit.sh
@@ -61,7 +62,7 @@ fn_update_remotebuild() {
 		fi
 	else
 		# Checks if remotebuild variable has been set.
-		if [ -z "${remotebuildversion}" ] || [ "${remotebuildversion}" == "null" ]; then
+		if [ -z "${remotebuild}" ] || [ "${remotebuild}" == "null" ]; then
 			fn_print_failure "Unable to get remote build"
 			fn_script_log_fail "Unable to get remote build"
 			core_exit.sh
@@ -72,35 +73,35 @@ fn_update_remotebuild() {
 fn_update_compare() {
 	fn_print_dots "Checking for update: ${remotelocation}"
 	# Update has been found or force update.
-	if [ "${localbuild}" != "${remotebuildversion}" ] || [ "${forceupdate}" == "1" ]; then
+	if [ "${localbuild}" != "${remotebuild}" ] || [ "${forceupdate}" == "1" ]; then
 		# Create update lockfile.
 		date '+%s' > "${lockdir:?}/update.lock"
 		fn_print_ok_nl "Checking for update: ${remotelocation}"
-		echo -en "\n"
-		echo -e "Update available"
-		echo -e "* Local build: ${red}${localbuild}${default}"
-		echo -e "* Remote build: ${green}${remotebuildversion}${default}"
+		fn_print "\n"
+		fn_print_nl "${bold}${underline}Update${default} available"
+		fn_print_nl "* Local build: ${red}${localbuild}${default}"
+		fn_print_nl "* Remote build: ${green}${remotebuild}${default}"
 		if [ -n "${branch}" ]; then
-			echo -e "* Branch: ${branch}"
+			fn_print_nl "* Branch: ${branch}"
 		fi
 		if [ -f "${rootdir}/.dev-debug" ]; then
-			echo -e "Remote build info"
-			echo -e "* apiurl: ${apiurl}"
-			echo -e "* remotebuildfilename: ${remotebuildfilename}"
-			echo -e "* remotebuildurl: ${remotebuildurl}"
-			echo -e "* remotebuildversion: ${remotebuildversion}"
+			fn_print_nl "Remote build info"
+			fn_print_nl "* apiurl: ${apiurl}"
+			fn_print_nl "* remotebuildfilename: ${remotebuildfilename}"
+			fn_print_nl "* remotebuildurl: ${remotebuildurl}"
+			fn_print_nl "* remotebuild: ${remotebuild}"
 		fi
-		echo -en "\n"
+		fn_print "\n"
 		fn_script_log_info "Update available"
 		fn_script_log_info "Local build: ${localbuild}"
-		fn_script_log_info "Remote build: ${remotebuildversion}"
+		fn_script_log_info "Remote build: ${remotebuild}"
 		if [ -n "${branch}" ]; then
 			fn_script_log_info "Branch: ${branch}"
 		fi
-		fn_script_log_info "${localbuild} > ${remotebuildversion}"
+		fn_script_log_info "${localbuild} > ${remotebuild}"
 
 		if [ "${commandname}" == "UPDATE" ]; then
-			date +%s > "${lockdir}/last-updated.lock"
+			date +%s > "${lockdir:?}/last-updated.lock"
 			unset updateonstart
 			check_status.sh
 			# If server stopped.
@@ -135,26 +136,26 @@ fn_update_compare() {
 		alert.sh
 	else
 		fn_print_ok_nl "Checking for update: ${remotelocation}"
-		echo -en "\n"
-		echo -e "No update available"
-		echo -e "* Local build: ${green}${localbuild}${default}"
-		echo -e "* Remote build: ${green}${remotebuildversion}${default}"
+		fn_print "\n"
+		fn_print_nl "${bold}${underline}No update${default} available"
+		fn_print_nl "* Local build: ${green}${localbuild}${default}"
+		fn_print_nl "* Remote build: ${green}${remotebuild}${default}"
 		if [ -n "${branch}" ]; then
-			echo -e "* Branch: ${branch}"
+			fn_print_nl "* Branch: ${branch}"
 		fi
-		echo -en "\n"
+		fn_print "\n"
 		fn_script_log_info "No update available"
 		fn_script_log_info "Local build: ${localbuild}"
-		fn_script_log_info "Remote build: ${remotebuildversion}"
+		fn_script_log_info "Remote build: ${remotebuild}"
 		if [ -n "${branch}" ]; then
 			fn_script_log_info "Branch: ${branch}"
 		fi
 		if [ -f "${rootdir}/.dev-debug" ]; then
-			echo -e "Remote build info"
-			echo -e "* apiurl: ${apiurl}"
-			echo -e "* remotebuildfilename: ${remotebuildfilename}"
-			echo -e "* remotebuildurl: ${remotebuildurl}"
-			echo -e "* remotebuildversion: ${remotebuildversion}"
+			fn_print_nl "Remote build info"
+			fn_print_nl "* apiurl: ${apiurl}"
+			fn_print_nl "* remotebuildfilename: ${remotebuildfilename}"
+			fn_print_nl "* remotebuildurl: ${remotebuildurl}"
+			fn_print_nl "* remotebuild: ${remotebuild}"
 		fi
 	fi
 }
@@ -162,12 +163,6 @@ fn_update_compare() {
 # The location where the builds are checked and downloaded.
 remotelocation="vintagestory.at"
 
-if [ ! "$(command -v jq 2> /dev/null)" ]; then
-	fn_print_fail_nl "jq is not installed"
-	fn_script_log_fail "jq is not installed"
-	core_exit.sh
-fi
-
 if [ "${firstcommandname}" == "INSTALL" ]; then
 	fn_update_remotebuild
 	fn_update_dl

+ 31 - 38
lgsm/modules/update_xnt.sh

@@ -54,13 +54,12 @@ fn_update_remotebuild() {
 	remotebuildfilename=$(echo "${remotebuildtag}" | tr -d 'v')
 	remotebuildfilename="${remotebuildfilename}.zip"
 	remotebuildurl="https://dl.xonotic.org/${remotebuildfilename}"
-
-	remotebuildversion="${remotebuildtag}"
+	remotebuild="${remotebuildtag}"
 
 	if [ "${firstcommandname}" != "INSTALL" ]; then
 		fn_print_dots "Checking remote build: ${remotelocation}"
-		# Checks if remotebuildversion variable has been set.
-		if [ -z "${remotebuildversion}" ] || [ "${remotebuildversion}" == "null" ]; then
+		# Checks if remotebuild variable has been set.
+		if [ -z "${remotebuild}" ] || [ "${remotebuild}" == "null" ]; then
 			fn_print_fail "Checking remote build: ${remotelocation}"
 			fn_script_log_fail "Checking remote build"
 			core_exit.sh
@@ -70,7 +69,7 @@ fn_update_remotebuild() {
 		fi
 	else
 		# Checks if remotebuild variable has been set.
-		if [ -z "${remotebuildversion}" ] || [ "${remotebuildversion}" == "null" ]; then
+		if [ -z "${remotebuild}" ] || [ "${remotebuild}" == "null" ]; then
 			fn_print_failure "Unable to get remote build"
 			fn_script_log_fail "Unable to get remote build"
 			core_exit.sh
@@ -81,35 +80,35 @@ fn_update_remotebuild() {
 fn_update_compare() {
 	fn_print_dots "Checking for update: ${remotelocation}"
 	# Update has been found or force update.
-	if [ "${localbuild}" != "${remotebuildversion}" ] || [ "${forceupdate}" == "1" ]; then
+	if [ "${localbuild}" != "${remotebuild}" ] || [ "${forceupdate}" == "1" ]; then
 		# Create update lockfile.
 		date '+%s' > "${lockdir:?}/update.lock"
 		fn_print_ok_nl "Checking for update: ${remotelocation}"
-		echo -en "\n"
-		echo -e "Update available"
-		echo -e "* Local build: ${red}${localbuild}${default}"
-		echo -e "* Remote build: ${green}${remotebuildversion}${default}"
+		fn_print "\n"
+		fn_print_nl "${bold}${underline}Update${default} available"
+		fn_print_nl "* Local build: ${red}${localbuild}${default}"
+		fn_print_nl "* Remote build: ${green}${remotebuild}${default}"
 		if [ -n "${branch}" ]; then
-			echo -e "* Branch: ${branch}"
+			fn_print_nl "* Branch: ${branch}"
 		fi
 		if [ -f "${rootdir}/.dev-debug" ]; then
-			echo -e "Remote build info"
-			echo -e "* apiurl: ${apiurl}"
-			echo -e "* remotebuildfilename: ${remotebuildfilename}"
-			echo -e "* remotebuildurl: ${remotebuildurl}"
-			echo -e "* remotebuildversion: ${remotebuildversion}"
+			fn_print_nl "Remote build info"
+			fn_print_nl "* apiurl: ${apiurl}"
+			fn_print_nl "* remotebuildfilename: ${remotebuildfilename}"
+			fn_print_nl "* remotebuildurl: ${remotebuildurl}"
+			fn_print_nl "* remotebuild: ${remotebuild}"
 		fi
-		echo -en "\n"
+		fn_print "\n"
 		fn_script_log_info "Update available"
 		fn_script_log_info "Local build: ${localbuild}"
-		fn_script_log_info "Remote build: ${remotebuildversion}"
+		fn_script_log_info "Remote build: ${remotebuild}"
 		if [ -n "${branch}" ]; then
 			fn_script_log_info "Branch: ${branch}"
 		fi
-		fn_script_log_info "${localbuild} > ${remotebuildversion}"
+		fn_script_log_info "${localbuild} > ${remotebuild}"
 
 		if [ "${commandname}" == "UPDATE" ]; then
-			date +%s > "${lockdir}/last-updated.lock"
+			date +%s > "${lockdir:?}/last-updated.lock"
 			unset updateonstart
 			check_status.sh
 			# If server stopped.
@@ -144,26 +143,26 @@ fn_update_compare() {
 		alert.sh
 	else
 		fn_print_ok_nl "Checking for update: ${remotelocation}"
-		echo -en "\n"
-		echo -e "No update available"
-		echo -e "* Local build: ${green}${localbuild}${default}"
-		echo -e "* Remote build: ${green}${remotebuildversion}${default}"
+		fn_print "\n"
+		fn_print_nl "${bold}${underline}No update${default} available"
+		fn_print_nl "* Local build: ${green}${localbuild}${default}"
+		fn_print_nl "* Remote build: ${green}${remotebuild}${default}"
 		if [ -n "${branch}" ]; then
-			echo -e "* Branch: ${branch}"
+			fn_print_nl "* Branch: ${branch}"
 		fi
-		echo -en "\n"
+		fn_print "\n"
 		fn_script_log_info "No update available"
 		fn_script_log_info "Local build: ${localbuild}"
-		fn_script_log_info "Remote build: ${remotebuildversion}"
+		fn_script_log_info "Remote build: ${remotebuild}"
 		if [ -n "${branch}" ]; then
 			fn_script_log_info "Branch: ${branch}"
 		fi
 		if [ -f "${rootdir}/.dev-debug" ]; then
-			echo -e "Remote build info"
-			echo -e "* apiurl: ${apiurl}"
-			echo -e "* remotebuildfilename: ${remotebuildfilename}"
-			echo -e "* remotebuildurl: ${remotebuildurl}"
-			echo -e "* remotebuildversion: ${remotebuildversion}"
+			fn_print_nl "Remote build info"
+			fn_print_nl "* apiurl: ${apiurl}"
+			fn_print_nl "* remotebuildfilename: ${remotebuildfilename}"
+			fn_print_nl "* remotebuildurl: ${remotebuildurl}"
+			fn_print_nl "* remotebuild: ${remotebuild}"
 		fi
 	fi
 }
@@ -171,12 +170,6 @@ fn_update_compare() {
 # The location where the builds are checked and downloaded.
 remotelocation="github.com"
 
-if [ ! "$(command -v jq 2> /dev/null)" ]; then
-	fn_print_fail_nl "jq is not installed"
-	fn_script_log_fail "jq is not installed"
-	core_exit.sh
-fi
-
 if [ "${firstcommandname}" == "INSTALL" ]; then
 	fn_update_remotebuild
 	fn_update_dl

+ 2 - 1
linuxgsm.sh

@@ -330,7 +330,8 @@ fn_install_menu() {
 # Gets server info from serverlist.csv and puts in to array.
 fn_server_info() {
 	IFS=","
-	server_info_array=($(grep -aw "${userinput}" "${serverlist}"))
+	server_info_line="$(grep -aw "${userinput}" "${serverlist}" | head -n 1)"
+	read -r -a server_info_array <<< "${server_info_line}"
 	shortname="${server_info_array[0]}"      # csgo
 	gameservername="${server_info_array[1]}" # csgoserver
 	gamename="${server_info_array[2]}"       # Counter Strike: Global Offensive

+ 25 - 25
package.json

@@ -1,27 +1,27 @@
 {
-  "name": "linuxgsm",
-  "description": "<h1 align=\"center\">   <br>   <a href=\"https://linuxgsm.com\"><img src=\"https://i.imgur.com/Eoh1jsi.jpg\" alt=\"LinuxGSM\"></a>   </h1>",
-  "directories": {
-    "test": "tests"
-  },
-  "devDependencies": {
-    "prettier": "^3.4.2",
-    "prettier-plugin-sh": "^0.14.0"
-  },
-  "scripts": {
-    "test": "echo \"Error: no test specified\" && exit 1"
-  },
-  "repository": {
-    "type": "git",
-    "url": "git+https://github.com/GameServerManagers/LinuxGSM.git"
-  },
-  "author": "",
-  "license": "MIT",
-  "bugs": {
-    "url": "https://github.com/GameServerManagers/LinuxGSM/issues"
-  },
-  "homepage": "https://github.com/GameServerManagers/LinuxGSM#readme",
-  "dependencies": {
-    "gamedig": "^5.1.4"
-  }
+	"name": "linuxgsm",
+	"description": "<h1 align=\"center\">   <br>   <a href=\"https://linuxgsm.com\"><img src=\"https://i.imgur.com/Eoh1jsi.jpg\" alt=\"LinuxGSM\"></a>   </h1>",
+	"directories": {
+		"test": "tests"
+	},
+	"devDependencies": {
+		"prettier": "^3.4.2",
+		"prettier-plugin-sh": "^0.14.0"
+	},
+	"scripts": {
+		"test": "echo \"Error: no test specified\" && exit 1"
+	},
+	"repository": {
+		"type": "git",
+		"url": "git+https://github.com/GameServerManagers/LinuxGSM.git"
+	},
+	"author": "",
+	"license": "MIT",
+	"bugs": {
+		"url": "https://github.com/GameServerManagers/LinuxGSM/issues"
+	},
+	"homepage": "https://github.com/GameServerManagers/LinuxGSM#readme",
+	"dependencies": {
+		"gamedig": "^5.1.4"
+	}
 }