From aee8f1656463888580bb141f2e451ffb6b050f8f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 2 Oct 2026 22:30:16 +0000 Subject: [PATCH 001/164] chore(deps): bump actions/add-to-project from 1.0.2 to 2.0.0 (#4926) Bumps [actions/add-to-project](https://github.com/actions/add-to-project) from 1.0.2 to 2.0.0. - [Release notes](https://github.com/actions/add-to-project/releases) - [Commits](https://github.com/actions/add-to-project/compare/v1.0.2...v2.0.0) --- updated-dependencies: - dependency-name: actions/add-to-project dependency-version: 2.0.0 dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Daniel Gibbs --- .github/workflows/action-add-to-project.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/action-add-to-project.yml b/.github/workflows/action-add-to-project.yml index e963362645..69ba24ee69 100644 --- a/.github/workflows/action-add-to-project.yml +++ b/.github/workflows/action-add-to-project.yml @@ -13,7 +13,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Add to Project - uses: actions/add-to-project@v1.0.2 + uses: actions/add-to-project@v2.0.0 with: project-url: https://github.com/orgs/GameServerManagers/projects/11 github-token: ${{ secrets.ADD_TO_PROJECT_PAT }} From d208f88d774717f25d2b3d793a8c7caf1ddb9b99 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 2 Oct 2026 23:31:14 +0100 Subject: [PATCH 002/164] chore(deps): bump actions/checkout from 5 to 7 (#4933) Bumps [actions/checkout](https://github.com/actions/checkout) from 5 to 7. - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/checkout/compare/v5...v7) --- updated-dependencies: - dependency-name: actions/checkout dependency-version: '7' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: Daniel Gibbs Co-authored-by: unknown Co-authored-by: LinuxGSM Co-authored-by: Knoxed <1338733+knoxed@users.noreply.github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: WildPenguin Co-authored-by: Copilot Co-authored-by: Jacob Gerega <22921310+jgerega107@users.noreply.github.com> Co-authored-by: dgibbs64 Co-authored-by: Nikolay Asenov <10465782+nasenov@users.noreply.github.com> Co-authored-by: Fabian Raab Co-authored-by: yourfate <2371889-youRFate@users.noreply.gitlab.com> Co-authored-by: Claude Sonnet 4.6 Co-authored-by: fwillo <37631375+fwillo@users.noreply.github.com> Co-authored-by: Silas J. Matson --- .github/workflows/action-details-check.yml | 2 +- .github/workflows/action-issue-triage-automation.yml | 2 +- .github/workflows/action-prettier.yml | 2 +- .github/workflows/action-serverlist-validate.yml | 2 +- .github/workflows/action-super-linter.yml | 2 +- .github/workflows/action-version-check.yml | 2 +- .github/workflows/sync-game-labels.yml | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/.github/workflows/action-details-check.yml b/.github/workflows/action-details-check.yml index bed3a41ada..55371afd64 100644 --- a/.github/workflows/action-details-check.yml +++ b/.github/workflows/action-details-check.yml @@ -26,7 +26,7 @@ jobs: matrix: ${{ steps.set-matrix.outputs.matrix }} steps: - name: Checkout - uses: actions/checkout@v6 + uses: actions/checkout@v7 with: # Full history so the base branch ref is available for the # `git diff origin/...HEAD` comparison below (a shallow diff --git a/.github/workflows/action-issue-triage-automation.yml b/.github/workflows/action-issue-triage-automation.yml index 4992613c48..1beb90d0ba 100644 --- a/.github/workflows/action-issue-triage-automation.yml +++ b/.github/workflows/action-issue-triage-automation.yml @@ -2294,7 +2294,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v5 + uses: actions/checkout@v7 - name: Sync game labels from serverlist env: diff --git a/.github/workflows/action-prettier.yml b/.github/workflows/action-prettier.yml index f5d51a44ae..49fbf6ac31 100644 --- a/.github/workflows/action-prettier.yml +++ b/.github/workflows/action-prettier.yml @@ -19,7 +19,7 @@ jobs: steps: - name: Checkout - uses: actions/checkout@v6 + uses: actions/checkout@v7 with: persist-credentials: false diff --git a/.github/workflows/action-serverlist-validate.yml b/.github/workflows/action-serverlist-validate.yml index 3e88074071..33da083857 100644 --- a/.github/workflows/action-serverlist-validate.yml +++ b/.github/workflows/action-serverlist-validate.yml @@ -15,7 +15,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v6 + uses: actions/checkout@v7 - name: Compare Versions run: .github/scripts/serverlist-validate.sh diff --git a/.github/workflows/action-super-linter.yml b/.github/workflows/action-super-linter.yml index 31b2fa9497..789b99c643 100644 --- a/.github/workflows/action-super-linter.yml +++ b/.github/workflows/action-super-linter.yml @@ -25,7 +25,7 @@ jobs: steps: - name: Checkout code - uses: actions/checkout@v6 + uses: actions/checkout@v7 with: # super-linter needs the full git history to get the # list of files that changed across commits diff --git a/.github/workflows/action-version-check.yml b/.github/workflows/action-version-check.yml index 0726295a43..a41edb16c0 100644 --- a/.github/workflows/action-version-check.yml +++ b/.github/workflows/action-version-check.yml @@ -11,7 +11,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v6 + uses: actions/checkout@v7 - name: Version Check run: .github/scripts/version-check.sh diff --git a/.github/workflows/sync-game-labels.yml b/.github/workflows/sync-game-labels.yml index eccb0ed467..ed7d66c954 100644 --- a/.github/workflows/sync-game-labels.yml +++ b/.github/workflows/sync-game-labels.yml @@ -18,7 +18,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v5 + uses: actions/checkout@v7 - name: Sync game labels from serverlist env: From 13a7bc4f7bd0e903e097e66f8371017c943e5bd0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 2 Oct 2026 22:40:01 +0000 Subject: [PATCH 003/164] chore(deps): bump actions/cache from 4 to 6 (#4945) Bumps [actions/cache](https://github.com/actions/cache) from 4 to 6. - [Release notes](https://github.com/actions/cache/releases) - [Changelog](https://github.com/actions/cache/blob/main/RELEASES.md) - [Commits](https://github.com/actions/cache/compare/v4...v6) --- updated-dependencies: - dependency-name: actions/cache dependency-version: '6' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: Daniel Gibbs Co-authored-by: unknown Co-authored-by: LinuxGSM Co-authored-by: Knoxed <1338733+knoxed@users.noreply.github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: WildPenguin Co-authored-by: Copilot Co-authored-by: Jacob Gerega <22921310+jgerega107@users.noreply.github.com> Co-authored-by: dgibbs64 Co-authored-by: Nikolay Asenov <10465782+nasenov@users.noreply.github.com> Co-authored-by: Fabian Raab Co-authored-by: yourfate <2371889-youRFate@users.noreply.gitlab.com> Co-authored-by: Claude Sonnet 4.6 Co-authored-by: fwillo <37631375+fwillo@users.noreply.github.com> Co-authored-by: Silas J. Matson --- .github/workflows/action-details-check.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/action-details-check.yml b/.github/workflows/action-details-check.yml index 55371afd64..f0e78a29d7 100644 --- a/.github/workflows/action-details-check.yml +++ b/.github/workflows/action-details-check.yml @@ -100,7 +100,7 @@ jobs: run: wget "https://raw.githubusercontent.com/GameServerManagers/LinuxGSM/${LGSM_REF}/linuxgsm.sh"; chmod +x linuxgsm.sh - name: Cache apt packages - uses: actions/cache@v4 + uses: actions/cache@v6 with: path: /var/cache/apt/archives key: apt-${{ runner.os }}-libxml2-utils-jq From 408126930d637254d9488ee6cfb5dc02468a4c7f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 2 Oct 2026 22:40:37 +0000 Subject: [PATCH 004/164] chore(deps): bump actions/github-script from 7 to 9 (#4946) Bumps [actions/github-script](https://github.com/actions/github-script) from 7 to 9. - [Release notes](https://github.com/actions/github-script/releases) - [Commits](https://github.com/actions/github-script/compare/v7...v9) --- updated-dependencies: - dependency-name: actions/github-script dependency-version: '9' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: Daniel Gibbs Co-authored-by: unknown Co-authored-by: LinuxGSM Co-authored-by: Knoxed <1338733+knoxed@users.noreply.github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: WildPenguin Co-authored-by: Copilot Co-authored-by: Jacob Gerega <22921310+jgerega107@users.noreply.github.com> Co-authored-by: dgibbs64 Co-authored-by: Nikolay Asenov <10465782+nasenov@users.noreply.github.com> Co-authored-by: Fabian Raab Co-authored-by: yourfate <2371889-youRFate@users.noreply.gitlab.com> Co-authored-by: Claude Sonnet 4.6 Co-authored-by: fwillo <37631375+fwillo@users.noreply.github.com> Co-authored-by: Silas J. Matson --- .github/workflows/ai-triage.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ai-triage.yml b/.github/workflows/ai-triage.yml index fba1e4cf1e..178cfe3b13 100644 --- a/.github/workflows/ai-triage.yml +++ b/.github/workflows/ai-triage.yml @@ -21,7 +21,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Triage issue with GitHub Models - uses: actions/github-script@v7 + uses: actions/github-script@v9 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: From 3ae187f121e40733bb48156f942ddc2cf1a7d86c Mon Sep 17 00:00:00 2001 From: Daniel Gibbs Date: Fri, 2 Oct 2026 23:41:41 +0100 Subject: [PATCH 005/164] chore(ci): remove dependabot auto-merge workflow (#4964) Dependabot minor/patch updates were auto-approved by github-actions[bot], which satisfied master's required review and merged straight to master. All dependency updates go back to manual review. The workflow has also been removed from dgibbs64/repo-sync so it is not synced back. Co-authored-by: Claude Opus 5.5 --- .../workflows/action-dependabot-automerge.yml | 27 ------------------- 1 file changed, 27 deletions(-) delete mode 100644 .github/workflows/action-dependabot-automerge.yml diff --git a/.github/workflows/action-dependabot-automerge.yml b/.github/workflows/action-dependabot-automerge.yml deleted file mode 100644 index 9107d55650..0000000000 --- a/.github/workflows/action-dependabot-automerge.yml +++ /dev/null @@ -1,27 +0,0 @@ -name: Dependabot auto-merge - -on: pull_request - -permissions: - contents: write - pull-requests: write - -jobs: - dependabot: - runs-on: ubuntu-latest - if: github.actor == 'dependabot[bot]' - steps: - - name: Fetch dependabot metadata - id: metadata - uses: dependabot/fetch-metadata@v2 - with: - github-token: "${{ secrets.GITHUB_TOKEN }}" - - - name: Approve and enable auto-merge for minor/patch updates - if: steps.metadata.outputs.update-type != 'version-update:semver-major' - env: - PR_URL: ${{ github.event.pull_request.html_url }} - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: | - gh pr review --approve "$PR_URL" - gh pr merge --auto --squash "$PR_URL" From be029422df0542b09d3b698ae6fcff6d7a8b19b5 Mon Sep 17 00:00:00 2001 From: Daniel Gibbs Date: Fri, 2 Oct 2026 23:42:33 +0100 Subject: [PATCH 006/164] chore(sync): synced file(s) with dgibbs64/repo-sync (#4949) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * chore(sync): synced local '.github/' with remote 'general/.github/' Synced from dgibbs64/repo-sync@a9c30906936debce9e57a782eb8896ddb4601fbb — Merge pull request #18 from dgibbs64/chore/remove-dependabot-automerge chore(workflows): remove dependabot auto-merge workflow * chore(sync): synced local './' with remote 'bash/' Synced from dgibbs64/repo-sync@a9c30906936debce9e57a782eb8896ddb4601fbb — Merge pull request #18 from dgibbs64/chore/remove-dependabot-automerge chore(workflows): remove dependabot auto-merge workflow * Add permissions for pull-requests in workflow Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- ...update-copyright-years-in-license-file.yml | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 .github/workflows/action-update-copyright-years-in-license-file.yml diff --git a/.github/workflows/action-update-copyright-years-in-license-file.yml b/.github/workflows/action-update-copyright-years-in-license-file.yml new file mode 100644 index 0000000000..7ad5a76dd7 --- /dev/null +++ b/.github/workflows/action-update-copyright-years-in-license-file.yml @@ -0,0 +1,25 @@ +name: Update copyright year(s) in license file + +on: + workflow_dispatch: + schedule: + - cron: "0 3 1 1 *" # 03:00 AM on January 1 + +permissions: + contents: write + pull-requests: write + +jobs: + update-license-year: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v7 + with: + fetch-depth: 0 + persist-credentials: false + - name: Action Update License Year + uses: FantasticFiasco/action-update-license-year@v3 + with: + token: ${{ secrets.GITHUB_TOKEN }} + path: LICENSE.md From a956798a537b7b9f4c9a20603108b63cf2c0efbb Mon Sep 17 00:00:00 2001 From: Daniel Gibbs Date: Fri, 2 Oct 2026 23:45:42 +0100 Subject: [PATCH 007/164] fix(modules): make update_bb.sh executable (#4965) update_bb.sh was the only module committed as 100644; all others are 100755. Co-authored-by: Claude Opus 5.5 --- lgsm/modules/update_bb.sh | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 lgsm/modules/update_bb.sh diff --git a/lgsm/modules/update_bb.sh b/lgsm/modules/update_bb.sh old mode 100644 new mode 100755 From 1455800117ca2fb5b024882019b99635fee256f6 Mon Sep 17 00:00:00 2001 From: Daniel Gibbs Date: Sat, 3 Oct 2026 00:10:24 +0100 Subject: [PATCH 008/164] fix(sdtd): read telnet password into telnetpassword (#4968) fn_info_game_sdtd stored TelnetPassword in ${telnetpass}, but command_stop.sh, info_messages.sh and the localhost check in the same function all read ${telnetpassword}. The graceful telnet shutdown never sent the password, and the telnet IP was always forced to 127.0.0.1, so stop fell back to killing the tmux session without a world save. Fixes #4957 Co-authored-by: Claude Opus 5.5 --- lgsm/modules/info_game.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lgsm/modules/info_game.sh b/lgsm/modules/info_game.sh index d39e2d143d..aab934db88 100755 --- a/lgsm/modules/info_game.sh +++ b/lgsm/modules/info_game.sh @@ -1960,7 +1960,7 @@ fn_info_game_sdtd() { fn_info_game_xml "serverpassword" "/ServerSettings/property[@name='ServerPassword']/@value" fn_info_game_xml "port" "/ServerSettings/property[@name='ServerPort']/@value" fn_info_game_xml "telnetenabled" "/ServerSettings/property[@name='TelnetEnabled']/@value" - fn_info_game_xml "telnetpass" "/ServerSettings/property[@name='TelnetPassword']/@value" + fn_info_game_xml "telnetpassword" "/ServerSettings/property[@name='TelnetPassword']/@value" fn_info_game_xml "telnetport" "/ServerSettings/property[@name='TelnetPort']/@value" fn_info_game_xml "worldname" "/ServerSettings/property[@name='GameWorld']/@value" fi @@ -1980,7 +1980,7 @@ fn_info_game_sdtd() { if [ -z "${telnetpassword}" ]; then telnetip="127.0.0.1" fi - telnetpass="${telnetpass:-"NOT SET"}" + telnetpassword="${telnetpassword:-"NOT SET"}" telnetport="${telnetport:-"0"}" worldname="${worldname:-"NOT SET"}" From 3f61ca657b300361ac06d22e3790f9e95a30aff7 Mon Sep 17 00:00:00 2001 From: Daniel Gibbs Date: Sat, 3 Oct 2026 00:23:54 +0100 Subject: [PATCH 009/164] fix(vh): document how to disable crossplay (#4969) * fix(vh): add crossplay setting to control -crossplay -crossplay was hard-coded in vhserver's startparameters, so Steam-only servers could not turn off the PlayFab relay without overriding the whole startparameters line. Add crossplay="true" (default unchanged) and only pass -crossplay when it is "true". Fixes #4930 Co-Authored-By: Claude Opus 5.5 * fix(vh): document how to disable crossplay instead of adding a toggle Drop the crossplay setting and the conditional in startparameters. Keep -crossplay in the defaults, consistent with arkserver, and explain how Steam-only servers remove it by overriding startparameters. Co-Authored-By: Claude Opus 5.5 --------- Co-authored-by: Claude Opus 5.5 --- lgsm/config-default/config-lgsm/vhserver/_default.cfg | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lgsm/config-default/config-lgsm/vhserver/_default.cfg b/lgsm/config-default/config-lgsm/vhserver/_default.cfg index a1691b8397..e4d498768a 100644 --- a/lgsm/config-default/config-lgsm/vhserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/vhserver/_default.cfg @@ -50,6 +50,9 @@ instanceid="1" worldmodifiers="" ## Server Parameters | https://docs.linuxgsm.com/configuration/start-parameters#additional-parameters +# -crossplay routes connections through the PlayFab relay so Xbox/Game Pass players can join. +# Steam-only servers joined by direct IP: copy startparameters to your instance config and remove -crossplay. +# https://docs.linuxgsm.com/game-servers/valheim#crossplay startparameters="-name '${servername}' -password ${serverpassword} -port ${port} -world ${worldname} -public ${public} -savedir '${savedir}' -saveinterval ${saveinterval} -backups ${backups} -backupshort ${backupshort} -backuplong ${backuplong} -crossplay -instanceid ${instanceid} ${logFile:+ -logFile '${logFile}'} ${worldmodifiers:+ ${worldmodifiers}}" #### LinuxGSM Settings #### From e12ae368fbd39c5ed4c23445d0441514e50e5d06 Mon Sep 17 00:00:00 2001 From: Daniel Gibbs Date: Sat, 3 Oct 2026 00:35:58 +0100 Subject: [PATCH 010/164] fix(steamcmd): improve missing configuration diagnostics (#4951) --- lgsm/modules/core_dl.sh | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/lgsm/modules/core_dl.sh b/lgsm/modules/core_dl.sh index c3194a915d..24859afab4 100755 --- a/lgsm/modules/core_dl.sh +++ b/lgsm/modules/core_dl.sh @@ -175,6 +175,11 @@ fn_dl_steamcmd() { elif [ -n "$(grep "0x6A6" "${steamcmdlog}" | tail -1)" ]; then fn_print_error2_nl "${commandaction} ${selfname}: ${remotelocation}: Corrupt update files" fn_script_log_error "${commandaction} ${selfname}: ${remotelocation}: Corrupt update files" + # Steam app metadata unavailable. + elif [ -n "$(grep -i "Missing configuration" "${steamcmdlog}" | tail -1)" ]; then + fn_print_error2_nl "${commandaction} ${selfname}: ${remotelocation}: Missing configuration - Steam app metadata unavailable for AppID ${appid}" + fn_print_nl "Please provide content log to LinuxGSM developers https://linuxgsm.com/steamcmd-error" + fn_script_log_error "${commandaction} ${selfname}: ${remotelocation}: Missing configuration - Steam app metadata unavailable for AppID ${appid}" else 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" From 25a94f5428b80974b6039badac543b123e5b8c88 Mon Sep 17 00:00:00 2001 From: Doug Murphy <1383347+Doug-Murphy@users.noreply.github.com> Date: Fri, 2 Oct 2026 19:42:31 -0400 Subject: [PATCH 011/164] fix: [Factorio] Update startparameters to load the latest server autosave (#4960) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * chore(sync): synced local '.github/' with remote 'general/.github/' (#4947) Synced from dgibbs64/repo-sync@0a4246db6891a1188edd959ccec352e6c4149eb4 — Merge pull request #12 from dgibbs64/dependabot/npm_and_yarn/brace-expansion-5.0.7 chore(deps): bump brace-expansion from 5.0.6 to 5.0.7 * Update startparameters to load the latest server autosave Swap --start-server ${serverfiles}/save1.zip with --start-server-load-latest * fix(fctr): create initial save in saves/ so load-latest finds it --start-server-load-latest only searches the saves directory. The initial save was created at ${serverfiles}/save1.zip, so a fresh install had no saves/ directory and failed to host ("cannot open directory"). Co-Authored-By: Claude Opus 5.5 --------- Signed-off-by: dependabot[bot] Co-authored-by: Daniel Gibbs Co-authored-by: unknown Co-authored-by: LinuxGSM Co-authored-by: Knoxed <1338733+knoxed@users.noreply.github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: WildPenguin Co-authored-by: Copilot Co-authored-by: Jacob Gerega <22921310+jgerega107@users.noreply.github.com> Co-authored-by: dgibbs64 Co-authored-by: Nikolay Asenov <10465782+nasenov@users.noreply.github.com> Co-authored-by: Fabian Raab Co-authored-by: yourfate <2371889-youRFate@users.noreply.gitlab.com> Co-authored-by: Claude Sonnet 4.6 Co-authored-by: fwillo <37631375+fwillo@users.noreply.github.com> Co-authored-by: Silas J. Matson --- lgsm/config-default/config-lgsm/fctrserver/_default.cfg | 2 +- lgsm/modules/install_factorio_save.sh | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/lgsm/config-default/config-lgsm/fctrserver/_default.cfg b/lgsm/config-default/config-lgsm/fctrserver/_default.cfg index ab885b5ea0..34d86d3ac0 100644 --- a/lgsm/config-default/config-lgsm/fctrserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/fctrserver/_default.cfg @@ -16,7 +16,7 @@ rconpassword="CHANGE_ME" branch="stable" # values: stable, experimental ## Server Parameters | https://docs.linuxgsm.com/configuration/start-parameters#additional-parameters -startparameters="--bind ${ip} --start-server ${serverfiles}/save1.zip --server-settings ${servercfgfullpath} --port ${port} --rcon-port ${rconport} --rcon-password ${rconpassword}" +startparameters="--bind ${ip} --start-server-load-latest --server-settings ${servercfgfullpath} --port ${port} --rcon-port ${rconport} --rcon-password ${rconpassword}" #### LinuxGSM Settings #### diff --git a/lgsm/modules/install_factorio_save.sh b/lgsm/modules/install_factorio_save.sh index 5dfb4758c1..ccaaa0615f 100755 --- a/lgsm/modules/install_factorio_save.sh +++ b/lgsm/modules/install_factorio_save.sh @@ -11,4 +11,6 @@ echo -e "" echo -e "${bold}${lightyellow}Creating initial Factorio savefile${default}" fn_messages_separator check_glibc.sh -"${executabledir}"/factorio --create "${serverfiles}/save1" +# Create the save in the saves directory so --start-server-load-latest can find it. +mkdir -p "${serverfiles}/saves" +"${executabledir}"/factorio --create "${serverfiles}/saves/save1" From f0db333093902437c26926beab3da24124d483e5 Mon Sep 17 00:00:00 2001 From: Breeze Date: Sat, 3 Oct 2026 22:31:42 +0200 Subject: [PATCH 012/164] fix(deps): support deb822 apt sources on Debian (#4952) * fix(deps): support deb822 apt sources on Debian * fix(deps): ignore commented-out non-free entries in apt sources The non-free check matched commented lines, so a disabled non-free entry (more likely now that sources.list.d is searched) made LinuxGSM try the unavailable steamcmd package instead of the tar fallback. Only count lines whose first non-space character is not #. Co-Authored-By: Claude Opus 5.5 --------- Co-authored-by: BreezeDelegate <271538431+BreezeDelegate@users.noreply.github.com> Co-authored-by: Daniel Gibbs Co-authored-by: Claude Opus 5.5 --- lgsm/modules/check_deps.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lgsm/modules/check_deps.sh b/lgsm/modules/check_deps.sh index b031898970..102cbceb6e 100755 --- a/lgsm/modules/check_deps.sh +++ b/lgsm/modules/check_deps.sh @@ -272,7 +272,8 @@ fn_deps_detector() { array_deps_required=("${array_deps_required[@]/steamcmd/}") steamcmdstatus=1 return - elif [ "${deptocheck}" == "steamcmd" ] && [ "${distroid}" == "debian" ] && ! grep -qE '[^deb]+non-free([^-]|$)' /etc/apt/sources.list; then + # Checks classic and deb822 sources for an uncommented non-free component (non-free-firmware does not count). + elif [ "${deptocheck}" == "steamcmd" ] && [ "${distroid}" == "debian" ] && ! grep -qE '^[[:space:]]*[^#[:space:]].*[[:space:]]non-free([[:space:]]|$)' /etc/apt/sources.list /etc/apt/sources.list.d/*.list /etc/apt/sources.list.d/*.sources 2> /dev/null; then array_deps_required=("${array_deps_required[@]/steamcmd/}") steamcmdstatus=1 return From 52373e88c2dd2743cacec818e5682ddea586281f Mon Sep 17 00:00:00 2001 From: Breeze Date: Sat, 3 Oct 2026 22:38:05 +0200 Subject: [PATCH 013/164] fix(fastdl): include Source resource files (#4953) Co-authored-by: BreezeDelegate <271538431+BreezeDelegate@users.noreply.github.com> Co-authored-by: Daniel Gibbs --- lgsm/modules/command_fastdl.sh | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/lgsm/modules/command_fastdl.sh b/lgsm/modules/command_fastdl.sh index dfdcc9ec8f..c73fe175a7 100755 --- a/lgsm/modules/command_fastdl.sh +++ b/lgsm/modules/command_fastdl.sh @@ -162,7 +162,7 @@ fn_fastdl_preview() { done # Source engine else - fastdl_directories_array=("maps" "materials" "models" "particles" "sound" "resources") + fastdl_directories_array=("maps" "materials" "models" "particles" "sound" "resource") for directory in "${fastdl_directories_array[@]}"; do if [ -d "${systemdir}/${directory}" ]; then if [ "${directory}" == "maps" ]; then @@ -175,6 +175,8 @@ fn_fastdl_preview() { local allowed_extentions_array=("*.pcf") elif [ "${directory}" == "sound" ]; then local allowed_extentions_array=("*.wav" "*.mp3" "*.ogg") + elif [ "${directory}" == "resource" ]; then + local allowed_extentions_array=("*") fi for allowed_extention in "${allowed_extentions_array[@]}"; do fileswc=0 @@ -323,6 +325,8 @@ fn_fastdl_source() { local allowed_extentions_array=("*.pcf") elif [ "${directory}" == "sound" ]; then local allowed_extentions_array=("*.wav" "*.mp3" "*.ogg") + elif [ "${directory}" == "resource" ]; then + local allowed_extentions_array=("*") fi for allowed_extention in "${allowed_extentions_array[@]}"; do fileswc=0 From 0a7c1e17d00f52d9e30333a9984d434f21ff0212 Mon Sep 17 00:00:00 2001 From: Attila <1230402+borzaka@users.noreply.github.com> Date: Sat, 3 Oct 2026 22:43:19 +0200 Subject: [PATCH 014/164] feat(cs2server): add Metamod:Source 2.0 and CounterStrikeSharp mod support (#4961) - Enable mod installation, updates and removal for CS2 - Add Metamod:Source 2.0 dev builds with gameinfo.gi configuration - Add CounterStrikeSharp using the latest Linux release with runtime - Require Metamod:Source 2.0 before installing CounterStrikeSharp - Preserve the shared Metamod directory when removing CounterStrikeSharp Co-authored-by: Daniel Gibbs --- lgsm/modules/command_mods_install.sh | 10 +++++ lgsm/modules/command_mods_remove.sh | 5 +++ lgsm/modules/command_mods_update.sh | 4 ++ lgsm/modules/core_getopt.sh | 2 +- lgsm/modules/mods_core.sh | 65 ++++++++++++++++++++++++++++ lgsm/modules/mods_list.sh | 18 +++++++- 6 files changed, 102 insertions(+), 2 deletions(-) diff --git a/lgsm/modules/command_mods_install.sh b/lgsm/modules/command_mods_install.sh index a8f90293b2..1a0f25119c 100755 --- a/lgsm/modules/command_mods_install.sh +++ b/lgsm/modules/command_mods_install.sh @@ -109,6 +109,11 @@ if [ -f "${modsinstalledlistfullpath}" ]; then fi ## Installation. +# CounterStrikeSharp requires Metamod:Source 2.0. +if [ "${modcommand}" == "counterstrikesharp" ]; then + fn_mod_exist "metamodsource2" +fi + # If amxmodx check if metamod exists first if [ "${modcommand}" == "amxmodx" ]; then fn_mod_exist "metamod" @@ -133,6 +138,11 @@ fn_mod_add_list fn_mod_tidy_files_list fn_mods_clear_tmp_dir +# Install the Metamod:Source search path for CS2. +if [ "${modcommand}" == "metamodsource2" ]; then + fn_mod_install_gameinfo_gi_file +fi + # Create/modify existing liblist.gam file for Metamod if [ "${modcommand}" == "metamod" ]; then fn_mod_install_liblist_gam_file diff --git a/lgsm/modules/command_mods_remove.sh b/lgsm/modules/command_mods_remove.sh index 04240eb60d..c9c06b15f0 100755 --- a/lgsm/modules/command_mods_remove.sh +++ b/lgsm/modules/command_mods_remove.sh @@ -151,6 +151,11 @@ if [ "${engine}" == "unity3d" ] && [[ "${modprettyname}" == *"Oxide"* ]]; then unset exitbypass fi +# Remove the Metamod:Source search path for CS2. +if [ "${modcommand}" == "metamodsource2" ]; then + fn_mod_remove_gameinfo_gi_file +fi + # Remove/modify existing liblist.gam file for Metamod if [ "${modcommand}" == "metamod" ]; then fn_mod_remove_liblist_gam_file diff --git a/lgsm/modules/command_mods_update.sh b/lgsm/modules/command_mods_update.sh index 10279b67b3..2d1eba650f 100755 --- a/lgsm/modules/command_mods_update.sh +++ b/lgsm/modules/command_mods_update.sh @@ -93,6 +93,10 @@ while [ "${installedmodsline}" -le "${installedmodscount}" ]; do fn_mod_add_list fn_mod_tidy_files_list fn_mods_clear_tmp_dir + # Restore the Metamod:Source search path if a CS2 update removed it. + if [ "${modcommand}" == "metamodsource2" ]; then + fn_mod_install_gameinfo_gi_file + fi fi ((installedmodsline++)) else diff --git a/lgsm/modules/core_getopt.sh b/lgsm/modules/core_getopt.sh index ad09bf1df5..fede1debbf 100755 --- a/lgsm/modules/core_getopt.sh +++ b/lgsm/modules/core_getopt.sh @@ -137,7 +137,7 @@ if [ "${shortname}" == "squad" ]; then fi ## Mods commands. -if [ "${engine}" == "source" ] || [ "${shortname}" == "rust" ] || [ "${shortname}" == "hq" ] || [ "${shortname}" == "sdtd" ] || [ "${shortname}" == "cs" ] || [ "${shortname}" == "dod" ] || [ "${shortname}" == "tfc" ] || [ "${shortname}" == "ns" ] || [ "${shortname}" == "ts" ] || [ "${shortname}" == "hldm" ] || [ "${shortname}" == "vh" ]; then +if [ "${engine}" == "source" ] || [ "${shortname}" == "cs2" ] || [ "${shortname}" == "rust" ] || [ "${shortname}" == "hq" ] || [ "${shortname}" == "sdtd" ] || [ "${shortname}" == "cs" ] || [ "${shortname}" == "dod" ] || [ "${shortname}" == "tfc" ] || [ "${shortname}" == "ns" ] || [ "${shortname}" == "ts" ] || [ "${shortname}" == "hldm" ] || [ "${shortname}" == "vh" ]; then currentopt+=("${cmd_mods_install[@]}" "${cmd_mods_remove[@]}" "${cmd_mods_update[@]}") fi diff --git a/lgsm/modules/mods_core.sh b/lgsm/modules/mods_core.sh index 3a14fcb84a..ac8f25a7b4 100755 --- a/lgsm/modules/mods_core.sh +++ b/lgsm/modules/mods_core.sh @@ -158,6 +158,11 @@ fn_mod_tidy_files_list() { sed -i "/^addons\/metamod\/sourcemod.vdf$/d" "${modsdir}/${modcommand}-files.txt" fi + # Keep Metamod:Source when removing CounterStrikeSharp, but remove its own VDF. + if [ "${modcommand}" == "counterstrikesharp" ]; then + sed -i "/^addons\/metamod$/d" "${modsdir}/${modcommand}-files.txt" + fi + # Remove common paths from deletion list (Add your sourcemod mod here) if [ "${modcommand}" == "gokz" ] || [ "${modcommand}" == "ttt" ] || [ "${modcommand}" == "steamworks" ] || [ "${modcommand}" == "get5" ]; then sed -i "/^addons\/sourcemod$/d" "${modsdir}/${modcommand}-files.txt" @@ -693,6 +698,66 @@ fn_mod_remove_liblist_gam_file() { fi } +# modifiers for gameinfo.gi to add/remove the Metamod:Source search path +# Counter-Strike 2 only: the csgo paths below are specific to that game. +fn_mod_install_gameinfo_gi_file() { + local gameinfofile="${modinstalldir}/gameinfo.gi" + local metamodpattern='^[[:space:]]*"?Game"?[[:space:]]+"?csgo/addons/metamod"?[[:space:]]*(//.*)?$' + local lowviolencepattern='^[[:space:]]*"?Game_LowViolence"?[[:space:]]+"?csgo_lv"?[[:space:]]*(//.*)?$' + + if [ -f "${gameinfofile}" ]; then + # the search path survives a mod update, only add it when it is missing + if grep -Eq "${metamodpattern}" "${gameinfofile}"; then + fn_script_log_info "Metamod:Source search path already set in ${gameinfofile}" + else + # insert the search path below Game_LowViolence as documented by Metamod:Source + logentry="line (Game csgo/addons/metamod) inserted into ${gameinfofile}" + echo -en "adding Metamod:Source search path in gameinfo.gi..." + sed -i -E "\\@${lowviolencepattern}@a\\\\t\\t\\tGame\\tcsgo/addons/metamod" "${gameinfofile}" + grep -Eq "${metamodpattern}" "${gameinfofile}" + exitcode=$? + # if the insert didn't happen, error out + if [ "${exitcode}" -ne 0 ]; then + fn_script_log_fail "${logentry}" + fn_print_fail_eol_nl + core_exit.sh + else + fn_script_log_pass "${logentry}" + fn_print_ok_eol_nl + fi + fi + else + fn_script_log_fail "Unable to find ${gameinfofile}" + fn_print_fail_nl "Unable to find ${gameinfofile}" + core_exit.sh + fi +} + +# Unlike the install counterpart this does not call core_exit.sh on failure: +# command_mods_remove.sh ends with fn_script_log, which leaves exitcode alone, +# while command_mods_install.sh ends with fn_script_log_pass, which resets it to 0. +fn_mod_remove_gameinfo_gi_file() { + local gameinfofile="${modinstalldir}/gameinfo.gi" + local metamodpattern='^[[:space:]]*"?Game"?[[:space:]]+"?csgo/addons/metamod"?[[:space:]]*(//.*)?$' + + if [ -f "${gameinfofile}" ]; then + # is the search path found? If so remove it and keep the rest of the file + if grep -Eq "${metamodpattern}" "${gameinfofile}"; then + logentry="line (Game csgo/addons/metamod) removed from ${gameinfofile}" + echo -en "removing Metamod:Source search path in gameinfo.gi..." + # delete the line we inserted + sed -i -E "\\@${metamodpattern}@d" "${gameinfofile}" + if grep -Eq "${metamodpattern}" "${gameinfofile}"; then + fn_script_log_fail "${logentry}" + fn_print_fail_eol_nl + else + fn_script_log_pass "${logentry}" + fn_print_ok_eol_nl + fi + fi + fi +} + fn_mod_install_amxmodx_file() { # does plugins.ini exist? if [ -f "${modinstalldir}/addons/metamod/plugins.ini" ]; then diff --git a/lgsm/modules/mods_list.sh b/lgsm/modules/mods_list.sh index 39eca5e429..94ac8fceda 100755 --- a/lgsm/modules/mods_list.sh +++ b/lgsm/modules/mods_list.sh @@ -60,6 +60,12 @@ metamodsourcescrapeurl="https://mms.alliedmods.net/mmsdrop/${metamodsourceversio metamodsourcelatestfile=$(wget "${metamodsourcescrapeurl}" -q -O -) metamodsourcedownloadurl="https://www.metamodsource.net/latest.php?os=linux&version=${metamodsourceversion}" metamodsourceurl="${metamodsourcedownloadurl}" +# Metamod:Source 2.0 +metamodsource2version="2.0" +metamodsource2scrapeurl="https://mms.alliedmods.net/mmsdrop/${metamodsource2version}/mmsource-latest-linux" +metamodsource2latestfile=$(wget "${metamodsource2scrapeurl}" -q -O -) +metamodsource2downloadurl="https://www.metamodsource.net/latest.php?os=linux&version=${metamodsource2version}" +metamodsource2url="${metamodsource2downloadurl}" # Sourcemod sourcemodversion="1.13" sourcemodscrapeurl="https://sm.alliedmods.net/smdrop/${sourcemodversion}/sourcemod-latest-linux" @@ -77,6 +83,12 @@ stripperlatestfile="stripper-${stripperversion}-linux.tar.gz" stripperdownloadurl="http://www.bailopan.net/stripper/snapshots/1.2/${stripperlatestfile}" stripperurl="${stripperdownloadurl}" +# CS2 Mods +counterstrikesharprelease=$(curl --connect-timeout 3 -sL https://api.github.com/repos/roflmuffin/CounterStrikeSharp/releases/latest) +counterstrikesharplastbuild=$(printf '%s\n' "${counterstrikesharprelease}" | jq '.assets[]? | select(.name | startswith("counterstrikesharp-with-runtime-linux-") and endswith(".zip"))' 2> /dev/null) +counterstrikesharplatestfile=$(printf '%s\n' "${counterstrikesharplastbuild}" | jq -r '.name') +counterstrikesharplatestlink=$(printf '%s\n' "${counterstrikesharplastbuild}" | jq -r '.browser_download_url') + # CS:GO Mods get5lastbuild=$(curl --connect-timeout 3 -sL https://api.github.com/repos/splewis/get5/releases/latest | jq '.assets[] |select(.browser_download_url | endswith(".tar.gz"))') get5latestfile=$(echo -e "${get5lastbuild}" | jq -r '.name') @@ -157,6 +169,10 @@ mod_info_sourcemod=(MOD "sourcemod" "SourceMod" "${sourcemodurl}" "${sourcemodla mod_info_steamworks=(MOD "steamworks" "SteamWorks" "${steamworksurl}" "${steamworkslatestfile}" "0" "LowercaseOff" "${systemdir}" "OVERWRITE" "ENGINES" "Counter-Strike: Global Offensive;" "NOTGAMES" "https://github.com/KyleSanderson/SteamWorks" "Exposing SteamWorks functions to SourcePawn") mod_info_stripper=(MOD "stripper" "Stripper Source" "${stripperurl}" "${stripperlatestfile}" "0" "LowercaseOff" "${systemdir}" "addons/stripper/maps;" "ENGINES" "Counter-Strike: Global Offensive;Counter-Strike: Source;Day of Defeat: Source;Half Life: Deathmatch;Half Life 2: Deathmatch;Insurgency;Left 4 Dead;Left 4 Dead 2;Nuclear Dawn;Team Fortress 2;" "NOTGAMES" "http://www.bailopan.net/stripper/" "Add or remove objects from map (requires MetaMod)") +# CS2 Mods +mod_info_metamodsource2=(MOD "metamodsource2" "Metamod:Source 2.0" "${metamodsource2url}" "${metamodsource2latestfile}" "0" "LowercaseOff" "${systemdir}" "addons/metamod/metaplugins.ini;" "ENGINES" "Counter-Strike 2;" "NOTGAMES" "https://www.metamodsource.net" "Plugins Framework (Dev Build)") +mod_info_counterstrikesharp=(MOD "counterstrikesharp" "CounterStrikeSharp" "${counterstrikesharplatestlink}" "${counterstrikesharplatestfile}" "0" "LowercaseOff" "${systemdir}" "OVERWRITE" "ENGINES" "Counter-Strike 2;" "NOTGAMES" "https://docs.cssharp.dev/" "Write server plugins in C# (requires Metamod:Source 2.0)") + # CS:GO Mods mod_info_gokz=(MOD "gokz" "GOKZ" "${gokzlatestlink}" "${gokzlatestfile}" "0" "LowercaseOff" "${systemdir}" "cfg;addons/sourcemod/configs;" "ENGINES" "Counter-Strike: Global Offensive;" "NOTGAMES" "https://github.com/KZGlobalTeam/gokz" "GOKZ ${gokzlatestversion} - Implements the KZ game mode (requires SourceMod and MetaMod)") mod_info_ttt=(MOD "ttt" "Trouble in Terrorist Town" "https://csgottt.com/downloads/ttt-latest-dev-${sourcemodversion}.zip" "ttt-latest.zip" "0" "LowercaseOff" "${systemdir}" "cfg;addons/sourcemod/configs;" "ENGINES" "Counter-Strike: Global Offensive;" "NOTGAMES" "https://github.com/Bara/TroubleinTerroristTown" "Implements the TTT game mode (requires SourceMod and MetaMod)") @@ -211,4 +227,4 @@ mod_info_valheimplus=(MOD "valheimplus" "Valheim PLUS" "${valheimpluslatestlink} mod_info_bepinexvh=(MOD "bepinexvh" "BepInEx Valheim" "${bepinexvhlatestlink}" "denikson-BepInExPack_Valheim.zip" "BepInExPack_Valheim" "LowercaseOff" "${systemdir}" "OVERWRITE" "ENGINES" "Valheim;" "NOTGAMES" "https://valheim.thunderstore.io/package/denikson/BepInExPack_Valheim/" "Unity / XNA game patcher and plugin framework") # REQUIRED: Set all mods info into the global array -mods_global_array=("${mod_info_metamod[@]}" "${mod_info_base_amxx[@]}" "${mod_info_cs_amxx[@]}" "${mod_info_dod_amxx[@]}" "${mod_info_tfc_amxx[@]}" "${mod_info_ns_amxx[@]}" "${mod_info_ts_amxx[@]}" "${mod_info_metamodsource[@]}" "${mod_info_sourcemod[@]}" "${mod_info_steamworks[@]}" "${mod_info_gokz[@]}" "${mod_info_ttt[@]}" "${mod_info_get5[@]}" "${mod_info_prac[@]}" "${mod_info_pug[@]}" "${mod_info_dhook[@]}" "${mod_info_movement[@]}" "${mod_info_cleaner[@]}" "${mod_info_ulib[@]}" "${mod_info_ulx[@]}" "${mod_info_utime[@]}" "${mod_info_uclip[@]}" "${mod_info_acf[@]}" "${mod_info_acf_missiles[@]}" "${mod_info_acf_sweps[@]}" "${mod_info_advdupe2[@]}" "${mod_info_pac3[@]}" "${mod_info_wiremod[@]}" "${mod_info_wiremodextras[@]}" "${mod_info_darkrp[@]}" "${mod_info_darkrpmodification[@]}" "${mod_info_rustcarbon[@]}" "${mod_info_rustoxide[@]}" "${mod_info_hwoxide[@]}" "${mod_info_sdtdoxide[@]}" "${mod_info_advduplicator[@]}" "${mod_info_trackassemblytool[@]}" "${mod_info_physpropertiesadv[@]}" "${mod_info_controlsystemse2[@]}" "${mod_info_e2pistontiming[@]}" "${mod_info_propcannontool[@]}" "${mod_info_gearassemblytool[@]}" "${mod_info_spinnertool[@]}" "${mod_info_surfacefrictiontool[@]}" "${mod_info_magneticdipole[@]}" "${mod_info_environmentorganizer[@]}" "${mod_info_precision_alignment[@]}" "${mod_info_improved_stacker[@]}" "${mod_info_improved_weight[@]}" "${mod_info_improved_antinoclip[@]}" "${mod_info_laserstool[@]}" "${mod_info_valheimplus[@]}" "${mod_info_bepinexvh[@]}") +mods_global_array=("${mod_info_metamod[@]}" "${mod_info_base_amxx[@]}" "${mod_info_cs_amxx[@]}" "${mod_info_dod_amxx[@]}" "${mod_info_tfc_amxx[@]}" "${mod_info_ns_amxx[@]}" "${mod_info_ts_amxx[@]}" "${mod_info_metamodsource[@]}" "${mod_info_metamodsource2[@]}" "${mod_info_counterstrikesharp[@]}" "${mod_info_sourcemod[@]}" "${mod_info_steamworks[@]}" "${mod_info_gokz[@]}" "${mod_info_ttt[@]}" "${mod_info_get5[@]}" "${mod_info_prac[@]}" "${mod_info_pug[@]}" "${mod_info_dhook[@]}" "${mod_info_movement[@]}" "${mod_info_cleaner[@]}" "${mod_info_ulib[@]}" "${mod_info_ulx[@]}" "${mod_info_utime[@]}" "${mod_info_uclip[@]}" "${mod_info_acf[@]}" "${mod_info_acf_missiles[@]}" "${mod_info_acf_sweps[@]}" "${mod_info_advdupe2[@]}" "${mod_info_pac3[@]}" "${mod_info_wiremod[@]}" "${mod_info_wiremodextras[@]}" "${mod_info_darkrp[@]}" "${mod_info_darkrpmodification[@]}" "${mod_info_rustcarbon[@]}" "${mod_info_rustoxide[@]}" "${mod_info_hwoxide[@]}" "${mod_info_sdtdoxide[@]}" "${mod_info_advduplicator[@]}" "${mod_info_trackassemblytool[@]}" "${mod_info_physpropertiesadv[@]}" "${mod_info_controlsystemse2[@]}" "${mod_info_e2pistontiming[@]}" "${mod_info_propcannontool[@]}" "${mod_info_gearassemblytool[@]}" "${mod_info_spinnertool[@]}" "${mod_info_surfacefrictiontool[@]}" "${mod_info_magneticdipole[@]}" "${mod_info_environmentorganizer[@]}" "${mod_info_precision_alignment[@]}" "${mod_info_improved_stacker[@]}" "${mod_info_improved_weight[@]}" "${mod_info_improved_antinoclip[@]}" "${mod_info_laserstool[@]}" "${mod_info_valheimplus[@]}" "${mod_info_bepinexvh[@]}") From fb03bd85bc8b84b3a1e7ab8e77f8da0716b99de3 Mon Sep 17 00:00:00 2001 From: Daniel Gibbs Date: Sat, 3 Oct 2026 21:53:21 +0100 Subject: [PATCH 015/164] fix(ci): label fork PRs and skip empty Details Check matrix (#4971) - pr-labeler ran on pull_request, which gets a read-only token for PRs from forks, so it failed on every contributor PR ("Could not add label(s)"). Run it on pull_request_target with job-scoped write permissions; no job checks out or runs PR code on that event. - details-check failed the whole run when create-matrix produced an empty matrix (PR touches no server configs). Skip the job instead. Co-authored-by: Claude Opus 5.5 --- .github/workflows/action-details-check.yml | 3 ++- .github/workflows/action-issue-triage-automation.yml | 10 ++++++++-- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/.github/workflows/action-details-check.yml b/.github/workflows/action-details-check.yml index f0e78a29d7..fc7e5e7e59 100644 --- a/.github/workflows/action-details-check.yml +++ b/.github/workflows/action-details-check.yml @@ -85,7 +85,8 @@ jobs: fi details-check: - if: github.repository_owner == 'GameServerManagers' + # Skip (rather than fail the run) when create-matrix found nothing to check. + if: github.repository_owner == 'GameServerManagers' && needs.create-matrix.outputs.matrix != '{"include":[]}' needs: create-matrix continue-on-error: true runs-on: ${{ matrix.runner }} diff --git a/.github/workflows/action-issue-triage-automation.yml b/.github/workflows/action-issue-triage-automation.yml index 1beb90d0ba..f98cb91055 100644 --- a/.github/workflows/action-issue-triage-automation.yml +++ b/.github/workflows/action-issue-triage-automation.yml @@ -43,7 +43,9 @@ on: - created - edited - deleted - pull_request: + # pull_request_target so pr-labeler can label PRs from forks (pull_request gets a read-only token for forks). + # Safe here: no job checks out or runs PR code on this event. + pull_request_target: types: - opened - edited @@ -2267,8 +2269,12 @@ jobs: } pr-labeler: - if: github.repository_owner == 'GameServerManagers' && github.event_name == 'pull_request' + if: github.repository_owner == 'GameServerManagers' && github.event_name == 'pull_request_target' runs-on: ubuntu-latest + permissions: + contents: read + issues: write + pull-requests: write steps: - name: PR Labeler uses: github/issue-labeler@v3.4 From 22f84b3d0c690255d6ec4f80d39e43ee76ce27be Mon Sep 17 00:00:00 2001 From: Attila <1230402+borzaka@users.noreply.github.com> Date: Sat, 3 Oct 2026 23:15:21 +0200 Subject: [PATCH 016/164] feat(csgoserver): support the standalone CS:GO client (App ID 4465480) with configurable clientappid and the NoLobbyReservation mod (#4963) * feat(csgoserver): support the standalone CS:GO client (App ID 4465480) with configurable runtimeappid and the NoLobbyReservation mod * feat(csgoserver): rename runtimeappid to clientappid, pin NoLobbyReservation, prefer spcomp64 - Rename runtimeappid to clientappid and reword the comments: appid is the SteamCMD download ID (740), clientappid is the App ID the server advertises and players' clients connect with (4465480 or 730). - Pin NoLobbyReservation to commit 003ab19f. It has no releases and is compiled from source on install, so do not follow master. - Prefer spcomp64 and fall back to spcomp, so compiling does not rely on i386 libraries. Co-Authored-By: Claude Opus 5.5 --------- Co-authored-by: Daniel Gibbs Co-authored-by: Claude Opus 5.5 --- .../config-lgsm/csgoserver/_default.cfg | 7 ++- lgsm/modules/command_mods_install.sh | 9 ++++ lgsm/modules/command_mods_update.sh | 4 ++ lgsm/modules/fix_csgo.sh | 25 ++++++++-- lgsm/modules/install_gslt.sh | 4 ++ lgsm/modules/mods_core.sh | 46 +++++++++++++++++-- lgsm/modules/mods_list.sh | 14 ++++-- 7 files changed, 99 insertions(+), 10 deletions(-) diff --git a/lgsm/config-default/config-lgsm/csgoserver/_default.cfg b/lgsm/config-default/config-lgsm/csgoserver/_default.cfg index a5887c0b05..d7d32cc025 100644 --- a/lgsm/config-default/config-lgsm/csgoserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/csgoserver/_default.cfg @@ -43,6 +43,7 @@ tickrate="64" ## Game Server Login Token (GSLT): Required # GSLT is required for running a public server. +# The GSLT must be created using the App ID set in clientappid (default 4465480). # More info: https://docs.linuxgsm.com/steamcmd/gslt gslt="" @@ -168,8 +169,12 @@ ansi="on" sleeptime="0.5" ## SteamCMD Settings | https://docs.linuxgsm.com/steamcmd -# Server appid +# App ID SteamCMD downloads the dedicated server files from. Do not change. appid="740" +# App ID the server advertises to players. Only clients of this App ID can connect, and the GSLT must be created for it. +# 4465480: standalone CS:GO | 730: CS2 csgo_legacy beta branch | "": leave steam_appid.txt and steam.inf unmanaged +# https://docs.linuxgsm.com/game-servers/counter-strike-global-offensive#client-app-id +clientappid="4465480" steamcmdforcewindows="no" # SteamCMD Branch | https://docs.linuxgsm.com/steamcmd/branch branch="" diff --git a/lgsm/modules/command_mods_install.sh b/lgsm/modules/command_mods_install.sh index 1a0f25119c..77dfd017e3 100755 --- a/lgsm/modules/command_mods_install.sh +++ b/lgsm/modules/command_mods_install.sh @@ -127,11 +127,20 @@ if [ "${modcommand}" == "amxmodxcs" ] \ fn_mod_exist "amxmodx" fi +# If nolobbyreservation check if sourcemod exists first as it is compiled using the SourceMod compiler +if [ "${modcommand}" == "nolobbyreservation" ]; then + fn_mod_exist "sourcemod" +fi + fn_create_mods_dir fn_mods_clear_tmp_dir fn_mods_create_tmp_dir fn_mod_install_files fn_mod_lowercase +# NoLobbyReservation is only distributed as source +if [ "${modcommand}" == "nolobbyreservation" ]; then + fn_mod_compile_sourcemod_plugin "nolobbyreservation" +fi fn_mod_create_filelist fn_mod_copy_destination fn_mod_add_list diff --git a/lgsm/modules/command_mods_update.sh b/lgsm/modules/command_mods_update.sh index 2d1eba650f..e84db47ad1 100755 --- a/lgsm/modules/command_mods_update.sh +++ b/lgsm/modules/command_mods_update.sh @@ -88,6 +88,10 @@ while [ "${installedmodsline}" -le "${installedmodscount}" ]; do fn_mod_install_files fn_mod_lowercase fn_remove_cfg_files + # NoLobbyReservation is only distributed as source + if [ "${modcommand}" == "nolobbyreservation" ]; then + fn_mod_compile_sourcemod_plugin "nolobbyreservation" + fi fn_mod_create_filelist fn_mod_copy_destination fn_mod_add_list diff --git a/lgsm/modules/fix_csgo.sh b/lgsm/modules/fix_csgo.sh index 8f5550ab53..979b470baf 100755 --- a/lgsm/modules/fix_csgo.sh +++ b/lgsm/modules/fix_csgo.sh @@ -7,11 +7,30 @@ moduleselfname="$(basename "$(readlink -f "${BASH_SOURCE[0]}")")" +# Server files are downloaded using App ID 740 (appid), but the App ID written to steam_appid.txt and steam.inf +# (clientappid) decides which client can connect: 4465480 for standalone CS:GO, 730 for the CS2 csgo_legacy branch. +# SteamCMD update/validate can revert these files, so this runs before every start. + # Fixes: server not always creating steam_appid.txt file. -if [ ! -f "${serverfiles}/steam_appid.txt" ]; then - fixname="730 steam_appid.txt" +# The server writes steam_appid.txt with a trailing null byte, which is removed before comparing. +if [ -n "${clientappid}" ] && { [ ! -f "${serverfiles}/steam_appid.txt" ] || [ "$(tr -d '\0' < "${serverfiles}/steam_appid.txt")" != "${clientappid}" ]; }; then + fixname="${clientappid} steam_appid.txt" + fn_fix_msg_start + if echo -n "${clientappid}" > "${serverfiles}/steam_appid.txt"; then + exitcode=0 + else + exitcode=1 + fi + fn_fix_msg_end +fi + +# Fixes: steam.inf not using the client App ID. +# steam.inf uses CRLF line endings, the whole value is replaced while keeping the line ending. +if [ -n "${clientappid}" ] && [ -f "${systemdir}/steam.inf" ] && grep -q "^appID=" "${systemdir}/steam.inf" && ! grep -qE "^appID=${clientappid}[[:cntrl:]]?$" "${systemdir}/steam.inf"; then + fixname="${clientappid} steam.inf" fn_fix_msg_start - echo -n "730" >> "${serverfiles}/steam_appid.txt" + sed -i "s/^appID=[^[:cntrl:]]*/appID=${clientappid}/" "${systemdir}/steam.inf" + exitcode=$? fn_fix_msg_end fi diff --git a/lgsm/modules/install_gslt.sh b/lgsm/modules/install_gslt.sh index e4e4dbad72..58ecdd216e 100755 --- a/lgsm/modules/install_gslt.sh +++ b/lgsm/modules/install_gslt.sh @@ -17,6 +17,10 @@ else echo -e "GSLT is an optional feature for ${gamename} server." fn_script_log_info "GSLT is an optional feature for ${gamename} server" fi +if [ "${shortname}" == "csgo" ] && [ -n "${clientappid}" ]; then + echo -e "The GSLT must be created using the App ID set in clientappid (${clientappid})." + fn_script_log_info "The GSLT must be created using the App ID set in clientappid (${clientappid})" +fi echo -e "" echo -e "More info: ${italic}https://docs.linuxgsm.com/steamcmd/gslt${default}" diff --git a/lgsm/modules/mods_core.sh b/lgsm/modules/mods_core.sh index ac8f25a7b4..daec8e367d 100755 --- a/lgsm/modules/mods_core.sh +++ b/lgsm/modules/mods_core.sh @@ -29,17 +29,54 @@ fn_mod_install_files() { mkdir -p "${extractdest}" fi fn_dl_extract "${modstmpdir}" "${modfilename}" "${extractdest}" - # If modsubdirs names a specific subfolder, use its contents as the install root. + # If modsubdirs names a specific subfolder (or path to one), use its contents as the install root. if [ "${modsubdirs}" != "0" ] && [ -d "${extractdest}/${modsubdirs}" ]; then local tmpsubdir tmpsubdir=$(mktemp -d) mv "${extractdest}/${modsubdirs}" "${tmpsubdir}/" rm -rf "${extractdest}" - mv "${tmpsubdir}/${modsubdirs}" "${extractdest}" + mv "${tmpsubdir}/$(basename "${modsubdirs}")" "${extractdest}" rm -rf "${tmpsubdir}" fi } +# Compile a SourceMod plugin that is only distributed as source, using the installed SourceMod compiler. +# The compiled plugin is added to the extracted mod files so it is installed, updated and removed with the mod. +fn_mod_compile_sourcemod_plugin() { + local pluginname="${1}" + local spcompdir="${modinstalldir}/addons/sourcemod/scripting" + # Prefer the 64-bit compiler; the 32-bit spcomp needs i386 libraries. + local spcomp="${spcompdir}/spcomp64" + if [ ! -x "${spcomp}" ]; then + spcomp="${spcompdir}/spcomp" + fi + echo -en "compiling ${pluginname}.sp..." + fn_sleep_time + if [ ! -x "${spcomp}" ]; then + fn_print_fail_eol_nl + fn_script_log_fail "Compiling ${pluginname}.sp: SourceMod compiler not found in ${spcompdir}" + echo -e "* SourceMod compiler not found in ${spcompdir}" + exitcode=1 + core_exit.sh + fi + mkdir -p "${extractdest}/addons/sourcemod/plugins" + spcompoutput=$("${spcomp}" -i"${spcompdir}/include" "${extractdest}/addons/sourcemod/scripting/${pluginname}.sp" -o"${extractdest}/addons/sourcemod/plugins/${pluginname}.smx" 2>&1) + exitcode=$? + if [ "${exitcode}" -ne 0 ] || [ ! -s "${extractdest}/addons/sourcemod/plugins/${pluginname}.smx" ]; then + fn_print_fail_eol_nl + fn_script_log_fail "Compiling ${pluginname}.sp" + if [ -f "${lgsmlog}" ]; then + echo -e "${spcompoutput}" >> "${lgsmlog}" + fi + echo -e "${spcompoutput}" + exitcode=1 + core_exit.sh + else + fn_print_ok_eol_nl + fn_script_log_pass "Compiling ${pluginname}.sp" + fi +} + # Convert mod files to lowercase if needed. fn_mod_lowercase() { # Checking lowercase settings from mods array definition @@ -164,7 +201,7 @@ fn_mod_tidy_files_list() { fi # Remove common paths from deletion list (Add your sourcemod mod here) - if [ "${modcommand}" == "gokz" ] || [ "${modcommand}" == "ttt" ] || [ "${modcommand}" == "steamworks" ] || [ "${modcommand}" == "get5" ]; then + if [ "${modcommand}" == "gokz" ] || [ "${modcommand}" == "ttt" ] || [ "${modcommand}" == "steamworks" ] || [ "${modcommand}" == "get5" ] || [ "${modcommand}" == "nolobbyreservation" ]; then sed -i "/^addons\/sourcemod$/d" "${modsdir}/${modcommand}-files.txt" sed -i "/^addons\/sourcemod\/configs$/d" "${modsdir}/${modcommand}-files.txt" sed -i "/^addons\/sourcemod\/extensions$/d" "${modsdir}/${modcommand}-files.txt" @@ -202,6 +239,9 @@ fn_mod_tidy_files_list() { sed -i "/^addons\/sourcemod\/scripting\/include\/dhooks.inc$/d" "${modsdir}/${modcommand}-files.txt" sed -i "/^addons\/sourcemod\/scripting\/include\/updater.inc$/d" "${modsdir}/${modcommand}-files.txt" fi + if [ "${modcommand}" == "nolobbyreservation" ]; then + sed -i "/^addons\/sourcemod\/gamedata$/d" "${modsdir}/${modcommand}-files.txt" + fi } ## Information Gathering. diff --git a/lgsm/modules/mods_list.sh b/lgsm/modules/mods_list.sh index 94ac8fceda..06a3e6e177 100755 --- a/lgsm/modules/mods_list.sh +++ b/lgsm/modules/mods_list.sh @@ -67,7 +67,12 @@ metamodsource2latestfile=$(wget "${metamodsource2scrapeurl}" -q -O -) metamodsource2downloadurl="https://www.metamodsource.net/latest.php?os=linux&version=${metamodsource2version}" metamodsource2url="${metamodsource2downloadurl}" # Sourcemod -sourcemodversion="1.13" +# Use the compatible stable SourceMod branch for Counter-Strike: Global Offensive. +if [ "${shortname}" == "csgo" ]; then + sourcemodversion="1.12" +else + sourcemodversion="1.13" +fi sourcemodscrapeurl="https://sm.alliedmods.net/smdrop/${sourcemodversion}/sourcemod-latest-linux" sourcemodlatestfile=$(wget "${sourcemodscrapeurl}" -q -O -) sourcemoddownloadurl="https://www.sourcemod.net/latest.php?os=linux&version=${sourcemodversion}" @@ -134,7 +139,7 @@ modseparator="MOD" # [2] | "Pretty Name": the common name people use to call the mod that will be displayed to the user # [3] | "URL": link to the mod archive file; can be a variable previously defined while scraping a URL # [4] | "filename": the output filename -# [5] | "modsubdirs": name of a subfolder within the archive to extract as the install root (use "0" to extract all contents) +# [5] | "modsubdirs": name of (or path to) a subfolder within the archive to extract as the install root (use "0" to extract all contents) # [6] | "LowercaseOn/Off": LowercaseOff or LowercaseOn: enable/disable converting extracted files and directories to lowercase (some games require it) # [7] | "modinstalldir": the directory in which to install the mode (use LGSM dir variables such as ${systemdir}) # [8] | "/files/to/keep;", files & directories that should not be overwritten upon update, separated and ended with a semicolon; you can also use "OVERWRITE" value to ignore the value or "NOUPDATE" to disallow updating; for files to keep upon uninstall, see fn_mod_tidy_files_list from mods_core.sh @@ -174,6 +179,9 @@ mod_info_metamodsource2=(MOD "metamodsource2" "Metamod:Source 2.0" "${metamodsou mod_info_counterstrikesharp=(MOD "counterstrikesharp" "CounterStrikeSharp" "${counterstrikesharplatestlink}" "${counterstrikesharplatestfile}" "0" "LowercaseOff" "${systemdir}" "OVERWRITE" "ENGINES" "Counter-Strike 2;" "NOTGAMES" "https://docs.cssharp.dev/" "Write server plugins in C# (requires Metamod:Source 2.0)") # CS:GO Mods +# NoLobbyReservation is pinned to a reviewed commit: it has no releases and is compiled from source on install. +nolobbyreservationcommit="003ab19fcf5e6eb67d21794218a4dc387d2923ca" +mod_info_nolobbyreservation=(MOD "nolobbyreservation" "NoLobbyReservation" "https://github.com/eldoradoel/NoLobbyReservation/archive/${nolobbyreservationcommit}.zip" "NoLobbyReservation-${nolobbyreservationcommit}.zip" "NoLobbyReservation-${nolobbyreservationcommit}/csgo" "LowercaseOff" "${systemdir}" "OVERWRITE" "ENGINES" "Counter-Strike: Global Offensive;" "NOTGAMES" "https://github.com/eldoradoel/NoLobbyReservation" "Allows players to connect without a Steam lobby reservation - Required for standalone CS:GO clients to connect (requires SourceMod and MetaMod)") mod_info_gokz=(MOD "gokz" "GOKZ" "${gokzlatestlink}" "${gokzlatestfile}" "0" "LowercaseOff" "${systemdir}" "cfg;addons/sourcemod/configs;" "ENGINES" "Counter-Strike: Global Offensive;" "NOTGAMES" "https://github.com/KZGlobalTeam/gokz" "GOKZ ${gokzlatestversion} - Implements the KZ game mode (requires SourceMod and MetaMod)") mod_info_ttt=(MOD "ttt" "Trouble in Terrorist Town" "https://csgottt.com/downloads/ttt-latest-dev-${sourcemodversion}.zip" "ttt-latest.zip" "0" "LowercaseOff" "${systemdir}" "cfg;addons/sourcemod/configs;" "ENGINES" "Counter-Strike: Global Offensive;" "NOTGAMES" "https://github.com/Bara/TroubleinTerroristTown" "Implements the TTT game mode (requires SourceMod and MetaMod)") mod_info_get5=(MOD "get5" "Get 5" "${get5latestfilelink}" "${get5latestfile}" "0" "LowercaseOff" "${systemdir}" "cfg;addons/sourcemod/configs;" "ENGINES" "Counter-Strike: Global Offensive;" "NOTGAMES" "https://github.com/splewis/get5" "Plugin for competitive matches/scrims (requires SourceMod and MetaMod)") @@ -227,4 +235,4 @@ mod_info_valheimplus=(MOD "valheimplus" "Valheim PLUS" "${valheimpluslatestlink} mod_info_bepinexvh=(MOD "bepinexvh" "BepInEx Valheim" "${bepinexvhlatestlink}" "denikson-BepInExPack_Valheim.zip" "BepInExPack_Valheim" "LowercaseOff" "${systemdir}" "OVERWRITE" "ENGINES" "Valheim;" "NOTGAMES" "https://valheim.thunderstore.io/package/denikson/BepInExPack_Valheim/" "Unity / XNA game patcher and plugin framework") # REQUIRED: Set all mods info into the global array -mods_global_array=("${mod_info_metamod[@]}" "${mod_info_base_amxx[@]}" "${mod_info_cs_amxx[@]}" "${mod_info_dod_amxx[@]}" "${mod_info_tfc_amxx[@]}" "${mod_info_ns_amxx[@]}" "${mod_info_ts_amxx[@]}" "${mod_info_metamodsource[@]}" "${mod_info_metamodsource2[@]}" "${mod_info_counterstrikesharp[@]}" "${mod_info_sourcemod[@]}" "${mod_info_steamworks[@]}" "${mod_info_gokz[@]}" "${mod_info_ttt[@]}" "${mod_info_get5[@]}" "${mod_info_prac[@]}" "${mod_info_pug[@]}" "${mod_info_dhook[@]}" "${mod_info_movement[@]}" "${mod_info_cleaner[@]}" "${mod_info_ulib[@]}" "${mod_info_ulx[@]}" "${mod_info_utime[@]}" "${mod_info_uclip[@]}" "${mod_info_acf[@]}" "${mod_info_acf_missiles[@]}" "${mod_info_acf_sweps[@]}" "${mod_info_advdupe2[@]}" "${mod_info_pac3[@]}" "${mod_info_wiremod[@]}" "${mod_info_wiremodextras[@]}" "${mod_info_darkrp[@]}" "${mod_info_darkrpmodification[@]}" "${mod_info_rustcarbon[@]}" "${mod_info_rustoxide[@]}" "${mod_info_hwoxide[@]}" "${mod_info_sdtdoxide[@]}" "${mod_info_advduplicator[@]}" "${mod_info_trackassemblytool[@]}" "${mod_info_physpropertiesadv[@]}" "${mod_info_controlsystemse2[@]}" "${mod_info_e2pistontiming[@]}" "${mod_info_propcannontool[@]}" "${mod_info_gearassemblytool[@]}" "${mod_info_spinnertool[@]}" "${mod_info_surfacefrictiontool[@]}" "${mod_info_magneticdipole[@]}" "${mod_info_environmentorganizer[@]}" "${mod_info_precision_alignment[@]}" "${mod_info_improved_stacker[@]}" "${mod_info_improved_weight[@]}" "${mod_info_improved_antinoclip[@]}" "${mod_info_laserstool[@]}" "${mod_info_valheimplus[@]}" "${mod_info_bepinexvh[@]}") +mods_global_array=("${mod_info_metamod[@]}" "${mod_info_base_amxx[@]}" "${mod_info_cs_amxx[@]}" "${mod_info_dod_amxx[@]}" "${mod_info_tfc_amxx[@]}" "${mod_info_ns_amxx[@]}" "${mod_info_ts_amxx[@]}" "${mod_info_metamodsource[@]}" "${mod_info_metamodsource2[@]}" "${mod_info_counterstrikesharp[@]}" "${mod_info_sourcemod[@]}" "${mod_info_nolobbyreservation[@]}" "${mod_info_steamworks[@]}" "${mod_info_gokz[@]}" "${mod_info_ttt[@]}" "${mod_info_get5[@]}" "${mod_info_prac[@]}" "${mod_info_pug[@]}" "${mod_info_dhook[@]}" "${mod_info_movement[@]}" "${mod_info_cleaner[@]}" "${mod_info_ulib[@]}" "${mod_info_ulx[@]}" "${mod_info_utime[@]}" "${mod_info_uclip[@]}" "${mod_info_acf[@]}" "${mod_info_acf_missiles[@]}" "${mod_info_acf_sweps[@]}" "${mod_info_advdupe2[@]}" "${mod_info_pac3[@]}" "${mod_info_wiremod[@]}" "${mod_info_wiremodextras[@]}" "${mod_info_darkrp[@]}" "${mod_info_darkrpmodification[@]}" "${mod_info_rustcarbon[@]}" "${mod_info_rustoxide[@]}" "${mod_info_hwoxide[@]}" "${mod_info_sdtdoxide[@]}" "${mod_info_advduplicator[@]}" "${mod_info_trackassemblytool[@]}" "${mod_info_physpropertiesadv[@]}" "${mod_info_controlsystemse2[@]}" "${mod_info_e2pistontiming[@]}" "${mod_info_propcannontool[@]}" "${mod_info_gearassemblytool[@]}" "${mod_info_spinnertool[@]}" "${mod_info_surfacefrictiontool[@]}" "${mod_info_magneticdipole[@]}" "${mod_info_environmentorganizer[@]}" "${mod_info_precision_alignment[@]}" "${mod_info_improved_stacker[@]}" "${mod_info_improved_weight[@]}" "${mod_info_improved_antinoclip[@]}" "${mod_info_laserstool[@]}" "${mod_info_valheimplus[@]}" "${mod_info_bepinexvh[@]}") From c3eb623528f7bd75110490e004b429111f822c56 Mon Sep 17 00:00:00 2001 From: Josh Saterdalen Date: Sat, 3 Oct 2026 17:58:37 -0500 Subject: [PATCH 017/164] feat(rsdwserver): add RuneScape: Dragonwilds server (#4921) * feat(rsdwserver): add RuneScape: Dragonwilds server * fix(rsdwserver): correct servercfgdir to LinuxServer * feat(rsdwserver): show world name, owner id, and ini path in details * fix(rsdwserver): point port edit guidance to start parameters The rsdw port is set via -Port=${port} in startparameters, not in DedicatedServer.ini, so move rsdw to the start parameters list. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_012svZAWTbYDdo2WuT2BZxQo * feat(rsdwserver): add distro dependency entries and OwnerId guidance - Add rsdw to every distro dependency CSV; without it the Server List Validation check fails once merged. No extra packages are needed, like other Unreal servers. - Add Owner ID to dev-parse-game-details, as info_game.sh requires for new variables. - State in _default.cfg that the server does not finish starting until OwnerId is set in DedicatedServer.ini, and drop the unused servername setting (the server reads its name from DedicatedServer.ini). Co-Authored-By: Claude Opus 5.5 * feat(rsdwserver): add game icon 32x32 RGB PNG from the Steam community app icon for RuneScape: Dragonwilds (app 1374490), matching the other game icons. Required by serverlist-validate-game-icons.sh. Co-Authored-By: Claude Opus 5.5 --------- Co-authored-by: Claude Co-authored-by: Daniel Gibbs --- .../config-lgsm/rsdwserver/_default.cfg | 198 ++++++++++++++++++ lgsm/data/almalinux-8.csv | 1 + lgsm/data/almalinux-9.csv | 1 + lgsm/data/centos-7.csv | 1 + lgsm/data/centos-8.csv | 1 + lgsm/data/centos-9.csv | 1 + lgsm/data/debian-10.csv | 1 + lgsm/data/debian-11.csv | 1 + lgsm/data/debian-12.csv | 1 + lgsm/data/debian-13.csv | 1 + lgsm/data/debian-9.csv | 1 + lgsm/data/gameicons/rsdw-icon.png | Bin 0 -> 2092 bytes lgsm/data/rhel-7.csv | 1 + lgsm/data/rhel-8.csv | 1 + lgsm/data/rhel-9.csv | 1 + lgsm/data/rocky-8.csv | 1 + lgsm/data/rocky-9.csv | 1 + lgsm/data/serverlist.csv | 1 + lgsm/data/ubuntu-16.04.csv | 1 + lgsm/data/ubuntu-18.04.csv | 1 + lgsm/data/ubuntu-20.04.csv | 1 + lgsm/data/ubuntu-22.04.csv | 1 + lgsm/data/ubuntu-23.04.csv | 1 + lgsm/data/ubuntu-23.10.csv | 1 + lgsm/data/ubuntu-24.04.csv | 1 + lgsm/data/ubuntu-26.04.csv | 1 + lgsm/modules/check_system_requirements.sh | 2 + .../modules/command_dev_parse_game_details.sh | 1 + lgsm/modules/info_game.sh | 24 +++ lgsm/modules/info_messages.sh | 18 +- 30 files changed, 266 insertions(+), 1 deletion(-) create mode 100644 lgsm/config-default/config-lgsm/rsdwserver/_default.cfg create mode 100644 lgsm/data/gameicons/rsdw-icon.png diff --git a/lgsm/config-default/config-lgsm/rsdwserver/_default.cfg b/lgsm/config-default/config-lgsm/rsdwserver/_default.cfg new file mode 100644 index 0000000000..b029431e3c --- /dev/null +++ b/lgsm/config-default/config-lgsm/rsdwserver/_default.cfg @@ -0,0 +1,198 @@ +################################## +######## Default Settings ######## +################################## +# DO NOT EDIT, ANY CHANGES WILL BE OVERWRITTEN! +# Copy settings from here and use them in either: +# common.cfg - applies settings to every instance. +# [instance].cfg - applies settings to a specific instance. + +#### Game Server Settings #### + +## Predefined Parameters | https://docs.linuxgsm.com/configuration/start-parameters +# Server name, passwords, owner ID and world name are read by the server from DedicatedServer.ini, not set here. +# Edit them in: serverfiles/RSDragonwilds/Saved/Config/LinuxServer/DedicatedServer.ini +# REQUIRED: the server will not finish starting until OwnerId is set in DedicatedServer.ini +# (your Player ID, shown in the in-game settings). DedicatedServer.ini is created on first start. +port="7777" + +## Server Parameters | https://docs.linuxgsm.com/configuration/start-parameters#additional-parameters +## Game Server Docs | https://dragonwilds.runescape.wiki/w/Dedicated_Servers +startparameters="-Port=${port} -log" + +#### LinuxGSM Settings #### + +## LinuxGSM Stats +# Send useful stats to LinuxGSM developers. +# https://docs.linuxgsm.com/configuration/linuxgsm-stats +# (on|off) +stats="off" + +## Notification Alerts +# (on|off) + +# Display IP | https://docs.linuxgsm.com/alerts#display-ip +displayip="" + +# More info | https://docs.linuxgsm.com/alerts#more-info +postalert="off" + +# Alert on Start/Stop/Restart +statusalert="off" + +# Discord Alerts | https://docs.linuxgsm.com/alerts/discord +discordalert="off" +discordwebhook="webhook" + +# Email Alerts | https://docs.linuxgsm.com/alerts/email +emailalert="off" +email="email@example.com" +emailfrom="" + +# Gotify Alerts | https://docs.linuxgsm.com/alerts/gotify +gotifyalert="off" +gotifytoken="token" +gotifywebhook="webhook" + +# IFTTT Alerts | https://docs.linuxgsm.com/alerts/ifttt +iftttalert="off" +ifttttoken="accesstoken" +iftttevent="linuxgsm_alert" + +# ntfy Alerts | https://docs.linuxgsm.com/alerts/ntfy +ntfyalert="off" +ntfytopic="LinuxGSM" +ntfyserver="https://ntfy.sh" +ntfytoken="" +ntfyusername="" +ntfypassword="" +ntfypriority="" +ntfytags="" + +# Pushbullet Alerts | https://docs.linuxgsm.com/alerts/pushbullet +pushbulletalert="off" +pushbullettoken="accesstoken" +channeltag="" + +# Pushover Alerts | https://docs.linuxgsm.com/alerts/pushover +pushoveralert="off" +pushovertoken="accesstoken" +pushoveruserkey="userkey" + +# Rocket.Chat Alerts | https://docs.linuxgsm.com/alerts/rocket.chat +rocketchatalert="off" +rocketchatwebhook="webhook" + +# Slack Alerts | https://docs.linuxgsm.com/alerts/slack +slackalert="off" +slackwebhook="webhook" + +# Telegram Alerts | https://docs.linuxgsm.com/alerts/telegram +# You can add a custom cURL string eg proxy (useful in Russia) in "curlcustomstring". +# For example "--socks5 ipaddr:port" for socks5 proxy see more in "curl --help all". +telegramapi="api.telegram.org" +telegramalert="off" +telegramtoken="accesstoken" +telegramchatid="" +telegramthreadid="" +telegramsilentnotification="false" +curlcustomstring="" + +## Updating | https://docs.linuxgsm.com/commands/update +updateonstart="off" + +## Backup | https://docs.linuxgsm.com/commands/backup +maxbackups="4" +maxbackupdays="30" +stoponbackup="on" + +## Logging | https://docs.linuxgsm.com/features/logging +consolelogging="on" +logdays="7" + +## Monitor | https://docs.linuxgsm.com/commands/monitor +# Query delay time +querydelay="5" + +## ANSI Colors | https://docs.linuxgsm.com/features/ansi-colors +ansi="on" + +#### Advanced Settings #### + +## Message Display Time | https://docs.linuxgsm.com/features/message-display-time +sleeptime="0.5" + +## SteamCMD Settings | https://docs.linuxgsm.com/steamcmd +# Server appid +appid="4019830" +steamcmdforcewindows="no" +# SteamCMD Branch | https://docs.linuxgsm.com/steamcmd/branch +branch="" +betapassword="" +# Master Server | https://docs.linuxgsm.com/steamcmd/steam-master-server +steammaster="false" + +## Stop Mode | https://docs.linuxgsm.com/features/stop-mode +# 1: tmux kill +# 2: CTRL+c +# 3: quit +# 4: quit 120s +# 5: stop +# 6: q +# 7: exit +# 8: 7 Days to Die +# 9: GoldSrc +# 10: Avorion +# 11: end +stopmode="2" + +## Query mode +# 1: session only +# 2: gamedig (gsquery fallback) +# 3: gamedig +# 4: gsquery +# 5: tcp +querymode="1" +querytype="" + +## Console type +consoleverbose="yes" +consoleinteract="no" + +## Game Server Details +# Do not edit +gamename="RuneScape: Dragonwilds" +engine="unreal5" +glibc="2.17" + +#### Directories #### +# Edit with care + +## Game Server Directories +systemdir="${serverfiles}/RSDragonwilds" +executabledir="${systemdir}/Binaries/Linux" +executable="./RSDragonwildsServer-Linux-Shipping" +servercfgdir="${systemdir}/Saved/Config/LinuxServer" +servercfg="DedicatedServer.ini" +servercfgdefault="DedicatedServer.ini" +servercfgfullpath="${servercfgdir}/${servercfg}" + +## Backup Directory +backupdir="${lgsmdir}/backup" + +## Logging Directories +[ -n "${LGSM_LOGDIR}" ] && logdir="${LGSM_LOGDIR}" || logdir="${rootdir}/log" +gamelogdir="${systemdir}/Saved/Logs" +lgsmlogdir="${logdir}/script" +consolelogdir="${logdir}/console" +lgsmlog="${lgsmlogdir}/${selfname}-script.log" +consolelog="${consolelogdir}/${selfname}-console.log" +alertlog="${lgsmlogdir}/${selfname}-alert.log" +postdetailslog="${lgsmlogdir}/${selfname}-postdetails.log" + +## Logs Naming +lgsmlogdate="${lgsmlogdir}/${selfname}-script-$(date '+%Y-%m-%d-%H:%M:%S').log" +consolelogdate="${consolelogdir}/${selfname}-console-$(date '+%Y-%m-%d-%H:%M:%S').log" + +## Log Parameters +logtimestamp="off" +logtimestampformat="%Y-%m-%d %H:%M:%S" diff --git a/lgsm/data/almalinux-8.csv b/lgsm/data/almalinux-8.csv index e02ca7858f..b9fde6b024 100644 --- a/lgsm/data/almalinux-8.csv +++ b/lgsm/data/almalinux-8.csv @@ -95,6 +95,7 @@ ql qw ricochet ro +rsdw rtcw rust,zlib-devel rw,java-11-openjdk diff --git a/lgsm/data/almalinux-9.csv b/lgsm/data/almalinux-9.csv index 5a6d996e76..40cea229c8 100644 --- a/lgsm/data/almalinux-9.csv +++ b/lgsm/data/almalinux-9.csv @@ -95,6 +95,7 @@ ql qw ricochet ro +rsdw rtcw rust,zlib-devel rw,java-21-openjdk diff --git a/lgsm/data/centos-7.csv b/lgsm/data/centos-7.csv index c5632722e1..6c67268e38 100644 --- a/lgsm/data/centos-7.csv +++ b/lgsm/data/centos-7.csv @@ -95,6 +95,7 @@ ql qw ricochet ro +rsdw rtcw rust,zlib-devel rw,java-11-openjdk diff --git a/lgsm/data/centos-8.csv b/lgsm/data/centos-8.csv index 0b0b766d04..ba2874629f 100644 --- a/lgsm/data/centos-8.csv +++ b/lgsm/data/centos-8.csv @@ -95,6 +95,7 @@ ql qw ricochet ro +rsdw rtcw rust,zlib-devel rw,java-11-openjdk diff --git a/lgsm/data/centos-9.csv b/lgsm/data/centos-9.csv index fd9c0fa39e..575c28ab62 100644 --- a/lgsm/data/centos-9.csv +++ b/lgsm/data/centos-9.csv @@ -95,6 +95,7 @@ ql qw ricochet ro +rsdw rtcw rust,zlib-devel rw,java-21-openjdk diff --git a/lgsm/data/debian-10.csv b/lgsm/data/debian-10.csv index 5b8d73a06a..7ebf3ec373 100644 --- a/lgsm/data/debian-10.csv +++ b/lgsm/data/debian-10.csv @@ -95,6 +95,7 @@ ql qw ricochet ro +rsdw rtcw rust,lib32z1 rw,openjdk-11-jre diff --git a/lgsm/data/debian-11.csv b/lgsm/data/debian-11.csv index adba97d278..eea8e2b7c7 100644 --- a/lgsm/data/debian-11.csv +++ b/lgsm/data/debian-11.csv @@ -96,6 +96,7 @@ ql qw ricochet ro +rsdw rtcw rust,lib32z1 rw,openjdk-17-jre diff --git a/lgsm/data/debian-12.csv b/lgsm/data/debian-12.csv index 40e325b6c3..55bf6b02cf 100644 --- a/lgsm/data/debian-12.csv +++ b/lgsm/data/debian-12.csv @@ -96,6 +96,7 @@ ql qw ricochet ro +rsdw rtcw rust,lib32z1 rw,openjdk-17-jre diff --git a/lgsm/data/debian-13.csv b/lgsm/data/debian-13.csv index 94c6cf1ae8..7f818d87c0 100644 --- a/lgsm/data/debian-13.csv +++ b/lgsm/data/debian-13.csv @@ -96,6 +96,7 @@ ql qw ricochet ro +rsdw rtcw rust,lib32z1 rw,openjdk-25-jre diff --git a/lgsm/data/debian-9.csv b/lgsm/data/debian-9.csv index c0e990961f..b3b81b3c46 100644 --- a/lgsm/data/debian-9.csv +++ b/lgsm/data/debian-9.csv @@ -96,6 +96,7 @@ ql qw ricochet ro +rsdw rtcw rust,lib32z1 rw,openjdk-8-jre diff --git a/lgsm/data/gameicons/rsdw-icon.png b/lgsm/data/gameicons/rsdw-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..0a15bc3ed0cb118103f4601b775376e031160e40 GIT binary patch literal 2092 zcmV+{2-Ek8P)`J z9+Z8{$;pCs4g|0WBBIgVao_jQnE@CS6d|;At_oJyhAA~$TWxQoq0nq;UemT9SW7~c zm}w0+!36>L0xzNqpg7=)DJVn$Dn&h4702(o1jU;O9u zZ~XGD`I0u!BvMYeJE&vc#n?SsV1Nn)+5#(-0@hZr%)8!s=Fv|*_P_%V6cMDItc_z? z?M!dQs1n0dPd)w3Z+`oUA3immV@@(!Cqv$EoC-7?bZHPIk^^1}g%IHn|KMYP@<*RP zee!f_>VCgiS*hB3K3m*cpG;J3Ih~(6b?T$%&re39XD&V2);Q#Yj&u|PxKI|fUWOql zM{1#6?NcdV`SS07;QbHJchX<}#f81SX_J@36+LqFwsYssoxb-sPn@_X=Ui6(Hk%n2 zzyI%F{L)u8_Xv?i>XL{ch(xRfO(`j6+6G~Z@c}gU;XpLhYt_d*XDbB=g&WU>GIQGyYP?87J)!Ca2$8V0CP+sVEvLK zhxqM}{nnxN(QLZ?;)_?dw&qQPWo}K`+~xWWu3VYF{L3Idktl$L>1nwy@l6Y;2h0g2OCx{BAz~$B)Fw#`UzA zw_p0xKil2j!%|MmW5@4!?}P6d^kP3oayPq%ns(hJ5YVcK5#IOE{o+lwx-8=>ue{PE zW=;*gf=@sCncw;NCr+Fkk1BTexN&3q!i5WF3Cot2A9>_MA&9DGvSKQZqh;*EH!#eH z{qmh>?{#Zt)7|-EZ)~A^vL+eZaW&Vx*D!t-FWMb*HT{W?rg4(C;h4ywaA{$DGH)P20=1S0ZMDRZRU$v zy%>*%ZQ~gf%h_(;oYu9NH93U0cBTW3vw7=o%be3JYMAcrq}oI(Aryr*iH--_ z(mFW?_V#wFqPM-hJH0g*6LE$GhPCZt!YK&zNfVI_e5oJEzRbf6~ zszlEU+P2;8DFQg2a1Ctjr1_$q&+1-p*tTgr7Rw9@1m?GHVvChQ`TVobmZ~{5$th!~ zs%p7hrj$1~x90QOgp7f7$m>|L&zua)h8M29-0Q8*rmaxC@1ghNR1tyM&f;&r@%76; zee#(nf4rPG$x;Pp-f?=^8^%x#2BS-tf1Zq#l3`KHg9&r*sAOat$Jw)Imy5TPD9KT4$vYNI_`kW0qeU}*KBOOdhPYAWxpJ+t-9mLa5Pb^7IiX- z$@tlG|M6FU`*;6x@rfJT82hj^)ahiGBQ8)uMv_2)aKO4j)HYd!!|VLU(b19HZaZ}7 z$jWFk9*y>bl^%xtp`m8--b&mn|k3xF5iUgHcmPPJ=d`S2yq|1jU3_p;rcoSfEiMPp%E zz0=tWSXY??P>ngxAp93B WDGG`Z19TDq0000 Date: Sun, 4 Oct 2026 00:02:34 +0100 Subject: [PATCH 018/164] fix(sm): convert sm-icon.png from JPEG to PNG (#4973) sm-icon.png was JPEG data with a .png extension; every other game icon is a 32x32 RGB PNG. Re-encoded as PNG with no visual change. Co-authored-by: Claude Opus 5.5 --- lgsm/data/gameicons/sm-icon.png | Bin 764 -> 2460 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/lgsm/data/gameicons/sm-icon.png b/lgsm/data/gameicons/sm-icon.png index 7948e002d650275f90ef0ef1ea5db87b14bbdb2c..70eb766c9898444f4bda5d3412aaa52819a2eb2c 100644 GIT binary patch literal 2460 zcmV;N31jw&P)By&6$kL|nVH{q@AZ<{&P_-hJBbOg69b7zLKB51K*JJ?L=Ny4l_3}PXr zR8mR-z;l!_hAfmINw5~Mt1*srj5V(7X`=x^3J?JhLMR~w3ARkIY*`A$%m6_s5MV8{ zF_sN1r~M#F;!KbxkT%8N`lz3f`yQ< z25}6sAOYV68#n?{gnB(9Kmdip(s#deKY+Avv)SzRp$Xqb7=r{DU=2qA!dgqlFd*2n z1zAAAI)VbD1z89IVG)He38Dx)Zd?2KV+Yr*g|Cou@#wL8ii;CED(~O7JKIiS2mm{G zZ0PQ65dbl)28@+}A^>b*0Vp6Ks{jGSY2U5aYZAzIsNHw;ty|anqaQr4lZ8_!hhO;K zq1H91RA!Sz1wQrlZmpaj>+8RzuW#4n)J)(zb2k@DWmtd#As`JIK$4U|;5(i+v4D{< zmU(Rpjz99?OF#eV^u)-AAD({pnI}g_KVB*>+_wGJ$%%=%B7LBXNRiQ>BEN(kBp4xatpin?D*^JALSPok~q0|xp41& zJ3HFjW@cvk`*#jr9X$QPuQpTw3OBJ(+_C4o-|uwzf2#_}hEehKdhA z(EHRAkF|AlOwZiRFBGCUG;B%8SSLgZ!opE__L(E4LVkQ?#FL_X^OoN2JK~5xIDKwx zym;U%cQ-Y!`Qr1d6S?UG*l}B1*XB)`l>7OG3)zk}{X2K1QmLzhLv#5;zEE4YVPh>c zH^%1}AR#D7BMy;C&RrVSU^WR<`-cJ=?sLz<4-)EFVx?7 z0mmw5bB1{l73;+QYCe}e($%r`=gw2~W+qZ8PFs0Js`t|D% z9y}DYb-mQfufAqL-+26y-~R3|*=**%uO8aIZF6hd6&zo={Q2B$uBoYME?+1v*T0;s zGo!i5DOD1~P(Y%Qu+h8vvM>GYg}e6jwq%^wUwh^H;7AlD7Y5EJ#?Iy!!)i?^H9mTy zIgoFzvs?4hCI$s4277d{`F&ez0BFZGlo0N+FZ?YDjP z@ZG6^&YgMx?UQeD+&KQ|v967sTf4UI+|lbvr(9Z!!&-iJQit4<_BL*8-+pU%PfzE= z4;?KPi>Kax|Kb;)1-`p!(+=Z>=R#((=b2ou8bTX>ZHky}vot)O_XgV5L?C*!TUm)-|wpCFqi~+)+Q3H2rX$er_q|m%p`vJ z{llrCsaB5-qgs!y58vompMC0^PygwUuUxux>GuAe-J3QDn1%do``WhQ;o%FPExG{= zu(-U^rYW&fGYD`9iLbyKnE($T-PPaQGch*&(b;P^=U3-iI)fxZ_ttc0*OnlaId$rM z6v9_&o%IY^|2nATz^WrFyz+L-xy!hfTI@+2~oqTiP z-`5Tv=s5bd2g~K^_2Dt!Px(O*X%ofCkt26D1wkB#o-69r%Fxg-GxqL3P(3@))ViUr z)u$J~WWe=OjVM+C5~D4kBzpVqSih;eQkri>rn_h3uYdWgC`xiOvn^}Z)#_m?m7ZTH zl*-E;9oePAVpHoHtCMt#dgS==6DR%=Mx2|?uiw7(~T%rAO=V&5aIWK zcs+@u=f3q+kZx^Tw=ps{ip}5O{O4z%UL>gqPPy6$0!JxTDm8o$j~+W(m@k7$emXNf zoA0@`_xk9Umj{Ov1_OnqB0y>dI*A4Y8aQ#{+#M+f8 zE+j^hEIQq4koAmRER2DX62oYwtxW0umRWt>5OQE7J!t(K!KI=Q`#CZ3&&&4S~D!96hcU529XdFL`1~Q zAPce*0$$1y(r3+pB$5D2NfuTcy9!Gpn*dNINnjaddDU$IQ7V-V8zDddSqp1n?W%1_ ai2nj)wF*~Idw;9|0000^lOiET&UP@Y7ModgWM?qOlT~kX_QeM|USHnP6LsJ7}2qQZ?I~NC+Fc+7w zhLo6;2Fc+60R}-11_cHMW=16jCP7AKLB{__7$g`Nm>C%vkO0uF>>NNDEdd55CMHH^ zW)?awse6$&vxPS{hr>B*US)IlIh@af9Iy-Gm`F1KPWF}x^LOO z#b;|>xhy@VoQ;gMeiZj`!usaT3*WArm{eR8aQsOE Date: Sun, 4 Oct 2026 00:17:56 +0100 Subject: [PATCH 019/164] fix(core): fall back to 80 columns when no terminal width is available (#4974) Separators and centred text used the width from tput cols. Without a terminal (cron, Docker, post-details), tput prints an error and returns nothing. bash 5.3 (Ubuntu 26.04) also rejects the empty printf width ("printf: : invalid number"). Hide tput's error and fall back to 80 columns. Terminal widths are still used when available. Co-authored-by: Claude Opus 5.5 --- lgsm/modules/core_messages.sh | 4 +++- linuxgsm.sh | 8 ++++++-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/lgsm/modules/core_messages.sh b/lgsm/modules/core_messages.sh index da5fd43e37..f00a44984e 100755 --- a/lgsm/modules/core_messages.sh +++ b/lgsm/modules/core_messages.sh @@ -222,7 +222,9 @@ fn_print_start_nl() { # Separator is different for details. fn_messages_separator() { if [ "${commandname}" == "DETAILS" ]; then - printf '%*s\n' "${COLUMNS:-$(tput cols)}" '' | tr ' ' = + # Fall back to 80 columns when there is no terminal (e.g. cron or Docker); bash 5.3+ rejects an empty printf width. + local columns="${COLUMNS:-$(tput cols 2> /dev/null)}" + printf '%*s\n' "${columns:-80}" '' | tr ' ' = else echo -e "${bold}=================================${default}" fn_sleep_time diff --git a/linuxgsm.sh b/linuxgsm.sh index 9274a071b6..9b51428a37 100755 --- a/linuxgsm.sh +++ b/linuxgsm.sh @@ -243,13 +243,17 @@ fn_bootstrap_fetch_file_github() { # Installer menu. fn_print_center() { - columns=$(tput cols) + # Fall back to 80 columns when there is no terminal. + columns="${COLUMNS:-$(tput cols 2> /dev/null)}" + columns="${columns:-80}" line="$*" printf "%*s\n" $(((${#line} + columns) / 2)) "${line}" } fn_print_horizontal() { - printf '%*s\n' "${COLUMNS:-$(tput cols)}" '' | tr ' ' "=" + # Fall back to 80 columns when there is no terminal; bash 5.3+ rejects an empty printf width. + local columns="${COLUMNS:-$(tput cols 2> /dev/null)}" + printf '%*s\n' "${columns:-80}" '' | tr ' ' "=" } # Bash menu. From b50339a828a16d85b5c7e393c11416827b33ce9e Mon Sep 17 00:00:00 2001 From: Daniel Gibbs Date: Sun, 4 Oct 2026 13:27:48 +0100 Subject: [PATCH 020/164] fix(deps): check passwordless sudo before prompting with sudo -v (#4980) sudo -v asks for a password with sudo-rs (Ubuntu 25.10+) even with NOPASSWD, and with classic sudo when the user also matches the default %sudo rule. Try sudo -n true first and only fall back to the sudo -v prompt when passwordless sudo is not available. --- lgsm/modules/check_deps.sh | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/lgsm/modules/check_deps.sh b/lgsm/modules/check_deps.sh index 102cbceb6e..dabdc348d2 100755 --- a/lgsm/modules/check_deps.sh +++ b/lgsm/modules/check_deps.sh @@ -156,13 +156,17 @@ fn_install_missing_deps() { fn_script_log_warn "Missing dependencies: ${array_deps_missing[*]}" fi - # Attempt automatic dependency installation - if [ "${autoinstall}" == "1" ]; then - sudo -n true > /dev/null 2>&1 + # Attempt automatic dependency installation. + # Check for passwordless sudo first: sudo-rs (default sudo from Ubuntu 25.10) always asks + # for a password for sudo -v, even when the user has NOPASSWD. + if sudo -n true > /dev/null 2>&1; then + autodepinstall="0" + elif [ "${autoinstall}" == "1" ]; then + autodepinstall="1" else sudo -v > /dev/null 2>&1 + autodepinstall="$?" fi - autodepinstall="$?" if [ "${monoinstalled}" == "false" ]; then fn_install_mono_repo From 27f070bc395b90048a099d416a28f5c420417056 Mon Sep 17 00:00:00 2001 From: Daniel Gibbs Date: Sun, 4 Oct 2026 14:02:38 +0100 Subject: [PATCH 021/164] fix(core): handle bootstrap before logging and exit modules are loaded (#4981) Bootstrap downloads and the Ctrl+C trap called logging, message and core_exit.sh functions before the modules defining them were loaded. This caused spurious "fn_script_log_pass: command not found" errors after the module cache was emptied, and a failed or cancelled early download carried on instead of exiting. - Guard bootstrap log calls on the logging function existing. - Add fn_bootstrap_exit: uses core_exit.sh once available, otherwise a plain exit. - Make the download trap bootstrap-safe (removes the partial file, exits 130). --- linuxgsm.sh | 38 +++++++++++++++++++++++++++----------- 1 file changed, 27 insertions(+), 11 deletions(-) diff --git a/linuxgsm.sh b/linuxgsm.sh index 9b51428a37..a374d8732f 100755 --- a/linuxgsm.sh +++ b/linuxgsm.sh @@ -70,17 +70,32 @@ core_modules.sh() { } # Bootstrap +# Exits during bootstrap. core_exit.sh is only usable once core_modules.sh (which defines it) +# and core_dl.sh (fn_fetch_module, which it uses) are loaded, so fall back to a plain exit. +fn_bootstrap_exit() { + if type core_exit.sh > /dev/null 2>&1 && type fn_fetch_module > /dev/null 2>&1; then + core_exit.sh + else + exit "${1:-1}" + fi +} + # Fetches the core modules required before passed off to core_dl.sh. fn_bootstrap_fetch_trap() { echo -e "" - echo -en "downloading ${local_filename}" - fn_print_canceled_eol_nl - fn_script_log_info "Downloading ${local_filename}...CANCELED" rm -f "${local_filedir:?}/${local_filename}" - echo -en "downloading ${local_filename}" - fn_print_removed_eol_nl - fn_script_log_info "Downloading ${local_filename}...REMOVED" - core_exit.sh + # Message and logging functions come from core_messages.sh, which may not be loaded yet. + if type fn_print_canceled_eol_nl > /dev/null 2>&1; then + echo -en "downloading ${local_filename}" + fn_print_canceled_eol_nl + echo -en "downloading ${local_filename}" + fn_print_removed_eol_nl + fn_script_log_info "Downloading ${local_filename}...CANCELED" + fn_script_log_info "Downloading ${local_filename}...REMOVED" + else + echo -e "downloading ${local_filename} ... CANCELED (removed)" + fi + fn_bootstrap_exit 130 } # Fetches modules from the Git repo during first download. @@ -175,14 +190,15 @@ fn_bootstrap_fetch_file() { if [ "${exitcode}" -ne 0 ]; then if [ ${counter} -ge 2 ]; then echo -e " ... FAIL" - if [ -f "${lgsmlog}" ]; then + # Logging functions come from core_messages.sh, which may not be loaded yet during bootstrap. + if [ -f "${lgsmlog}" ] && type fn_script_log_fail > /dev/null 2>&1; then fn_script_log_fail "Downloading ${local_filename}..." fn_script_log_fail "${fileurl}" fi - core_exit.sh + fn_bootstrap_exit 1 else echo -e " ... ERROR" - if [ -f "${lgsmlog}" ]; then + if [ -f "${lgsmlog}" ] && type fn_script_log_error > /dev/null 2>&1; then fn_script_log_error "Downloading ${local_filename}..." fn_script_log_error "${fileurl}" fi @@ -191,7 +207,7 @@ fn_bootstrap_fetch_file() { echo -en " ... OK" sleep "0.1" echo -e "\033\\r" - if [ -f "${lgsmlog}" ]; then + if [ -f "${lgsmlog}" ] && type fn_script_log_pass > /dev/null 2>&1; then fn_script_log_pass "Downloading ${local_filename}..." fi From bf864f0e864899679bb0f89d81d275cecdda6a37 Mon Sep 17 00:00:00 2001 From: Daniel Gibbs Date: Sun, 4 Oct 2026 14:34:43 +0100 Subject: [PATCH 022/164] fix(rsdwserver): download default DedicatedServer.ini on install (#4982) RuneScape: Dragonwilds had no install_config.sh block, so no DedicatedServer.ini was created on install and the details-check (rsdw) CI job failed downloading the default config. - Download DedicatedServer.ini from Game-Server-Configs (GameServerManagers/Game-Server-Configs#157), set the server and world name, and generate an admin password. - Update the rsdwserver _default.cfg comment: the INI is now created during install, so OwnerId can be set before the first start. --- lgsm/config-default/config-lgsm/rsdwserver/_default.cfg | 3 ++- lgsm/modules/install_config.sh | 5 +++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/lgsm/config-default/config-lgsm/rsdwserver/_default.cfg b/lgsm/config-default/config-lgsm/rsdwserver/_default.cfg index b029431e3c..1b428f7025 100644 --- a/lgsm/config-default/config-lgsm/rsdwserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/rsdwserver/_default.cfg @@ -12,7 +12,8 @@ # Server name, passwords, owner ID and world name are read by the server from DedicatedServer.ini, not set here. # Edit them in: serverfiles/RSDragonwilds/Saved/Config/LinuxServer/DedicatedServer.ini # REQUIRED: the server will not finish starting until OwnerId is set in DedicatedServer.ini -# (your Player ID, shown in the in-game settings). DedicatedServer.ini is created on first start. +# (your Player ID, shown in the in-game settings). DedicatedServer.ini is created during install, +# so OwnerId can be set before the first start. port="7777" ## Server Parameters | https://docs.linuxgsm.com/configuration/start-parameters#additional-parameters diff --git a/lgsm/modules/install_config.sh b/lgsm/modules/install_config.sh index e25b8de5c7..ccd9d92327 100755 --- a/lgsm/modules/install_config.sh +++ b/lgsm/modules/install_config.sh @@ -668,6 +668,11 @@ elif [ "${shortname}" == "ricochet" ]; then fn_default_config_remote fn_set_config_vars fn_list_config_locations +elif [ "${shortname}" == "rsdw" ]; then + array_configs+=(DedicatedServer.ini) + fn_default_config_remote + fn_set_config_vars + fn_list_config_locations elif [ "${shortname}" == "rtcw" ]; then array_configs+=(server.cfg) fn_default_config_remote From 004385134bea754af7c0bfd5a6fe4667742fca31 Mon Sep 17 00:00:00 2001 From: Andrew Quenehen <56467992+andrewqsantos@users.noreply.github.com> Date: Sun, 4 Oct 2026 14:59:30 -0300 Subject: [PATCH 023/164] feat(newserver): add Hytale server support (#4928) Adds the Hytale server (hyt): install, default config from Game-Server-Configs, Java 25 dependency check and first-start server login. --- .../config-lgsm/hytserver/_default.cfg | 195 +++++++++++ lgsm/data/almalinux-8.csv | 1 + lgsm/data/almalinux-9.csv | 1 + lgsm/data/centos-7.csv | 1 + lgsm/data/centos-8.csv | 1 + lgsm/data/centos-9.csv | 1 + lgsm/data/debian-10.csv | 1 + lgsm/data/debian-11.csv | 1 + lgsm/data/debian-12.csv | 1 + lgsm/data/debian-13.csv | 1 + lgsm/data/debian-9.csv | 1 + lgsm/data/gameicons/hyt-icon.png | Bin 0 -> 146 bytes lgsm/data/rhel-7.csv | 1 + lgsm/data/rhel-8.csv | 1 + lgsm/data/rhel-9.csv | 1 + lgsm/data/rocky-8.csv | 1 + lgsm/data/rocky-9.csv | 1 + lgsm/data/serverlist.csv | 1 + lgsm/data/ubuntu-16.04.csv | 1 + lgsm/data/ubuntu-18.04.csv | 1 + lgsm/data/ubuntu-20.04.csv | 1 + lgsm/data/ubuntu-22.04.csv | 1 + lgsm/data/ubuntu-23.04.csv | 1 + lgsm/data/ubuntu-23.10.csv | 1 + lgsm/data/ubuntu-24.04.csv | 1 + lgsm/data/ubuntu-26.04.csv | 1 + lgsm/modules/alert.sh | 13 + lgsm/modules/check_deps.sh | 19 +- lgsm/modules/check_system_requirements.sh | 2 + lgsm/modules/command_check_update.sh | 2 + lgsm/modules/command_monitor.sh | 2 +- lgsm/modules/command_start.sh | 59 ++++ lgsm/modules/command_update.sh | 2 + lgsm/modules/core_getopt.sh | 4 +- lgsm/modules/core_modules.sh | 5 + lgsm/modules/info_game.sh | 23 ++ lgsm/modules/info_messages.sh | 13 +- lgsm/modules/install_config.sh | 3 + lgsm/modules/install_server_files.sh | 2 + lgsm/modules/update_hyt.sh | 307 ++++++++++++++++++ 40 files changed, 667 insertions(+), 8 deletions(-) create mode 100644 lgsm/config-default/config-lgsm/hytserver/_default.cfg create mode 100644 lgsm/data/gameicons/hyt-icon.png create mode 100755 lgsm/modules/update_hyt.sh diff --git a/lgsm/config-default/config-lgsm/hytserver/_default.cfg b/lgsm/config-default/config-lgsm/hytserver/_default.cfg new file mode 100644 index 0000000000..16ff695d50 --- /dev/null +++ b/lgsm/config-default/config-lgsm/hytserver/_default.cfg @@ -0,0 +1,195 @@ +################################## +######## Default Settings ######## +################################## +# DO NOT EDIT, ANY CHANGES WILL BE OVERWRITTEN! +# Copy settings from here and use them in either: +# common.cfg - applies settings to every instance. +# [instance].cfg - applies settings to a specific instance. + +#### Game Server Settings #### + +## Predefined Parameters | https://docs.linuxgsm.com/configuration/start-parameters +# A Hytale account that owns the game is needed for two one-time logins: +# 1. Install: the Hytale downloader shows a login URL to approve in a browser (also in docker logs). +# 2. First start: LinuxGSM shows the server login URL (and sends it as an alert) to approve. +# The server saves it (Server/auth.enc) and restores it on restart. To log in again manually: +# ./hytserver send "/auth login device" +# https://docs.linuxgsm.com/game-servers/hytale +# Server name, password and max players are set in Server/config.json, created on first start. +ip="0.0.0.0" +port="5520" + +## Server Parameters | https://docs.linuxgsm.com/configuration/start-parameters#additional-parameters +startparameters="--bind ${ip}:${port}" + +## Release Settings +# Patchline (release|pre-release) +hytalepatchline="release" + +#### LinuxGSM Settings #### + +## LinuxGSM Stats +# Send useful stats to LinuxGSM developers. +# https://docs.linuxgsm.com/configuration/linuxgsm-stats +# (on|off) +stats="off" + +## Notification Alerts +# (on|off) + +# Display IP | https://docs.linuxgsm.com/alerts#display-ip +displayip="" + +# More info | https://docs.linuxgsm.com/alerts#more-info +postalert="off" + +# Alert on Start/Stop/Restart +statusalert="off" + +# Discord Alerts | https://docs.linuxgsm.com/alerts/discord +discordalert="off" +discordwebhook="webhook" + +# Email Alerts | https://docs.linuxgsm.com/alerts/email +emailalert="off" +email="email@example.com" +emailfrom="" + +# Gotify Alerts | https://docs.linuxgsm.com/alerts/gotify +gotifyalert="off" +gotifytoken="token" +gotifywebhook="webhook" + +# IFTTT Alerts | https://docs.linuxgsm.com/alerts/ifttt +iftttalert="off" +ifttttoken="accesstoken" +iftttevent="linuxgsm_alert" + +# ntfy Alerts | https://docs.linuxgsm.com/alerts/ntfy +ntfyalert="off" +ntfytopic="LinuxGSM" +ntfyserver="https://ntfy.sh" +ntfytoken="" +ntfyusername="" +ntfypassword="" +ntfypriority="" +ntfytags="" + +# Pushbullet Alerts | https://docs.linuxgsm.com/alerts/pushbullet +pushbulletalert="off" +pushbullettoken="accesstoken" +channeltag="" + +# Pushover Alerts | https://docs.linuxgsm.com/alerts/pushover +pushoveralert="off" +pushovertoken="accesstoken" +pushoveruserkey="userkey" + +# Rocket.Chat Alerts | https://docs.linuxgsm.com/alerts/rocket.chat +rocketchatalert="off" +rocketchatwebhook="webhook" + +# Slack Alerts | https://docs.linuxgsm.com/alerts/slack +slackalert="off" +slackwebhook="webhook" + +# Telegram Alerts | https://docs.linuxgsm.com/alerts/telegram +# You can add a custom cURL string eg proxy (useful in Russia) in "curlcustomstring". +# For example "--socks5 ipaddr:port" for socks5 proxy see more in "curl --help all". +telegramapi="api.telegram.org" +telegramalert="off" +telegramtoken="accesstoken" +telegramchatid="" +telegramthreadid="" +telegramsilentnotification="false" +curlcustomstring="" + +## Updating | https://docs.linuxgsm.com/commands/update +updateonstart="off" + +## Backup | https://docs.linuxgsm.com/commands/backup +maxbackups="4" +maxbackupdays="30" +stoponbackup="on" + +## Logging | https://docs.linuxgsm.com/features/logging +consolelogging="on" +logdays="7" + +## Monitor | https://docs.linuxgsm.com/commands/monitor +# Query delay time +querydelay="1" + +## ANSI Colors | https://docs.linuxgsm.com/features/ansi-colors +ansi="on" + +#### Advanced Settings #### + +## Message Display Time | https://docs.linuxgsm.com/features/message-display-time +sleeptime="0.5" + +## Stop Mode | https://docs.linuxgsm.com/features/stop-mode +# 1: tmux kill +# 2: CTRL+c +# 3: quit +# 4: quit 120s +# 5: stop +# 6: q +# 7: exit +# 8: 7 Days to Die +# 9: GoldSrc +# 10: Avorion +# 11: end +stopmode="5" + +## Query mode +# 1: session only +# 2: gamedig (gsquery fallback) +# 3: gamedig +# 4: gsquery +# 5: tcp +querymode="1" +querytype="" + +## Console type +consoleverbose="yes" +consoleinteract="yes" + +## Game Server Details +# Do not edit +gamename="Hytale" +engine="hytale" +glibc="null" + +#### Directories #### +# Edit with care + +## Game Server Directories +systemdir="${serverfiles}/Server" +executabledir="${serverfiles}" +executable="./start.sh" +servercfgdir="${systemdir}" +servercfg="config.json" +servercfgdefault="config.json" +servercfgfullpath="${servercfgdir}/${servercfg}" + +## Backup Directory +backupdir="${lgsmdir}/backup" + +## Logging Directories +[ -n "${LGSM_LOGDIR}" ] && logdir="${LGSM_LOGDIR}" || logdir="${rootdir}/log" +gamelogdir="${systemdir}/logs" +lgsmlogdir="${logdir}/script" +consolelogdir="${logdir}/console" +lgsmlog="${lgsmlogdir}/${selfname}-script.log" +consolelog="${consolelogdir}/${selfname}-console.log" +alertlog="${lgsmlogdir}/${selfname}-alert.log" +postdetailslog="${lgsmlogdir}/${selfname}-postdetails.log" + +## Logs Naming +lgsmlogdate="${lgsmlogdir}/${selfname}-script-$(date '+%Y-%m-%d-%H:%M:%S').log" +consolelogdate="${consolelogdir}/${selfname}-console-$(date '+%Y-%m-%d-%H:%M:%S').log" + +## Log Parameters +logtimestamp="off" +logtimestampformat="%Y-%m-%d %H:%M:%S" diff --git a/lgsm/data/almalinux-8.csv b/lgsm/data/almalinux-8.csv index b9fde6b024..8ce65a4d91 100644 --- a/lgsm/data/almalinux-8.csv +++ b/lgsm/data/almalinux-8.csv @@ -54,6 +54,7 @@ hl2dm hldm hldms hw,zlib-devel +hyt,java-25-openjdk hz ins inss diff --git a/lgsm/data/almalinux-9.csv b/lgsm/data/almalinux-9.csv index 40cea229c8..6888992a36 100644 --- a/lgsm/data/almalinux-9.csv +++ b/lgsm/data/almalinux-9.csv @@ -54,6 +54,7 @@ hl2dm hldm hldms hw,zlib-devel +hyt,java-25-openjdk hz ins inss diff --git a/lgsm/data/centos-7.csv b/lgsm/data/centos-7.csv index 6c67268e38..1bffbf0bfe 100644 --- a/lgsm/data/centos-7.csv +++ b/lgsm/data/centos-7.csv @@ -54,6 +54,7 @@ hl2dm hldm hldms hw,zlib-devel +hyt,java-25-openjdk hz ins inss diff --git a/lgsm/data/centos-8.csv b/lgsm/data/centos-8.csv index ba2874629f..b25eae1f58 100644 --- a/lgsm/data/centos-8.csv +++ b/lgsm/data/centos-8.csv @@ -54,6 +54,7 @@ hl2dm hldm hldms hw,zlib-devel +hyt,java-25-openjdk hz ins inss diff --git a/lgsm/data/centos-9.csv b/lgsm/data/centos-9.csv index 575c28ab62..d472cb2229 100644 --- a/lgsm/data/centos-9.csv +++ b/lgsm/data/centos-9.csv @@ -54,6 +54,7 @@ hl2dm hldm hldms hw,zlib-devel +hyt,java-25-openjdk hz ins inss diff --git a/lgsm/data/debian-10.csv b/lgsm/data/debian-10.csv index 7ebf3ec373..308af0aa12 100644 --- a/lgsm/data/debian-10.csv +++ b/lgsm/data/debian-10.csv @@ -53,6 +53,7 @@ hl2dm hldm hldms hw,lib32z1 +hyt,openjdk-25-jre hz ins inss diff --git a/lgsm/data/debian-11.csv b/lgsm/data/debian-11.csv index eea8e2b7c7..a5da6de630 100644 --- a/lgsm/data/debian-11.csv +++ b/lgsm/data/debian-11.csv @@ -54,6 +54,7 @@ hl2dm hldm hldms hw,lib32z1 +hyt,openjdk-25-jre hz ins inss diff --git a/lgsm/data/debian-12.csv b/lgsm/data/debian-12.csv index 55bf6b02cf..c0a6615d6e 100644 --- a/lgsm/data/debian-12.csv +++ b/lgsm/data/debian-12.csv @@ -54,6 +54,7 @@ hl2dm hldm hldms hw,lib32z1 +hyt,openjdk-25-jre hz ins inss diff --git a/lgsm/data/debian-13.csv b/lgsm/data/debian-13.csv index 7f818d87c0..1c63c4d4d2 100644 --- a/lgsm/data/debian-13.csv +++ b/lgsm/data/debian-13.csv @@ -54,6 +54,7 @@ hl2dm hldm hldms hw,lib32z1 +hyt,openjdk-25-jre hz ins inss diff --git a/lgsm/data/debian-9.csv b/lgsm/data/debian-9.csv index b3b81b3c46..fde9c06f80 100644 --- a/lgsm/data/debian-9.csv +++ b/lgsm/data/debian-9.csv @@ -54,6 +54,7 @@ hl2dm hldm hldms hw,lib32z1 +hyt,openjdk-25-jre hz ins inss diff --git a/lgsm/data/gameicons/hyt-icon.png b/lgsm/data/gameicons/hyt-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..3942ea6161ec27dd29057a738fa6d5268cb357ed GIT binary patch literal 146 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=ffJNKY5Xkcv6U6E<=D(9akAP`@Cf zt#ONti*Zlefea3wUjjcWTI5-SqiqigIG9hk^~&8j!GxtPj$=aCN;#$_k1h&GoMm0C tXduPpY|oP6%m2^pVFpJ}8^hX6hQ-z)LRDKcvw)T`c)I$ztaD0e0suyVE~fwh literal 0 HcmV?d00001 diff --git a/lgsm/data/rhel-7.csv b/lgsm/data/rhel-7.csv index 35343676d1..0b197f7c86 100644 --- a/lgsm/data/rhel-7.csv +++ b/lgsm/data/rhel-7.csv @@ -55,6 +55,7 @@ hl2dm hldm hldms hw,zlib-devel +hyt,java-25-openjdk hz ins inss diff --git a/lgsm/data/rhel-8.csv b/lgsm/data/rhel-8.csv index 420f301c31..20bd06bcbf 100644 --- a/lgsm/data/rhel-8.csv +++ b/lgsm/data/rhel-8.csv @@ -54,6 +54,7 @@ hl2dm hldm hldms hw,zlib-devel +hyt,java-25-openjdk hz ins inss diff --git a/lgsm/data/rhel-9.csv b/lgsm/data/rhel-9.csv index 40cea229c8..6888992a36 100644 --- a/lgsm/data/rhel-9.csv +++ b/lgsm/data/rhel-9.csv @@ -54,6 +54,7 @@ hl2dm hldm hldms hw,zlib-devel +hyt,java-25-openjdk hz ins inss diff --git a/lgsm/data/rocky-8.csv b/lgsm/data/rocky-8.csv index 420f301c31..20bd06bcbf 100644 --- a/lgsm/data/rocky-8.csv +++ b/lgsm/data/rocky-8.csv @@ -54,6 +54,7 @@ hl2dm hldm hldms hw,zlib-devel +hyt,java-25-openjdk hz ins inss diff --git a/lgsm/data/rocky-9.csv b/lgsm/data/rocky-9.csv index 40cea229c8..6888992a36 100644 --- a/lgsm/data/rocky-9.csv +++ b/lgsm/data/rocky-9.csv @@ -54,6 +54,7 @@ hl2dm hldm hldms hw,zlib-devel +hyt,java-25-openjdk hz ins inss diff --git a/lgsm/data/serverlist.csv b/lgsm/data/serverlist.csv index ca3dd46720..aa9c02a819 100644 --- a/lgsm/data/serverlist.csv +++ b/lgsm/data/serverlist.csv @@ -53,6 +53,7 @@ hl2dm,hl2dmserver,Half-Life 2: Deathmatch,ubuntu-24.04 hldm,hldmserver,Half-Life: Deathmatch,ubuntu-24.04 hldms,hldmsserver,Half-Life Deathmatch: Source,ubuntu-24.04 hw,hwserver,Hurtworld,ubuntu-24.04 +hyt,hytserver,Hytale,ubuntu-24.04 hz,hzserver,Humanitz,ubuntu-24.04 ins,insserver,Insurgency,ubuntu-24.04 inss,inssserver,Insurgency: Sandstorm,ubuntu-24.04 diff --git a/lgsm/data/ubuntu-16.04.csv b/lgsm/data/ubuntu-16.04.csv index 8955831dad..e1db83488a 100644 --- a/lgsm/data/ubuntu-16.04.csv +++ b/lgsm/data/ubuntu-16.04.csv @@ -55,6 +55,7 @@ hl2dm hldm hldms hw,lib32z1 +hyt,openjdk-25-jre hz ins inss diff --git a/lgsm/data/ubuntu-18.04.csv b/lgsm/data/ubuntu-18.04.csv index 12bdb5e68b..7ea128ddfa 100644 --- a/lgsm/data/ubuntu-18.04.csv +++ b/lgsm/data/ubuntu-18.04.csv @@ -55,6 +55,7 @@ hl2dm hldm hldms hw,lib32z1 +hyt,openjdk-25-jre hz ins inss diff --git a/lgsm/data/ubuntu-20.04.csv b/lgsm/data/ubuntu-20.04.csv index 7b77e090e6..4e5ae9fdc5 100644 --- a/lgsm/data/ubuntu-20.04.csv +++ b/lgsm/data/ubuntu-20.04.csv @@ -54,6 +54,7 @@ hl2dm hldm hldms hw,lib32z1 +hyt,openjdk-25-jre hz ins inss diff --git a/lgsm/data/ubuntu-22.04.csv b/lgsm/data/ubuntu-22.04.csv index 08060760ef..96a745493c 100644 --- a/lgsm/data/ubuntu-22.04.csv +++ b/lgsm/data/ubuntu-22.04.csv @@ -54,6 +54,7 @@ hl2dm hldm hldms hw,lib32z1 +hyt,openjdk-25-jre hz ins inss diff --git a/lgsm/data/ubuntu-23.04.csv b/lgsm/data/ubuntu-23.04.csv index 8fe8572068..39ff561a35 100644 --- a/lgsm/data/ubuntu-23.04.csv +++ b/lgsm/data/ubuntu-23.04.csv @@ -54,6 +54,7 @@ hl2dm hldm hldms hw,lib32z1 +hyt,openjdk-25-jre hz ins inss diff --git a/lgsm/data/ubuntu-23.10.csv b/lgsm/data/ubuntu-23.10.csv index 8fe8572068..39ff561a35 100644 --- a/lgsm/data/ubuntu-23.10.csv +++ b/lgsm/data/ubuntu-23.10.csv @@ -54,6 +54,7 @@ hl2dm hldm hldms hw,lib32z1 +hyt,openjdk-25-jre hz ins inss diff --git a/lgsm/data/ubuntu-24.04.csv b/lgsm/data/ubuntu-24.04.csv index be293d416b..e6364f2683 100644 --- a/lgsm/data/ubuntu-24.04.csv +++ b/lgsm/data/ubuntu-24.04.csv @@ -54,6 +54,7 @@ hl2dm hldm hldms hw,lib32z1 +hyt,openjdk-25-jre hz ins inss diff --git a/lgsm/data/ubuntu-26.04.csv b/lgsm/data/ubuntu-26.04.csv index be293d416b..e6364f2683 100644 --- a/lgsm/data/ubuntu-26.04.csv +++ b/lgsm/data/ubuntu-26.04.csv @@ -54,6 +54,7 @@ hl2dm hldm hldms hw,lib32z1 +hyt,openjdk-25-jre hz ins inss diff --git a/lgsm/modules/alert.sh b/lgsm/modules/alert.sh index b256390df6..8b5adfda35 100755 --- a/lgsm/modules/alert.sh +++ b/lgsm/modules/alert.sh @@ -169,6 +169,17 @@ fn_alert_backup() { alertcolourdec="52480" } +fn_alert_hytale_login() { + fn_script_log_info "Sending alert: ${selfname} needs a Hytale server login" + alertaction="Login Required" + alertemoji="🔑" + alertsound="2" + alertmessage="${selfname} needs a Hytale server login. Open ${hytloginurl} and log in with a Hytale account that owns the game. The code expires in 10 minutes." + # Blue + alertcolourhex="#1e90ff" + alertcolourdec="2003199" +} + fn_alert_permissions() { fn_script_log_info "Sending alert: ${selfname} has permissions issues" alertaction="Checked Permissions" @@ -250,6 +261,8 @@ elif [ "${alert}" == "update-linuxgsm" ]; then fn_alert_update_linuxgsm elif [ "${alert}" == "backup" ]; then fn_alert_backup +elif [ "${alert}" == "hytale-login" ]; then + fn_alert_hytale_login else fn_print_fail_nl "Missing alert type" fn_script_log_fail "Missing alert type" diff --git a/lgsm/modules/check_deps.sh b/lgsm/modules/check_deps.sh index dabdc348d2..0f01181318 100755 --- a/lgsm/modules/check_deps.sh +++ b/lgsm/modules/check_deps.sh @@ -285,9 +285,22 @@ fn_deps_detector() { elif [[ ${deptocheck} == "openjdk"* ]] || [[ ${deptocheck} == "java"* ]]; then # Is java already installed? if [ -n "${javaversion}" ]; then - # Added for users using Oracle JRE to bypass check. - depstatus=0 - deptocheck="${javaversion}" + javamajorversion="$(echo "${javaversion}" | grep -Eo 'version "[0-9]+' | grep -Eo '[0-9]+' | head -1)" + if [ "${shortname}" == "hyt" ] && { [ -z "${javamajorversion}" ] || [ "${javamajorversion}" -lt "25" ]; }; then + # Java 25 installed but not the active java: installing it again would not change that. + if compgen -G "/usr/lib/jvm/*25*/bin/java" > /dev/null; then + depstatus=0 + deptocheck="${javaversion}" + fn_print_warn_nl "Java 25 is installed but the active java is version ${javamajorversion:-unknown}. Select Java 25 with: sudo update-alternatives --config java" + fn_script_log_warn "Java 25 is installed but the active java is version ${javamajorversion:-unknown}" + else + depstatus=1 + fi + else + # Added for users using Oracle JRE to bypass check. + depstatus=0 + deptocheck="${javaversion}" + fi else depstatus=1 fi diff --git a/lgsm/modules/check_system_requirements.sh b/lgsm/modules/check_system_requirements.sh index 69897bb1d6..2bee99738a 100755 --- a/lgsm/modules/check_system_requirements.sh +++ b/lgsm/modules/check_system_requirements.sh @@ -31,6 +31,8 @@ elif [ "${shortname}" == "dodr" ]; then ramrequirementgb="2" elif [ "${shortname}" == "hw" ]; then ramrequirementgb="3" +elif [ "${shortname}" == "hyt" ]; then + ramrequirementgb="4" elif [ "${shortname}" == "mc" ]; then ramrequirementgb="1" elif [ "${shortname}" == "pmc" ]; then diff --git a/lgsm/modules/command_check_update.sh b/lgsm/modules/command_check_update.sh index 93a770e794..3bdd25bcdd 100755 --- a/lgsm/modules/command_check_update.sh +++ b/lgsm/modules/command_check_update.sh @@ -24,6 +24,8 @@ elif [ "${shortname}" == "pmc" ] || [ "${shortname}" == "vpmc" ] || [ "${shortna update_pmc.sh elif [ "${shortname}" == "fctr" ]; then update_fctr.sh +elif [ "${shortname}" == "hyt" ]; then + update_hyt.sh elif [ "${shortname}" == "mta" ]; then update_mta.sh elif [ "${shortname}" == "jk2" ]; then diff --git a/lgsm/modules/command_monitor.sh b/lgsm/modules/command_monitor.sh index 0a80fcbf74..4dc32765b0 100755 --- a/lgsm/modules/command_monitor.sh +++ b/lgsm/modules/command_monitor.sh @@ -165,7 +165,7 @@ fn_monitor_check_update() { fi fi - if [ -f "${lockdir}/update.lock" ] && [[ "$(pgrep -fcx -u "${USER}" "/bin/bash ./${selfname} update")" != "0" || "$(pgrep -fcx -u "${USER}" "/bin/bash ./${selfname} validate")" != "0" || "$(pgrep -fcx -u "${USER}" "/bin/bash ./${selfname} v")" != "0" || "$(pgrep -fc force-update "${USER}" "/bin/bash ./${selfname} fu")" != "0" ]]; then + if [ -f "${lockdir}/update.lock" ] && [[ "$(pgrep -fcx -u "${USER}" "/bin/bash ./${selfname} update")" != "0" || "$(pgrep -fcx -u "${USER}" "/bin/bash ./${selfname} validate")" != "0" || "$(pgrep -fcx -u "${USER}" "/bin/bash ./${selfname} v")" != "0" || "$(pgrep -fcx -u "${USER}" "/bin/bash ./${selfname} force-update")" != "0" || "$(pgrep -fcx -u "${USER}" "/bin/bash ./${selfname} fu")" != "0" || "$(pgrep -fcx -u "${USER}" "/bin/bash ./${selfname} update-restart")" != "0" || "$(pgrep -fcx -u "${USER}" "/bin/bash ./${selfname} ur")" != "0" ]]; then fn_print_dots "Checking update" fn_print_checking_eol fn_print_info "Checking update: LinuxGSM is updating the game server" diff --git a/lgsm/modules/command_start.sh b/lgsm/modules/command_start.sh index 43b7a3858f..1ee35f0ee2 100755 --- a/lgsm/modules/command_start.sh +++ b/lgsm/modules/command_start.sh @@ -18,6 +18,55 @@ fn_start_jk2() { TERM=screen tmux -L "${socketname}" end -t "${sessionname}" version ENTER > /dev/null 2>&1 } +# Hytale: after the server boots, check whether it logged in. If it didn't (no saved login, or one that +# can't be decrypted, e.g. created on another machine or container), start the login, then show the +# login URL and send it as an alert, so it can be approved without opening the console. +# Prints the server console: the console log, or the tmux pane when console logging is off. +fn_start_hyt_console() { + if [ "${consolelogging}" == "off" ]; then + TERM=screen tmux -L "${socketname}" capture-pane -p -J -S - -t "${sessionname}" 2> /dev/null + else + cat "${consolelog}" 2> /dev/null + fi +} + +fn_start_hyt_login() { + hytloginurl="" + local hytloginsent="${hytloginpending}" + for _ in {1..120}; do + hytloginurl=$(fn_start_hyt_console | grep -a -oE "https://[^ ]*device/verify\?user_code=[A-Za-z0-9]+" | tail -1) + if [ -n "${hytloginurl}" ]; then + break + fi + # Logged in with the saved server login: nothing to do. + if fn_start_hyt_console | grep -a -q "Authentication successful"; then + fn_script_log_info "Hytale server login restored from saved credentials" + return + fi + # Booted without a usable login: ask the server to start one. + if [ "${hytloginsent}" != "1" ] && fn_start_hyt_console | grep -a -q "Hytale Server Booted" && fn_start_hyt_console | grep -a -q "No server tokens configured"; then + fn_script_log_info "Hytale server has no usable saved login, starting login" + TERM=screen tmux -L "${socketname}" send-keys -t "${sessionname}" "auth login device" ENTER + hytloginsent="1" + fi + sleep 1 + done + echo -e "" + if [ -n "${hytloginurl}" ]; then + echo -e "${bold}${lightyellow}Hytale server login required${default}" + echo -e "Open the URL below in a browser and log in with a Hytale account that owns the game." + echo -e "The code expires in 10 minutes. This is only needed once; the server saves the login." + echo -e "${hytloginurl}" + fn_script_log_info "Hytale server login required: ${hytloginurl}" + alert="hytale-login" + alert.sh + else + fn_print_warn_nl "Hytale server login required, but no login URL was found in the console yet" + echo -e "* Run ./${selfname} send \"/auth login device\" and approve the code shown in the console." + fn_script_log_warn "Hytale server login required, but no login URL was found in the console" + fi +} + fn_start_tmux() { # check for tmux size variables. if [[ "${servercfgtmuxwidth}" =~ ^[0-9]+$ ]]; then @@ -48,6 +97,13 @@ fn_start_tmux() { fn_reload_startparameters + # Hytale: with no saved server login file, have the server start its login (OAuth device code) on boot. + # A saved login that can't be used is handled after boot by fn_start_hyt_login. + if [ "${shortname}" == "hyt" ] && [ ! -f "${systemdir}/auth.enc" ]; then + startparameters="${startparameters} --boot-command 'auth login device'" + hytloginpending="1" + fi + # Create uid to ensure unique tmux socket name. if [ ! -f "${datadir}/${selfname}.uid" ]; then check_status.sh @@ -160,6 +216,9 @@ fn_start_tmux() { alert="restarted" alert.sh fi + if [ "${shortname}" == "hyt" ]; then + fn_start_hyt_login + fi fi rm -f "${lgsmlogdir:?}/.${selfname}-tmux-error.tmp" 2> /dev/null echo -en "\n" diff --git a/lgsm/modules/command_update.sh b/lgsm/modules/command_update.sh index a7cfc1b127..097664be35 100755 --- a/lgsm/modules/command_update.sh +++ b/lgsm/modules/command_update.sh @@ -25,6 +25,8 @@ elif [ "${shortname}" == "pmc" ] || [ "${shortname}" == "vpmc" ] || [ "${shortna update_pmc.sh elif [ "${shortname}" == "fctr" ]; then update_fctr.sh +elif [ "${shortname}" == "hyt" ]; then + update_hyt.sh elif [ "${shortname}" == "mta" ]; then update_mta.sh elif [ "${shortname}" == "jk2" ]; then diff --git a/lgsm/modules/core_getopt.sh b/lgsm/modules/core_getopt.sh index fede1debbf..a9e4592045 100755 --- a/lgsm/modules/core_getopt.sh +++ b/lgsm/modules/core_getopt.sh @@ -69,8 +69,8 @@ currentopt+=("${cmd_update_linuxgsm[@]}") if [ "${shortname}" == "jk2" ] || [ "${shortname}" == "etl" ] || [ "${engine}" != "idtech3" ]; then if [ "${shortname}" != "bf1942" ] && [ "${shortname}" != "bfv" ] && [ "${engine}" != "idtech2" ] && [ "${engine}" != "iw2.0" ] && [ "${engine}" != "iw3.0" ] && [ "${engine}" != "quake" ] && [ "${shortname}" != "samp" ] && [ "${shortname}" != "ut2k4" ]; then currentopt+=("${cmd_update[@]}" "${cmd_check_update[@]}") - # force update for SteamCMD or Multi Theft Auto only. - if [ "${appid}" ] || [ "${shortname}" == "mta" ]; then + # force update for SteamCMD, Multi Theft Auto or Hytale only. + if [ "${appid}" ] || [ "${shortname}" == "mta" ] || [ "${shortname}" == "hyt" ]; then currentopt+=("${cmd_force_update[@]}") fi fi diff --git a/lgsm/modules/core_modules.sh b/lgsm/modules/core_modules.sh index 9d72f5ce7c..9444aa4788 100755 --- a/lgsm/modules/core_modules.sh +++ b/lgsm/modules/core_modules.sh @@ -680,6 +680,11 @@ update_fctr.sh() { fn_fetch_module } +update_hyt.sh() { + modulefile="${FUNCNAME[0]}" + fn_fetch_module +} + update_jk2.sh() { modulefile="${FUNCNAME[0]}" fn_fetch_module diff --git a/lgsm/modules/info_game.sh b/lgsm/modules/info_game.sh index 09f91f67e9..fecfc8ccad 100755 --- a/lgsm/modules/info_game.sh +++ b/lgsm/modules/info_game.sh @@ -1350,6 +1350,27 @@ fn_info_game_hz() { servername="${servername:-"NOT SET"}" } +# Config Type: json +# Parameters: true +# Comment: +# Example: "ServerName": "SERVERNAME" +# Filetype: json +fn_info_game_hyt() { + # config.json is created by the server on first start. + if [ -f "${servercfgfullpath}" ]; then + fn_info_game_json "maxplayers" ".MaxPlayers // empty" + fn_info_game_json "servername" ".ServerName // empty" + fn_info_game_json "serverpassword" ".Password // empty" + fi + configtype="json" + configip="${ip:-"0.0.0.0"}" + maxplayers="${maxplayers:-"0"}" + port="${port:-"5520"}" + queryport="${port}" + servername="${servername:-"NOT SET"}" + serverpassword="${serverpassword:-"NOT SET"}" +} + # Config Type: parameters # Parameters: true # Comment: @@ -2397,6 +2418,8 @@ elif [ "${shortname}" == "hw" ]; then fn_info_game_hw elif [ "${shortname}" == "hz" ]; then fn_info_game_hz +elif [ "${shortname}" == "hyt" ]; then + fn_info_game_hyt elif [ "${shortname}" == "inss" ]; then fn_info_game_inss elif [ "${shortname}" == "jc2" ]; then diff --git a/lgsm/modules/info_messages.sh b/lgsm/modules/info_messages.sh index eb94b793cc..860b22af19 100755 --- a/lgsm/modules/info_messages.sh +++ b/lgsm/modules/info_messages.sh @@ -730,7 +730,7 @@ fn_info_messages_ports_edit() { fi done # engines/games that require editing the start parameters. - local ports_edit_array=("av" "ck" "col" "cs2" "fctr" "goldsrc" "hcu" "hw" "iw3.0" "ioquake3" "pw" "qfusion" "rsdw" "rust" "scpsl" "scpslsm" "sf" "sol" "spark" "source" "unreal4" "arma3" "dayz" "unt" "vh") + local ports_edit_array=("av" "ck" "col" "cs2" "fctr" "goldsrc" "hcu" "hw" "hyt" "iw3.0" "ioquake3" "pw" "qfusion" "rsdw" "rust" "scpsl" "scpslsm" "sf" "sol" "spark" "source" "unreal4" "arma3" "dayz" "unt" "vh") for port_edit in "${ports_edit_array[@]}"; do if [ "${engine}" == "${port_edit}" ] || [ "${gamename}" == "${port_edit}" ] || [ "${shortname}" == "${port_edit}" ]; then startparameterslocation="${configdirserver}" @@ -754,7 +754,7 @@ fn_info_messages_ports() { portcommand="ss -tuplwn | grep enfMain" elif [ "${shortname}" == "q4" ]; then portcommand="ss -tuplwn | grep q4ded.x86" - elif [ "${shortname}" == "mc" ] || [ "${shortname}" == "nec" ] || [ "${shortname}" == "pmc" ] || [ "${shortname}" == "vpmc" ] || [ "${shortname}" == "wmc" ]; then + elif [ "${shortname}" == "hyt" ] || [ "${shortname}" == "mc" ] || [ "${shortname}" == "nec" ] || [ "${shortname}" == "pmc" ] || [ "${shortname}" == "vpmc" ] || [ "${shortname}" == "wmc" ]; then portcommand="ss -tuplwn | grep java" elif [ "${shortname}" == "terraria" ]; then portcommand="ss -tuplwn | grep Main" @@ -1131,6 +1131,13 @@ fn_info_messages_hz() { } | column -s $'\t' -t } +fn_info_messages_hyt() { + { + fn_port "header" + fn_port "Game" port udp + } | column -s $'\t' -t +} + fn_info_messages_ins() { { fn_port "header" @@ -1874,6 +1881,8 @@ fn_info_messages_select_engine() { fn_info_messages_hw elif [ "${shortname}" == "hz" ]; then fn_info_messages_hz + elif [ "${shortname}" == "hyt" ]; then + fn_info_messages_hyt elif [ "${shortname}" == "ins" ]; then fn_info_messages_ins elif [ "${shortname}" == "inss" ]; then diff --git a/lgsm/modules/install_config.sh b/lgsm/modules/install_config.sh index ccd9d92327..6c5019a227 100755 --- a/lgsm/modules/install_config.sh +++ b/lgsm/modules/install_config.sh @@ -520,6 +520,9 @@ elif [ "${shortname}" == "hl2dm" ]; then elif [ "${shortname}" == "hz" ]; then # Config is generated on first run : +elif [ "${shortname}" == "hyt" ]; then + # Config is generated on first run + : elif [ "${shortname}" == "ins" ]; then array_configs+=(server.cfg) fn_default_config_remote diff --git a/lgsm/modules/install_server_files.sh b/lgsm/modules/install_server_files.sh index e5f10739d2..abf2293f6b 100755 --- a/lgsm/modules/install_server_files.sh +++ b/lgsm/modules/install_server_files.sh @@ -256,6 +256,8 @@ elif [ "${shortname}" == "mta" ]; then elif [ "${shortname}" == "fctr" ]; then update_fctr.sh install_factorio_save.sh +elif [ "${shortname}" == "hyt" ]; then + update_hyt.sh elif [ "${shortname}" == "jk2" ]; then update_jk2.sh elif [ "${shortname}" == "vints" ]; then diff --git a/lgsm/modules/update_hyt.sh b/lgsm/modules/update_hyt.sh new file mode 100755 index 0000000000..86829bb686 --- /dev/null +++ b/lgsm/modules/update_hyt.sh @@ -0,0 +1,307 @@ +#!/bin/bash +# LinuxGSM update_hyt.sh module +# Author: Andrew dos Santos +# Contributors: https://linuxgsm.com/contrib +# Website: https://linuxgsm.com +# Description: Handles updating of Hytale servers. + +moduleselfname="$(basename "$(readlink -f "${BASH_SOURCE[0]}")")" + +fn_update_hyt_downloader_arch() { + case "${arch}" in + x86_64 | amd64) + hytaledownloaderfile="hytale-downloader-linux-amd64" + ;; + aarch64 | arm64) + fn_print_failure "Hytale supports arm64 servers, but the official downloader archive currently used by LinuxGSM does not include a Linux arm64 downloader." + fn_script_log_fail "Unsupported Hytale downloader architecture: ${arch}" + core_exit.sh + ;; + *) + fn_print_failure "Unknown or unsupported hytale-downloader architecture: ${arch}" + fn_script_log_fail "Unknown or unsupported hytale-downloader architecture: ${arch}" + core_exit.sh + ;; + esac + hytaledownloader="${serverfiles}/${hytaledownloaderfile}" +} + +fn_update_downloader() { + fn_update_hyt_downloader_arch + if [ ! -f "${hytaledownloader}" ] || [ "${forceupdate}" == "1" ]; then + fn_fetch_file "https://downloader.hytale.com/hytale-downloader.zip" "" "" "" "${tmpdir}" "hytale-downloader.zip" "nochmodx" "norun" "forcedl" "nohash" + echo -en "extracting hytale-downloader..." + unzip -oq "${tmpdir}/hytale-downloader.zip" "${hytaledownloaderfile}" "QUICKSTART.md" -d "${serverfiles}" + exitcode=$? + if [ "${exitcode}" -ne 0 ]; then + fn_print_fail_eol_nl + fn_script_log_fail "Extracting hytale-downloader" + core_exit.sh + else + chmod +x "${hytaledownloader}" + fn_print_ok_eol_nl + fn_script_log_pass "Extracting hytale-downloader" + fi + fi +} + +fn_update_hyt_patchline_args() { + hytalepatchline="${hytalepatchline:-release}" + hytalepatchlineargs=() + if [ "${hytalepatchline}" != "release" ]; then + hytalepatchlineargs=(-patchline "${hytalepatchline}") + fi +} + +# The downloader needs a Hytale account login (OAuth device code) the first time it runs, and again +# if the saved credentials stop working. It waits for the login with no time limit, so it must +# never run unattended without credentials, otherwise cron jobs hang. +# Install always shows the login and waits: someone is watching, either in a terminal or in the +# container logs (e.g. docker logs) during the first install. +fn_update_hyt_auth() { + hytalecredentials="${serverfiles}/.hytale-downloader-credentials.json" + if [ "${firstcommandname}" == "INSTALL" ] || { [ -t 0 ] && [ -t 1 ]; }; then + hytaledownloadertimeout="900" + if [ ! -f "${hytalecredentials}" ]; then + echo -e "" + echo -e "${bold}${lightyellow}Hytale account login required${default}" + echo -e "The Hytale downloader needs you to log in with a Hytale account that owns the game." + echo -e "Open the URL shown below in a browser and approve the code within 15 minutes. This is only needed once." + echo -e "Running in Docker? The URL is also shown in the container logs (docker logs)." + echo -e "" + fn_script_log_info "Hytale downloader login required" + fi + else + hytaledownloadertimeout="300" + if [ ! -f "${hytalecredentials}" ]; then + fn_print_failure_nl "Hytale downloader is not logged in" + echo -e "* Run ./${selfname} update in a terminal and approve the Hytale account login once." + fn_script_log_fail "Hytale downloader is not logged in: ${hytalecredentials} not found" + core_exit.sh + fi + fi +} + +# Report a downloader timeout, which usually means it was waiting for a login. +fn_update_hyt_timeout_check() { + if [ "${exitcode}" -eq 124 ]; then + fn_print_failure_nl "Hytale downloader timed out, it is probably waiting for a Hytale account login" + echo -e "* The saved credentials may have expired. Run ./${selfname} update in a terminal to log in again." + fn_script_log_fail "Hytale downloader timed out after ${hytaledownloadertimeout}s" + core_exit.sh + fi +} + +fn_update_extract() { + extractdir="${tmpdir}/hytale-game" + rm -rf "${extractdir:?}" + mkdir -p "${extractdir}" + echo -en "extracting ${remotebuildfilename}..." + unzip -oq "${tmpdir}/${remotebuildfilename}" -d "${extractdir}" + exitcode=$? + if [ "${exitcode}" -ne 0 ]; then + fn_print_fail_eol_nl + fn_script_log_fail "Extracting ${remotebuildfilename}" + core_exit.sh + fi + + if [ -d "${extractdir}/game/Server" ]; then + extractedroot="${extractdir}/game" + else + extractedroot="${extractdir}" + fi + + mkdir -p "${serverfiles}" + if [ "${firstcommandname}" == "INSTALL" ]; then + cp -a "${extractedroot}/." "${serverfiles}/" + else + for item in "${extractedroot}"/*; do + [ -e "${item}" ] || continue + itemname="$(basename "${item}")" + case "${itemname}" in + Server | .hytale-downloader-credentials.json) + continue + ;; + jvm.options) + if [ -f "${serverfiles}/jvm.options" ]; then + continue + fi + ;; + esac + cp -a "${item}" "${serverfiles}/" + done + mkdir -p "${serverfiles}/Server" + for item in "${extractedroot}/Server"/*; do + [ -e "${item}" ] || continue + itemname="$(basename "${item}")" + case "${itemname}" in + backups | bans.json | config.json | logs | mods | permissions.json | universe | whitelist.json) + continue + ;; + esac + cp -a "${item}" "${serverfiles}/Server/" + done + fi + [ -f "${serverfiles}/start.sh" ] && chmod +x "${serverfiles}/start.sh" + fn_print_ok_eol_nl + fn_script_log_pass "Extracting ${remotebuildfilename}" + rm -rf "${extractdir:?}" +} + +fn_update_dl() { + fn_update_downloader + fn_update_hyt_patchline_args + remotebuildfilename="hytale-server-${remotebuild:-latest}.zip" + echo -e "downloading file [ ${italic}${remotebuildfilename}${default} ]" + fn_sleep_time + cd "${serverfiles}" || exit + fn_update_hyt_auth + timeout --foreground "${hytaledownloadertimeout}" "${hytaledownloader}" -download-path "${tmpdir}/${remotebuildfilename}" "${hytalepatchlineargs[@]}" -skip-update-check + exitcode=$? + fn_update_hyt_timeout_check + if [ "${exitcode}" -ne 0 ]; then + fn_print_failure_nl "Downloading ${remotebuildfilename}" + fn_script_log_fail "Downloading ${remotebuildfilename}" + core_exit.sh + fi + fn_update_extract + if [ -n "${remotebuild}" ]; then + echo "${remotebuild}" > "${localbuildfile}" + fi + fn_clear_tmp +} + +fn_update_hyt_check_localbuild_tracking() { + if [ -f "${localbuildfile}" ] && [ -f "${serverfiles}/Server/HytaleServer.jar" ] && [ "${serverfiles}/Server/HytaleServer.jar" -nt "${localbuildfile}" ]; then + fn_print_warn_nl "Hytale server files are newer than LinuxGSM build tracking" + echo -e "* Hytale may have updated itself outside LinuxGSM." + echo -e "* Run ./${selfname} update to refresh LinuxGSM version tracking." + fn_script_log_warn "Hytale server files are newer than LinuxGSM build tracking" + fi +} + +fn_update_localbuild() { + fn_print_dots "Checking local build: ${remotelocation}" + if [ -f "${localbuildfile}" ]; then + localbuild="$(cat "${localbuildfile}")" + fi + if [ -z "${localbuild}" ]; then + fn_print_error "Checking local build: ${remotelocation}: missing local build info" + 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}" + fn_script_log_pass "Checking local build" + fn_update_hyt_check_localbuild_tracking + fi +} + +fn_update_remotebuild() { + fn_update_downloader + fn_update_hyt_patchline_args + cd "${serverfiles}" || exit + remotebuildresponsefile="${tmpdir}/hytale-print-version-response.txt" + rm -f "${remotebuildresponsefile}" + fn_update_hyt_auth + timeout --foreground "${hytaledownloadertimeout}" "${hytaledownloader}" -print-version "${hytalepatchlineargs[@]}" -skip-update-check 2>&1 | tee "${remotebuildresponsefile}" + exitcode=${PIPESTATUS[0]} + fn_update_hyt_timeout_check + remotebuildresponse="$(cat "${remotebuildresponsefile}")" + if [ -f "${lgsmlog}" ]; then + cat "${remotebuildresponsefile}" >> "${lgsmlog}" + fi + remotebuild=$(echo "${remotebuildresponse}" | grep -Eo "[0-9]{4}\.[0-9]{2}\.[0-9]{2}-[A-Za-z0-9]+" | tail -1) + if [ -z "${remotebuild}" ]; then + remotebuild=$(echo "${remotebuildresponse}" | tail -1) + fi + + if [ "${firstcommandname}" != "INSTALL" ]; then + fn_print_dots "Checking remote build: ${remotelocation}" + if [ "${exitcode}" -ne 0 ] || [ -z "${remotebuild}" ] || [ "${remotebuild}" == "null" ]; then + fn_print_fail "Checking remote build: ${remotelocation}" + fn_script_log_fail "Checking remote build" + core_exit.sh + else + fn_print_ok "Checking remote build: ${remotelocation}" + fn_script_log_pass "Checking remote build" + fi + else + if [ "${exitcode}" -ne 0 ] || [ -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 + fi + fi +} + +fn_update_compare() { + fn_print_dots "Checking for update: ${remotelocation}" + if [ "${localbuild}" != "${remotebuild}" ] || [ "${forceupdate}" == "1" ]; then + 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}${remotebuild}${default}" + fn_print_nl "* Patchline: ${hytalepatchline}" + fn_print "\n" + fn_script_log_info "Update available" + fn_script_log_info "Local build: ${localbuild}" + fn_script_log_info "Remote build: ${remotebuild}" + fn_script_log_info "Patchline: ${hytalepatchline}" + + if [ "${commandname}" == "UPDATE" ]; then + date +%s > "${lockdir:?}/last-updated.lock" + unset updateonstart + check_status.sh + if [ "${status}" == "0" ]; then + fn_update_dl + else + fn_print_restart_warning + exitbypass=1 + command_stop.sh + fn_firstcommand_reset + exitbypass=1 + fn_update_dl + exitbypass=1 + command_start.sh + fn_firstcommand_reset + fi + unset exitbypass + alert="update" + elif [ "${commandname}" == "CHECK-UPDATE" ]; then + alert="check-update" + fi + alert.sh + else + fn_print_ok_nl "Checking for update: ${remotelocation}" + 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}" + fn_print_nl "* Patchline: ${hytalepatchline}" + fn_print "\n" + fn_script_log_info "No update available" + fn_script_log_info "Local build: ${localbuild}" + fn_script_log_info "Remote build: ${remotebuild}" + fn_script_log_info "Patchline: ${hytalepatchline}" + fi +} + +info_distro.sh + +localbuildfile="${datadir}/${selfname}-hytale-version" +remotelocation="hytale.com" + +if [ "${firstcommandname}" == "INSTALL" ]; then + fn_update_remotebuild + fn_update_dl +else + fn_print_dots "Checking for update" + fn_print_dots "Checking for update: ${remotelocation}" + fn_script_log_info "Checking for update: ${remotelocation}" + fn_update_localbuild + fn_update_remotebuild + fn_update_compare +fi From f9b9bcc40c52ed214b3ed05d816a5ece952321a5 Mon Sep 17 00:00:00 2001 From: Daniel Gibbs Date: Fri, 9 Oct 2026 23:07:13 +0100 Subject: [PATCH 024/164] fix(deps): add libatomic for American Truck Simulator and Euro Truck Simulator 2 (#4990) The amtrucks_server and eurotrucks2_server binaries link libatomic.so.1, which is not installed by default, so both servers failed to start. --- lgsm/data/almalinux-8.csv | 4 ++-- lgsm/data/almalinux-9.csv | 4 ++-- lgsm/data/centos-7.csv | 4 ++-- lgsm/data/centos-8.csv | 4 ++-- lgsm/data/centos-9.csv | 4 ++-- lgsm/data/debian-10.csv | 4 ++-- lgsm/data/debian-11.csv | 4 ++-- lgsm/data/debian-12.csv | 4 ++-- lgsm/data/debian-13.csv | 4 ++-- lgsm/data/debian-9.csv | 4 ++-- lgsm/data/rhel-7.csv | 4 ++-- lgsm/data/rhel-8.csv | 4 ++-- lgsm/data/rhel-9.csv | 4 ++-- lgsm/data/rocky-8.csv | 4 ++-- lgsm/data/rocky-9.csv | 4 ++-- lgsm/data/ubuntu-16.04.csv | 4 ++-- lgsm/data/ubuntu-18.04.csv | 4 ++-- lgsm/data/ubuntu-20.04.csv | 4 ++-- lgsm/data/ubuntu-22.04.csv | 4 ++-- lgsm/data/ubuntu-23.04.csv | 4 ++-- lgsm/data/ubuntu-23.10.csv | 4 ++-- lgsm/data/ubuntu-24.04.csv | 4 ++-- lgsm/data/ubuntu-26.04.csv | 4 ++-- 23 files changed, 46 insertions(+), 46 deletions(-) diff --git a/lgsm/data/almalinux-8.csv b/lgsm/data/almalinux-8.csv index 8ce65a4d91..b55ad0bc8b 100644 --- a/lgsm/data/almalinux-8.csv +++ b/lgsm/data/almalinux-8.csv @@ -6,7 +6,7 @@ ahl2 ark arma3 armar,libcurl,openssl-libs -ats +ats,libatomic av bb bb2,libcurl.i686 @@ -45,7 +45,7 @@ dys eco,libgdiplus em etl -ets2 +ets2,libatomic fctr fof gmod,ncurses-libs.i686 diff --git a/lgsm/data/almalinux-9.csv b/lgsm/data/almalinux-9.csv index 6888992a36..f17e59cda0 100644 --- a/lgsm/data/almalinux-9.csv +++ b/lgsm/data/almalinux-9.csv @@ -6,7 +6,7 @@ ahl2 ark arma3 armar,libcurl,openssl-libs -ats +ats,libatomic av bb bb2,libcurl.i686 @@ -45,7 +45,7 @@ dys eco,libgdiplus em etl -ets2 +ets2,libatomic fctr fof gmod,ncurses-libs.i686 diff --git a/lgsm/data/centos-7.csv b/lgsm/data/centos-7.csv index 1bffbf0bfe..4e8379ca3a 100644 --- a/lgsm/data/centos-7.csv +++ b/lgsm/data/centos-7.csv @@ -6,7 +6,7 @@ ahl2 ark arma3 armar,libcurl,openssl11-libs -ats +ats,libatomic av bb bb2,libcurl.i686 @@ -45,7 +45,7 @@ dys eco,libgdiplus em etl -ets2 +ets2,libatomic fctr fof gmod,ncurses-libs.i686 diff --git a/lgsm/data/centos-8.csv b/lgsm/data/centos-8.csv index b25eae1f58..dda247ea13 100644 --- a/lgsm/data/centos-8.csv +++ b/lgsm/data/centos-8.csv @@ -6,7 +6,7 @@ ahl2 ark arma3 armar,libcurl,openssl-libs -ats +ats,libatomic av bb bb2,libcurl.i686 @@ -45,7 +45,7 @@ dys eco,libgdiplus em etl -ets2 +ets2,libatomic fctr fof gmod,ncurses-libs.i686 diff --git a/lgsm/data/centos-9.csv b/lgsm/data/centos-9.csv index d472cb2229..08e4a8489b 100644 --- a/lgsm/data/centos-9.csv +++ b/lgsm/data/centos-9.csv @@ -6,7 +6,7 @@ ahl2 ark arma3 armar,libcurl,openssl-libs -ats +ats,libatomic av bb bb2,libcurl.i686 @@ -45,7 +45,7 @@ dys eco,libgdiplus em etl -ets2 +ets2,libatomic fctr fof gmod,ncurses-libs.i686 diff --git a/lgsm/data/debian-10.csv b/lgsm/data/debian-10.csv index 308af0aa12..e13675db7a 100644 --- a/lgsm/data/debian-10.csv +++ b/lgsm/data/debian-10.csv @@ -5,7 +5,7 @@ all,bc,binutils,bsdmainutils,bzip2,ca-certificates,cpio,curl,distro-info,file,gz ark arma3 armar,libcurl4 -ats +ats,libatomic1 av bb bb2,libcurl4-gnutls-dev:i386 @@ -44,7 +44,7 @@ dys eco,libgdiplus em etl -ets2 +ets2,libatomic1 fctr fof gmod,libtinfo5:i386 diff --git a/lgsm/data/debian-11.csv b/lgsm/data/debian-11.csv index a5da6de630..7562add0c5 100644 --- a/lgsm/data/debian-11.csv +++ b/lgsm/data/debian-11.csv @@ -6,7 +6,7 @@ ahl2 ark arma3 armar,libcurl4 -ats +ats,libatomic1 av bb bb2,libcurl4-gnutls-dev:i386 @@ -45,7 +45,7 @@ dys eco,libgdiplus em etl -ets2 +ets2,libatomic1 fctr fof gmod,libtinfo5:i386 diff --git a/lgsm/data/debian-12.csv b/lgsm/data/debian-12.csv index c0a6615d6e..0cba73d33a 100644 --- a/lgsm/data/debian-12.csv +++ b/lgsm/data/debian-12.csv @@ -6,7 +6,7 @@ ahl2 ark arma3 armar,libcurl4 -ats +ats,libatomic1 av bb bb2,libcurl4-gnutls-dev:i386 @@ -45,7 +45,7 @@ dys eco,libgdiplus em etl -ets2 +ets2,libatomic1 fctr fof gmod,libtinfo5:i386 diff --git a/lgsm/data/debian-13.csv b/lgsm/data/debian-13.csv index 1c63c4d4d2..6176812082 100644 --- a/lgsm/data/debian-13.csv +++ b/lgsm/data/debian-13.csv @@ -6,7 +6,7 @@ ahl2 ark arma3 armar,libcurl4 -ats +ats,libatomic1 av bb bb2,libcurl4-gnutls-dev:i386 @@ -45,7 +45,7 @@ dys eco,libgdiplus em etl -ets2 +ets2,libatomic1 fctr fof gmod diff --git a/lgsm/data/debian-9.csv b/lgsm/data/debian-9.csv index fde9c06f80..b571e41bc0 100644 --- a/lgsm/data/debian-9.csv +++ b/lgsm/data/debian-9.csv @@ -6,7 +6,7 @@ ahl2 ark arma3 armar,libcurl4 -ats +ats,libatomic1 av bb bb2,libcurl4-gnutls-dev:i386 @@ -45,7 +45,7 @@ dys eco,libgdiplus em etl -ets2 +ets2,libatomic1 fctr fof gmod,libtinfo5:i386 diff --git a/lgsm/data/rhel-7.csv b/lgsm/data/rhel-7.csv index 0b197f7c86..f00dfda987 100644 --- a/lgsm/data/rhel-7.csv +++ b/lgsm/data/rhel-7.csv @@ -6,7 +6,7 @@ ahl2 ark arma3 armar,libcurl,openssl11-libs -ats +ats,libatomic av bb pw @@ -46,7 +46,7 @@ dys eco,libgdiplus em etl -ets2 +ets2,libatomic fctr fof gmod,ncurses-libs.i686 diff --git a/lgsm/data/rhel-8.csv b/lgsm/data/rhel-8.csv index 20bd06bcbf..3bef755af2 100644 --- a/lgsm/data/rhel-8.csv +++ b/lgsm/data/rhel-8.csv @@ -6,7 +6,7 @@ ahl2 ark arma3 armar,libcurl,openssl-libs -ats +ats,libatomic av bb bb2,libcurl.i686 @@ -45,7 +45,7 @@ dys eco,libgdiplus em etl -ets2 +ets2,libatomic fctr fof gmod,ncurses-libs.i686 diff --git a/lgsm/data/rhel-9.csv b/lgsm/data/rhel-9.csv index 6888992a36..f17e59cda0 100644 --- a/lgsm/data/rhel-9.csv +++ b/lgsm/data/rhel-9.csv @@ -6,7 +6,7 @@ ahl2 ark arma3 armar,libcurl,openssl-libs -ats +ats,libatomic av bb bb2,libcurl.i686 @@ -45,7 +45,7 @@ dys eco,libgdiplus em etl -ets2 +ets2,libatomic fctr fof gmod,ncurses-libs.i686 diff --git a/lgsm/data/rocky-8.csv b/lgsm/data/rocky-8.csv index 20bd06bcbf..3bef755af2 100644 --- a/lgsm/data/rocky-8.csv +++ b/lgsm/data/rocky-8.csv @@ -6,7 +6,7 @@ ahl2 ark arma3 armar,libcurl,openssl-libs -ats +ats,libatomic av bb bb2,libcurl.i686 @@ -45,7 +45,7 @@ dys eco,libgdiplus em etl -ets2 +ets2,libatomic fctr fof gmod,ncurses-libs.i686 diff --git a/lgsm/data/rocky-9.csv b/lgsm/data/rocky-9.csv index 6888992a36..f17e59cda0 100644 --- a/lgsm/data/rocky-9.csv +++ b/lgsm/data/rocky-9.csv @@ -6,7 +6,7 @@ ahl2 ark arma3 armar,libcurl,openssl-libs -ats +ats,libatomic av bb bb2,libcurl.i686 @@ -45,7 +45,7 @@ dys eco,libgdiplus em etl -ets2 +ets2,libatomic fctr fof gmod,ncurses-libs.i686 diff --git a/lgsm/data/ubuntu-16.04.csv b/lgsm/data/ubuntu-16.04.csv index e1db83488a..0bc4fb1697 100644 --- a/lgsm/data/ubuntu-16.04.csv +++ b/lgsm/data/ubuntu-16.04.csv @@ -6,7 +6,7 @@ ahl2 ark arma3 armar,libcurl4 -ats +ats,libatomic1 av bb pw @@ -46,7 +46,7 @@ dys eco,libgdiplus em etl -ets2 +ets2,libatomic1 fctr fof gmod,libtinfo5:i386 diff --git a/lgsm/data/ubuntu-18.04.csv b/lgsm/data/ubuntu-18.04.csv index 7ea128ddfa..ddcd75cc5e 100644 --- a/lgsm/data/ubuntu-18.04.csv +++ b/lgsm/data/ubuntu-18.04.csv @@ -6,7 +6,7 @@ ahl2 ark arma3 armar,libcurl4 -ats +ats,libatomic1 av pw bb @@ -46,7 +46,7 @@ dys eco,libgdiplus em etl -ets2 +ets2,libatomic1 fctr fof gmod,libtinfo5:i386 diff --git a/lgsm/data/ubuntu-20.04.csv b/lgsm/data/ubuntu-20.04.csv index 4e5ae9fdc5..91b610bffa 100644 --- a/lgsm/data/ubuntu-20.04.csv +++ b/lgsm/data/ubuntu-20.04.csv @@ -6,7 +6,7 @@ ahl2 ark arma3 armar,libcurl4 -ats +ats,libatomic1 av bb bb2,libcurl4-gnutls-dev:i386 @@ -45,7 +45,7 @@ dys eco,libgdiplus em etl -ets2 +ets2,libatomic1 fctr fof gmod,libtinfo5:i386 diff --git a/lgsm/data/ubuntu-22.04.csv b/lgsm/data/ubuntu-22.04.csv index 96a745493c..04d7da8bb1 100644 --- a/lgsm/data/ubuntu-22.04.csv +++ b/lgsm/data/ubuntu-22.04.csv @@ -6,7 +6,7 @@ ahl2 ark arma3 armar,libcurl4 -ats +ats,libatomic1 av bb bb2,libcurl4-gnutls-dev:i386 @@ -45,7 +45,7 @@ dys eco,libgdiplus em etl -ets2 +ets2,libatomic1 fctr fof gmod,libtinfo5:i386 diff --git a/lgsm/data/ubuntu-23.04.csv b/lgsm/data/ubuntu-23.04.csv index 39ff561a35..3f01a39643 100644 --- a/lgsm/data/ubuntu-23.04.csv +++ b/lgsm/data/ubuntu-23.04.csv @@ -6,7 +6,7 @@ ahl2 ark arma3 armar,libcurl4 -ats +ats,libatomic1 av bb bb2,libcurl4-gnutls-dev:i386 @@ -45,7 +45,7 @@ dys eco,libgdiplus em etl -ets2 +ets2,libatomic1 fctr fof gmod,libtinfo5:i386 diff --git a/lgsm/data/ubuntu-23.10.csv b/lgsm/data/ubuntu-23.10.csv index 39ff561a35..3f01a39643 100644 --- a/lgsm/data/ubuntu-23.10.csv +++ b/lgsm/data/ubuntu-23.10.csv @@ -6,7 +6,7 @@ ahl2 ark arma3 armar,libcurl4 -ats +ats,libatomic1 av bb bb2,libcurl4-gnutls-dev:i386 @@ -45,7 +45,7 @@ dys eco,libgdiplus em etl -ets2 +ets2,libatomic1 fctr fof gmod,libtinfo5:i386 diff --git a/lgsm/data/ubuntu-24.04.csv b/lgsm/data/ubuntu-24.04.csv index e6364f2683..bddd70e4b6 100644 --- a/lgsm/data/ubuntu-24.04.csv +++ b/lgsm/data/ubuntu-24.04.csv @@ -6,7 +6,7 @@ ahl2 ark arma3 armar,libcurl4t64 -ats +ats,libatomic1 av bb bb2,libcurl4-gnutls-dev:i386 @@ -45,7 +45,7 @@ dys eco,libgdiplus em etl -ets2 +ets2,libatomic1 fctr fof gmod diff --git a/lgsm/data/ubuntu-26.04.csv b/lgsm/data/ubuntu-26.04.csv index e6364f2683..bddd70e4b6 100644 --- a/lgsm/data/ubuntu-26.04.csv +++ b/lgsm/data/ubuntu-26.04.csv @@ -6,7 +6,7 @@ ahl2 ark arma3 armar,libcurl4t64 -ats +ats,libatomic1 av bb bb2,libcurl4-gnutls-dev:i386 @@ -45,7 +45,7 @@ dys eco,libgdiplus em etl -ets2 +ets2,libatomic1 fctr fof gmod From fe8e3afc6742ade8d3e528e5a562964a7726b50d Mon Sep 17 00:00:00 2001 From: Daniel Gibbs Date: Fri, 9 Oct 2026 23:13:10 +0100 Subject: [PATCH 025/164] fix(ci): run apt-get update before installing Details Check dependencies (#4992) The runner image's package index goes stale. Ubuntu replaced the libxml2-utils build it lists, so apt-get install got a 404 and the details-check job failed before any LinuxGSM code ran. --- .github/workflows/action-details-check.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/action-details-check.yml b/.github/workflows/action-details-check.yml index fc7e5e7e59..10474968ee 100644 --- a/.github/workflows/action-details-check.yml +++ b/.github/workflows/action-details-check.yml @@ -107,7 +107,7 @@ jobs: key: apt-${{ runner.os }}-libxml2-utils-jq - name: Install dependencies - run: sudo apt-get install -y --no-install-recommends libxml2-utils jq + run: sudo apt-get update && sudo apt-get install -y --no-install-recommends libxml2-utils jq - name: Create serverfiles directory run: mkdir -p serverfiles From 15f542d4c6c7172d146ea189c26ab6b18cc9097f Mon Sep 17 00:00:00 2001 From: Daniel Gibbs Date: Fri, 9 Oct 2026 23:18:55 +0100 Subject: [PATCH 026/164] fix(pz): pass the admin password as a start parameter (#4991) Project Zomboid prompts for an admin password on first start when none is given, and the server waits there forever because LinuxGSM runs it in tmux (and Docker has no terminal at all). --- lgsm/config-default/config-lgsm/pzserver/_default.cfg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lgsm/config-default/config-lgsm/pzserver/_default.cfg b/lgsm/config-default/config-lgsm/pzserver/_default.cfg index a0456d6e3a..e8e139f8a5 100644 --- a/lgsm/config-default/config-lgsm/pzserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/pzserver/_default.cfg @@ -13,7 +13,7 @@ ip="0.0.0.0" adminpassword="CHANGE_ME" ## Server Parameters | https://docs.linuxgsm.com/configuration/start-parameters#additional-parameters -startparameters="-servername ${selfname}" +startparameters="-servername ${selfname} -adminpassword ${adminpassword}" #### LinuxGSM Settings #### From af8cb385c78f8f56b492dec952c34efcebbb268c Mon Sep 17 00:00:00 2001 From: Daniel Gibbs Date: Fri, 9 Oct 2026 23:54:34 +0100 Subject: [PATCH 027/164] fix(ts3): query the ServerQuery address set in query_ip (#4975) The monitor connects to the query port on each address in queryips. When voice_ip was set to a specific address, queryips only held that address and the public IP, so a ServerQuery bound to localhost (query_ip=127.0.0.1) was never tried and monitor restarted the server. Read query_ip from ts3server.ini (first address if several) and, when it is a specific IPv4 address not already listed, query it first. Fixes #4966 --- lgsm/modules/check_ip.sh | 6 ++++++ lgsm/modules/command_dev_parse_game_details.sh | 1 + lgsm/modules/info_game.sh | 4 ++++ 3 files changed, 11 insertions(+) diff --git a/lgsm/modules/check_ip.sh b/lgsm/modules/check_ip.sh index 8f943c5687..57c7f5e8f2 100755 --- a/lgsm/modules/check_ip.sh +++ b/lgsm/modules/check_ip.sh @@ -61,3 +61,9 @@ else httpip=("${ip}") telnetip=("${ip}") fi + +# If the game config binds its query interface to a specific IPv4 address (e.g. TeamSpeak 3 query_ip), +# query that address first. This also covers a query interface bound to localhost. +if grep -qE '^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$' <<< "${configqueryip}" && [ "${configqueryip}" != "0.0.0.0" ] && [[ " ${queryips[*]} " != *" ${configqueryip} "* ]]; then + queryips=("${configqueryip}" "${queryips[@]}") +fi diff --git a/lgsm/modules/command_dev_parse_game_details.sh b/lgsm/modules/command_dev_parse_game_details.sh index 15e6657f90..f9903dec18 100755 --- a/lgsm/modules/command_dev_parse_game_details.sh +++ b/lgsm/modules/command_dev_parse_game_details.sh @@ -84,6 +84,7 @@ declare -A server_details=( ['Query Enabled']="${queryenabled}" ['Query HTTP Port']="${httpqueryport}" ['Query HTTPS Port']="${httpsqueryport}" + ['Query IP']="${configqueryip}" ['Query Mode']="${querymode}" ['Query Port GS']="${gamespyqueryport}" ['Query Port']="${queryport}" diff --git a/lgsm/modules/info_game.sh b/lgsm/modules/info_game.sh index fecfc8ccad..a0b17a657c 100755 --- a/lgsm/modules/info_game.sh +++ b/lgsm/modules/info_game.sh @@ -757,8 +757,12 @@ fn_info_game_ts3() { fn_info_game_ini "httpqueryport" "query_http_port" fn_info_game_ini "httpsqueryport" "query_https_port" fn_info_game_ini "queryport" "query_port" + fn_info_game_ini "configqueryip" "query_ip" fn_info_game_ini "sshqueryport" "query_ssh_port" fi + # query_ip can list several addresses (e.g. "0.0.0.0, ::"), use the first. + configqueryip="${configqueryip%%,*}" + configqueryip="${configqueryip// /}" configip="${configip:-"0.0.0.0"}" dbplugin="${dbplugin:-"NOT SET"}" fileport="${fileport:-"0"}" From 3cf75e2c16f3656112a1cd14e0e2bb34adaf5a6d Mon Sep 17 00:00:00 2001 From: Daniel Gibbs Date: Sat, 10 Oct 2026 00:19:47 +0100 Subject: [PATCH 028/164] ci(details-check): run servers in shards from the checkout (#4993) * ci(details-check): run servers in shards from the checkout - Check servers in 12 shards instead of one job per server, so jobs no longer queue behind the concurrency limit. - Seed lgsm/modules, config-default and data from the checkout, so each server takes about 20s instead of about 80s and the PR's own code is what gets checked. - Run bf1942, bfv, btl and onset in an ubuntu:20.04 container. The ubuntu-20.04 runner is retired, so btl and onset never started. - Changes to the details-check workflow or scripts trigger a full run. * ci(details-check): use the config filename for the Game-Server-Configs URL servercfgdefault can include a directory variable (xnt uses ${systemdir}/server.cfg). Game-Server-Configs stores files flat per game, so use only the filename. * ci(details-check): keep config subdirectories in the Game-Server-Configs URL Only drop a leading ${variable}/ (xnt). pc2's config lives in config_sample/ in Game-Server-Configs. * ci(details-check): fix the Game-Server-Configs path expansion Strip a leading ${variable}/ with a pattern test instead of a nested parameter expansion, which bash mangled. Keeps pc2's config_sample/. --- .../scripts/details-check-generate-matrix.sh | 88 ++++++------ .github/scripts/details-check-run.sh | 66 +++++++++ .github/workflows/action-details-check.yml | 128 +++++++----------- 3 files changed, 157 insertions(+), 125 deletions(-) create mode 100755 .github/scripts/details-check-run.sh diff --git a/.github/scripts/details-check-generate-matrix.sh b/.github/scripts/details-check-generate-matrix.sh index cf37b528c0..9aaa0a18db 100755 --- a/.github/scripts/details-check-generate-matrix.sh +++ b/.github/scripts/details-check-generate-matrix.sh @@ -1,50 +1,50 @@ #!/bin/bash +# Splits the servers to check into shards (one job each) and a list of legacy servers. +# Legacy servers need an older glibc than the hosted runners have, so they run in an ubuntu:20.04 container. +# Writes shards.json (matrix) and legacy.txt (space-separated shortnames). ref="${LGSM_REF:-${GITHUB_REF#refs/heads/}}" -curl "https://raw.githubusercontent.com/GameServerManagers/LinuxGSM/${ref}/lgsm/data/serverlist.csv" | grep -v '^[[:blank:]]*$' > serverlist.csv +maxshards="${DETAILS_CHECK_SHARDS:-12}" +legacyservers="bfv bf1942 btl onset" -echo -n "{" > "shortnamearray.json" -echo -n "\"include\":[" >> "shortnamearray.json" +if [ -f lgsm/data/serverlist.csv ]; then + serverlist="lgsm/data/serverlist.csv" +else + curl -fsS "https://raw.githubusercontent.com/GameServerManagers/LinuxGSM/${ref}/lgsm/data/serverlist.csv" -o serverlist.csv + serverlist="serverlist.csv" +fi -while read -r line; do - shortname=$(echo "$line" | awk -F, '{ print $1 }') - # If TARGETED_SHORTNAMES is set, skip servers not in the list - if [ -n "${TARGETED_SHORTNAMES:-}" ]; then - if ! echo "${TARGETED_SHORTNAMES}" | grep -qw "${shortname}"; then - continue - fi +shortnames=() +legacy=() +while IFS=, read -r shortname _; do + [ -z "${shortname}" ] && continue + if [ -n "${TARGETED_SHORTNAMES:-}" ] && ! echo "${TARGETED_SHORTNAMES}" | grep -qw "${shortname}"; then + continue fi - export shortname - servername=$(echo "$line" | awk -F, '{ print $2 }') - export servername - gamename=$(echo "$line" | awk -F, '{ print $3 }') - export gamename - distro=$(echo "$line" | awk -F, '{ print $4 }') - export distro - # Legacy servers that require older Ubuntu/Debian versions due to glibc compatibility - case "${shortname}" in - bfv | bf1942) - # Requires Ubuntu <= 22.04 or Debian <= 12 (glibc 2.31 compatible) - runner="ubuntu-22.04" - ;; - btl | onset) - # Requires Ubuntu <= 20.04 or Debian <= 11 (glibc 2.31 compatible) - runner="ubuntu-20.04" - ;; - *) - runner="ubuntu-latest" - ;; - esac - { - echo -n "{" - echo -n "\"shortname\":" - echo -n "\"${shortname}\"" - echo -n ",\"runner\":" - echo -n "\"${runner}\"" - echo -n "}," - } >> "shortnamearray.json" -done < <(tail -n +2 serverlist.csv) -sed -i '$ s/.$//' "shortnamearray.json" -echo -n "]" >> "shortnamearray.json" -echo -n "}" >> "shortnamearray.json" -rm serverlist.csv + if echo "${legacyservers}" | grep -qw "${shortname}"; then + legacy+=("${shortname}") + else + shortnames+=("${shortname}") + fi +done < <(tail -n +2 "${serverlist}" | grep -v '^[[:blank:]]*$') + +count="${#shortnames[@]}" +shards=$((count < maxshards ? count : maxshards)) +declare -a shard +for i in "${!shortnames[@]}"; do + shard[i % shards]+="${shortnames[i]} " +done + +{ + echo -n '{"include":[' + for ((i = 0; i < shards; i++)); do + [ "${i}" -gt 0 ] && echo -n ',' + echo -n "{\"shard\":\"$((i + 1))/${shards}\",\"shortnames\":\"${shard[i]% }\"}" + done + echo -n ']}' +} > shards.json + +echo -n "${legacy[*]}" > legacy.txt +[ "${serverlist}" == "serverlist.csv" ] && rm serverlist.csv + +echo "Servers: ${count} in ${shards} shard(s), legacy: ${legacy[*]:-none}" diff --git a/.github/scripts/details-check-run.sh b/.github/scripts/details-check-run.sh new file mode 100755 index 0000000000..5131fc829a --- /dev/null +++ b/.github/scripts/details-check-run.sh @@ -0,0 +1,66 @@ +#!/bin/bash +# Runs the details check for each shortname given, in one shared LinuxGSM directory. +# Modules, default configs and data come from the checkout, so the code under test is used and nothing is downloaded per server. +# Usage: details-check-run.sh ... + +src="${GITHUB_WORKSPACE:-${PWD}}" +workdir="${DETAILS_CHECK_DIR:-${HOME}/details-check}" +summary="${GITHUB_STEP_SUMMARY:-/dev/null}" +export LGSM_GITHUBBRANCH="${LGSM_REF:?LGSM_REF must be set}" + +rm -rf "${workdir}" +mkdir -p "${workdir}/lgsm" "${workdir}/serverfiles" +cp "${src}/linuxgsm.sh" "${workdir}/" +cp -r "${src}/lgsm/modules" "${src}/lgsm/config-default" "${src}/lgsm/data" "${workdir}/lgsm/" +cd "${workdir}" || exit 1 + +result() { + if [ "${1}" -eq 0 ]; then echo "✅ pass"; else echo "❌ fail"; fi +} + +failed=() +{ + echo "| Server | Config | Details | Parse game details | Query raw |" + echo "|--------|--------|---------|--------------------|-----------|" +} >> "${summary}" + +for shortname in "$@"; do + gameserver="${shortname}server" + echo "::group::${gameserver}" + ./linuxgsm.sh "${gameserver}" + ./"${gameserver}" developer + + servercfg=$(sed -n "/^\/ { s/.*= *\"\?\([^\"']*\)\"\?/\1/p;q }" "lgsm/config-lgsm/${gameserver}/_default.cfg") + if [ -n "${servercfg}" ]; then + cfgpath="${servercfg}" + [[ "${cfgpath}" == \$\{*\}/* ]] && cfgpath="${cfgpath#*\}/}" + curl -fsS -o "config-${shortname}" "https://raw.githubusercontent.com/GameServerManagers/Game-Server-Configs/main/${shortname}/${cfgpath}" + config=$? + [ "${config}" -eq 0 ] && cat "config-${shortname}" + configresult=$(result "${config}") + else + echo "This game server has no config file." + config=0 + configresult="➖ none" + fi + grep "startparameters" "lgsm/config-default/config-lgsm/${gameserver}/_default.cfg" + + ./"${gameserver}" details + details=$? + ./"${gameserver}" parse-game-details + parse=$? + ./"${gameserver}" query-raw + query=$? + echo "::endgroup::" + + if [ "${config}" -ne 0 ] || [ "${details}" -ne 0 ] || [ "${parse}" -ne 0 ] || [ "${query}" -ne 0 ]; then + failed+=("${gameserver}") + echo "::error title=${gameserver}::config=${config} details=${details} parse-game-details=${parse} query-raw=${query}" + fi + echo "| ${gameserver} | ${configresult} | $(result "${details}") | $(result "${parse}") | $(result "${query}") |" >> "${summary}" +done + +if [ "${#failed[@]}" -gt 0 ]; then + echo -e "\n**Failed:** ${failed[*]}" >> "${summary}" + exit 1 +fi diff --git a/.github/workflows/action-details-check.yml b/.github/workflows/action-details-check.yml index 10474968ee..0d31848b67 100644 --- a/.github/workflows/action-details-check.yml +++ b/.github/workflows/action-details-check.yml @@ -16,18 +16,21 @@ concurrency: group: details-check-${{ github.ref_name }} cancel-in-progress: true +env: + LGSM_REF: ${{ github.event.pull_request.head.sha || github.sha }} + jobs: create-matrix: if: github.repository_owner == 'GameServerManagers' runs-on: ubuntu-latest - env: - LGSM_REF: ${{ github.event.pull_request.head.sha || github.ref_name }} outputs: matrix: ${{ steps.set-matrix.outputs.matrix }} + legacy: ${{ steps.set-matrix.outputs.legacy }} steps: - name: Checkout uses: actions/checkout@v7 with: + ref: ${{ env.LGSM_REF }} # Full history so the base branch ref is available for the # `git diff origin/...HEAD` comparison below (a shallow # checkout has no origin/ and the diff fails). @@ -44,7 +47,7 @@ jobs: # Only these modules directly affect what 'details', 'parse-game-details' # and 'query-raw' output. Everything else (install, fix, update, check_*, # data CSVs, game icons, etc.) is irrelevant to this check. - details_core='^(linuxgsm\.sh|lgsm/modules/(info_game|info_messages|command_details|command_dev_parse_game_details|command_dev_query_raw|core_modules)\.sh)$' + details_core='^(linuxgsm\.sh|lgsm/modules/(info_game|info_messages|command_details|command_dev_parse_game_details|command_dev_query_raw|core_modules)\.sh|\.github/workflows/action-details-check\.yml|\.github/scripts/details-check-.*\.sh)$' if echo "$changed" | grep -qE "${details_core}"; then echo "Details-relevant core file changed — using full matrix." echo "mode=full" >> "$GITHUB_OUTPUT" @@ -64,7 +67,7 @@ jobs: fi fi - - name: Generate matrix with generate-matrix.sh + - name: Generate matrix if: github.event_name != 'pull_request' || steps.targeted.outputs.mode != 'skip' run: | if [ -f targeted_shortnames.txt ]; then @@ -76,29 +79,30 @@ jobs: - name: Set Matrix id: set-matrix run: | - if [ ! -f shortnamearray.json ]; then + if [ ! -f shards.json ]; then echo 'matrix={"include":[]}' >> "$GITHUB_OUTPUT" + echo 'legacy=' >> "$GITHUB_OUTPUT" else - shortnamearray=$(cat shortnamearray.json) - echo "${shortnamearray}" - echo -n "matrix=${shortnamearray}" >> "$GITHUB_OUTPUT" + cat shards.json + echo "matrix=$(cat shards.json)" >> "$GITHUB_OUTPUT" + echo "legacy=$(cat legacy.txt)" >> "$GITHUB_OUTPUT" fi details-check: + name: details-check (${{ matrix.shard }}) # Skip (rather than fail the run) when create-matrix found nothing to check. if: github.repository_owner == 'GameServerManagers' && needs.create-matrix.outputs.matrix != '{"include":[]}' needs: create-matrix continue-on-error: true - runs-on: ${{ matrix.runner }} - env: - LGSM_REF: ${{ github.event.pull_request.head.sha || github.ref_name }} - + runs-on: ubuntu-latest strategy: + fail-fast: false matrix: ${{ fromJSON(needs.create-matrix.outputs.matrix) }} - steps: - - name: Download linuxgsm.sh - run: wget "https://raw.githubusercontent.com/GameServerManagers/LinuxGSM/${LGSM_REF}/linuxgsm.sh"; chmod +x linuxgsm.sh + - name: Checkout + uses: actions/checkout@v7 + with: + ref: ${{ env.LGSM_REF }} - name: Cache apt packages uses: actions/cache@v6 @@ -109,74 +113,36 @@ jobs: - name: Install dependencies run: sudo apt-get update && sudo apt-get install -y --no-install-recommends libxml2-utils jq - - name: Create serverfiles directory - run: mkdir -p serverfiles - - - name: Grab server - run: LGSM_GITHUBBRANCH="${LGSM_REF}" ./linuxgsm.sh ${{ matrix.shortname }}server - - - name: Enable developer mode - run: LGSM_GITHUBBRANCH="${LGSM_REF}" ./${{ matrix.shortname }}server developer - - - name: Generate servercfgname - id: sets-servercfgname - run: | - servercfg=$(sed -n "/^\/ { s/.*= *\"\?\([^\"']*\)\"\?/\1/p;q }" lgsm/config-lgsm/${{ matrix.shortname }}server/_default.cfg) - echo "servercfgname=$servercfg" >> "$GITHUB_OUTPUT" - - - name: Download config - run: | - if [ "${{ steps.sets-servercfgname.outputs.servercfgname }}" == "" ]; then - echo "This game server has no config file." - else - curl -f -o config "https://raw.githubusercontent.com/GameServerManagers/Game-Server-Configs/main/${{ matrix.shortname }}/${{ steps.sets-servercfgname.outputs.servercfgname }}" - fi + - name: Details check + run: .github/scripts/details-check-run.sh ${{ matrix.shortnames }} - - name: Pre-load LinuxGSM - run: LGSM_GITHUBBRANCH="${LGSM_REF}" ./${{ matrix.shortname }}server details - - - name: Display config + details-check-legacy: + name: details-check (legacy) + if: github.repository_owner == 'GameServerManagers' && needs.create-matrix.outputs.legacy != '' + needs: create-matrix + continue-on-error: true + runs-on: ubuntu-latest + container: public.ecr.aws/ubuntu/ubuntu:20.04 + steps: + - name: Install dependencies + env: + DEBIAN_FRONTEND: noninteractive run: | - if [ "${{ steps.sets-servercfgname.outputs.servercfgname }}" == "" ]; then - echo "This game server has no config file." - else - cat config - fi - - - name: Display parameters - run: grep "startparameters" lgsm/config-default/config-lgsm/${{ matrix.shortname }}server/_default.cfg - - - name: Details - id: details - run: LGSM_GITHUBBRANCH="${LGSM_REF}" ./${{ matrix.shortname }}server details - - - name: Detect details - id: detect-details - run: LGSM_GITHUBBRANCH="${LGSM_REF}" ./${{ matrix.shortname }}server parse-game-details + apt-get update + apt-get install -y --no-install-recommends ca-certificates curl wget git sudo iproute2 libxml2-utils jq \ + bc binutils bsdmainutils bzip2 cpio distro-info file gzip hostname lib32gcc-s1 lib32stdc++6 \ + netcat-openbsd pigz python3 tar tmux unzip util-linux uuid-runtime xz-utils - - name: Query Raw - id: query-raw - run: LGSM_GITHUBBRANCH="${LGSM_REF}" ./${{ matrix.shortname }}server query-raw + - name: Checkout + uses: actions/checkout@v7 + with: + ref: ${{ env.LGSM_REF }} - - name: Write job summary - if: always() + - name: Details check run: | - status_icon() { - case "$1" in - success) echo "✅" ;; - failure) echo "❌" ;; - skipped) echo "⏭️" ;; - *) echo "⚠️" ;; - esac - } - details_icon=$(status_icon "${{ steps.details.outcome }}") - parse_icon=$(status_icon "${{ steps.detect-details.outcome }}") - query_icon=$(status_icon "${{ steps.query-raw.outcome }}") - { - echo "## ${{ matrix.shortname }}server" - echo "| Step | Result |" - echo "|------|--------|" - echo "| Details | ${details_icon} ${{ steps.details.outcome }} |" - echo "| Parse game details | ${parse_icon} ${{ steps.detect-details.outcome }} |" - echo "| Query raw | ${query_icon} ${{ steps.query-raw.outcome }} |" - } >> "$GITHUB_STEP_SUMMARY" + useradd -m linuxgsm + echo "linuxgsm ALL=(ALL) NOPASSWD:ALL" > /etc/sudoers.d/linuxgsm + chown -R linuxgsm:linuxgsm "${GITHUB_WORKSPACE}" + chmod a+w "${GITHUB_STEP_SUMMARY}" + sudo -u linuxgsm -H env LGSM_REF="${LGSM_REF}" GITHUB_WORKSPACE="${GITHUB_WORKSPACE}" GITHUB_STEP_SUMMARY="${GITHUB_STEP_SUMMARY}" \ + "${GITHUB_WORKSPACE}/.github/scripts/details-check-run.sh" ${{ needs.create-matrix.outputs.legacy }} From a390ebe311d39fdf4c2e8b2a6e08ba2bbac0214b Mon Sep 17 00:00:00 2001 From: Daniel Gibbs Date: Sat, 10 Oct 2026 00:26:06 +0100 Subject: [PATCH 029/164] fix(sf): drop ServerQueryPort and BeaconPort removed in Satisfactory 1.0 (#4976) * fix(sf): drop ServerQueryPort and BeaconPort removed in Satisfactory 1.0 Satisfactory 1.0+ uses port for the game (UDP) and the server API (TCP), plus ReliablePort (TCP). -ServerQueryPort and -BeaconPort are no longer used, but LinuxGSM still passed them and listed their ports in details, so admins opened ports nothing listens on. - Remove queryport/beaconport from sfserver _default.cfg and startparameters. - details: list Game (UDP), Server API (TCP) and ReliableMessaging (TCP). - queryport now follows port. Monitoring is session-only (querymode 1), so this doesn't change it. Fixes #4967 * fix(sf): drop code comment --- lgsm/config-default/config-lgsm/sfserver/_default.cfg | 7 +++---- lgsm/modules/info_game.sh | 3 +-- lgsm/modules/info_messages.sh | 3 +-- 3 files changed, 5 insertions(+), 8 deletions(-) diff --git a/lgsm/config-default/config-lgsm/sfserver/_default.cfg b/lgsm/config-default/config-lgsm/sfserver/_default.cfg index 1fbcbf52ef..778a04ddf5 100644 --- a/lgsm/config-default/config-lgsm/sfserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/sfserver/_default.cfg @@ -10,14 +10,13 @@ ## Predefined Parameters | https://docs.linuxgsm.com/configuration/start-parameters ip="0.0.0.0" -queryport="15777" -beaconport="15000" -reliableport="8888" +# Satisfactory 1.0+: port is used for the game (UDP) and the server API (TCP). port="7777" +reliableport="8888" ## Server Parameters | https://docs.linuxgsm.com/configuration/start-parameters#additional-parameters ## Game Server Docs | https://satisfactory.fandom.com/wiki/Dedicated_servers -startparameters="FactoryGame -Port=${port} -ServerQueryPort=${queryport} -BeaconPort=${beaconport} -ReliablePort=${reliableport} -log" +startparameters="FactoryGame -Port=${port} -ReliablePort=${reliableport} -log" #### LinuxGSM Settings #### diff --git a/lgsm/modules/info_game.sh b/lgsm/modules/info_game.sh index a0b17a657c..8ce8605c6b 100755 --- a/lgsm/modules/info_game.sh +++ b/lgsm/modules/info_game.sh @@ -2038,8 +2038,7 @@ fn_info_game_sf() { # Parameters servername="${servername:-"NOT SET"}" port="${port:-"0"}" - queryport="${queryport:-"0"}" - beaconport="${beaconport:-"0"}" + queryport="${port}" reliableport="${reliableport:-"0"}" } diff --git a/lgsm/modules/info_messages.sh b/lgsm/modules/info_messages.sh index 860b22af19..392f810072 100755 --- a/lgsm/modules/info_messages.sh +++ b/lgsm/modules/info_messages.sh @@ -1523,8 +1523,7 @@ fn_info_messages_sf() { { fn_port "header" fn_port "Game" port udp - fn_port "Query" queryport udp - fn_port "Beacon" beaconport udp + fn_port "Server API" port tcp fn_port "ReliableMessaging" reliableport tcp } | column -s $'\t' -t } From 77d8b6f0181fa3a6b68077094eeb6e432c139ddc Mon Sep 17 00:00:00 2001 From: Daniel Gibbs Date: Sat, 10 Oct 2026 00:28:27 +0100 Subject: [PATCH 030/164] fix(col): monitor Colony Survival with a TCP query (#4977) * fix(col): monitor Colony Survival with a TCP query Colony Survival hosts with SteamOnline networking and doesn't answer A2S (protocol-valve) queries on its UDP game port. Monitor always failed the query and restarted a working server every few minutes. The query port listens on TCP (details already shows it as TCP), so use query mode 5 (TCP). * fix(col): keep querytype set for the gamedig query modes querytype is ignored by the TCP query, but an empty value would break monitoring if querymode is switched back to a gamedig mode. --- lgsm/config-default/config-lgsm/colserver/_default.cfg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lgsm/config-default/config-lgsm/colserver/_default.cfg b/lgsm/config-default/config-lgsm/colserver/_default.cfg index 82cf3de7b5..3c7329f33f 100644 --- a/lgsm/config-default/config-lgsm/colserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/colserver/_default.cfg @@ -154,7 +154,7 @@ stopmode="2" # 3: gamedig # 4: gsquery # 5: tcp -querymode="2" +querymode="5" querytype="protocol-valve" ## Console type From b8007e8aa22d9823cf729785621e5a778b83c010 Mon Sep 17 00:00:00 2001 From: Daniel Gibbs Date: Sat, 10 Oct 2026 00:29:34 +0100 Subject: [PATCH 031/164] fix(steamcmd): work around Invalid platform errors (L4D2) (#4979) * fix(steamcmd): work around Invalid platform errors (L4D2) SteamCMD fails some app installs on Linux with "Failed to install app '222860' (Invalid platform)", a long-standing SteamCMD bug (ValveSoftware/steam-for-linux#11522) that breaks every new Left 4 Dead 2 install. The known workaround is to download the Windows depot once, then update and validate as Linux. When SteamCMD reports Invalid platform, run app_update once with +@sSteamCmdForcePlatformType windows, then retry the normal Linux update with validate. The workaround runs at most once per download. Fixes #4754 * fix(steamcmd): run the Invalid platform workaround before the fatal check The existing Invalid platform branch exits, and it came first in the chain, so the workaround was never reached. Move the workaround above it; the fatal branch still catches a repeat or forced-Windows case. * fix(steamcmd): keep the Invalid platform workaround to one attempt per download Make invalidplatformworkaround local to fn_dl_steamcmd. Manifest repair calls the downloader several times, and a global flag stopped later downloads from trying the workaround. --- lgsm/modules/core_dl.sh | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/lgsm/modules/core_dl.sh b/lgsm/modules/core_dl.sh index 24859afab4..00c02d6f2e 100755 --- a/lgsm/modules/core_dl.sh +++ b/lgsm/modules/core_dl.sh @@ -65,6 +65,7 @@ fn_dl_steamcmd() { if [ -f "${steamcmdlog}" ]; then rm -f "${steamcmdlog:?}" fi + local invalidplatformworkaround="" counter=0 while [ "${counter}" -eq 0 ] || [ "${exitcode}" -ne 0 ]; do counter=$((counter + 1)) @@ -139,7 +140,16 @@ fn_dl_steamcmd() { fn_print_failure_nl "${commandaction} ${selfname}: ${remotelocation}: Not enough disk space to download server files" fn_script_log_fail "${commandaction} ${selfname}: ${remotelocation}: Not enough disk space to download server files" core_exit.sh - # Invalid platform for app/update request. + # Invalid platform (SteamCMD bug, e.g. Left 4 Dead 2): retry once after a Windows platform download. + elif [ -n "$(grep -i "Invalid platform" "${steamcmdlog}" | tail -1)" ] && [ "${steamcmdforcewindows}" != "yes" ] && [ -z "${invalidplatformworkaround}" ]; then + invalidplatformworkaround="1" + fn_print_error2_nl "${commandaction} ${selfname}: ${remotelocation}: Invalid platform - applying SteamCMD Windows platform workaround" + fn_script_log_error "${commandaction} ${selfname}: ${remotelocation}: Invalid platform - applying SteamCMD Windows platform workaround" + "${unbuffercommand[@]}" "${steamcmdcommandarray[@]}" +@sSteamCmdForcePlatformType windows +force_install_dir "${serverfiles}" +login "${steamuser}" "${steampass}" +app_update "${appid}" +quit | uniq | tee -a "${lgsmlog}" "${steamcmdlog}" + validateparam=("validate") + rm -f "${steamcmdlog:?}" + counter=0 + # Invalid platform for app/update request (after the workaround, or when forcing Windows). elif [ -n "$(grep -i "Invalid platform" "${steamcmdlog}" | tail -1)" ]; then fn_print_failure_nl "${commandaction} ${selfname}: ${remotelocation}: Invalid platform for AppID ${appid}" fn_print_nl "Check steamcmdforcewindows setting and system architecture (x86_64 required for most servers)" From af194936d29d8c469c6fd17d91f063d2b0a40483 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 10 Oct 2026 00:30:58 +0100 Subject: [PATCH 032/164] chore(deps): bump github/issue-labeler from 3.4 to 3.5 (#4984) Bumps [github/issue-labeler](https://github.com/github/issue-labeler) from 3.4 to 3.5. - [Release notes](https://github.com/github/issue-labeler/releases) - [Commits](https://github.com/github/issue-labeler/compare/v3.4...v3.5) --- updated-dependencies: - dependency-name: github/issue-labeler dependency-version: '3.5' dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/action-issue-triage-automation.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/action-issue-triage-automation.yml b/.github/workflows/action-issue-triage-automation.yml index 4992613c48..e0243ea90d 100644 --- a/.github/workflows/action-issue-triage-automation.yml +++ b/.github/workflows/action-issue-triage-automation.yml @@ -71,7 +71,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Issue Labeler - uses: github/issue-labeler@v3.4 + uses: github/issue-labeler@v3.5 with: repo-token: "${{ secrets.GITHUB_TOKEN }}" configuration-path: .github/labeler.yml @@ -2271,7 +2271,7 @@ jobs: runs-on: ubuntu-latest steps: - name: PR Labeler - uses: github/issue-labeler@v3.4 + uses: github/issue-labeler@v3.5 with: repo-token: "${{ secrets.GITHUB_TOKEN }}" configuration-path: .github/labeler.yml From 76170b9aec55f9e5e7dd65e655f601dd826a1950 Mon Sep 17 00:00:00 2001 From: Daniel Gibbs Date: Sat, 10 Oct 2026 00:31:27 +0100 Subject: [PATCH 033/164] chore(sync): synced file(s) with dgibbs64/repo-sync (#4978) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Synced from dgibbs64/repo-sync@71ef73688c5389507602dbe9774ea861fc5c6cb0 — fix(workflows): restore pull-requests: write for the copyright-year workflow (#21) action-update-license-year opens its update as a pull request, which needs pull-requests: write. It was removed with the auto-merge step. Co-authored-by: dgibbs64 --- .github/workflows/action-super-linter.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/action-super-linter.yml b/.github/workflows/action-super-linter.yml index 789b99c643..3eff60805f 100644 --- a/.github/workflows/action-super-linter.yml +++ b/.github/workflows/action-super-linter.yml @@ -37,7 +37,7 @@ jobs: npm install --no-save prettier prettier-plugin-sh prettier-plugin-jinja-template || true - name: Super-linter - uses: super-linter/super-linter@v8 + uses: super-linter/super-linter@v9 env: # To report GitHub Actions status checks GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} From 6cf5aa3ed3fe7c355d4833bc19812024a43145b5 Mon Sep 17 00:00:00 2001 From: yourfate <47528796+yourfate@users.noreply.github.com> Date: Sat, 10 Oct 2026 10:07:37 +0200 Subject: [PATCH 034/164] fix(monitor): anchor tmux session checks to avoid matching other instances (#4989) * fix(monitor): anchor tmux session checks to avoid matching other instances The monitor's session migration checks used unanchored pgrep/pkill patterns. With multiple instances under one user where one session name is a prefix of another (e.g. vhserver and vhserver-2), the shorter instance's "old type tmux session" check matched the other instance's concurrently running pgrep command line, causing spurious restarts whenever both monitors ran at the same time. Anchor the patterns to the start of the command line and require the session name to be followed by a space or end of line. Co-Authored-By: Claude Opus 5.5 * fix(monitor): drop code comment --------- Co-authored-by: yourfate <2371889-youRFate@users.noreply.gitlab.com> Co-authored-by: Claude Opus 5.5 Co-authored-by: Daniel Gibbs --- lgsm/modules/command_monitor.sh | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lgsm/modules/command_monitor.sh b/lgsm/modules/command_monitor.sh index 4dc32765b0..e5cb8c6dec 100755 --- a/lgsm/modules/command_monitor.sh +++ b/lgsm/modules/command_monitor.sh @@ -211,23 +211,23 @@ fn_monitor_check_session() { command_restart.sh core_exit.sh # Check for tmux pids with the same tmux session and socket names. This will reduce issues with migration to release v23.5.0. #4296 - elif [ "$(pgrep -fc -u "${USER}" "tmux -L ${sessionname} new-session -d -x ${sessionwidth} -y ${sessionheight} -s ${sessionname}")" != "0" ]; then + elif [ "$(pgrep -fc -u "${USER}" "^tmux -L ${sessionname} new-session -d -x ${sessionwidth} -y ${sessionheight} -s ${sessionname}( |$)")" != "0" ]; then fn_print_error "Checking session: PIDS with the same tmux session and socket names are running" fn_print_error_eol_nl fn_script_log_error "Checking session: ERROR" fn_script_log_error "Checking session: PIDS with the same tmux session and socket names are running" fn_script_log_error "Checking session: Killing session with the socketname name ${sessionname} and session name ${sessionname}" - pkill -f "tmux -L ${sessionname} new-session -d -x ${sessionwidth} -y ${sessionheight} -s ${sessionname}" + pkill -f "^tmux -L ${sessionname} new-session -d -x ${sessionwidth} -y ${sessionheight} -s ${sessionname}( |$)" command_restart.sh core_exit.sh # Check for tmux pids that are using the old type of tmux session. This will reduce issues with migration to release v23.5.0. #4296 - elif [ "$(pgrep -fc -u "${USER}" "tmux new-session -d -x ${sessionwidth} -y ${sessionheight} -s ${sessionname}")" != "0" ]; then + elif [ "$(pgrep -fc -u "${USER}" "^tmux new-session -d -x ${sessionwidth} -y ${sessionheight} -s ${sessionname}( |$)")" != "0" ]; then fn_print_error "Checking session: PIDS with old type tmux session are running" fn_print_error_eol_nl fn_script_log_error "Checking session: ERROR" fn_script_log_error "Checking session: PIDS with old type tmux session are running" fn_script_log_error "Checking session: Killing session with the session name ${sessionname}" - pkill -f "tmux new-session -d -x ${sessionwidth} -y ${sessionheight} -s ${sessionname}" + pkill -f "^tmux new-session -d -x ${sessionwidth} -y ${sessionheight} -s ${sessionname}( |$)" command_restart.sh core_exit.sh elif [ "${status}" != "0" ]; then From 28b1d67dee91f18528fe4f44483398b5af7a14a4 Mon Sep 17 00:00:00 2001 From: BorzakA <1230402+borzaka@users.noreply.github.com> Date: Sat, 10 Oct 2026 10:13:00 +0200 Subject: [PATCH 035/164] fix(mods): only look up mod URLs for the game the server runs (#4983) * fix(mods): only look up mod URLs for the game the server runs mods_list.sh ran every mod lookup on each mods command regardless of the game, so a Counter-Strike 2 server also queried the CS:GO, Rust, Hurtworld, 7 Days To Die and Valheim mod releases. That is 11 GitHub API requests per command, which exhausts the unauthenticated limit of 60 requests per hour per IP address after five mods-install runs, and even sooner when several servers share an address. Once it is gone, curl returns a rate limit error body, the jq filters yield empty strings, and the mod URL and filename end up blank, which reaches the user only as a generic "An issue occurred downloading" failure. Guard each lookup with the ${gamename} or ${engine} it belongs to, the non-GitHub ones (Metamod:Source, Metamod:Source 2.0, SourceMod, SteamWorks and BepInEx) included. Both variables are set from _default.cfg before mods_core.sh sources this file, and the conditions match the compatibility filters already declared in the mod_info arrays, so the set of mods offered to the user is unchanged. * fix(mods): guard lookups by shortname and drop code comment --------- Co-authored-by: Daniel Gibbs --- lgsm/modules/mods_list.sh | 83 ++++++++++++++++++++++++--------------- 1 file changed, 52 insertions(+), 31 deletions(-) diff --git a/lgsm/modules/mods_list.sh b/lgsm/modules/mods_list.sh index 06a3e6e177..9f997c13ac 100755 --- a/lgsm/modules/mods_list.sh +++ b/lgsm/modules/mods_list.sh @@ -57,13 +57,17 @@ amxxtsurl="${amxxtsdownloadurl}" # Metamod:Source metamodsourceversion="1.12" metamodsourcescrapeurl="https://mms.alliedmods.net/mmsdrop/${metamodsourceversion}/mmsource-latest-linux" -metamodsourcelatestfile=$(wget "${metamodsourcescrapeurl}" -q -O -) +if [ "${engine}" == "source" ]; then + metamodsourcelatestfile=$(wget "${metamodsourcescrapeurl}" -q -O -) +fi metamodsourcedownloadurl="https://www.metamodsource.net/latest.php?os=linux&version=${metamodsourceversion}" metamodsourceurl="${metamodsourcedownloadurl}" # Metamod:Source 2.0 metamodsource2version="2.0" metamodsource2scrapeurl="https://mms.alliedmods.net/mmsdrop/${metamodsource2version}/mmsource-latest-linux" -metamodsource2latestfile=$(wget "${metamodsource2scrapeurl}" -q -O -) +if [ "${shortname}" == "cs2" ]; then + metamodsource2latestfile=$(wget "${metamodsource2scrapeurl}" -q -O -) +fi metamodsource2downloadurl="https://www.metamodsource.net/latest.php?os=linux&version=${metamodsource2version}" metamodsource2url="${metamodsource2downloadurl}" # Sourcemod @@ -74,12 +78,16 @@ else sourcemodversion="1.13" fi sourcemodscrapeurl="https://sm.alliedmods.net/smdrop/${sourcemodversion}/sourcemod-latest-linux" -sourcemodlatestfile=$(wget "${sourcemodscrapeurl}" -q -O -) +if [ "${engine}" == "source" ]; then + sourcemodlatestfile=$(wget "${sourcemodscrapeurl}" -q -O -) +fi sourcemoddownloadurl="https://www.sourcemod.net/latest.php?os=linux&version=${sourcemodversion}" sourcemodurl="${sourcemoddownloadurl}" # Steamworks steamworksscrapeurl="https://users.alliedmods.net/~kyles/builds/SteamWorks" -steamworkslatestfile=$(curl --connect-timeout 3 -sL ${steamworksscrapeurl} | grep -m 1 linux | cut -d '"' -f 4) +if [ "${shortname}" == "csgo" ]; then + steamworkslatestfile=$(curl --connect-timeout 3 -sL ${steamworksscrapeurl} | grep -m 1 linux | cut -d '"' -f 4) +fi steamworksdownloadurl="${steamworksscrapeurl}/${steamworkslatestfile}" steamworksurl="${steamworksdownloadurl}" # Stripper:Source @@ -89,40 +97,53 @@ stripperdownloadurl="http://www.bailopan.net/stripper/snapshots/1.2/${stripperla stripperurl="${stripperdownloadurl}" # CS2 Mods -counterstrikesharprelease=$(curl --connect-timeout 3 -sL https://api.github.com/repos/roflmuffin/CounterStrikeSharp/releases/latest) -counterstrikesharplastbuild=$(printf '%s\n' "${counterstrikesharprelease}" | jq '.assets[]? | select(.name | startswith("counterstrikesharp-with-runtime-linux-") and endswith(".zip"))' 2> /dev/null) -counterstrikesharplatestfile=$(printf '%s\n' "${counterstrikesharplastbuild}" | jq -r '.name') -counterstrikesharplatestlink=$(printf '%s\n' "${counterstrikesharplastbuild}" | jq -r '.browser_download_url') +if [ "${shortname}" == "cs2" ]; then + counterstrikesharprelease=$(curl --connect-timeout 3 -sL https://api.github.com/repos/roflmuffin/CounterStrikeSharp/releases/latest) + counterstrikesharplastbuild=$(printf '%s\n' "${counterstrikesharprelease}" | jq '.assets[]? | select(.name | startswith("counterstrikesharp-with-runtime-linux-") and endswith(".zip"))' 2> /dev/null) + counterstrikesharplatestfile=$(printf '%s\n' "${counterstrikesharplastbuild}" | jq -r '.name') + counterstrikesharplatestlink=$(printf '%s\n' "${counterstrikesharplastbuild}" | jq -r '.browser_download_url') +fi # CS:GO Mods -get5lastbuild=$(curl --connect-timeout 3 -sL https://api.github.com/repos/splewis/get5/releases/latest | jq '.assets[] |select(.browser_download_url | endswith(".tar.gz"))') -get5latestfile=$(echo -e "${get5lastbuild}" | jq -r '.name') -get5latestfilelink=$(echo -e "${get5lastbuild}" | jq -r '.browser_download_url') -csgopracticelatest=$(curl --connect-timeout 3 -sL https://api.github.com/repos/splewis/csgo-practice-mode/releases/latest | jq '.assets[]') -csgopracticelatestfile=$(echo -e "${csgopracticelatest}" | jq -r '.name') -csgopracticelatestlink=$(echo -e "${csgopracticelatest}" | jq -r '.browser_download_url') -csgopuglatest=$(curl --connect-timeout 3 -sL https://api.github.com/repos/splewis/csgo-pug-setup/releases/latest | jq '.assets[]') -csgopuglatestfile=$(echo -e "${csgopuglatest}" | jq -r '.name') -csgopuglatestlink=$(echo -e "${csgopuglatest}" | jq -r '.browser_download_url') -gokzlatestversion=$(curl --connect-timeout 3 -s https://api.github.com/repos/KZGlobalTeam/gokz/releases/latest | grep "tag_name" | cut -d : -f 2,3 | sed -E 's/.*"([^"]+)".*/\1/') -gokzlatestfile="GOKZ-v${gokzlatestversion}.zip" -gokzlatestlink="https://github.com/KZGlobalTeam/gokz/releases/download/${gokzlatestversion}/${gokzlatestfile}" -movementapilatestversion=$(curl --connect-timeout 3 -s https://api.github.com/repos/danzayau/MovementAPI/releases/latest | grep "tag_name" | cut -d : -f 2,3 | sed -E 's/.*"([^"]+)".*/\1/') -movementapilatestfile="MovementAPI-v${movementapilatestversion}.zip" -movementapilatestlink="https://github.com/danzayau/MovementAPI/releases/download/${movementapilatestversion}/${movementapilatestfile}" +if [ "${shortname}" == "csgo" ]; then + get5lastbuild=$(curl --connect-timeout 3 -sL https://api.github.com/repos/splewis/get5/releases/latest | jq '.assets[] |select(.browser_download_url | endswith(".tar.gz"))') + get5latestfile=$(echo -e "${get5lastbuild}" | jq -r '.name') + get5latestfilelink=$(echo -e "${get5lastbuild}" | jq -r '.browser_download_url') + csgopracticelatest=$(curl --connect-timeout 3 -sL https://api.github.com/repos/splewis/csgo-practice-mode/releases/latest | jq '.assets[]') + csgopracticelatestfile=$(echo -e "${csgopracticelatest}" | jq -r '.name') + csgopracticelatestlink=$(echo -e "${csgopracticelatest}" | jq -r '.browser_download_url') + csgopuglatest=$(curl --connect-timeout 3 -sL https://api.github.com/repos/splewis/csgo-pug-setup/releases/latest | jq '.assets[]') + csgopuglatestfile=$(echo -e "${csgopuglatest}" | jq -r '.name') + csgopuglatestlink=$(echo -e "${csgopuglatest}" | jq -r '.browser_download_url') + gokzlatestversion=$(curl --connect-timeout 3 -s https://api.github.com/repos/KZGlobalTeam/gokz/releases/latest | grep "tag_name" | cut -d : -f 2,3 | sed -E 's/.*"([^"]+)".*/\1/') + gokzlatestfile="GOKZ-v${gokzlatestversion}.zip" + gokzlatestlink="https://github.com/KZGlobalTeam/gokz/releases/download/${gokzlatestversion}/${gokzlatestfile}" + movementapilatestversion=$(curl --connect-timeout 3 -s https://api.github.com/repos/danzayau/MovementAPI/releases/latest | grep "tag_name" | cut -d : -f 2,3 | sed -E 's/.*"([^"]+)".*/\1/') + movementapilatestfile="MovementAPI-v${movementapilatestversion}.zip" + movementapilatestlink="https://github.com/danzayau/MovementAPI/releases/download/${movementapilatestversion}/${movementapilatestfile}" +fi # Rust carbonrustapilatestfile="Carbon.Linux.Release.tar.gz" -carbonrustlatestlink=$(curl --connect-timeout 3 -sL https://api.github.com/repos/CarbonCommunity/Carbon.Core/releases/tags/production_build | jq -r '.assets[]|select(.name == "Carbon.Linux.Release.tar.gz") | .browser_download_url') +if [ "${shortname}" == "rust" ]; then + carbonrustlatestlink=$(curl --connect-timeout 3 -sL https://api.github.com/repos/CarbonCommunity/Carbon.Core/releases/tags/production_build | jq -r '.assets[]|select(.name == "Carbon.Linux.Release.tar.gz") | .browser_download_url') +fi # Oxide -oxiderustlatestlink=$(curl --connect-timeout 3 -sL https://api.github.com/repos/OxideMod/Oxide.Rust/releases/latest | jq -r '.assets[]|select(.browser_download_url | contains("linux")) | .browser_download_url') -oxidehurtworldlatestlink=$(curl --connect-timeout 3 -sL https://api.github.com/repos/OxideMod/Oxide.Hurtworld/releases/latest | jq -r '.assets[].browser_download_url') -oxidesdtdlatestlink=$(curl --connect-timeout 3 -sL https://api.github.com/repos/OxideMod/Oxide.SevenDaysToDie/releases/latest | jq -r '.assets[]|select(.browser_download_url | contains("linux")) | .browser_download_url') -# Valheim Plus -valheimpluslatestlink=$(curl --connect-timeout 3 -sL https://api.github.com/repos/Grantapher/ValheimPlus/releases/latest | jq -r '.assets[]|select(.browser_download_url | contains("UnixServer.tar.gz")) | .browser_download_url') -# Valheim BepInEx -bepinexvhlatestlink=$(curl --connect-timeout 3 -sL "https://thunderstore.io/api/experimental/package/denikson/BepInExPack_Valheim/" -H "accept: application/json" | jq -r '.latest.download_url') +if [ "${shortname}" == "rust" ]; then + oxiderustlatestlink=$(curl --connect-timeout 3 -sL https://api.github.com/repos/OxideMod/Oxide.Rust/releases/latest | jq -r '.assets[]|select(.browser_download_url | contains("linux")) | .browser_download_url') +elif [ "${shortname}" == "hw" ]; then + oxidehurtworldlatestlink=$(curl --connect-timeout 3 -sL https://api.github.com/repos/OxideMod/Oxide.Hurtworld/releases/latest | jq -r '.assets[].browser_download_url') +elif [ "${shortname}" == "sdtd" ]; then + oxidesdtdlatestlink=$(curl --connect-timeout 3 -sL https://api.github.com/repos/OxideMod/Oxide.SevenDaysToDie/releases/latest | jq -r '.assets[]|select(.browser_download_url | contains("linux")) | .browser_download_url') +fi + +if [ "${shortname}" == "vh" ]; then + # Valheim Plus + valheimpluslatestlink=$(curl --connect-timeout 3 -sL https://api.github.com/repos/Grantapher/ValheimPlus/releases/latest | jq -r '.assets[]|select(.browser_download_url | contains("UnixServer.tar.gz")) | .browser_download_url') + # Valheim BepInEx + bepinexvhlatestlink=$(curl --connect-timeout 3 -sL "https://thunderstore.io/api/experimental/package/denikson/BepInExPack_Valheim/" -H "accept: application/json" | jq -r '.latest.download_url') +fi # Define mods information (required) From ee5b54b7b23892508327f303dc0289b88a4ab755 Mon Sep 17 00:00:00 2001 From: Daniel Gibbs Date: Sat, 10 Oct 2026 20:37:21 +0100 Subject: [PATCH 036/164] fix(install): stop when a server has no download configuration (#4996) fn_install_server_files logged the failure but carried on, then tried to fetch and extract with an empty URL. Exit after the failure instead. Found in #4155 by @jusito. --- lgsm/modules/install_server_files.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/lgsm/modules/install_server_files.sh b/lgsm/modules/install_server_files.sh index abf2293f6b..c860ac1e1a 100755 --- a/lgsm/modules/install_server_files.sh +++ b/lgsm/modules/install_server_files.sh @@ -220,6 +220,7 @@ fn_install_server_files() { else fn_print_fail_nl "Installing ${gamename} Server failed, missing default configuration" fn_script_log_fail "Installing ${gamename} Server failed, missing default configuration" + core_exit.sh fi fn_fetch_file "${remote_fileurl}" "" "" "" "${local_filedir}" "${local_filename}" "${chmodx}" "${run}" "${forcedl}" "${md5}" fn_dl_extract "${local_filedir}" "${local_filename}" "${serverfiles}" From 00960d857bff3e8b73bdda1ef9d69afd5a55a676 Mon Sep 17 00:00:00 2001 From: Daniel Gibbs Date: Sat, 10 Oct 2026 20:58:27 +0100 Subject: [PATCH 037/164] chore(lint): fix Super Linter errors on develop (#5001) - Make .github/scripts/sync-game-labels.sh executable (BASH_EXEC). - Don't check indent width in Markdown: list continuation lines are indented to the list marker (3 spaces for "1. "), as Prettier formats them (EDITORCONFIG, CODE_OF_CONDUCT.md). - Quote $shortnames in the Details Check targeted-server step (actionlint SC2086). The file content is unchanged. --- .editorconfig | 4 ++++ .github/scripts/sync-game-labels.sh | 0 .github/workflows/action-details-check.yml | 2 +- 3 files changed, 5 insertions(+), 1 deletion(-) mode change 100644 => 100755 .github/scripts/sync-game-labels.sh diff --git a/.editorconfig b/.editorconfig index fba6f1fb33..51413030f0 100644 --- a/.editorconfig +++ b/.editorconfig @@ -30,3 +30,7 @@ indent_size = 4 [*.py] indent_style = space indent_size = 4 + +# Markdown Files +[*.md] +indent_size = unset diff --git a/.github/scripts/sync-game-labels.sh b/.github/scripts/sync-game-labels.sh old mode 100644 new mode 100755 diff --git a/.github/workflows/action-details-check.yml b/.github/workflows/action-details-check.yml index 0d31848b67..f97b028616 100644 --- a/.github/workflows/action-details-check.yml +++ b/.github/workflows/action-details-check.yml @@ -63,7 +63,7 @@ jobs: else echo "Targeted servers: $shortnames" echo "mode=targeted" >> "$GITHUB_OUTPUT" - printf '%s\n' $shortnames > targeted_shortnames.txt + echo "$shortnames" > targeted_shortnames.txt fi fi From 75d4a7783f453dff2ef23e87e23088b3c243d868 Mon Sep 17 00:00:00 2001 From: Daniel Gibbs Date: Sat, 10 Oct 2026 20:58:35 +0100 Subject: [PATCH 038/164] fix(monitor): detect update, start and stop run with their short aliases (#5002) Monitor checked for the u alias of update nowhere, and checked s (sponsor) instead of st and sp for start and stop. An update started with ./gameserver u was not detected, so monitor restarted the server mid-update. Fixes #4997 and #4999. --- lgsm/modules/command_monitor.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lgsm/modules/command_monitor.sh b/lgsm/modules/command_monitor.sh index e5cb8c6dec..62c05efdf1 100755 --- a/lgsm/modules/command_monitor.sh +++ b/lgsm/modules/command_monitor.sh @@ -76,7 +76,7 @@ fn_monitor_check_starting() { fi fi - if [ -f "${lockdir}/${selfname}-starting.lock" ] && [[ "$(pgrep -fcx -u "${USER}" "/bin/bash ./${selfname} start")" != "0" || "$(pgrep -fcx -u "${USER}" "/bin/bash ./${selfname} s")" != "0" ]]; then + if [ -f "${lockdir}/${selfname}-starting.lock" ] && [[ "$(pgrep -fcx -u "${USER}" "/bin/bash ./${selfname} start")" != "0" || "$(pgrep -fcx -u "${USER}" "/bin/bash ./${selfname} st")" != "0" ]]; then fn_print_dots "Checking start" fn_print_checking_eol fn_print_info "Checking start: LinuxGSM is starting" @@ -99,7 +99,7 @@ fn_monitor_check_stopping() { fi fi - if [ -f "${lockdir}/${selfname}-stopping.lock" ] && [[ "$(pgrep -fcx -u "${USER}" "/bin/bash ./${selfname} stop")" != "0" || "$(pgrep -fcx -u "${USER}" "/bin/bash ./${selfname} s")" != "0" ]]; then + if [ -f "${lockdir}/${selfname}-stopping.lock" ] && [[ "$(pgrep -fcx -u "${USER}" "/bin/bash ./${selfname} stop")" != "0" || "$(pgrep -fcx -u "${USER}" "/bin/bash ./${selfname} sp")" != "0" ]]; then fn_print_dots "Checking stop" fn_print_checking_eol fn_print_info "Checking stop: LinuxGSM is stopping" @@ -165,7 +165,7 @@ fn_monitor_check_update() { fi fi - if [ -f "${lockdir}/update.lock" ] && [[ "$(pgrep -fcx -u "${USER}" "/bin/bash ./${selfname} update")" != "0" || "$(pgrep -fcx -u "${USER}" "/bin/bash ./${selfname} validate")" != "0" || "$(pgrep -fcx -u "${USER}" "/bin/bash ./${selfname} v")" != "0" || "$(pgrep -fcx -u "${USER}" "/bin/bash ./${selfname} force-update")" != "0" || "$(pgrep -fcx -u "${USER}" "/bin/bash ./${selfname} fu")" != "0" || "$(pgrep -fcx -u "${USER}" "/bin/bash ./${selfname} update-restart")" != "0" || "$(pgrep -fcx -u "${USER}" "/bin/bash ./${selfname} ur")" != "0" ]]; then + if [ -f "${lockdir}/update.lock" ] && [[ "$(pgrep -fcx -u "${USER}" "/bin/bash ./${selfname} update")" != "0" || "$(pgrep -fcx -u "${USER}" "/bin/bash ./${selfname} u")" != "0" || "$(pgrep -fcx -u "${USER}" "/bin/bash ./${selfname} validate")" != "0" || "$(pgrep -fcx -u "${USER}" "/bin/bash ./${selfname} v")" != "0" || "$(pgrep -fcx -u "${USER}" "/bin/bash ./${selfname} force-update")" != "0" || "$(pgrep -fcx -u "${USER}" "/bin/bash ./${selfname} fu")" != "0" || "$(pgrep -fcx -u "${USER}" "/bin/bash ./${selfname} update-restart")" != "0" || "$(pgrep -fcx -u "${USER}" "/bin/bash ./${selfname} ur")" != "0" ]]; then fn_print_dots "Checking update" fn_print_checking_eol fn_print_info "Checking update: LinuxGSM is updating the game server" From f098804d4de769efbf887559368d06d44f39a883 Mon Sep 17 00:00:00 2001 From: Daniel Gibbs Date: Sat, 10 Oct 2026 21:07:58 +0100 Subject: [PATCH 039/164] chore(lint): fix Ruff errors in query_gsquery.py (#5003) - Add .github/linters/.ruff.toml with line-length 88 to match Black. Super Linter's default Ruff config uses 120, so ruff format and Black disagreed about the same file. target-version py38 keeps Ruff from suggesting changes that need a newer Python than Ubuntu 20.04 has. - query_gsquery.py: make executable (EXE001), drop the redundant coding declaration (UP009) and an empty comment (PLR2044), and catch OSError instead of its alias socket.error (UP024). --- .github/linters/.ruff.toml | 11 +++++++++++ lgsm/modules/query_gsquery.py | 4 +--- 2 files changed, 12 insertions(+), 3 deletions(-) create mode 100644 .github/linters/.ruff.toml mode change 100644 => 100755 lgsm/modules/query_gsquery.py diff --git a/.github/linters/.ruff.toml b/.github/linters/.ruff.toml new file mode 100644 index 0000000000..01f243f4bd --- /dev/null +++ b/.github/linters/.ruff.toml @@ -0,0 +1,11 @@ +# Store the cache in a temporary location +cache-dir = "/tmp/.ruff_cache" + +# Same as Black +line-length = 88 + +# Oldest Python on supported distros (Ubuntu 20.04) +target-version = "py38" + +[lint] +ignore = ["E203"] diff --git a/lgsm/modules/query_gsquery.py b/lgsm/modules/query_gsquery.py old mode 100644 new mode 100755 index c4b8c3ddcf..180f49a086 --- a/lgsm/modules/query_gsquery.py +++ b/lgsm/modules/query_gsquery.py @@ -1,5 +1,4 @@ #! /usr/bin/env python3 -# -*- coding: utf-8 -*- # LinuxGSM query_gsquery.py module # Author: Daniel Gibbs # Contributors: https://linuxgsm.com/contrib @@ -65,7 +64,6 @@ 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" elif self.argument.engine in self.idtech2query: @@ -135,7 +133,7 @@ def responding(self): # Receive. try: self.response = connection.recv(self.default_buffer_length) - except socket.error: + except OSError: self.fatal_error("Unable to receive", 2) connection.close() # Response. From 5b099d54faf05b1abb05e4f0826131ae8d016a65 Mon Sep 17 00:00:00 2001 From: BorzakA <1230402+borzaka@users.noreply.github.com> Date: Sat, 10 Oct 2026 22:24:29 +0200 Subject: [PATCH 040/164] fix(monitor): show the queried address on the DELAY and WAIT lines (#5006) fn_monitor_query loops over queryips, but the DELAY print and log line and the WAIT countdown still used ${ip}. With no IP set this is 0.0.0.0, so monitor printed and logged an address it never queried. Fixes #5004 Co-authored-by: Claude Opus 5.5 --- lgsm/modules/command_monitor.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lgsm/modules/command_monitor.sh b/lgsm/modules/command_monitor.sh index 62c05efdf1..21d99bd062 100755 --- a/lgsm/modules/command_monitor.sh +++ b/lgsm/modules/command_monitor.sh @@ -291,9 +291,9 @@ fn_monitor_query() { fn_script_log_info "Querying port: ${querymethod}: ${queryip}:${queryport} : ${queryattempt} : QUERYING" # querydelay if [ "$(head -n 1 "${lockdir}/${selfname}-started.lock")" -gt "$(date "+%s" -d "${querydelay} mins ago")" ]; then - fn_print_ok "Querying port: ${querymethod}: ${ip}:${queryport} : ${totalseconds}/${queryattempt}" + fn_print_ok "Querying port: ${querymethod}: ${queryip}:${queryport} : ${totalseconds}/${queryattempt}" fn_print_delay_eol_nl - fn_script_log_info "Querying port: ${querymethod}: ${ip}:${queryport} : ${queryattempt} : DELAY" + fn_script_log_info "Querying port: ${querymethod}: ${queryip}:${queryport} : ${queryattempt} : DELAY" fn_script_log_info "Query bypassed: ${gameservername} started less than ${querydelay} minutes ago" fn_script_log_info "Server started: $(date -d "@$(head -n 1 "${lockdir}/${selfname}-started.lock")")" fn_script_log_info "Current time: $(date)" @@ -364,7 +364,7 @@ fn_monitor_query() { done # Second counter will wait for 15s before breaking loop. for seconds in {1..15}; do - fn_print_fail "Querying port: ${querymethod}: ${ip}:${queryport} : ${totalseconds}/${queryattempt}" + fn_print_fail "Querying port: ${querymethod}: ${queryip}:${queryport} : ${totalseconds}/${queryattempt}" fn_print_wait_eol fn_sleep_time_1 totalseconds=$((totalseconds + 1)) From fe5ae6bcbc0e1013c8fe1a2c56aee17a77b2c9bf Mon Sep 17 00:00:00 2001 From: Daniel Gibbs Date: Sat, 10 Oct 2026 21:26:39 +0100 Subject: [PATCH 041/164] Release v26.3.0 --- lgsm/modules/core_modules.sh | 2 +- linuxgsm.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lgsm/modules/core_modules.sh b/lgsm/modules/core_modules.sh index 9444aa4788..c5cc3a487e 100755 --- a/lgsm/modules/core_modules.sh +++ b/lgsm/modules/core_modules.sh @@ -8,7 +8,7 @@ moduleselfname="$(basename "$(readlink -f "${BASH_SOURCE[0]}")")" -modulesversion="v26.2.0" +modulesversion="v26.3.0" # Core diff --git a/linuxgsm.sh b/linuxgsm.sh index a374d8732f..643673b319 100755 --- a/linuxgsm.sh +++ b/linuxgsm.sh @@ -24,7 +24,7 @@ if [ -f ".dev-debug" ]; then set -x fi -version="v26.2.0" +version="v26.3.0" shortname="core" gameservername="core" commandname="CORE" From 37fc36951bf3653b84a9f8c890a61659f06ef2af Mon Sep 17 00:00:00 2001 From: Daniel Gibbs Date: Sat, 10 Oct 2026 23:47:30 +0100 Subject: [PATCH 042/164] feat(workshop): download Steam Workshop mods for Arma 3 and DayZ (#5008) * feat(workshop): download Steam Workshop mods for Arma 3 and DayZ Arma 3 and DayZ servers can't download Workshop content themselves. Add workshopmods (item and collection IDs) and a workshop-update command that downloads changed items with one SteamCMD login, installs them to serverfiles/workshop/@, lowercases them, copies BattlEye keys and removes mods no longer listed. update and check-update include Workshop mods, and start appends installed mods to -mod= in order. * chore(workshop): make workshop_core.sh executable * fix(workshop): download before stopping the server, and skip the restart when nothing changed --- .../config-lgsm/arma3server/_default.cfg | 7 + .../config-lgsm/dayzserver/_default.cfg | 7 + lgsm/modules/check.sh | 18 +- lgsm/modules/command_check_update.sh | 5 + lgsm/modules/command_update.sh | 5 + lgsm/modules/command_workshop_update.sh | 28 ++ lgsm/modules/core_getopt.sh | 7 + lgsm/modules/core_modules.sh | 12 + lgsm/modules/workshop_core.sh | 458 ++++++++++++++++++ 9 files changed, 543 insertions(+), 4 deletions(-) create mode 100755 lgsm/modules/command_workshop_update.sh create mode 100755 lgsm/modules/workshop_core.sh diff --git a/lgsm/config-default/config-lgsm/arma3server/_default.cfg b/lgsm/config-default/config-lgsm/arma3server/_default.cfg index 46a98ed463..5351c46aab 100644 --- a/lgsm/config-default/config-lgsm/arma3server/_default.cfg +++ b/lgsm/config-default/config-lgsm/arma3server/_default.cfg @@ -27,6 +27,13 @@ mods="" ## Server-side Mods servermods="" +## Steam Workshop Mods | https://docs.linuxgsm.com/steamcmd/workshop +# Workshop item or collection IDs, separated by spaces. Collections are expanded. +# Installed to serverfiles/workshop and added to -mod= in the order listed. +# Run ./arma3server workshop-update after changing, or let update apply it. +# workshopmods="450814997" +workshopmods="" + ## Path to BattlEye # Leave empty for default bepath="" diff --git a/lgsm/config-default/config-lgsm/dayzserver/_default.cfg b/lgsm/config-default/config-lgsm/dayzserver/_default.cfg index e55b0f3fd9..4fc6307594 100644 --- a/lgsm/config-default/config-lgsm/dayzserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/dayzserver/_default.cfg @@ -27,6 +27,13 @@ mods="" ## Server-side Mods servermods="" +## Steam Workshop Mods | https://docs.linuxgsm.com/steamcmd/workshop +# Workshop item or collection IDs, separated by spaces. Collections are expanded. +# Installed to serverfiles/workshop and added to -mod= in the order listed. +# Run ./dayzserver workshop-update after changing, or let update apply it. +# workshopmods="1559212036" +workshopmods="" + ## Path to BattlEye # Leave empty for default bepath="" diff --git a/lgsm/modules/check.sh b/lgsm/modules/check.sh index 3922aec215..9404965793 100755 --- a/lgsm/modules/check.sh +++ b/lgsm/modules/check.sh @@ -47,14 +47,14 @@ if [ "$(whoami)" != "root" ]; then done fi -allowed_commands_array=(BACKUP CONSOLE DEBUG DETAILS MAP-COMPRESSOR FASTDL MODS-INSTALL MODS-REMOVE MODS-UPDATE MONITOR POST-DETAILS RESTART START STOP TEST-ALERT CHANGE-PASSWORD UPDATE UPDATE-LGSM VALIDATE WIPE) +allowed_commands_array=(BACKUP CONSOLE DEBUG DETAILS MAP-COMPRESSOR FASTDL MODS-INSTALL MODS-REMOVE MODS-UPDATE MONITOR POST-DETAILS RESTART START STOP TEST-ALERT CHANGE-PASSWORD UPDATE UPDATE-LGSM VALIDATE WIPE WORKSHOP-UPDATE) for allowed_command in "${allowed_commands_array[@]}"; do if [ "${allowed_command}" == "${commandname}" ]; then check_logs.sh fi done -allowed_commands_array=(BACKUP DEBUG DETAILS RESTART START UPDATE) +allowed_commands_array=(BACKUP DEBUG DETAILS RESTART START UPDATE WORKSHOP-UPDATE) for allowed_command in "${allowed_commands_array[@]}"; do if [ "${allowed_command}" == "${commandname}" ]; then check_deps.sh @@ -77,7 +77,7 @@ for allowed_command in "${allowed_commands_array[@]}"; do fi done -allowed_commands_array=(DEBUG RESTART START UPDATE VALIDATE CHECK-UPDATE) +allowed_commands_array=(DEBUG RESTART START UPDATE VALIDATE CHECK-UPDATE WORKSHOP-UPDATE) for allowed_command in "${allowed_commands_array[@]}"; do if [ "${allowed_command}" == "${commandname}" ]; then if [ "${appid}" ]; then @@ -86,7 +86,7 @@ for allowed_command in "${allowed_commands_array[@]}"; do fi done -allowed_commands_array=(CHANGE-PASSWORD DETAILS MONITOR RESTART START STOP UPDATE VALIDATE POST-DETAILS) +allowed_commands_array=(CHANGE-PASSWORD DETAILS MONITOR RESTART START STOP UPDATE VALIDATE POST-DETAILS WORKSHOP-UPDATE) for allowed_command in "${allowed_commands_array[@]}"; do if [ "${allowed_command}" == "${commandname}" ]; then check_status.sh @@ -106,3 +106,13 @@ for allowed_command in "${allowed_commands_array[@]}"; do check_gamedig.sh fi done + +if [ "${shortname}" == "arma3" ] || [ "${shortname}" == "dayz" ]; then + allowed_commands_array=(DEBUG DETAILS POST-DETAILS RESTART START) + for allowed_command in "${allowed_commands_array[@]}"; do + if [ "${allowed_command}" == "${commandname}" ] && { [ -n "${workshopmods}" ] || [ -d "${serverfiles}/workshop" ]; }; then + workshop_core.sh + fn_workshop_mods_startparameters + fi + done +fi diff --git a/lgsm/modules/command_check_update.sh b/lgsm/modules/command_check_update.sh index 3bdd25bcdd..85750eed8d 100755 --- a/lgsm/modules/command_check_update.sh +++ b/lgsm/modules/command_check_update.sh @@ -44,4 +44,9 @@ else update_steamcmd.sh fi +if { [ "${shortname}" == "arma3" ] || [ "${shortname}" == "dayz" ]; } && { [ -n "${workshopmods}" ] || [ -d "${serverfiles}/workshop" ]; }; then + workshop_core.sh + fn_workshop_update +fi + core_exit.sh diff --git a/lgsm/modules/command_update.sh b/lgsm/modules/command_update.sh index 097664be35..adaedbe65c 100755 --- a/lgsm/modules/command_update.sh +++ b/lgsm/modules/command_update.sh @@ -45,6 +45,11 @@ else update_steamcmd.sh fi +if { [ "${shortname}" == "arma3" ] || [ "${shortname}" == "dayz" ]; } && { [ -n "${workshopmods}" ] || [ -d "${serverfiles}/workshop" ]; }; then + workshop_core.sh + fn_workshop_update +fi + # remove update lockfile. rm -f "${lockdir:?}/update.lock" diff --git a/lgsm/modules/command_workshop_update.sh b/lgsm/modules/command_workshop_update.sh new file mode 100755 index 0000000000..e8a8f2dcfa --- /dev/null +++ b/lgsm/modules/command_workshop_update.sh @@ -0,0 +1,28 @@ +#!/bin/bash +# LinuxGSM command_workshop_update.sh module +# Author: Daniel Gibbs +# Contributors: https://linuxgsm.com/contrib +# Website: https://linuxgsm.com +# Description: Downloads, updates and removes Steam Workshop mods set in workshopmods. + +commandname="WORKSHOP-UPDATE" +commandaction="Updating Workshop Mods" +moduleselfname="$(basename "$(readlink -f "${BASH_SOURCE[0]}")")" +fn_firstcommand_set + +fn_print_dots "" +check.sh +core_logs.sh + +if [ -z "${workshopmods}" ] && [ ! -d "${serverfiles}/workshop" ]; then + fn_print_info_nl "No Workshop mods set. Add Workshop IDs to workshopmods in ${configdirserver}" + fn_script_log_info "No Workshop mods set" + core_exit.sh +fi + +workshop_core.sh +fn_workshop_update + +rm -f "${lockdir:?}/update.lock" + +core_exit.sh diff --git a/lgsm/modules/core_getopt.sh b/lgsm/modules/core_getopt.sh index a9e4592045..1debb2c7a9 100755 --- a/lgsm/modules/core_getopt.sh +++ b/lgsm/modules/core_getopt.sh @@ -37,6 +37,8 @@ cmd_validate=("v;validate" "command_validate.sh" "Validate server files with Ste cmd_mods_install=("mi;mods-install" "command_mods_install.sh" "View and install available mods/addons.") cmd_mods_remove=("mr;mods-remove" "command_mods_remove.sh" "View and remove an installed mod/addon.") cmd_mods_update=("mu;mods-update" "command_mods_update.sh" "Update installed mods/addons.") +# Server with Steam Workshop downloads. +cmd_workshop_update=("wu;workshop-update" "command_workshop_update.sh" "Install and update Steam Workshop mods.") # Server specific. cmd_change_password=("pw;change-password" "command_ts3_server_pass.sh" "Change TS3 serveradmin password.") cmd_install_default_resources=("ir;install-default-resources" "command_install_resources_mta.sh" "Install the MTA default resources.") @@ -141,6 +143,11 @@ if [ "${engine}" == "source" ] || [ "${shortname}" == "cs2" ] || [ "${shortname} currentopt+=("${cmd_mods_install[@]}" "${cmd_mods_remove[@]}" "${cmd_mods_update[@]}") fi +## Workshop commands. +if [ "${shortname}" == "arma3" ] || [ "${shortname}" == "dayz" ]; then + currentopt+=("${cmd_workshop_update[@]}") +fi + ## Installer. currentopt+=("${cmd_install[@]}" "${cmd_auto_install[@]}") diff --git a/lgsm/modules/core_modules.sh b/lgsm/modules/core_modules.sh index 9444aa4788..c0975bb60e 100755 --- a/lgsm/modules/core_modules.sh +++ b/lgsm/modules/core_modules.sh @@ -181,6 +181,11 @@ command_wipe.sh() { fn_fetch_module } +command_workshop_update.sh() { + modulefile="${FUNCNAME[0]}" + fn_fetch_module +} + install_squad_license.sh() { modulefile="${FUNCNAME[0]}" fn_fetch_module @@ -292,6 +297,13 @@ mods_list.sh() { fn_fetch_module } +# Workshop + +workshop_core.sh() { + modulefile="${FUNCNAME[0]}" + fn_fetch_module +} + # Dev command_dev_clear_modules.sh() { diff --git a/lgsm/modules/workshop_core.sh b/lgsm/modules/workshop_core.sh new file mode 100755 index 0000000000..f0358fcfe1 --- /dev/null +++ b/lgsm/modules/workshop_core.sh @@ -0,0 +1,458 @@ +#!/bin/bash +# LinuxGSM workshop_core.sh module +# Author: Daniel Gibbs +# Contributors: https://linuxgsm.com/contrib +# Website: https://linuxgsm.com +# Description: Downloads and installs Steam Workshop mods for game servers that cannot download them. + +moduleselfname="$(basename "$(readlink -f "${BASH_SOURCE[0]}")")" + +workshopdir="${serverfiles}/workshop" +workshopdldir="${tmpdir}/workshop" +workshopmodlist="${datadir}/${selfname}-workshop.txt" +workshopapi="https://api.steampowered.com/ISteamRemoteStorage" +workshopapimax="100" +workshopretries="5" + +# Converts workshopmods into an ordered list of IDs. Accepts space, comma or semicolon separators. +fn_workshop_config_ids() { + workshopconfigids=() + local id + for id in ${workshopmods//[,;]/ }; do + if [[ "${id}" =~ ^[0-9]+$ ]]; then + workshopconfigids+=("${id}") + else + fn_print_warn_nl "Ignoring invalid Workshop ID: ${id}" + fn_script_log_warn "Ignoring invalid Workshop ID: ${id}" + fi + done +} + +# Queries the Steam Web API. Usage: fn_workshop_api ... +fn_workshop_api() { + local method="$1" + shift + local countparam="itemcount" + if [ "${method}" == "GetCollectionDetails" ]; then + countparam="collectioncount" + fi + local postdata=("--data-urlencode" "${countparam}=$#") + local index=0 + local id + for id in "$@"; do + postdata+=("--data-urlencode" "publishedfileids[${index}]=${id}") + index=$((index + 1)) + done + curl -sSL --connect-timeout 10 --max-time 60 "${postdata[@]}" "${workshopapi}/${method}/v1/" +} + +# Records which IDs are collections and their children, in batches. +fn_workshop_get_collections() { + local ids=("$@") + local start response + for ((start = 0; start < ${#ids[@]}; start += workshopapimax)); do + if ! response="$(fn_workshop_api GetCollectionDetails "${ids[@]:start:workshopapimax}")" || ! jq -e '.response' <<< "${response}" > /dev/null 2>&1; then + fn_print_fail_nl "Checking for update: ${remotelocation}: Unable to get collection details from Steam" + fn_script_log_fail "Checking for update: ${remotelocation}: Unable to get collection details from Steam" + core_exit.sh + fi + local id result children + while IFS=$'\t' read -r id result children; do + workshopchecked["${id}"]=1 + if [ "${result}" == "1" ]; then + workshopchildren["${id}"]="${children}" + fi + done < <(jq -r '.response.collectiondetails[] | [.publishedfileid, (.result | tostring), ([.children[]? | "\(.publishedfileid):\(.filetype)"] | join(" "))] | @tsv' <<< "${response}") + done +} + +# Adds an ID to workshopitems, expanding collections in their sort order. +fn_workshop_expand() { + local id="$1" + local depth="$2" + if [ -n "${workshopseen[${id}]}" ]; then + return + fi + workshopseen["${id}"]=1 + if [ -n "${workshopchildren[${id}]+set}" ]; then + if [ "${depth}" -gt 3 ]; then + fn_print_warn_nl "Skipping Workshop collection ${id}: collections are nested too deeply" + fn_script_log_warn "Skipping Workshop collection ${id}: collections are nested too deeply" + return + fi + local child + for child in ${workshopchildren[${id}]}; do + fn_workshop_expand "${child%%:*}" $((depth + 1)) + done + else + workshopitems+=("${id}") + fi +} + +# Builds workshopitems: the ordered list of Workshop items to install, with collections expanded. +fn_workshop_resolve() { + declare -gA workshopchecked=() + declare -gA workshopchildren=() + declare -gA workshopseen=() + workshopitems=() + fn_workshop_config_ids + if [ "${#workshopconfigids[@]}" -eq 0 ]; then + return + fi + local tocheck=("${workshopconfigids[@]}") + local round id child + for ((round = 0; round < 4 && ${#tocheck[@]} > 0; round++)); do + fn_workshop_get_collections "${tocheck[@]}" + local nested=() + for id in "${tocheck[@]}"; do + for child in ${workshopchildren[${id}]}; do + if [ "${child##*:}" == "2" ] && [ -z "${workshopchecked[${child%%:*}]}" ]; then + nested+=("${child%%:*}") + fi + done + done + tocheck=("${nested[@]}") + done + for id in "${workshopconfigids[@]}"; do + fn_workshop_expand "${id}" 0 + done +} + +# Gets title, game appid and last updated time for each item in workshopitems. +fn_workshop_get_details() { + declare -gA workshoptitle=() + declare -gA workshopappid=() + declare -gA workshoptimeupdated=() + local validitems=() + local start response + for ((start = 0; start < ${#workshopitems[@]}; start += workshopapimax)); do + if ! response="$(fn_workshop_api GetPublishedFileDetails "${workshopitems[@]:start:workshopapimax}")" || ! jq -e '.response' <<< "${response}" > /dev/null 2>&1; then + fn_print_fail_nl "Checking for update: ${remotelocation}: Unable to get Workshop item details from Steam" + fn_script_log_fail "Checking for update: ${remotelocation}: Unable to get Workshop item details from Steam" + core_exit.sh + fi + local id result appid timeupdated title + while IFS=$'\t' read -r id result appid timeupdated title; do + if [ "${result}" != "1" ] || [ -z "${timeupdated}" ]; then + fn_print_warn_nl "Skipping Workshop item ${id}: not found, or not public" + fn_script_log_warn "Skipping Workshop item ${id}: not found, or not public" + continue + fi + workshoptitle["${id}"]="${title}" + workshopappid["${id}"]="${appid}" + workshoptimeupdated["${id}"]="${timeupdated}" + done < <(jq -r '.response.publishedfiledetails[] | [.publishedfileid, (.result | tostring), (.consumer_app_id // "" | tostring), (.time_updated // "" | tostring), (.title // "" | gsub("[\t\n\r]"; " "))] | @tsv' <<< "${response}") + done + local item + for item in "${workshopitems[@]}"; do + if [ -n "${workshoptimeupdated[${item}]}" ]; then + validitems+=("${item}") + fi + done + workshopitems=("${validitems[@]}") +} + +# Reads a value from an installed mod's state file. Usage: fn_workshop_state +fn_workshop_state() { + local statefile="${workshopdir}/@${1}/.lgsm-workshop" + if [ -f "${statefile}" ]; then + sed -n "s/^${2}=//p" "${statefile}" + fi +} + +# Works out which mods need downloading and which installed mods are no longer used. +fn_workshop_compare() { + workshopupdates=() + workshopremovals=() + local item + for item in "${workshopitems[@]}"; do + if [ "$(fn_workshop_state "${item}" timeupdated)" != "${workshoptimeupdated[${item}]}" ]; then + workshopupdates+=("${item}") + fi + done + if [ -d "${workshopdir}" ]; then + # Mods used by any instance sharing these serverfiles are kept. + local inuse=" ${workshopitems[*]} " + local listfile + for listfile in "${datadir}"/*-workshop.txt; do + if [ -f "${listfile}" ] && [ "${listfile}" != "${workshopmodlist}" ]; then + inuse+="$(grep -v '^#' "${listfile}" | tr '\n' ' ') " + fi + done + local moddir + for moddir in "${workshopdir}"/@*; do + item="${moddir##*/@}" + if [ -d "${moddir}" ] && [[ "${inuse}" != *" ${item} "* ]]; then + workshopremovals+=("${item}") + fi + done + fi +} + +# Downloads Workshop items with a single SteamCMD login. Failed items are retried. +fn_workshop_download() { + local pending=("$@") + local attempt=0 + local item params + steamcmdlog="${lgsmlogdir}/${selfname}-steamcmd.log" + rm -rf "${workshopdldir:?}" + mkdir -p "${workshopdldir}" + if [ -d "${steamcmddir}" ]; then + cd "${steamcmddir}" || exit + fi + unbuffercommand=() + if [ "$(command -v unbuffer 2> /dev/null)" ]; then + unbuffercommand=("unbuffer") + fi + while [ "${#pending[@]}" -gt 0 ] && [ "${attempt}" -lt "${workshopretries}" ]; do + attempt=$((attempt + 1)) + params=(+force_install_dir "${workshopdldir}" +login "${steamuser}" "${steampass}") + for item in "${pending[@]}"; do + params+=(+workshop_download_item "${workshopappid[${item}]}" "${item}") + done + params+=(+quit) + rm -f "${steamcmdlog:?}" + "${unbuffercommand[@]}" "${steamcmdcommand}" "${params[@]}" | uniq | tee -a "${lgsmlog}" "${steamcmdlog}" + + if grep -q "FAILED (" "${steamcmdlog}" || grep -q "Two-factor code mismatch" "${steamcmdlog}"; then + fn_print_failure_nl "${commandaction} ${selfname}: ${remotelocation}: Steam login failed" + fn_print_nl "Check steamuser and steampass in ${configdirserver}" + fn_script_log_fail "${commandaction} ${selfname}: ${remotelocation}: Steam login failed" + core_exit.sh + fi + + local failed=() + for item in "${pending[@]}"; do + if [ -z "$(find "${workshopdldir}/steamapps/workshop/content/${workshopappid[${item}]}/${item}" -mindepth 1 -print -quit 2> /dev/null)" ]; then + failed+=("${item}") + fi + done + pending=("${failed[@]}") + if [ "${#pending[@]}" -gt 0 ] && [ "${attempt}" -lt "${workshopretries}" ]; then + fn_print_error2_nl "${commandaction} ${selfname}: ${remotelocation}: ${#pending[@]} item(s) did not download, retrying" + fn_script_log_error "${commandaction} ${selfname}: ${remotelocation}: ${#pending[@]} item(s) did not download, retrying" + fi + done + workshopfailed=("${pending[@]}") + if [ "${#workshopfailed[@]}" -gt 0 ]; then + fn_print_failure_nl "${commandaction} ${selfname}: ${remotelocation}: ${#workshopfailed[@]} item(s) failed to download" + for item in "${workshopfailed[@]}"; do + fn_print_nl "* ${workshoptitle[${item}]} (${item})" + fn_script_log_fail "${commandaction} ${selfname}: ${remotelocation}: ${workshoptitle[${item}]} (${item}) failed to download" + done + fn_print_nl "The Steam account must own the game for its Workshop items to download" + fi +} + +# Renames files and directories in a mod to lowercase, deepest first. +fn_workshop_lowercase() { + local path name lower + while IFS= read -r -d '' path; do + name="${path##*/}" + lower="${name,,}" + if [ -e "${path%/*}/${lower}" ]; then + fn_script_log_warn "Lowercase name already exists, not renaming: ${path}" + else + mv "${path}" "${path%/*}/${lower}" + fi + done < <(find "$1" -mindepth 1 -depth -name '*[[:upper:]]*' -print0) +} + +# Removes the BattlEye keys a mod installed, unless another installed mod also uses them. +fn_workshop_remove_keys() { + local item="$1" + local key moddir + for key in $(fn_workshop_state "${item}" keys); do + local shared="" + for moddir in "${workshopdir}"/@*; do + if [ "${moddir}" != "${workshopdir}/@${item}" ] && [[ " $(fn_workshop_state "${moddir##*/@}" keys) " == *" ${key} "* ]]; then + shared=1 + fi + done + if [ -z "${shared}" ]; then + rm -f "${serverfiles:?}/keys/${key}" + fi + done +} + +# Moves a downloaded item into serverfiles/workshop/@ and prepares it for the game. +fn_workshop_install() { + local item="$1" + local src="${workshopdldir}/steamapps/workshop/content/${workshopappid[${item}]}/${item}" + local dst="${workshopdir}/@${item}" + local keys=() + local key + fn_print_dots "Installing ${workshoptitle[${item}]} (${item})" + if [ -d "${dst}" ]; then + fn_workshop_remove_keys "${item}" + rm -rf "${dst:?}" + fi + mkdir -p "${workshopdir}" + if ! mv "${src}" "${dst}"; then + fn_print_fail_nl "Installing ${workshoptitle[${item}]} (${item})" + fn_script_log_fail "Installing ${workshoptitle[${item}]} (${item})" + core_exit.sh + fi + if [ "${shortname}" == "arma3" ] || [ "${shortname}" == "dayz" ]; then + fn_workshop_lowercase "${dst}" + mkdir -p "${serverfiles}/keys" + while IFS= read -r -d '' key; do + cp -f "${key}" "${serverfiles}/keys/" + keys+=("${key##*/}") + done < <(find "${dst}" -type f -name '*.bikey' -print0) + fi + { + echo "title=${workshoptitle[${item}]}" + echo "timeupdated=${workshoptimeupdated[${item}]}" + echo "keys=${keys[*]}" + } > "${dst}/.lgsm-workshop" + fn_print_ok_nl "Installing ${workshoptitle[${item}]} (${item})" + fn_script_log_pass "Installing ${workshoptitle[${item}]} (${item})" +} + +# Removes an installed mod that is no longer in workshopmods. +fn_workshop_remove() { + local item="$1" + local title + title="$(fn_workshop_state "${item}" title)" + fn_print_dots "Removing ${title} (${item})" + fn_workshop_remove_keys "${item}" + rm -rf "${workshopdir:?}/@${item}" + fn_print_ok_nl "Removing ${title} (${item})" + fn_script_log_pass "Removing ${title} (${item})" +} + +# Installs downloaded items and removes unused ones. Downloads happen first, so the server only stops for this step. +fn_workshop_apply() { + local item + for item in "${workshopinstalls[@]}"; do + fn_workshop_install "${item}" + done + for item in "${workshopremovals[@]}"; do + fn_workshop_remove "${item}" + done + rm -rf "${workshopdldir:?}" +} + +# Saves the resolved mod order so start can build the mod list without querying Steam. +fn_workshop_save_list() { + { + echo "# workshopmods=${workshopmods}" + printf '%s\n' "${workshopitems[@]}" + } > "${workshopmodlist}" +} + +# Checks for Workshop mod updates and, for update commands, applies them. +fn_workshop_update() { + remotelocation="Steam Workshop" + fn_print_dots "Checking for update: ${remotelocation}" + fn_workshop_resolve + if [ "${#workshopitems[@]}" -gt 0 ]; then + fn_workshop_get_details + fi + fn_workshop_compare + fn_print_ok_nl "Checking for update: ${remotelocation}" + fn_script_log_info "Checking for update: ${remotelocation}" + + local item + if [ "${#workshopupdates[@]}" -eq 0 ] && [ "${#workshopremovals[@]}" -eq 0 ]; then + fn_print "\n" + fn_print_nl "${bold}${underline}No update${default} available" + fn_print_nl "* Workshop mods: ${#workshopitems[@]}" + fn_print "\n" + fn_script_log_info "No update available: ${remotelocation}" + if [ "${commandname}" != "CHECK-UPDATE" ]; then + fn_workshop_save_list + fi + return + fi + + fn_print "\n" + fn_print_nl "${bold}${underline}Update${default} available" + for item in "${workshopupdates[@]}"; do + if [ -d "${workshopdir}/@${item}" ]; then + fn_print_nl "* Update: ${workshoptitle[${item}]} (${item})" + else + fn_print_nl "* Install: ${workshoptitle[${item}]} (${item})" + fi + fn_script_log_info "Update available: ${workshoptitle[${item}]} (${item})" + done + for item in "${workshopremovals[@]}"; do + fn_print_nl "* Remove: $(fn_workshop_state "${item}" title) (${item})" + fn_script_log_info "Remove: $(fn_workshop_state "${item}" title) (${item})" + done + fn_print "\n" + + if [ "${commandname}" == "CHECK-UPDATE" ]; then + return + fi + + fn_workshop_save_list + date '+%s' > "${lockdir:?}/update.lock" + workshopinstalls=() + workshopfailed=() + if [ "${#workshopupdates[@]}" -gt 0 ]; then + fn_print_start_nl "${remotelocation}" + fn_workshop_download "${workshopupdates[@]}" + for item in "${workshopupdates[@]}"; do + if [[ " ${workshopfailed[*]} " != *" ${item} "* ]]; then + workshopinstalls+=("${item}") + fi + done + fi + if [ "${#workshopinstalls[@]}" -eq 0 ] && [ "${#workshopremovals[@]}" -eq 0 ]; then + rm -rf "${workshopdldir:?}" + return + fi + + check_status.sh + if [ "${status}" == "0" ]; then + fn_workshop_apply + else + fn_print_restart_warning + exitbypass=1 + command_stop.sh + fn_firstcommand_reset + fn_workshop_apply + exitbypass=1 + command_start.sh + fn_firstcommand_reset + fi + unset exitbypass +} + +# Adds installed Workshop mods to the mods start parameter, in workshopmods order. +fn_workshop_mods_startparameters() { + if [ -n "${workshopmodsadded}" ]; then + return + fi + workshopmodsadded=1 + local items=() + if [ -f "${workshopmodlist}" ]; then + mapfile -t items < <(grep -v '^#' "${workshopmodlist}") + if [ "$(sed -n 's/^# workshopmods=//p' "${workshopmodlist}")" != "${workshopmods}" ]; then + fn_print_warn_nl "workshopmods has changed. Run ./${selfname} workshop-update to apply it" + fn_script_log_warn "workshopmods has changed. Run ./${selfname} workshop-update to apply it" + fi + else + fn_workshop_config_ids + items=("${workshopconfigids[@]}") + fi + local workshopmodsparam="" + local missing=0 + local item + for item in "${items[@]}"; do + if [ -d "${workshopdir}/@${item}" ]; then + workshopmodsparam+="${workshopmodsparam:+\\;}workshop/@${item}" + else + missing=$((missing + 1)) + fi + done + if [ "${missing}" -gt 0 ]; then + fn_print_warn_nl "${missing} Workshop mod(s) not installed. Run ./${selfname} workshop-update to install them" + fn_script_log_warn "${missing} Workshop mod(s) not installed" + fi + if [ -n "${workshopmodsparam}" ]; then + mods="${mods:+${mods}\\;}${workshopmodsparam}" + fi +} From b516b9c2b0bee57fda74d6b926808eae5e93d3d2 Mon Sep 17 00:00:00 2001 From: Daniel Gibbs Date: Sun, 11 Oct 2026 11:23:01 +0100 Subject: [PATCH 043/164] feat(workshop): add Steam Workshop downloads for Squad and Starbound (#5009) * feat(workshop): add Steam Workshop downloads for Squad and Starbound * fix(workshop): remove the saved mod list once no Workshop mods are left --- .../config-lgsm/sbserver/_default.cfg | 6 ++ .../config-lgsm/squadserver/_default.cfg | 6 ++ lgsm/modules/check.sh | 2 +- lgsm/modules/command_check_update.sh | 2 +- lgsm/modules/command_update.sh | 2 +- lgsm/modules/command_workshop_update.sh | 2 +- lgsm/modules/core_getopt.sh | 2 +- lgsm/modules/workshop_core.sh | 67 ++++++++++++++----- 8 files changed, 67 insertions(+), 22 deletions(-) diff --git a/lgsm/config-default/config-lgsm/sbserver/_default.cfg b/lgsm/config-default/config-lgsm/sbserver/_default.cfg index fbca63afc0..a10b42f7a8 100644 --- a/lgsm/config-default/config-lgsm/sbserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/sbserver/_default.cfg @@ -18,6 +18,12 @@ ip="0.0.0.0" ## Server Parameters | https://docs.linuxgsm.com/configuration/start-parameters#additional-parameters startparameters="" +## Steam Workshop Mods | https://docs.linuxgsm.com/steamcmd/workshop +# Workshop item or collection IDs, separated by spaces. Collections are expanded. +# Installed to serverfiles/workshop and linked into serverfiles/mods. Run ./sbserver workshop-update after changing, or let update apply it. +# workshopmods="3816094872" +workshopmods="" + #### LinuxGSM Settings #### ## LinuxGSM Stats diff --git a/lgsm/config-default/config-lgsm/squadserver/_default.cfg b/lgsm/config-default/config-lgsm/squadserver/_default.cfg index b19d59ce6b..18045e3f57 100644 --- a/lgsm/config-default/config-lgsm/squadserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/squadserver/_default.cfg @@ -16,6 +16,12 @@ queryport="27165" ## Game Server Docs | https://squad.fandom.com/wiki/Dedicated_server startparameters="-MultiHome=${ip} -Port=${port} -QueryPort=${queryport}" +## Steam Workshop Mods | https://docs.linuxgsm.com/steamcmd/workshop +# Workshop item or collection IDs, separated by spaces. Collections are expanded. +# Installed to SquadGame/Plugins/Mods. Run ./squadserver workshop-update after changing, or let update apply it. +# workshopmods="3813515660" +workshopmods="" + #### LinuxGSM Settings #### ## LinuxGSM Stats diff --git a/lgsm/modules/check.sh b/lgsm/modules/check.sh index 9404965793..71a5db7478 100755 --- a/lgsm/modules/check.sh +++ b/lgsm/modules/check.sh @@ -110,7 +110,7 @@ done if [ "${shortname}" == "arma3" ] || [ "${shortname}" == "dayz" ]; then allowed_commands_array=(DEBUG DETAILS POST-DETAILS RESTART START) for allowed_command in "${allowed_commands_array[@]}"; do - if [ "${allowed_command}" == "${commandname}" ] && { [ -n "${workshopmods}" ] || [ -d "${serverfiles}/workshop" ]; }; then + if [ "${allowed_command}" == "${commandname}" ] && { [ -n "${workshopmods}" ] || [ -f "${datadir}/${selfname}-workshop.txt" ]; }; then workshop_core.sh fn_workshop_mods_startparameters fi diff --git a/lgsm/modules/command_check_update.sh b/lgsm/modules/command_check_update.sh index 85750eed8d..5b3f70d138 100755 --- a/lgsm/modules/command_check_update.sh +++ b/lgsm/modules/command_check_update.sh @@ -44,7 +44,7 @@ else update_steamcmd.sh fi -if { [ "${shortname}" == "arma3" ] || [ "${shortname}" == "dayz" ]; } && { [ -n "${workshopmods}" ] || [ -d "${serverfiles}/workshop" ]; }; then +if { [ "${shortname}" == "arma3" ] || [ "${shortname}" == "dayz" ] || [ "${shortname}" == "sb" ] || [ "${shortname}" == "squad" ]; } && { [ -n "${workshopmods}" ] || [ -f "${datadir}/${selfname}-workshop.txt" ]; }; then workshop_core.sh fn_workshop_update fi diff --git a/lgsm/modules/command_update.sh b/lgsm/modules/command_update.sh index adaedbe65c..1a5392599a 100755 --- a/lgsm/modules/command_update.sh +++ b/lgsm/modules/command_update.sh @@ -45,7 +45,7 @@ else update_steamcmd.sh fi -if { [ "${shortname}" == "arma3" ] || [ "${shortname}" == "dayz" ]; } && { [ -n "${workshopmods}" ] || [ -d "${serverfiles}/workshop" ]; }; then +if { [ "${shortname}" == "arma3" ] || [ "${shortname}" == "dayz" ] || [ "${shortname}" == "sb" ] || [ "${shortname}" == "squad" ]; } && { [ -n "${workshopmods}" ] || [ -f "${datadir}/${selfname}-workshop.txt" ]; }; then workshop_core.sh fn_workshop_update fi diff --git a/lgsm/modules/command_workshop_update.sh b/lgsm/modules/command_workshop_update.sh index e8a8f2dcfa..479ff492fe 100755 --- a/lgsm/modules/command_workshop_update.sh +++ b/lgsm/modules/command_workshop_update.sh @@ -14,7 +14,7 @@ fn_print_dots "" check.sh core_logs.sh -if [ -z "${workshopmods}" ] && [ ! -d "${serverfiles}/workshop" ]; then +if [ -z "${workshopmods}" ] && [ ! -f "${datadir}/${selfname}-workshop.txt" ]; then fn_print_info_nl "No Workshop mods set. Add Workshop IDs to workshopmods in ${configdirserver}" fn_script_log_info "No Workshop mods set" core_exit.sh diff --git a/lgsm/modules/core_getopt.sh b/lgsm/modules/core_getopt.sh index 1debb2c7a9..9fdb3e156c 100755 --- a/lgsm/modules/core_getopt.sh +++ b/lgsm/modules/core_getopt.sh @@ -144,7 +144,7 @@ if [ "${engine}" == "source" ] || [ "${shortname}" == "cs2" ] || [ "${shortname} fi ## Workshop commands. -if [ "${shortname}" == "arma3" ] || [ "${shortname}" == "dayz" ]; then +if [ "${shortname}" == "arma3" ] || [ "${shortname}" == "dayz" ] || [ "${shortname}" == "sb" ] || [ "${shortname}" == "squad" ]; then currentopt+=("${cmd_workshop_update[@]}") fi diff --git a/lgsm/modules/workshop_core.sh b/lgsm/modules/workshop_core.sh index f0358fcfe1..34f7691d3c 100755 --- a/lgsm/modules/workshop_core.sh +++ b/lgsm/modules/workshop_core.sh @@ -7,7 +7,14 @@ moduleselfname="$(basename "$(readlink -f "${BASH_SOURCE[0]}")")" -workshopdir="${serverfiles}/workshop" +# Installed mods are named ${workshopprefix} in the directory the game loads them from. +if [ "${shortname}" == "squad" ]; then + workshopdir="${systemdir}/Plugins/Mods" + workshopprefix="" +else + workshopdir="${serverfiles}/workshop" + workshopprefix="@" +fi workshopdldir="${tmpdir}/workshop" workshopmodlist="${datadir}/${selfname}-workshop.txt" workshopapi="https://api.steampowered.com/ISteamRemoteStorage" @@ -154,7 +161,7 @@ fn_workshop_get_details() { # Reads a value from an installed mod's state file. Usage: fn_workshop_state fn_workshop_state() { - local statefile="${workshopdir}/@${1}/.lgsm-workshop" + local statefile="${workshopdir}/${workshopprefix}${1}/.lgsm-workshop" if [ -f "${statefile}" ]; then sed -n "s/^${2}=//p" "${statefile}" fi @@ -179,11 +186,15 @@ fn_workshop_compare() { inuse+="$(grep -v '^#' "${listfile}" | tr '\n' ' ') " fi done - local moddir - for moddir in "${workshopdir}"/@*; do - item="${moddir##*/@}" - if [ -d "${moddir}" ] && [[ "${inuse}" != *" ${item} "* ]]; then - workshopremovals+=("${item}") + local statefile moddir + for statefile in "${workshopdir}"/*/.lgsm-workshop; do + if [ -f "${statefile}" ]; then + moddir="${statefile%/*}" + moddir="${moddir##*/}" + item="${moddir#"${workshopprefix}"}" + if [[ "${inuse}" != *" ${item} "* ]]; then + workshopremovals+=("${item}") + fi fi done fi @@ -261,11 +272,11 @@ fn_workshop_lowercase() { # Removes the BattlEye keys a mod installed, unless another installed mod also uses them. fn_workshop_remove_keys() { local item="$1" - local key moddir + local key statefile for key in $(fn_workshop_state "${item}" keys); do local shared="" - for moddir in "${workshopdir}"/@*; do - if [ "${moddir}" != "${workshopdir}/@${item}" ] && [[ " $(fn_workshop_state "${moddir##*/@}" keys) " == *" ${key} "* ]]; then + for statefile in "${workshopdir}"/*/.lgsm-workshop; do + if [ "${statefile}" != "${workshopdir}/${workshopprefix}${item}/.lgsm-workshop" ] && [[ " $(sed -n 's/^keys=//p' "${statefile}" 2> /dev/null) " == *" ${key} "* ]]; then shared=1 fi done @@ -275,16 +286,26 @@ fn_workshop_remove_keys() { done } -# Moves a downloaded item into serverfiles/workshop/@ and prepares it for the game. +# Removes the links a mod added to the Starbound mods directory. +fn_workshop_remove_links() { + local link + for link in $(fn_workshop_state "$1" links); do + rm -f "${serverfiles:?}/mods/${link}" + done +} + +# Moves a downloaded item into the game's mod directory and prepares it for the game. fn_workshop_install() { local item="$1" local src="${workshopdldir}/steamapps/workshop/content/${workshopappid[${item}]}/${item}" - local dst="${workshopdir}/@${item}" + local dst="${workshopdir}/${workshopprefix}${item}" local keys=() - local key + local links=() + local key pak fn_print_dots "Installing ${workshoptitle[${item}]} (${item})" if [ -d "${dst}" ]; then fn_workshop_remove_keys "${item}" + fn_workshop_remove_links "${item}" rm -rf "${dst:?}" fi mkdir -p "${workshopdir}" @@ -300,11 +321,18 @@ fn_workshop_install() { cp -f "${key}" "${serverfiles}/keys/" keys+=("${key##*/}") done < <(find "${dst}" -type f -name '*.bikey' -print0) + elif [ "${shortname}" == "sb" ]; then + mkdir -p "${serverfiles}/mods" + while IFS= read -r -d '' pak; do + ln -sfn "../workshop/${workshopprefix}${item}/${pak##*/}" "${serverfiles}/mods/workshop-${item}-${pak##*/}" + links+=("workshop-${item}-${pak##*/}") + done < <(find "${dst}" -maxdepth 1 -type f -name '*.pak' -print0) fi { echo "title=${workshoptitle[${item}]}" echo "timeupdated=${workshoptimeupdated[${item}]}" echo "keys=${keys[*]}" + echo "links=${links[*]}" } > "${dst}/.lgsm-workshop" fn_print_ok_nl "Installing ${workshoptitle[${item}]} (${item})" fn_script_log_pass "Installing ${workshoptitle[${item}]} (${item})" @@ -317,7 +345,8 @@ fn_workshop_remove() { title="$(fn_workshop_state "${item}" title)" fn_print_dots "Removing ${title} (${item})" fn_workshop_remove_keys "${item}" - rm -rf "${workshopdir:?}/@${item}" + fn_workshop_remove_links "${item}" + rm -rf "${workshopdir:?}/${workshopprefix}${item}" fn_print_ok_nl "Removing ${title} (${item})" fn_script_log_pass "Removing ${title} (${item})" } @@ -336,6 +365,10 @@ fn_workshop_apply() { # Saves the resolved mod order so start can build the mod list without querying Steam. fn_workshop_save_list() { + if [ "${#workshopitems[@]}" -eq 0 ]; then + rm -f "${workshopmodlist}" + return + fi { echo "# workshopmods=${workshopmods}" printf '%s\n' "${workshopitems[@]}" @@ -370,7 +403,7 @@ fn_workshop_update() { fn_print "\n" fn_print_nl "${bold}${underline}Update${default} available" for item in "${workshopupdates[@]}"; do - if [ -d "${workshopdir}/@${item}" ]; then + if [ -d "${workshopdir}/${workshopprefix}${item}" ]; then fn_print_nl "* Update: ${workshoptitle[${item}]} (${item})" else fn_print_nl "* Install: ${workshoptitle[${item}]} (${item})" @@ -442,8 +475,8 @@ fn_workshop_mods_startparameters() { local missing=0 local item for item in "${items[@]}"; do - if [ -d "${workshopdir}/@${item}" ]; then - workshopmodsparam+="${workshopmodsparam:+\\;}workshop/@${item}" + if [ -d "${workshopdir}/${workshopprefix}${item}" ]; then + workshopmodsparam+="${workshopmodsparam:+\\;}workshop/${workshopprefix}${item}" else missing=$((missing + 1)) fi From eafa45aab3d742bba9cd8da4b1670ca228975413 Mon Sep 17 00:00:00 2001 From: Daniel Gibbs Date: Sun, 11 Oct 2026 12:19:32 +0100 Subject: [PATCH 044/164] feat(workshop): add Steam Workshop downloads for Squad 44 and Operation: Harsh Doorstop (#5012) * feat(workshop): add Steam Workshop downloads for Squad 44 and Operation: Harsh Doorstop * fix(workshop): install OHD mods as their plugin folder so the game can mount them --- .../config-lgsm/ohdserver/_default.cfg | 7 ++ .../config-lgsm/squad44server/_default.cfg | 6 ++ lgsm/modules/command_check_update.sh | 2 +- lgsm/modules/command_update.sh | 2 +- lgsm/modules/core_getopt.sh | 2 +- lgsm/modules/workshop_core.sh | 72 +++++++++++++++---- 6 files changed, 74 insertions(+), 17 deletions(-) diff --git a/lgsm/config-default/config-lgsm/ohdserver/_default.cfg b/lgsm/config-default/config-lgsm/ohdserver/_default.cfg index 17d4c8a186..f3b3510708 100644 --- a/lgsm/config-default/config-lgsm/ohdserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/ohdserver/_default.cfg @@ -21,6 +21,13 @@ maxplayers="16" ## Server Parameters | https://docs.linuxgsm.com/configuration/start-parameters#additional-parameters startparameters="${defaultmap}?MaxPlayers=${maxplayers} -MultiHome=${ip} -Port=${port} -QueryPort=${queryport} -RconPort=${rconport} -SteamServerName='${servername}' -log" +## Steam Workshop Mods | https://docs.linuxgsm.com/steamcmd/workshop +# Workshop item or collection IDs, separated by spaces. Collections are expanded. +# Installed to HarshDoorstop/Mods. Select mod maps and modes with defaultmap or startparameters. +# Run ./ohdserver workshop-update after changing, or let update apply it. +# workshopmods="3131976970" +workshopmods="" + #### LinuxGSM Settings #### ## LinuxGSM Stats diff --git a/lgsm/config-default/config-lgsm/squad44server/_default.cfg b/lgsm/config-default/config-lgsm/squad44server/_default.cfg index 0235f155e9..99cf2a4bd4 100644 --- a/lgsm/config-default/config-lgsm/squad44server/_default.cfg +++ b/lgsm/config-default/config-lgsm/squad44server/_default.cfg @@ -16,6 +16,12 @@ queryport="10037" ## Server Parameters | https://docs.linuxgsm.com/configuration/start-parameters#additional-parameters startparameters="-MultiHome=${ip} -Port=${port} -QueryPort=${queryport} -log" +## Steam Workshop Mods | https://docs.linuxgsm.com/steamcmd/workshop +# Workshop item or collection IDs, separated by spaces. Collections are expanded. +# Installed to PostScriptum/Plugins/Mods. Run ./squad44server workshop-update after changing, or let update apply it. +# workshopmods="2303078092" +workshopmods="" + #### LinuxGSM Settings #### ## LinuxGSM Stats diff --git a/lgsm/modules/command_check_update.sh b/lgsm/modules/command_check_update.sh index 5b3f70d138..a9184e2d90 100755 --- a/lgsm/modules/command_check_update.sh +++ b/lgsm/modules/command_check_update.sh @@ -44,7 +44,7 @@ else update_steamcmd.sh fi -if { [ "${shortname}" == "arma3" ] || [ "${shortname}" == "dayz" ] || [ "${shortname}" == "sb" ] || [ "${shortname}" == "squad" ]; } && { [ -n "${workshopmods}" ] || [ -f "${datadir}/${selfname}-workshop.txt" ]; }; then +if { [ "${shortname}" == "arma3" ] || [ "${shortname}" == "dayz" ] || [ "${shortname}" == "ohd" ] || [ "${shortname}" == "sb" ] || [ "${shortname}" == "squad" ] || [ "${shortname}" == "squad44" ]; } && { [ -n "${workshopmods}" ] || [ -f "${datadir}/${selfname}-workshop.txt" ]; }; then workshop_core.sh fn_workshop_update fi diff --git a/lgsm/modules/command_update.sh b/lgsm/modules/command_update.sh index 1a5392599a..39cf392d86 100755 --- a/lgsm/modules/command_update.sh +++ b/lgsm/modules/command_update.sh @@ -45,7 +45,7 @@ else update_steamcmd.sh fi -if { [ "${shortname}" == "arma3" ] || [ "${shortname}" == "dayz" ] || [ "${shortname}" == "sb" ] || [ "${shortname}" == "squad" ]; } && { [ -n "${workshopmods}" ] || [ -f "${datadir}/${selfname}-workshop.txt" ]; }; then +if { [ "${shortname}" == "arma3" ] || [ "${shortname}" == "dayz" ] || [ "${shortname}" == "ohd" ] || [ "${shortname}" == "sb" ] || [ "${shortname}" == "squad" ] || [ "${shortname}" == "squad44" ]; } && { [ -n "${workshopmods}" ] || [ -f "${datadir}/${selfname}-workshop.txt" ]; }; then workshop_core.sh fn_workshop_update fi diff --git a/lgsm/modules/core_getopt.sh b/lgsm/modules/core_getopt.sh index 9fdb3e156c..adfc5ac6bb 100755 --- a/lgsm/modules/core_getopt.sh +++ b/lgsm/modules/core_getopt.sh @@ -144,7 +144,7 @@ if [ "${engine}" == "source" ] || [ "${shortname}" == "cs2" ] || [ "${shortname} fi ## Workshop commands. -if [ "${shortname}" == "arma3" ] || [ "${shortname}" == "dayz" ] || [ "${shortname}" == "sb" ] || [ "${shortname}" == "squad" ]; then +if [ "${shortname}" == "arma3" ] || [ "${shortname}" == "dayz" ] || [ "${shortname}" == "ohd" ] || [ "${shortname}" == "sb" ] || [ "${shortname}" == "squad" ] || [ "${shortname}" == "squad44" ]; then currentopt+=("${cmd_workshop_update[@]}") fi diff --git a/lgsm/modules/workshop_core.sh b/lgsm/modules/workshop_core.sh index 34f7691d3c..f3d6ddff7a 100755 --- a/lgsm/modules/workshop_core.sh +++ b/lgsm/modules/workshop_core.sh @@ -8,9 +8,13 @@ moduleselfname="$(basename "$(readlink -f "${BASH_SOURCE[0]}")")" # Installed mods are named ${workshopprefix} in the directory the game loads them from. -if [ "${shortname}" == "squad" ]; then +if [ "${shortname}" == "squad" ] || [ "${shortname}" == "squad44" ]; then workshopdir="${systemdir}/Plugins/Mods" workshopprefix="" +elif [ "${shortname}" == "ohd" ]; then + workshopdir="${systemdir}/Mods" + workshopprefix="" + workshopflatten=1 else workshopdir="${serverfiles}/workshop" workshopprefix="@" @@ -159,11 +163,27 @@ fn_workshop_get_details() { workshopitems=("${validitems[@]}") } +# Prints the directory a Workshop item is installed in, if it is installed. +fn_workshop_moddir() { + local statefile + if [ -f "${workshopdir}/${workshopprefix}${1}/.lgsm-workshop" ]; then + echo "${workshopdir}/${workshopprefix}${1}" + return + fi + for statefile in "${workshopdir}"/*/.lgsm-workshop; do + if [ -f "${statefile}" ] && grep -qx "id=${1}" "${statefile}"; then + echo "${statefile%/.lgsm-workshop}" + return + fi + done +} + # Reads a value from an installed mod's state file. Usage: fn_workshop_state fn_workshop_state() { - local statefile="${workshopdir}/${workshopprefix}${1}/.lgsm-workshop" - if [ -f "${statefile}" ]; then - sed -n "s/^${2}=//p" "${statefile}" + local moddir + moddir="$(fn_workshop_moddir "${1}")" + if [ -n "${moddir}" ]; then + sed -n "s/^${2}=//p" "${moddir}/.lgsm-workshop" fi } @@ -189,9 +209,12 @@ fn_workshop_compare() { local statefile moddir for statefile in "${workshopdir}"/*/.lgsm-workshop; do if [ -f "${statefile}" ]; then - moddir="${statefile%/*}" - moddir="${moddir##*/}" - item="${moddir#"${workshopprefix}"}" + item="$(sed -n 's/^id=//p' "${statefile}")" + if [ -z "${item}" ]; then + moddir="${statefile%/*}" + moddir="${moddir##*/}" + item="${moddir#"${workshopprefix}"}" + fi if [[ "${inuse}" != *" ${item} "* ]]; then workshopremovals+=("${item}") fi @@ -272,11 +295,12 @@ fn_workshop_lowercase() { # Removes the BattlEye keys a mod installed, unless another installed mod also uses them. fn_workshop_remove_keys() { local item="$1" - local key statefile + local key statefile moddir + moddir="$(fn_workshop_moddir "${item}")" for key in $(fn_workshop_state "${item}" keys); do local shared="" for statefile in "${workshopdir}"/*/.lgsm-workshop; do - if [ "${statefile}" != "${workshopdir}/${workshopprefix}${item}/.lgsm-workshop" ] && [[ " $(sed -n 's/^keys=//p' "${statefile}" 2> /dev/null) " == *" ${key} "* ]]; then + if [ "${statefile}" != "${moddir}/.lgsm-workshop" ] && [[ " $(sed -n 's/^keys=//p' "${statefile}" 2> /dev/null) " == *" ${key} "* ]]; then shared=1 fi done @@ -299,14 +323,30 @@ fn_workshop_install() { local item="$1" local src="${workshopdldir}/steamapps/workshop/content/${workshopappid[${item}]}/${item}" local dst="${workshopdir}/${workshopprefix}${item}" + local installed local keys=() local links=() local key pak fn_print_dots "Installing ${workshoptitle[${item}]} (${item})" - if [ -d "${dst}" ]; then + installed="$(fn_workshop_moddir "${item}")" + if [ -n "${installed}" ]; then fn_workshop_remove_keys "${item}" fn_workshop_remove_links "${item}" - rm -rf "${dst:?}" + rm -rf "${installed:?}" + fi + # A mod that is a single plugin folder is installed as that folder, for games that load mods by folder name. + if [ -n "${workshopflatten}" ]; then + local subdirs=() + mapfile -t subdirs < <(find "${src}" -mindepth 1 -maxdepth 1 -type d) + if [ "${#subdirs[@]}" -eq 1 ] && [ -z "$(find "${src}" -mindepth 1 -maxdepth 1 -type f -print -quit)" ]; then + dst="${workshopdir}/${subdirs[0]##*/}" + src="${subdirs[0]}" + fi + fi + if [ -e "${dst}" ]; then + fn_print_fail_nl "Installing ${workshoptitle[${item}]} (${item}): ${dst} already exists" + fn_script_log_fail "Installing ${workshoptitle[${item}]} (${item}): ${dst} already exists" + return fi mkdir -p "${workshopdir}" if ! mv "${src}" "${dst}"; then @@ -329,6 +369,7 @@ fn_workshop_install() { done < <(find "${dst}" -maxdepth 1 -type f -name '*.pak' -print0) fi { + echo "id=${item}" echo "title=${workshoptitle[${item}]}" echo "timeupdated=${workshoptimeupdated[${item}]}" echo "keys=${keys[*]}" @@ -341,12 +382,15 @@ fn_workshop_install() { # Removes an installed mod that is no longer in workshopmods. fn_workshop_remove() { local item="$1" - local title + local title moddir title="$(fn_workshop_state "${item}" title)" + moddir="$(fn_workshop_moddir "${item}")" fn_print_dots "Removing ${title} (${item})" fn_workshop_remove_keys "${item}" fn_workshop_remove_links "${item}" - rm -rf "${workshopdir:?}/${workshopprefix}${item}" + if [ -n "${moddir}" ]; then + rm -rf "${moddir:?}" + fi fn_print_ok_nl "Removing ${title} (${item})" fn_script_log_pass "Removing ${title} (${item})" } @@ -403,7 +447,7 @@ fn_workshop_update() { fn_print "\n" fn_print_nl "${bold}${underline}Update${default} available" for item in "${workshopupdates[@]}"; do - if [ -d "${workshopdir}/${workshopprefix}${item}" ]; then + if [ -n "$(fn_workshop_moddir "${item}")" ]; then fn_print_nl "* Update: ${workshoptitle[${item}]} (${item})" else fn_print_nl "* Install: ${workshoptitle[${item}]} (${item})" From f6eb8cd47ff4be0e293c5249342de0e020606c6c Mon Sep 17 00:00:00 2001 From: Daniel Gibbs Date: Sun, 11 Oct 2026 12:50:23 +0100 Subject: [PATCH 045/164] feat(workshop): add Steam Workshop downloads for Barotrauma and Stationeers (#5014) * feat(workshop): add Steam Workshop downloads for Barotrauma and Stationeers * fix(workshop): restore an empty Barotrauma regularpackages element to its original form --- .../config-lgsm/btserver/_default.cfg | 6 +++ .../config-lgsm/stserver/_default.cfg | 6 +++ lgsm/modules/command_check_update.sh | 2 +- lgsm/modules/command_update.sh | 2 +- lgsm/modules/core_getopt.sh | 2 +- lgsm/modules/workshop_core.sh | 42 +++++++++++++++++++ 6 files changed, 57 insertions(+), 3 deletions(-) diff --git a/lgsm/config-default/config-lgsm/btserver/_default.cfg b/lgsm/config-default/config-lgsm/btserver/_default.cfg index 0134772b3a..a950676e71 100644 --- a/lgsm/config-default/config-lgsm/btserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/btserver/_default.cfg @@ -11,6 +11,12 @@ ## Server Parameters | https://docs.linuxgsm.com/configuration/start-parameters#additional-parameters startparameters="" +## Steam Workshop Mods | https://docs.linuxgsm.com/steamcmd/workshop +# Workshop item or collection IDs, separated by spaces. Collections are expanded. +# Installed to LocalMods and enabled in config_player.xml. Run ./btserver workshop-update after changing, or let update apply it. +# workshopmods="3815618949" +workshopmods="" + #### LinuxGSM Settings #### ## LinuxGSM Stats diff --git a/lgsm/config-default/config-lgsm/stserver/_default.cfg b/lgsm/config-default/config-lgsm/stserver/_default.cfg index c724f2c194..a14fc812a6 100644 --- a/lgsm/config-default/config-lgsm/stserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/stserver/_default.cfg @@ -15,6 +15,12 @@ worldtype="Moon" ## Server Parameters | https://docs.linuxgsm.com/configuration/start-parameters#additional-parameters startparameters="-LOAD ${worldsave} ${worldtype}" +## Steam Workshop Mods | https://docs.linuxgsm.com/steamcmd/workshop +# Workshop item or collection IDs, separated by spaces. Collections are expanded. +# Installed to mods, where the server enables them. Run ./stserver workshop-update after changing, or let update apply it. +# workshopmods="3813753764" +workshopmods="" + #### LinuxGSM Settings #### ## LinuxGSM Stats diff --git a/lgsm/modules/command_check_update.sh b/lgsm/modules/command_check_update.sh index a9184e2d90..58ef67962e 100755 --- a/lgsm/modules/command_check_update.sh +++ b/lgsm/modules/command_check_update.sh @@ -44,7 +44,7 @@ else update_steamcmd.sh fi -if { [ "${shortname}" == "arma3" ] || [ "${shortname}" == "dayz" ] || [ "${shortname}" == "ohd" ] || [ "${shortname}" == "sb" ] || [ "${shortname}" == "squad" ] || [ "${shortname}" == "squad44" ]; } && { [ -n "${workshopmods}" ] || [ -f "${datadir}/${selfname}-workshop.txt" ]; }; then +if { [ "${shortname}" == "arma3" ] || [ "${shortname}" == "dayz" ] || [ "${shortname}" == "bt" ] || [ "${shortname}" == "ohd" ] || [ "${shortname}" == "sb" ] || [ "${shortname}" == "squad" ] || [ "${shortname}" == "squad44" ] || [ "${shortname}" == "st" ]; } && { [ -n "${workshopmods}" ] || [ -f "${datadir}/${selfname}-workshop.txt" ]; }; then workshop_core.sh fn_workshop_update fi diff --git a/lgsm/modules/command_update.sh b/lgsm/modules/command_update.sh index 39cf392d86..b1780c7b2e 100755 --- a/lgsm/modules/command_update.sh +++ b/lgsm/modules/command_update.sh @@ -45,7 +45,7 @@ else update_steamcmd.sh fi -if { [ "${shortname}" == "arma3" ] || [ "${shortname}" == "dayz" ] || [ "${shortname}" == "ohd" ] || [ "${shortname}" == "sb" ] || [ "${shortname}" == "squad" ] || [ "${shortname}" == "squad44" ]; } && { [ -n "${workshopmods}" ] || [ -f "${datadir}/${selfname}-workshop.txt" ]; }; then +if { [ "${shortname}" == "arma3" ] || [ "${shortname}" == "dayz" ] || [ "${shortname}" == "bt" ] || [ "${shortname}" == "ohd" ] || [ "${shortname}" == "sb" ] || [ "${shortname}" == "squad" ] || [ "${shortname}" == "squad44" ] || [ "${shortname}" == "st" ]; } && { [ -n "${workshopmods}" ] || [ -f "${datadir}/${selfname}-workshop.txt" ]; }; then workshop_core.sh fn_workshop_update fi diff --git a/lgsm/modules/core_getopt.sh b/lgsm/modules/core_getopt.sh index adfc5ac6bb..51b85d4567 100755 --- a/lgsm/modules/core_getopt.sh +++ b/lgsm/modules/core_getopt.sh @@ -144,7 +144,7 @@ if [ "${engine}" == "source" ] || [ "${shortname}" == "cs2" ] || [ "${shortname} fi ## Workshop commands. -if [ "${shortname}" == "arma3" ] || [ "${shortname}" == "dayz" ] || [ "${shortname}" == "ohd" ] || [ "${shortname}" == "sb" ] || [ "${shortname}" == "squad" ] || [ "${shortname}" == "squad44" ]; then +if [ "${shortname}" == "arma3" ] || [ "${shortname}" == "dayz" ] || [ "${shortname}" == "bt" ] || [ "${shortname}" == "ohd" ] || [ "${shortname}" == "sb" ] || [ "${shortname}" == "squad" ] || [ "${shortname}" == "squad44" ] || [ "${shortname}" == "st" ]; then currentopt+=("${cmd_workshop_update[@]}") fi diff --git a/lgsm/modules/workshop_core.sh b/lgsm/modules/workshop_core.sh index f3d6ddff7a..65f32a7f25 100755 --- a/lgsm/modules/workshop_core.sh +++ b/lgsm/modules/workshop_core.sh @@ -15,6 +15,12 @@ elif [ "${shortname}" == "ohd" ]; then workshopdir="${systemdir}/Mods" workshopprefix="" workshopflatten=1 +elif [ "${shortname}" == "bt" ]; then + workshopdir="${serverfiles}/LocalMods" + workshopprefix="" +elif [ "${shortname}" == "st" ]; then + workshopdir="${serverfiles}/mods" + workshopprefix="" else workshopdir="${serverfiles}/workshop" workshopprefix="@" @@ -395,6 +401,39 @@ fn_workshop_remove() { fn_script_log_pass "Removing ${title} (${item})" } +# Barotrauma only loads mods listed in config_player.xml. Replaces LinuxGSM's entries with the installed mods, in order. +fn_workshop_bt_packages() { + local config="${serverfiles}/config_player.xml" + local item managed=() enabled=() + if [ ! -f "${config}" ]; then + fn_print_warn_nl "${config} not found. Start the server once, then run ./${selfname} workshop-update to enable Workshop mods" + fn_script_log_warn "${config} not found, Workshop mods not enabled" + return + fi + managed=("${workshopremovals[@]}" "${workshopitems[@]}") + for item in "${workshopitems[@]}"; do + if [ -f "${workshopdir}/${item}/filelist.xml" ]; then + enabled+=("${item}") + fi + done + python3 - "${config}" "${managed[*]}" "${enabled[*]}" << 'PYEOF' +import re +import sys + +config, managed, enabled = sys.argv[1], sys.argv[2].split(), sys.argv[3].split() +with open(config, encoding="utf-8-sig", newline="") as f: + text = f.read() +text = text.replace("", "\n ") +for item in managed: + text = re.sub(r'\s*]*?path="LocalMods/' + re.escape(item) + r'/filelist\.xml"[^>]*/>', "", text) +entries = "".join('\n ' for item in enabled) +text = re.sub(r"(\s*)", entries + r"\1", text, count=1) +text = re.sub(r"\s*", "", text) +with open(config, "w", encoding="utf-8", newline="") as f: + f.write(text) +PYEOF +} + # Installs downloaded items and removes unused ones. Downloads happen first, so the server only stops for this step. fn_workshop_apply() { local item @@ -404,6 +443,9 @@ fn_workshop_apply() { for item in "${workshopremovals[@]}"; do fn_workshop_remove "${item}" done + if [ "${shortname}" == "bt" ]; then + fn_workshop_bt_packages + fi rm -rf "${workshopdldir:?}" } From f3026d3143b7c7ccf48c8c87a6d4d3cff6bb0698 Mon Sep 17 00:00:00 2001 From: Daniel Gibbs Date: Sun, 11 Oct 2026 13:35:12 +0100 Subject: [PATCH 046/164] refactor(workshop): edit Barotrauma config_player.xml with sed instead of Python (#5017) --- lgsm/modules/workshop_core.sh | 27 ++++++++------------------- 1 file changed, 8 insertions(+), 19 deletions(-) diff --git a/lgsm/modules/workshop_core.sh b/lgsm/modules/workshop_core.sh index 65f32a7f25..df12841f7e 100755 --- a/lgsm/modules/workshop_core.sh +++ b/lgsm/modules/workshop_core.sh @@ -404,34 +404,23 @@ fn_workshop_remove() { # Barotrauma only loads mods listed in config_player.xml. Replaces LinuxGSM's entries with the installed mods, in order. fn_workshop_bt_packages() { local config="${serverfiles}/config_player.xml" - local item managed=() enabled=() + local item entries="" if [ ! -f "${config}" ]; then fn_print_warn_nl "${config} not found. Start the server once, then run ./${selfname} workshop-update to enable Workshop mods" fn_script_log_warn "${config} not found, Workshop mods not enabled" return fi - managed=("${workshopremovals[@]}" "${workshopitems[@]}") + sed -z -i 's##\n #' "${config}" + for item in "${workshopremovals[@]}" "${workshopitems[@]}"; do + sed -z -i -E "s#[[:space:]]*##g" "${config}" + done for item in "${workshopitems[@]}"; do if [ -f "${workshopdir}/${item}/filelist.xml" ]; then - enabled+=("${item}") + entries+="\\n " fi done - python3 - "${config}" "${managed[*]}" "${enabled[*]}" << 'PYEOF' -import re -import sys - -config, managed, enabled = sys.argv[1], sys.argv[2].split(), sys.argv[3].split() -with open(config, encoding="utf-8-sig", newline="") as f: - text = f.read() -text = text.replace("", "\n ") -for item in managed: - text = re.sub(r'\s*]*?path="LocalMods/' + re.escape(item) + r'/filelist\.xml"[^>]*/>', "", text) -entries = "".join('\n ' for item in enabled) -text = re.sub(r"(\s*)", entries + r"\1", text, count=1) -text = re.sub(r"\s*", "", text) -with open(config, "w", encoding="utf-8", newline="") as f: - f.write(text) -PYEOF + sed -z -i -E "s#([[:space:]]*)#${entries}\\1#" "${config}" + sed -z -i -E 's#[[:space:]]*##' "${config}" } # Installs downloaded items and removes unused ones. Downloads happen first, so the server only stops for this step. From ed1162ed04b8eff187339e5f77721ccf4048f2c8 Mon Sep 17 00:00:00 2001 From: Daniel Gibbs Date: Sun, 11 Oct 2026 13:38:32 +0100 Subject: [PATCH 047/164] feat(workshop): add Steam Workshop downloads for Colony Survival (#5016) * feat(workshop): add Steam Workshop downloads for Colony Survival * refactor(workshop): edit Colony Survival worldconfig.json with jq instead of Python --- .../config-lgsm/colserver/_default.cfg | 12 +++++ lgsm/modules/command_check_update.sh | 2 +- lgsm/modules/command_update.sh | 2 +- lgsm/modules/core_getopt.sh | 2 +- lgsm/modules/workshop_core.sh | 47 +++++++++++++++++++ 5 files changed, 62 insertions(+), 3 deletions(-) diff --git a/lgsm/config-default/config-lgsm/colserver/_default.cfg b/lgsm/config-default/config-lgsm/colserver/_default.cfg index 3c7329f33f..45287684ad 100644 --- a/lgsm/config-default/config-lgsm/colserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/colserver/_default.cfg @@ -8,10 +8,22 @@ #### Game Server Settings #### +## SteamCMD Login | https://docs.linuxgsm.com/steamcmd#steamcmd-login +# Only needed for Workshop mods. The account must own Colony Survival. +steamuser="" +steampass='' + ## Server Parameters | https://docs.linuxgsm.com/configuration/start-parameters#additional-parameters ## https://colonysurvival.gamepedia.com/Dedicated_Server#Installation_.28Linux.29 startparameters="-batchmode -nographics +server.config ${servercfgfullpath}" +## Steam Workshop Mods | https://docs.linuxgsm.com/steamcmd/workshop +# Workshop item or collection IDs, separated by spaces. Collections are expanded. +# Needs steamuser to own Colony Survival. Installed to gamedata/mods and enabled in each world's worldconfig.json. +# Run ./colserver workshop-update after changing, or let update apply it. +# workshopmods="3816302400" +workshopmods="" + #### LinuxGSM Settings #### ## LinuxGSM Stats diff --git a/lgsm/modules/command_check_update.sh b/lgsm/modules/command_check_update.sh index 58ef67962e..780dafae93 100755 --- a/lgsm/modules/command_check_update.sh +++ b/lgsm/modules/command_check_update.sh @@ -44,7 +44,7 @@ else update_steamcmd.sh fi -if { [ "${shortname}" == "arma3" ] || [ "${shortname}" == "dayz" ] || [ "${shortname}" == "bt" ] || [ "${shortname}" == "ohd" ] || [ "${shortname}" == "sb" ] || [ "${shortname}" == "squad" ] || [ "${shortname}" == "squad44" ] || [ "${shortname}" == "st" ]; } && { [ -n "${workshopmods}" ] || [ -f "${datadir}/${selfname}-workshop.txt" ]; }; then +if { [ "${shortname}" == "arma3" ] || [ "${shortname}" == "dayz" ] || [ "${shortname}" == "bt" ] || [ "${shortname}" == "col" ] || [ "${shortname}" == "ohd" ] || [ "${shortname}" == "sb" ] || [ "${shortname}" == "squad" ] || [ "${shortname}" == "squad44" ] || [ "${shortname}" == "st" ]; } && { [ -n "${workshopmods}" ] || [ -f "${datadir}/${selfname}-workshop.txt" ]; }; then workshop_core.sh fn_workshop_update fi diff --git a/lgsm/modules/command_update.sh b/lgsm/modules/command_update.sh index b1780c7b2e..9a7336b57f 100755 --- a/lgsm/modules/command_update.sh +++ b/lgsm/modules/command_update.sh @@ -45,7 +45,7 @@ else update_steamcmd.sh fi -if { [ "${shortname}" == "arma3" ] || [ "${shortname}" == "dayz" ] || [ "${shortname}" == "bt" ] || [ "${shortname}" == "ohd" ] || [ "${shortname}" == "sb" ] || [ "${shortname}" == "squad" ] || [ "${shortname}" == "squad44" ] || [ "${shortname}" == "st" ]; } && { [ -n "${workshopmods}" ] || [ -f "${datadir}/${selfname}-workshop.txt" ]; }; then +if { [ "${shortname}" == "arma3" ] || [ "${shortname}" == "dayz" ] || [ "${shortname}" == "bt" ] || [ "${shortname}" == "col" ] || [ "${shortname}" == "ohd" ] || [ "${shortname}" == "sb" ] || [ "${shortname}" == "squad" ] || [ "${shortname}" == "squad44" ] || [ "${shortname}" == "st" ]; } && { [ -n "${workshopmods}" ] || [ -f "${datadir}/${selfname}-workshop.txt" ]; }; then workshop_core.sh fn_workshop_update fi diff --git a/lgsm/modules/core_getopt.sh b/lgsm/modules/core_getopt.sh index 51b85d4567..e9d693a592 100755 --- a/lgsm/modules/core_getopt.sh +++ b/lgsm/modules/core_getopt.sh @@ -144,7 +144,7 @@ if [ "${engine}" == "source" ] || [ "${shortname}" == "cs2" ] || [ "${shortname} fi ## Workshop commands. -if [ "${shortname}" == "arma3" ] || [ "${shortname}" == "dayz" ] || [ "${shortname}" == "bt" ] || [ "${shortname}" == "ohd" ] || [ "${shortname}" == "sb" ] || [ "${shortname}" == "squad" ] || [ "${shortname}" == "squad44" ] || [ "${shortname}" == "st" ]; then +if [ "${shortname}" == "arma3" ] || [ "${shortname}" == "dayz" ] || [ "${shortname}" == "bt" ] || [ "${shortname}" == "col" ] || [ "${shortname}" == "ohd" ] || [ "${shortname}" == "sb" ] || [ "${shortname}" == "squad" ] || [ "${shortname}" == "squad44" ] || [ "${shortname}" == "st" ]; then currentopt+=("${cmd_workshop_update[@]}") fi diff --git a/lgsm/modules/workshop_core.sh b/lgsm/modules/workshop_core.sh index df12841f7e..f137ea6d19 100755 --- a/lgsm/modules/workshop_core.sh +++ b/lgsm/modules/workshop_core.sh @@ -18,6 +18,9 @@ elif [ "${shortname}" == "ohd" ]; then elif [ "${shortname}" == "bt" ]; then workshopdir="${serverfiles}/LocalMods" workshopprefix="" +elif [ "${shortname}" == "col" ]; then + workshopdir="${serverfiles}/gamedata/mods" + workshopprefix="" elif [ "${shortname}" == "st" ]; then workshopdir="${serverfiles}/mods" workshopprefix="" @@ -374,8 +377,13 @@ fn_workshop_install() { links+=("workshop-${item}-${pak##*/}") done < <(find "${dst}" -maxdepth 1 -type f -name '*.pak' -print0) fi + local modname="" + if [ "${shortname}" == "col" ] && [ -f "${dst}/modInfo.json" ]; then + modname="$(jq -r 'if type == "array" then .[0].name else .name end // empty' "${dst}/modInfo.json" 2> /dev/null)" + fi { echo "id=${item}" + echo "modname=${modname}" echo "title=${workshoptitle[${item}]}" echo "timeupdated=${workshoptimeupdated[${item}]}" echo "keys=${keys[*]}" @@ -391,6 +399,7 @@ fn_workshop_remove() { local title moddir title="$(fn_workshop_state "${item}" title)" moddir="$(fn_workshop_moddir "${item}")" + workshopremovednames+=("$(fn_workshop_state "${item}" modname)") fn_print_dots "Removing ${title} (${item})" fn_workshop_remove_keys "${item}" fn_workshop_remove_links "${item}" @@ -423,9 +432,45 @@ fn_workshop_bt_packages() { sed -z -i -E 's#[[:space:]]*##' "${config}" } +# Colony Survival only loads mods enabled in each world's worldconfig.json. Replaces LinuxGSM's entries with the installed mods, in order. +fn_workshop_col_worlds() { + local item name worldconfig managedjson enabledjson + local managed=("${workshopremovednames[@]}") + local enabled=() + for item in "${workshopitems[@]}"; do + name="$(fn_workshop_state "${item}" modname)" + if [ -n "${name}" ]; then + managed+=("${name}") + enabled+=("${name}") + fi + done + managedjson="$(jq -cn '$ARGS.positional' --args "${managed[@]}")" + enabledjson="$(jq -cn '$ARGS.positional' --args "${enabled[@]}")" + for worldconfig in "${serverfiles}"/gamedata/savegames/*/worldconfig.json; do + if [ ! -f "${worldconfig}" ]; then + fn_print_warn_nl "No Colony Survival world found. Start the server once, then run ./${selfname} workshop-update to enable Workshop mods" + fn_script_log_warn "No Colony Survival world found, Workshop mods not enabled" + return + fi + if jq -c --argjson managed "${managedjson}" --argjson enabled "${enabledjson}" ' + (.ModConfigEntries // []) as $old + | ($old | map({key: .ModName, value: .}) | from_entries) as $existing + | .ModConfigEntries = [$old[] | select(.ModName as $n | any($managed[]; . == $n) | not)] + + [$enabled[] | . as $n | ($existing[$n] // {ModName: $n, ModVersionLastKnown: "---"}) | .Enabled = true] + ' "${worldconfig}" > "${worldconfig}.tmp" 2> /dev/null; then + mv "${worldconfig}.tmp" "${worldconfig}" + else + rm -f "${worldconfig}.tmp" + fn_print_warn_nl "Unable to update ${worldconfig}" + fn_script_log_warn "Unable to update ${worldconfig}" + fi + done +} + # Installs downloaded items and removes unused ones. Downloads happen first, so the server only stops for this step. fn_workshop_apply() { local item + workshopremovednames=() for item in "${workshopinstalls[@]}"; do fn_workshop_install "${item}" done @@ -434,6 +479,8 @@ fn_workshop_apply() { done if [ "${shortname}" == "bt" ]; then fn_workshop_bt_packages + elif [ "${shortname}" == "col" ]; then + fn_workshop_col_worlds fi rm -rf "${workshopdldir:?}" } From 65de3b40d88331ba90c031ec0c021626d8ff397d Mon Sep 17 00:00:00 2001 From: Daniel Gibbs Date: Sun, 11 Oct 2026 14:11:50 +0100 Subject: [PATCH 048/164] feat(workshop): add Steam Workshop downloads for Left 4 Dead 2 (#5018) --- .../config-lgsm/l4d2server/_default.cfg | 6 +++++ lgsm/modules/command_check_update.sh | 2 +- lgsm/modules/command_update.sh | 2 +- lgsm/modules/core_getopt.sh | 2 +- lgsm/modules/workshop_core.sh | 22 +++++++++++++++---- 5 files changed, 27 insertions(+), 7 deletions(-) diff --git a/lgsm/config-default/config-lgsm/l4d2server/_default.cfg b/lgsm/config-default/config-lgsm/l4d2server/_default.cfg index 3e15847063..eea3b160b2 100644 --- a/lgsm/config-default/config-lgsm/l4d2server/_default.cfg +++ b/lgsm/config-default/config-lgsm/l4d2server/_default.cfg @@ -18,6 +18,12 @@ maxplayers="8" ## Server Parameters | https://docs.linuxgsm.com/configuration/start-parameters#additional-parameters startparameters="-game left4dead2 -strictportbind -ip ${ip} -port ${port} +clientport ${clientport} +map ${defaultmap} +servercfgfile ${servercfg} -maxplayers ${maxplayers}" +## Steam Workshop Mods | https://docs.linuxgsm.com/steamcmd/workshop +# Workshop item or collection IDs, separated by spaces. Collections are expanded. +# Installed to serverfiles/workshop and linked into left4dead2/addons. Run ./l4d2server workshop-update after changing, or let update apply it. +# workshopmods="3815658696" +workshopmods="" + #### LinuxGSM Settings #### ## LinuxGSM Stats diff --git a/lgsm/modules/command_check_update.sh b/lgsm/modules/command_check_update.sh index 780dafae93..04b919385e 100755 --- a/lgsm/modules/command_check_update.sh +++ b/lgsm/modules/command_check_update.sh @@ -44,7 +44,7 @@ else update_steamcmd.sh fi -if { [ "${shortname}" == "arma3" ] || [ "${shortname}" == "dayz" ] || [ "${shortname}" == "bt" ] || [ "${shortname}" == "col" ] || [ "${shortname}" == "ohd" ] || [ "${shortname}" == "sb" ] || [ "${shortname}" == "squad" ] || [ "${shortname}" == "squad44" ] || [ "${shortname}" == "st" ]; } && { [ -n "${workshopmods}" ] || [ -f "${datadir}/${selfname}-workshop.txt" ]; }; then +if { [ "${shortname}" == "arma3" ] || [ "${shortname}" == "dayz" ] || [ "${shortname}" == "bt" ] || [ "${shortname}" == "col" ] || [ "${shortname}" == "l4d2" ] || [ "${shortname}" == "ohd" ] || [ "${shortname}" == "sb" ] || [ "${shortname}" == "squad" ] || [ "${shortname}" == "squad44" ] || [ "${shortname}" == "st" ]; } && { [ -n "${workshopmods}" ] || [ -f "${datadir}/${selfname}-workshop.txt" ]; }; then workshop_core.sh fn_workshop_update fi diff --git a/lgsm/modules/command_update.sh b/lgsm/modules/command_update.sh index 9a7336b57f..00588d7662 100755 --- a/lgsm/modules/command_update.sh +++ b/lgsm/modules/command_update.sh @@ -45,7 +45,7 @@ else update_steamcmd.sh fi -if { [ "${shortname}" == "arma3" ] || [ "${shortname}" == "dayz" ] || [ "${shortname}" == "bt" ] || [ "${shortname}" == "col" ] || [ "${shortname}" == "ohd" ] || [ "${shortname}" == "sb" ] || [ "${shortname}" == "squad" ] || [ "${shortname}" == "squad44" ] || [ "${shortname}" == "st" ]; } && { [ -n "${workshopmods}" ] || [ -f "${datadir}/${selfname}-workshop.txt" ]; }; then +if { [ "${shortname}" == "arma3" ] || [ "${shortname}" == "dayz" ] || [ "${shortname}" == "bt" ] || [ "${shortname}" == "col" ] || [ "${shortname}" == "l4d2" ] || [ "${shortname}" == "ohd" ] || [ "${shortname}" == "sb" ] || [ "${shortname}" == "squad" ] || [ "${shortname}" == "squad44" ] || [ "${shortname}" == "st" ]; } && { [ -n "${workshopmods}" ] || [ -f "${datadir}/${selfname}-workshop.txt" ]; }; then workshop_core.sh fn_workshop_update fi diff --git a/lgsm/modules/core_getopt.sh b/lgsm/modules/core_getopt.sh index e9d693a592..093e5afe9b 100755 --- a/lgsm/modules/core_getopt.sh +++ b/lgsm/modules/core_getopt.sh @@ -144,7 +144,7 @@ if [ "${engine}" == "source" ] || [ "${shortname}" == "cs2" ] || [ "${shortname} fi ## Workshop commands. -if [ "${shortname}" == "arma3" ] || [ "${shortname}" == "dayz" ] || [ "${shortname}" == "bt" ] || [ "${shortname}" == "col" ] || [ "${shortname}" == "ohd" ] || [ "${shortname}" == "sb" ] || [ "${shortname}" == "squad" ] || [ "${shortname}" == "squad44" ] || [ "${shortname}" == "st" ]; then +if [ "${shortname}" == "arma3" ] || [ "${shortname}" == "dayz" ] || [ "${shortname}" == "bt" ] || [ "${shortname}" == "col" ] || [ "${shortname}" == "l4d2" ] || [ "${shortname}" == "ohd" ] || [ "${shortname}" == "sb" ] || [ "${shortname}" == "squad" ] || [ "${shortname}" == "squad44" ] || [ "${shortname}" == "st" ]; then currentopt+=("${cmd_workshop_update[@]}") fi diff --git a/lgsm/modules/workshop_core.sh b/lgsm/modules/workshop_core.sh index f137ea6d19..67835d9bf7 100755 --- a/lgsm/modules/workshop_core.sh +++ b/lgsm/modules/workshop_core.sh @@ -28,6 +28,12 @@ else workshopdir="${serverfiles}/workshop" workshopprefix="@" fi +# Games that load mod files from their own directory get links to the installed files there. +if [ "${shortname}" == "sb" ]; then + workshoplinkdir="${serverfiles}/mods" +elif [ "${shortname}" == "l4d2" ]; then + workshoplinkdir="${serverfiles}/left4dead2/addons" +fi workshopdldir="${tmpdir}/workshop" workshopmodlist="${datadir}/${selfname}-workshop.txt" workshopapi="https://api.steampowered.com/ISteamRemoteStorage" @@ -319,11 +325,11 @@ fn_workshop_remove_keys() { done } -# Removes the links a mod added to the Starbound mods directory. +# Removes the links a mod added to the game's mod directory. fn_workshop_remove_links() { local link for link in $(fn_workshop_state "$1" links); do - rm -f "${serverfiles:?}/mods/${link}" + rm -f "${workshoplinkdir:?}/${link}" done } @@ -371,11 +377,19 @@ fn_workshop_install() { keys+=("${key##*/}") done < <(find "${dst}" -type f -name '*.bikey' -print0) elif [ "${shortname}" == "sb" ]; then - mkdir -p "${serverfiles}/mods" + mkdir -p "${workshoplinkdir}" while IFS= read -r -d '' pak; do - ln -sfn "../workshop/${workshopprefix}${item}/${pak##*/}" "${serverfiles}/mods/workshop-${item}-${pak##*/}" + ln -srfn "${pak}" "${workshoplinkdir}/workshop-${item}-${pak##*/}" links+=("workshop-${item}-${pak##*/}") done < <(find "${dst}" -maxdepth 1 -type f -name '*.pak' -print0) + elif [ "${shortname}" == "l4d2" ]; then + # Legacy Workshop items download as _legacy.bin, which is the addon's .vpk. + pak="$(find "${dst}" -maxdepth 1 -type f \( -name '*.vpk' -o -name '*_legacy.bin' \) -print -quit)" + if [ -n "${pak}" ]; then + mkdir -p "${workshoplinkdir}" + ln -srfn "${pak}" "${workshoplinkdir}/${item}.vpk" + links+=("${item}.vpk") + fi fi local modname="" if [ "${shortname}" == "col" ] && [ -f "${dst}/modInfo.json" ]; then From c0a5ced6adbc4b5153fbb4a95472c1e0219df0f9 Mon Sep 17 00:00:00 2001 From: Daniel Gibbs Date: Sun, 11 Oct 2026 16:52:45 +0100 Subject: [PATCH 049/164] feat(workshop): add Steam Workshop downloads for Hurtworld (#5019) --- .../config-lgsm/hwserver/_default.cfg | 9 +++- lgsm/modules/check.sh | 2 +- lgsm/modules/command_check_update.sh | 2 +- lgsm/modules/command_update.sh | 2 +- lgsm/modules/core_getopt.sh | 2 +- lgsm/modules/workshop_core.sh | 51 ++++++++++++------- 6 files changed, 45 insertions(+), 23 deletions(-) diff --git a/lgsm/config-default/config-lgsm/hwserver/_default.cfg b/lgsm/config-default/config-lgsm/hwserver/_default.cfg index c0c4f0eaa8..56d455910e 100644 --- a/lgsm/config-default/config-lgsm/hwserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/hwserver/_default.cfg @@ -27,7 +27,14 @@ loadsave="" ## Server Parameters | https://docs.linuxgsm.com/configuration/start-parameters#additional-parameters # http://hurtworld.wikia.com/wiki/Hosting_A_Server -startparameters="-batchmode -nographics -logfile ${gamelog} -exec \"host ${port} ${defaultmap} ${loadsave};queryport ${queryport};maxplayers ${maxplayers};servername ${servername};creativemode ${creativemode};addadmin ${admins}\"" +startparameters="-batchmode -nographics -logfile ${gamelog} -exec \"host ${port} ${defaultmap} ${loadsave};queryport ${queryport};maxplayers ${maxplayers};servername ${servername};creativemode ${creativemode}${workshoploadmods};addadmin ${admins}\"" + +## Steam Workshop Mods | https://docs.linuxgsm.com/steamcmd/workshop +# Workshop item or collection IDs, separated by spaces. Collections are expanded. +# Downloaded with SteamCMD and loaded with loadmod on start. If you set your own startparameters, keep ${workshoploadmods} in -exec. +# Run ./hwserver workshop-update after changing, or let update apply it. +# workshopmods="2015422570" +workshopmods="" #### LinuxGSM Settings #### diff --git a/lgsm/modules/check.sh b/lgsm/modules/check.sh index 71a5db7478..a892dd1a35 100755 --- a/lgsm/modules/check.sh +++ b/lgsm/modules/check.sh @@ -107,7 +107,7 @@ for allowed_command in "${allowed_commands_array[@]}"; do fi done -if [ "${shortname}" == "arma3" ] || [ "${shortname}" == "dayz" ]; then +if [ "${shortname}" == "arma3" ] || [ "${shortname}" == "dayz" ] || [ "${shortname}" == "hw" ]; then allowed_commands_array=(DEBUG DETAILS POST-DETAILS RESTART START) for allowed_command in "${allowed_commands_array[@]}"; do if [ "${allowed_command}" == "${commandname}" ] && { [ -n "${workshopmods}" ] || [ -f "${datadir}/${selfname}-workshop.txt" ]; }; then diff --git a/lgsm/modules/command_check_update.sh b/lgsm/modules/command_check_update.sh index 04b919385e..0a86405616 100755 --- a/lgsm/modules/command_check_update.sh +++ b/lgsm/modules/command_check_update.sh @@ -44,7 +44,7 @@ else update_steamcmd.sh fi -if { [ "${shortname}" == "arma3" ] || [ "${shortname}" == "dayz" ] || [ "${shortname}" == "bt" ] || [ "${shortname}" == "col" ] || [ "${shortname}" == "l4d2" ] || [ "${shortname}" == "ohd" ] || [ "${shortname}" == "sb" ] || [ "${shortname}" == "squad" ] || [ "${shortname}" == "squad44" ] || [ "${shortname}" == "st" ]; } && { [ -n "${workshopmods}" ] || [ -f "${datadir}/${selfname}-workshop.txt" ]; }; then +if { [ "${shortname}" == "arma3" ] || [ "${shortname}" == "dayz" ] || [ "${shortname}" == "bt" ] || [ "${shortname}" == "col" ] || [ "${shortname}" == "hw" ] || [ "${shortname}" == "l4d2" ] || [ "${shortname}" == "ohd" ] || [ "${shortname}" == "sb" ] || [ "${shortname}" == "squad" ] || [ "${shortname}" == "squad44" ] || [ "${shortname}" == "st" ]; } && { [ -n "${workshopmods}" ] || [ -f "${datadir}/${selfname}-workshop.txt" ]; }; then workshop_core.sh fn_workshop_update fi diff --git a/lgsm/modules/command_update.sh b/lgsm/modules/command_update.sh index 00588d7662..68d8c0f958 100755 --- a/lgsm/modules/command_update.sh +++ b/lgsm/modules/command_update.sh @@ -45,7 +45,7 @@ else update_steamcmd.sh fi -if { [ "${shortname}" == "arma3" ] || [ "${shortname}" == "dayz" ] || [ "${shortname}" == "bt" ] || [ "${shortname}" == "col" ] || [ "${shortname}" == "l4d2" ] || [ "${shortname}" == "ohd" ] || [ "${shortname}" == "sb" ] || [ "${shortname}" == "squad" ] || [ "${shortname}" == "squad44" ] || [ "${shortname}" == "st" ]; } && { [ -n "${workshopmods}" ] || [ -f "${datadir}/${selfname}-workshop.txt" ]; }; then +if { [ "${shortname}" == "arma3" ] || [ "${shortname}" == "dayz" ] || [ "${shortname}" == "bt" ] || [ "${shortname}" == "col" ] || [ "${shortname}" == "hw" ] || [ "${shortname}" == "l4d2" ] || [ "${shortname}" == "ohd" ] || [ "${shortname}" == "sb" ] || [ "${shortname}" == "squad" ] || [ "${shortname}" == "squad44" ] || [ "${shortname}" == "st" ]; } && { [ -n "${workshopmods}" ] || [ -f "${datadir}/${selfname}-workshop.txt" ]; }; then workshop_core.sh fn_workshop_update fi diff --git a/lgsm/modules/core_getopt.sh b/lgsm/modules/core_getopt.sh index 093e5afe9b..5623f2376f 100755 --- a/lgsm/modules/core_getopt.sh +++ b/lgsm/modules/core_getopt.sh @@ -144,7 +144,7 @@ if [ "${engine}" == "source" ] || [ "${shortname}" == "cs2" ] || [ "${shortname} fi ## Workshop commands. -if [ "${shortname}" == "arma3" ] || [ "${shortname}" == "dayz" ] || [ "${shortname}" == "bt" ] || [ "${shortname}" == "col" ] || [ "${shortname}" == "l4d2" ] || [ "${shortname}" == "ohd" ] || [ "${shortname}" == "sb" ] || [ "${shortname}" == "squad" ] || [ "${shortname}" == "squad44" ] || [ "${shortname}" == "st" ]; then +if [ "${shortname}" == "arma3" ] || [ "${shortname}" == "dayz" ] || [ "${shortname}" == "bt" ] || [ "${shortname}" == "col" ] || [ "${shortname}" == "hw" ] || [ "${shortname}" == "l4d2" ] || [ "${shortname}" == "ohd" ] || [ "${shortname}" == "sb" ] || [ "${shortname}" == "squad" ] || [ "${shortname}" == "squad44" ] || [ "${shortname}" == "st" ]; then currentopt+=("${cmd_workshop_update[@]}") fi diff --git a/lgsm/modules/workshop_core.sh b/lgsm/modules/workshop_core.sh index 67835d9bf7..569d256f10 100755 --- a/lgsm/modules/workshop_core.sh +++ b/lgsm/modules/workshop_core.sh @@ -18,6 +18,10 @@ elif [ "${shortname}" == "ohd" ]; then elif [ "${shortname}" == "bt" ]; then workshopdir="${serverfiles}/LocalMods" workshopprefix="" +elif [ "${shortname}" == "hw" ]; then + workshopdir="${serverfiles}/steamapps/workshop/content/393420" + workshopprefix="" + workshopinplace=1 elif [ "${shortname}" == "col" ]; then workshopdir="${serverfiles}/gamedata/mods" workshopprefix="" @@ -244,8 +248,13 @@ fn_workshop_download() { local attempt=0 local item params steamcmdlog="${lgsmlogdir}/${selfname}-steamcmd.log" - rm -rf "${workshopdldir:?}" - mkdir -p "${workshopdldir}" + if [ -n "${workshopinplace}" ]; then + workshopdlroot="${serverfiles}" + else + workshopdlroot="${workshopdldir}" + rm -rf "${workshopdldir:?}" + mkdir -p "${workshopdldir}" + fi if [ -d "${steamcmddir}" ]; then cd "${steamcmddir}" || exit fi @@ -255,7 +264,7 @@ fn_workshop_download() { fi while [ "${#pending[@]}" -gt 0 ] && [ "${attempt}" -lt "${workshopretries}" ]; do attempt=$((attempt + 1)) - params=(+force_install_dir "${workshopdldir}" +login "${steamuser}" "${steampass}") + params=(+force_install_dir "${workshopdlroot}" +login "${steamuser}" "${steampass}") for item in "${pending[@]}"; do params+=(+workshop_download_item "${workshopappid[${item}]}" "${item}") done @@ -272,7 +281,7 @@ fn_workshop_download() { local failed=() for item in "${pending[@]}"; do - if [ -z "$(find "${workshopdldir}/steamapps/workshop/content/${workshopappid[${item}]}/${item}" -mindepth 1 -print -quit 2> /dev/null)" ]; then + if [ -z "$(find "${workshopdlroot}/steamapps/workshop/content/${workshopappid[${item}]}/${item}" -mindepth 1 -print -quit 2> /dev/null)" ]; then failed+=("${item}") fi done @@ -336,7 +345,7 @@ fn_workshop_remove_links() { # Moves a downloaded item into the game's mod directory and prepares it for the game. fn_workshop_install() { local item="$1" - local src="${workshopdldir}/steamapps/workshop/content/${workshopappid[${item}]}/${item}" + local src="${workshopdlroot}/steamapps/workshop/content/${workshopappid[${item}]}/${item}" local dst="${workshopdir}/${workshopprefix}${item}" local installed local keys=() @@ -347,7 +356,9 @@ fn_workshop_install() { if [ -n "${installed}" ]; then fn_workshop_remove_keys "${item}" fn_workshop_remove_links "${item}" - rm -rf "${installed:?}" + if [ "${installed}" != "${src}" ]; then + rm -rf "${installed:?}" + fi fi # A mod that is a single plugin folder is installed as that folder, for games that load mods by folder name. if [ -n "${workshopflatten}" ]; then @@ -358,16 +369,18 @@ fn_workshop_install() { src="${subdirs[0]}" fi fi - if [ -e "${dst}" ]; then - fn_print_fail_nl "Installing ${workshoptitle[${item}]} (${item}): ${dst} already exists" - fn_script_log_fail "Installing ${workshoptitle[${item}]} (${item}): ${dst} already exists" - return - fi - mkdir -p "${workshopdir}" - if ! mv "${src}" "${dst}"; then - fn_print_fail_nl "Installing ${workshoptitle[${item}]} (${item})" - fn_script_log_fail "Installing ${workshoptitle[${item}]} (${item})" - core_exit.sh + if [ "${src}" != "${dst}" ]; then + if [ -e "${dst}" ]; then + fn_print_fail_nl "Installing ${workshoptitle[${item}]} (${item}): ${dst} already exists" + fn_script_log_fail "Installing ${workshoptitle[${item}]} (${item}): ${dst} already exists" + return + fi + mkdir -p "${workshopdir}" + if ! mv "${src}" "${dst}"; then + fn_print_fail_nl "Installing ${workshoptitle[${item}]} (${item})" + fn_script_log_fail "Installing ${workshoptitle[${item}]} (${item})" + core_exit.sh + fi fi if [ "${shortname}" == "arma3" ] || [ "${shortname}" == "dayz" ]; then fn_workshop_lowercase "${dst}" @@ -590,7 +603,7 @@ fn_workshop_update() { unset exitbypass } -# Adds installed Workshop mods to the mods start parameter, in workshopmods order. +# Adds installed Workshop mods to the start parameters, in workshopmods order: -mod= for Arma 3 and DayZ, loadmod for Hurtworld. fn_workshop_mods_startparameters() { if [ -n "${workshopmodsadded}" ]; then return @@ -611,7 +624,9 @@ fn_workshop_mods_startparameters() { local missing=0 local item for item in "${items[@]}"; do - if [ -d "${workshopdir}/${workshopprefix}${item}" ]; then + if [ -d "${workshopdir}/${workshopprefix}${item}" ] && [ "${shortname}" == "hw" ]; then + workshoploadmods+=";loadmod ${item}" + elif [ -d "${workshopdir}/${workshopprefix}${item}" ]; then workshopmodsparam+="${workshopmodsparam:+\\;}workshop/${workshopprefix}${item}" else missing=$((missing + 1)) From b081a57190f1a7154a9f8f2b4e0c9996f9364e42 Mon Sep 17 00:00:00 2001 From: Daniel Gibbs Date: Sun, 11 Oct 2026 16:56:24 +0100 Subject: [PATCH 050/164] feat(workshop): add Steam Workshop downloads for Soldat (#5020) --- .../config-lgsm/solserver/_default.cfg | 7 +++++ lgsm/modules/command_check_update.sh | 2 +- lgsm/modules/command_update.sh | 2 +- lgsm/modules/core_getopt.sh | 2 +- lgsm/modules/workshop_core.sh | 31 ++++++++++++++++--- 5 files changed, 36 insertions(+), 8 deletions(-) diff --git a/lgsm/config-default/config-lgsm/solserver/_default.cfg b/lgsm/config-default/config-lgsm/solserver/_default.cfg index 41d83dc5e9..bdf677e805 100644 --- a/lgsm/config-default/config-lgsm/solserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/solserver/_default.cfg @@ -15,6 +15,13 @@ maplist="mapslist.txt" ## Server Parameters | https://docs.linuxgsm.com/configuration/start-parameters#additional-parameters startparameters="-b ${ip} -m ${maplist} -c ${servercfg}" +## Steam Workshop Mods | https://docs.linuxgsm.com/steamcmd/workshop +# Workshop item or collection IDs, separated by spaces. Collections are expanded. +# Installed to serverfiles/workshop and linked into maps, textures and scenery-gfx. Add the maps you want to mapslist.txt. +# Run ./solserver workshop-update after changing, or let update apply it. +# workshopmods="2049686708" +workshopmods="" + #### LinuxGSM Settings #### ## LinuxGSM Stats diff --git a/lgsm/modules/command_check_update.sh b/lgsm/modules/command_check_update.sh index 0a86405616..9b6a8a319a 100755 --- a/lgsm/modules/command_check_update.sh +++ b/lgsm/modules/command_check_update.sh @@ -44,7 +44,7 @@ else update_steamcmd.sh fi -if { [ "${shortname}" == "arma3" ] || [ "${shortname}" == "dayz" ] || [ "${shortname}" == "bt" ] || [ "${shortname}" == "col" ] || [ "${shortname}" == "hw" ] || [ "${shortname}" == "l4d2" ] || [ "${shortname}" == "ohd" ] || [ "${shortname}" == "sb" ] || [ "${shortname}" == "squad" ] || [ "${shortname}" == "squad44" ] || [ "${shortname}" == "st" ]; } && { [ -n "${workshopmods}" ] || [ -f "${datadir}/${selfname}-workshop.txt" ]; }; then +if { [ "${shortname}" == "arma3" ] || [ "${shortname}" == "dayz" ] || [ "${shortname}" == "bt" ] || [ "${shortname}" == "col" ] || [ "${shortname}" == "hw" ] || [ "${shortname}" == "l4d2" ] || [ "${shortname}" == "ohd" ] || [ "${shortname}" == "sb" ] || [ "${shortname}" == "squad" ] || [ "${shortname}" == "squad44" ] || [ "${shortname}" == "sol" ] || [ "${shortname}" == "st" ]; } && { [ -n "${workshopmods}" ] || [ -f "${datadir}/${selfname}-workshop.txt" ]; }; then workshop_core.sh fn_workshop_update fi diff --git a/lgsm/modules/command_update.sh b/lgsm/modules/command_update.sh index 68d8c0f958..7d135c7a56 100755 --- a/lgsm/modules/command_update.sh +++ b/lgsm/modules/command_update.sh @@ -45,7 +45,7 @@ else update_steamcmd.sh fi -if { [ "${shortname}" == "arma3" ] || [ "${shortname}" == "dayz" ] || [ "${shortname}" == "bt" ] || [ "${shortname}" == "col" ] || [ "${shortname}" == "hw" ] || [ "${shortname}" == "l4d2" ] || [ "${shortname}" == "ohd" ] || [ "${shortname}" == "sb" ] || [ "${shortname}" == "squad" ] || [ "${shortname}" == "squad44" ] || [ "${shortname}" == "st" ]; } && { [ -n "${workshopmods}" ] || [ -f "${datadir}/${selfname}-workshop.txt" ]; }; then +if { [ "${shortname}" == "arma3" ] || [ "${shortname}" == "dayz" ] || [ "${shortname}" == "bt" ] || [ "${shortname}" == "col" ] || [ "${shortname}" == "hw" ] || [ "${shortname}" == "l4d2" ] || [ "${shortname}" == "ohd" ] || [ "${shortname}" == "sb" ] || [ "${shortname}" == "squad" ] || [ "${shortname}" == "squad44" ] || [ "${shortname}" == "sol" ] || [ "${shortname}" == "st" ]; } && { [ -n "${workshopmods}" ] || [ -f "${datadir}/${selfname}-workshop.txt" ]; }; then workshop_core.sh fn_workshop_update fi diff --git a/lgsm/modules/core_getopt.sh b/lgsm/modules/core_getopt.sh index 5623f2376f..d0e0679c5a 100755 --- a/lgsm/modules/core_getopt.sh +++ b/lgsm/modules/core_getopt.sh @@ -144,7 +144,7 @@ if [ "${engine}" == "source" ] || [ "${shortname}" == "cs2" ] || [ "${shortname} fi ## Workshop commands. -if [ "${shortname}" == "arma3" ] || [ "${shortname}" == "dayz" ] || [ "${shortname}" == "bt" ] || [ "${shortname}" == "col" ] || [ "${shortname}" == "hw" ] || [ "${shortname}" == "l4d2" ] || [ "${shortname}" == "ohd" ] || [ "${shortname}" == "sb" ] || [ "${shortname}" == "squad" ] || [ "${shortname}" == "squad44" ] || [ "${shortname}" == "st" ]; then +if [ "${shortname}" == "arma3" ] || [ "${shortname}" == "dayz" ] || [ "${shortname}" == "bt" ] || [ "${shortname}" == "col" ] || [ "${shortname}" == "hw" ] || [ "${shortname}" == "l4d2" ] || [ "${shortname}" == "ohd" ] || [ "${shortname}" == "sb" ] || [ "${shortname}" == "squad" ] || [ "${shortname}" == "squad44" ] || [ "${shortname}" == "sol" ] || [ "${shortname}" == "st" ]; then currentopt+=("${cmd_workshop_update[@]}") fi diff --git a/lgsm/modules/workshop_core.sh b/lgsm/modules/workshop_core.sh index 569d256f10..e52265bddc 100755 --- a/lgsm/modules/workshop_core.sh +++ b/lgsm/modules/workshop_core.sh @@ -37,6 +37,8 @@ if [ "${shortname}" == "sb" ]; then workshoplinkdir="${serverfiles}/mods" elif [ "${shortname}" == "l4d2" ]; then workshoplinkdir="${serverfiles}/left4dead2/addons" +elif [ "${shortname}" == "sol" ]; then + workshoplinkdir="${serverfiles}" fi workshopdldir="${tmpdir}/workshop" workshopmodlist="${datadir}/${selfname}-workshop.txt" @@ -337,9 +339,11 @@ fn_workshop_remove_keys() { # Removes the links a mod added to the game's mod directory. fn_workshop_remove_links() { local link - for link in $(fn_workshop_state "$1" links); do - rm -f "${workshoplinkdir:?}/${link}" - done + while IFS= read -r link; do + if [ -n "${link}" ]; then + rm -f "${workshoplinkdir:?}/${link}" + fi + done < <(fn_workshop_state "$1" link) } # Moves a downloaded item into the game's mod directory and prepares it for the game. @@ -350,7 +354,7 @@ fn_workshop_install() { local installed local keys=() local links=() - local key pak + local key pak file rel fn_print_dots "Installing ${workshoptitle[${item}]} (${item})" installed="$(fn_workshop_moddir "${item}")" if [ -n "${installed}" ]; then @@ -403,6 +407,21 @@ fn_workshop_install() { ln -srfn "${pak}" "${workshoplinkdir}/${item}.vpk" links+=("${item}.vpk") fi + elif [ "${shortname}" == "sol" ]; then + # Soldat items mirror the server's maps, textures and scenery-gfx directories. The server only finds lowercase .pms maps. + while IFS= read -r -d '' file; do + rel="${file#"${dst}/"}" + if [[ "${rel,,}" == maps/*.pms ]]; then + rel="${rel%.*}.pms" + fi + if [ -e "${workshoplinkdir}/${rel}" ] || [ -L "${workshoplinkdir}/${rel}" ]; then + fn_script_log_warn "Not linking ${rel} from ${workshoptitle[${item}]} (${item}): file already exists" + continue + fi + mkdir -p "${workshoplinkdir}/${rel%/*}" + ln -sr "${file}" "${workshoplinkdir}/${rel}" + links+=("${rel}") + done < <(find "${dst}" -mindepth 2 -type f -print0) fi local modname="" if [ "${shortname}" == "col" ] && [ -f "${dst}/modInfo.json" ]; then @@ -414,7 +433,9 @@ fn_workshop_install() { echo "title=${workshoptitle[${item}]}" echo "timeupdated=${workshoptimeupdated[${item}]}" echo "keys=${keys[*]}" - echo "links=${links[*]}" + if [ "${#links[@]}" -gt 0 ]; then + printf 'link=%s\n' "${links[@]}" + fi } > "${dst}/.lgsm-workshop" fn_print_ok_nl "Installing ${workshoptitle[${item}]} (${item})" fn_script_log_pass "Installing ${workshoptitle[${item}]} (${item})" From 60173005097f808bd91a271429c60e6df09878e1 Mon Sep 17 00:00:00 2001 From: BorzakA <1230402+borzaka@users.noreply.github.com> Date: Sun, 11 Oct 2026 18:08:00 +0200 Subject: [PATCH 051/164] fix(monitor): log the start and stop checks under their own name (#5011) fn_monitor_check_starting and fn_monitor_check_stopping printed "Checking start" / "Checking stop" on screen but wrote "Checking backup" to the script log, a leftover from copying fn_monitor_check_backup. Fixes #5010 Co-authored-by: Claude Opus 5.5 Co-authored-by: Daniel Gibbs --- lgsm/modules/command_monitor.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lgsm/modules/command_monitor.sh b/lgsm/modules/command_monitor.sh index 21d99bd062..7e56ffef06 100755 --- a/lgsm/modules/command_monitor.sh +++ b/lgsm/modules/command_monitor.sh @@ -81,7 +81,7 @@ fn_monitor_check_starting() { fn_print_checking_eol fn_print_info "Checking start: LinuxGSM is starting" fn_print_info_eol_nl - fn_script_log_info "Checking backup: LinuxGSM is starting" + fn_script_log_info "Checking start: LinuxGSM is starting" core_exit.sh fi } @@ -104,7 +104,7 @@ fn_monitor_check_stopping() { fn_print_checking_eol fn_print_info "Checking stop: LinuxGSM is stopping" fn_print_info_eol_nl - fn_script_log_info "Checking backup: LinuxGSM is stopping" + fn_script_log_info "Checking stop: LinuxGSM is stopping" core_exit.sh fi } From 76491eb4f49fcb40217d7ef68c70189e2964ae04 Mon Sep 17 00:00:00 2001 From: BorzakA <1230402+borzaka@users.noreply.github.com> Date: Sun, 11 Oct 2026 18:10:44 +0200 Subject: [PATCH 052/164] fix(monitor): detect running commands when the script is run by its full path (#5015) Monitor only found commands started as ./gameserver , because the checks used pgrep -x with the /bin/bash ./ prefix. The cron, systemd and Docker examples in the docs run the script by its full path, so monitor missed updates and backups and restarted the server in the middle of them. One helper now builds a single pattern per check that accepts any path to the script. Fixes #5013. Co-authored-by: Claude Opus 5.5 Co-authored-by: Daniel Gibbs --- lgsm/modules/command_monitor.sh | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/lgsm/modules/command_monitor.sh b/lgsm/modules/command_monitor.sh index 7e56ffef06..cc39f0ca34 100755 --- a/lgsm/modules/command_monitor.sh +++ b/lgsm/modules/command_monitor.sh @@ -11,6 +11,12 @@ commandaction="Monitoring" moduleselfname="$(basename "$(readlink -f "${BASH_SOURCE[0]}")")" fn_firstcommand_set +# Checks if this instance is running one of the given commands, e.g. "update|u". +# Matches the script run as ./gameserver, /path/to/gameserver or bash gameserver. +fn_monitor_command_running() { + [ "$(pgrep -fc -u "${USER}" "^([^ ]*/)?bash ([^ ]*/)?${selfname} ($1)( |$)")" != "0" ] +} + fn_monitor_check_monitoring() { if [ -f "${lockdir}/${selfname}.lock" ]; then # Part of migration to v23.5.0. #4296 @@ -30,7 +36,7 @@ fn_monitor_check_monitoring() { } fn_monitor_check_install() { - if [ "$(pgrep -fc -u "${USER}" "/bin/bash ./${selfname} install")" != "0" ] || [ "$(pgrep -fcx -u "${USER}" "/bin/bash ./${selfname} i")" != "0" ] || [ "$(pgrep -fcx -u "${USER}" "/bin/bash ./${selfname} auto-install")" != "0" ] || [ "$(pgrep -fcx -u "${USER}" "/bin/bash ./${selfname} ai")" != "0" ]; then + if fn_monitor_command_running "install|i|auto-install|ai"; then fn_print_dots "Checking installer" fn_print_checking_eol fn_script_log_info "Checking installer: CHECKING" @@ -42,7 +48,7 @@ fn_monitor_check_install() { } fn_monitor_check_debug() { - if [ "$(pgrep -fcx -u "${USER}" "/bin/bash ./${selfname} debug")" != "0" ] || [ "$(pgrep -fcx -u "${USER}" "/bin/bash ./${selfname} d")" != "0" ]; then + if fn_monitor_command_running "debug|d"; then fn_print_dots "Checking debug" fn_print_checking_eol fn_print_info "Checking debug: Debug is running" @@ -53,7 +59,7 @@ fn_monitor_check_debug() { } fn_monitor_check_details() { - if [ "$(pgrep -fcx -u "${USER}" "/bin/bash ./${selfname} details")" != "0" ] || [ "$(pgrep -fcx -u "${USER}" "/bin/bash ./${selfname} dt")" != "0" ]; then + if fn_monitor_command_running "details|dt"; then fn_print_dots "Checking details" fn_print_checking_eol fn_print_info "Checking details: Details is running" @@ -76,7 +82,7 @@ fn_monitor_check_starting() { fi fi - if [ -f "${lockdir}/${selfname}-starting.lock" ] && [[ "$(pgrep -fcx -u "${USER}" "/bin/bash ./${selfname} start")" != "0" || "$(pgrep -fcx -u "${USER}" "/bin/bash ./${selfname} st")" != "0" ]]; then + if [ -f "${lockdir}/${selfname}-starting.lock" ] && fn_monitor_command_running "start|st"; then fn_print_dots "Checking start" fn_print_checking_eol fn_print_info "Checking start: LinuxGSM is starting" @@ -99,7 +105,7 @@ fn_monitor_check_stopping() { fi fi - if [ -f "${lockdir}/${selfname}-stopping.lock" ] && [[ "$(pgrep -fcx -u "${USER}" "/bin/bash ./${selfname} stop")" != "0" || "$(pgrep -fcx -u "${USER}" "/bin/bash ./${selfname} sp")" != "0" ]]; then + if [ -f "${lockdir}/${selfname}-stopping.lock" ] && fn_monitor_command_running "stop|sp"; then fn_print_dots "Checking stop" fn_print_checking_eol fn_print_info "Checking stop: LinuxGSM is stopping" @@ -142,7 +148,7 @@ fn_monitor_check_backup() { fi fi - if [ -f "${lockdir}/backup.lock" ] && [[ "$(pgrep -fcx -u "${USER}" "/bin/bash ./${selfname} backup")" != "0" || "$(pgrep -fcx -u "${USER}" "/bin/bash ./${selfname} b")" != "0" ]]; then + if [ -f "${lockdir}/backup.lock" ] && fn_monitor_command_running "backup|b"; then fn_print_dots "Checking backup" fn_print_checking_eol fn_print_info "Checking backup: Backup is running" @@ -165,7 +171,7 @@ fn_monitor_check_update() { fi fi - if [ -f "${lockdir}/update.lock" ] && [[ "$(pgrep -fcx -u "${USER}" "/bin/bash ./${selfname} update")" != "0" || "$(pgrep -fcx -u "${USER}" "/bin/bash ./${selfname} u")" != "0" || "$(pgrep -fcx -u "${USER}" "/bin/bash ./${selfname} validate")" != "0" || "$(pgrep -fcx -u "${USER}" "/bin/bash ./${selfname} v")" != "0" || "$(pgrep -fcx -u "${USER}" "/bin/bash ./${selfname} force-update")" != "0" || "$(pgrep -fcx -u "${USER}" "/bin/bash ./${selfname} fu")" != "0" || "$(pgrep -fcx -u "${USER}" "/bin/bash ./${selfname} update-restart")" != "0" || "$(pgrep -fcx -u "${USER}" "/bin/bash ./${selfname} ur")" != "0" ]]; then + if [ -f "${lockdir}/update.lock" ] && fn_monitor_command_running "update|u|validate|v|force-update|fu|update-restart|ur"; then fn_print_dots "Checking update" fn_print_checking_eol fn_print_info "Checking update: LinuxGSM is updating the game server" From c0b5b9b108a4ac716de96b157da5c3298df6bd70 Mon Sep 17 00:00:00 2001 From: Daniel Gibbs Date: Sun, 11 Oct 2026 19:22:15 +0100 Subject: [PATCH 053/164] feat(rwrserver): add Running With Rifles server (#5021) * feat(newserver): add Running With Rifles server * fix(rwrserver): show rwr_server in the port diagnostic command * feat(rwrserver): start game modes from their own package with startpackage * fix(rwrserver): add the 32-bit libgpg-error dependency * docs(rwrserver): note the game and DLC ownership requirements in the config --- .../config-lgsm/rwrserver/_default.cfg | 207 ++++++++++++++++++ lgsm/data/almalinux-8.csv | 1 + lgsm/data/almalinux-9.csv | 1 + lgsm/data/centos-7.csv | 1 + lgsm/data/centos-8.csv | 1 + lgsm/data/centos-9.csv | 1 + lgsm/data/debian-10.csv | 1 + lgsm/data/debian-11.csv | 1 + lgsm/data/debian-12.csv | 1 + lgsm/data/debian-13.csv | 1 + lgsm/data/debian-9.csv | 1 + lgsm/data/gameicons/rwr-icon.png | Bin 0 -> 2880 bytes lgsm/data/rhel-7.csv | 1 + lgsm/data/rhel-8.csv | 1 + lgsm/data/rhel-9.csv | 1 + lgsm/data/rocky-8.csv | 1 + lgsm/data/rocky-9.csv | 1 + lgsm/data/serverlist.csv | 1 + lgsm/data/ubuntu-16.04.csv | 1 + lgsm/data/ubuntu-18.04.csv | 1 + lgsm/data/ubuntu-20.04.csv | 1 + lgsm/data/ubuntu-22.04.csv | 1 + lgsm/data/ubuntu-23.04.csv | 1 + lgsm/data/ubuntu-23.10.csv | 1 + lgsm/data/ubuntu-24.04.csv | 1 + lgsm/data/ubuntu-26.04.csv | 1 + lgsm/modules/check_system_requirements.sh | 2 + lgsm/modules/command_start.sh | 21 ++ lgsm/modules/command_stop.sh | 12 + lgsm/modules/info_game.sh | 23 ++ lgsm/modules/info_messages.sh | 21 +- lgsm/modules/install_config.sh | 3 + 32 files changed, 312 insertions(+), 1 deletion(-) create mode 100644 lgsm/config-default/config-lgsm/rwrserver/_default.cfg create mode 100644 lgsm/data/gameicons/rwr-icon.png mode change 100755 => 100644 lgsm/modules/info_messages.sh diff --git a/lgsm/config-default/config-lgsm/rwrserver/_default.cfg b/lgsm/config-default/config-lgsm/rwrserver/_default.cfg new file mode 100644 index 0000000000..a3f15d0074 --- /dev/null +++ b/lgsm/config-default/config-lgsm/rwrserver/_default.cfg @@ -0,0 +1,207 @@ +################################## +######## Default Settings ######## +################################## +# DO NOT EDIT, ANY CHANGES WILL BE OVERWRITTEN! +# Copy settings from here and use them in either: +# common.cfg - applies settings to every instance. +# [instance].cfg - applies settings to a specific instance. + +#### Game Server Settings #### + +## SteamCMD Login | https://docs.linuxgsm.com/steamcmd#steamcmd-login +# The Steam account must own Running With Rifles. The server is part of the game. +# WW2 game modes also need the account to own the Pacific and/or Edelweiss DLC. +steamuser="username" +steampass='password' + +## Game Mode Script | https://docs.linuxgsm.com/game-servers/running-with-rifles +# Server name, port, comment, mode and max players are set in the start script. +# Edit them in: serverfiles/media/packages/vanilla/scripts/rwrserver.as (a copy of start_invasion.as, created on install). +# For another game mode, set the package and its start script, e.g. +# startpackage="media/packages/deathmatch" and startscript="start_deathmatch_server.as" +startpackage="media/packages/vanilla" +startscript="${selfname}.as" + +## Server Parameters | https://docs.linuxgsm.com/configuration/start-parameters#additional-parameters +## Game Server Docs | https://runningwithrifles.fandom.com/wiki/How_to_host_a_different_game_mode_as_dedicated_server +startparameters="" + +#### LinuxGSM Settings #### + +## LinuxGSM Stats +# Send useful stats to LinuxGSM developers. +# https://docs.linuxgsm.com/configuration/linuxgsm-stats +# (on|off) +stats="off" + +## Notification Alerts +# (on|off) + +# Display IP | https://docs.linuxgsm.com/alerts#display-ip +displayip="" + +# More info | https://docs.linuxgsm.com/alerts#more-info +postalert="off" + +# Alert on Start/Stop/Restart +statusalert="off" + +# Discord Alerts | https://docs.linuxgsm.com/alerts/discord +discordalert="off" +discordwebhook="webhook" + +# Email Alerts | https://docs.linuxgsm.com/alerts/email +emailalert="off" +email="email@example.com" +emailfrom="" + +# Gotify Alerts | https://docs.linuxgsm.com/alerts/gotify +gotifyalert="off" +gotifytoken="token" +gotifywebhook="webhook" + +# IFTTT Alerts | https://docs.linuxgsm.com/alerts/ifttt +iftttalert="off" +ifttttoken="accesstoken" +iftttevent="linuxgsm_alert" + +# ntfy Alerts | https://docs.linuxgsm.com/alerts/ntfy +ntfyalert="off" +ntfytopic="LinuxGSM" +ntfyserver="https://ntfy.sh" +ntfytoken="" +ntfyusername="" +ntfypassword="" +ntfypriority="" +ntfytags="" + +# Pushbullet Alerts | https://docs.linuxgsm.com/alerts/pushbullet +pushbulletalert="off" +pushbullettoken="accesstoken" +channeltag="" + +# Pushover Alerts | https://docs.linuxgsm.com/alerts/pushover +pushoveralert="off" +pushovertoken="accesstoken" +pushoveruserkey="userkey" + +# Rocket.Chat Alerts | https://docs.linuxgsm.com/alerts/rocket.chat +rocketchatalert="off" +rocketchatwebhook="webhook" + +# Slack Alerts | https://docs.linuxgsm.com/alerts/slack +slackalert="off" +slackwebhook="webhook" + +# Telegram Alerts | https://docs.linuxgsm.com/alerts/telegram +# You can add a custom cURL string eg proxy (useful in Russia) in "curlcustomstring". +# For example "--socks5 ipaddr:port" for socks5 proxy see more in "curl --help all". +telegramapi="api.telegram.org" +telegramalert="off" +telegramtoken="accesstoken" +telegramchatid="" +telegramthreadid="" +telegramsilentnotification="false" +curlcustomstring="" + +## Updating | https://docs.linuxgsm.com/commands/update +updateonstart="off" + +## Backup | https://docs.linuxgsm.com/commands/backup +maxbackups="4" +maxbackupdays="30" +stoponbackup="on" + +## Logging | https://docs.linuxgsm.com/features/logging +consolelogging="on" +logdays="7" + +## Monitor | https://docs.linuxgsm.com/commands/monitor +# Query delay time +querydelay="5" + +## ANSI Colors | https://docs.linuxgsm.com/features/ansi-colors +ansi="on" + +#### Advanced Settings #### + +## Message Display Time | https://docs.linuxgsm.com/features/message-display-time +sleeptime="0.5" + +## SteamCMD Settings | https://docs.linuxgsm.com/steamcmd +# Server appid +appid="270150" +steamcmdforcewindows="no" +# SteamCMD Branch | https://docs.linuxgsm.com/steamcmd/branch +branch="" +betapassword="" +# Master Server | https://docs.linuxgsm.com/steamcmd/steam-master-server +steammaster="false" + +## Stop Mode | https://docs.linuxgsm.com/features/stop-mode +# 1: tmux kill +# 2: CTRL+c +# 3: quit +# 4: quit 120s +# 5: stop +# 6: q +# 7: exit +# 8: 7 Days to Die +# 9: GoldSrc +# 10: Avorion +# 11: end +# 12: shutdown +# 13: soulmask +# 14: Running With Rifles +stopmode="14" + +## Query mode +# 1: session only +# 2: gamedig (gsquery fallback) +# 3: gamedig +# 4: gsquery +# 5: tcp +querymode="1" +querytype="" + +## Console type +consoleverbose="yes" +consoleinteract="no" + +## Game Server Details +# Do not edit +gamename="Running With Rifles" +engine="rwr" +glibc="2.11" + +#### Directories #### +# Edit with care + +## Game Server Directories +systemdir="${serverfiles}" +executabledir="${serverfiles}" +executable="./launch_server" +servercfgdir="${systemdir}/media/packages/vanilla/scripts" +servercfg="${selfname}.as" +servercfgdefault="start_invasion.as" +servercfgfullpath="${servercfgdir}/${servercfg}" + +## Backup Directory +backupdir="${lgsmdir}/backup" + +## Logging Directories +[ -n "${LGSM_LOGDIR}" ] && logdir="${LGSM_LOGDIR}" || logdir="${rootdir}/log" +lgsmlogdir="${logdir}/script" +consolelogdir="${logdir}/console" +lgsmlog="${lgsmlogdir}/${selfname}-script.log" +consolelog="${consolelogdir}/${selfname}-console.log" +alertlog="${lgsmlogdir}/${selfname}-alert.log" +postdetailslog="${lgsmlogdir}/${selfname}-postdetails.log" + +## Logs Naming +lgsmlogdate="${lgsmlogdir}/${selfname}-script-$(date '+%Y-%m-%d-%H:%M:%S').log" +consolelogdate="${consolelogdir}/${selfname}-console-$(date '+%Y-%m-%d-%H:%M:%S').log" + +## Log Parameters +logtimestamp="off" +logtimestampformat="%Y-%m-%d %H:%M:%S" diff --git a/lgsm/data/almalinux-8.csv b/lgsm/data/almalinux-8.csv index b55ad0bc8b..519bf0cd0f 100644 --- a/lgsm/data/almalinux-8.csv +++ b/lgsm/data/almalinux-8.csv @@ -100,6 +100,7 @@ rsdw rtcw rust,zlib-devel rw,java-11-openjdk +rwr,libgpg-error.i686,libX11.i686,libXext.i686,zlib.i686 samp sb sbots diff --git a/lgsm/data/almalinux-9.csv b/lgsm/data/almalinux-9.csv index f17e59cda0..c6834b24c3 100644 --- a/lgsm/data/almalinux-9.csv +++ b/lgsm/data/almalinux-9.csv @@ -100,6 +100,7 @@ rsdw rtcw rust,zlib-devel rw,java-21-openjdk +rwr,libgpg-error.i686,libX11.i686,libXext.i686,zlib.i686 samp sb sbots diff --git a/lgsm/data/centos-7.csv b/lgsm/data/centos-7.csv index 4e8379ca3a..bb068562b4 100644 --- a/lgsm/data/centos-7.csv +++ b/lgsm/data/centos-7.csv @@ -100,6 +100,7 @@ rsdw rtcw rust,zlib-devel rw,java-11-openjdk +rwr,libgpg-error.i686,libX11.i686,libXext.i686,zlib.i686 samp sb sbots diff --git a/lgsm/data/centos-8.csv b/lgsm/data/centos-8.csv index dda247ea13..3dca174c79 100644 --- a/lgsm/data/centos-8.csv +++ b/lgsm/data/centos-8.csv @@ -100,6 +100,7 @@ rsdw rtcw rust,zlib-devel rw,java-11-openjdk +rwr,libgpg-error.i686,libX11.i686,libXext.i686,zlib.i686 samp sb sbots diff --git a/lgsm/data/centos-9.csv b/lgsm/data/centos-9.csv index 08e4a8489b..f385b0f95d 100644 --- a/lgsm/data/centos-9.csv +++ b/lgsm/data/centos-9.csv @@ -100,6 +100,7 @@ rsdw rtcw rust,zlib-devel rw,java-21-openjdk +rwr,libgpg-error.i686,libX11.i686,libXext.i686,zlib.i686 samp sb sbots diff --git a/lgsm/data/debian-10.csv b/lgsm/data/debian-10.csv index e13675db7a..8750c676b8 100644 --- a/lgsm/data/debian-10.csv +++ b/lgsm/data/debian-10.csv @@ -100,6 +100,7 @@ rsdw rtcw rust,lib32z1 rw,openjdk-11-jre +rwr,libgpg-error0:i386,libx11-6:i386,libxext6:i386,zlib1g:i386 samp sb sbots diff --git a/lgsm/data/debian-11.csv b/lgsm/data/debian-11.csv index 7562add0c5..30e4bdbd21 100644 --- a/lgsm/data/debian-11.csv +++ b/lgsm/data/debian-11.csv @@ -101,6 +101,7 @@ rsdw rtcw rust,lib32z1 rw,openjdk-17-jre +rwr,libgpg-error0:i386,libx11-6:i386,libxext6:i386,zlib1g:i386 samp sb sbots diff --git a/lgsm/data/debian-12.csv b/lgsm/data/debian-12.csv index 0cba73d33a..40aafa29b1 100644 --- a/lgsm/data/debian-12.csv +++ b/lgsm/data/debian-12.csv @@ -101,6 +101,7 @@ rsdw rtcw rust,lib32z1 rw,openjdk-17-jre +rwr,libgpg-error0:i386,libx11-6:i386,libxext6:i386,zlib1g:i386 samp sb sbots diff --git a/lgsm/data/debian-13.csv b/lgsm/data/debian-13.csv index 6176812082..c5029d353a 100644 --- a/lgsm/data/debian-13.csv +++ b/lgsm/data/debian-13.csv @@ -101,6 +101,7 @@ rsdw rtcw rust,lib32z1 rw,openjdk-25-jre +rwr,libgpg-error0:i386,libx11-6:i386,libxext6:i386,zlib1g:i386 samp sb sbots diff --git a/lgsm/data/debian-9.csv b/lgsm/data/debian-9.csv index b571e41bc0..f5b3cac230 100644 --- a/lgsm/data/debian-9.csv +++ b/lgsm/data/debian-9.csv @@ -101,6 +101,7 @@ rsdw rtcw rust,lib32z1 rw,openjdk-8-jre +rwr,libgpg-error0:i386,libx11-6:i386,libxext6:i386,zlib1g:i386 samp sb sbots diff --git a/lgsm/data/gameicons/rwr-icon.png b/lgsm/data/gameicons/rwr-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..9e92ba1d7b5aa5350aec4417b85dfe0b5f257214 GIT binary patch literal 2880 zcmZ`*c{J3I7XKn*kg=~3vixdj##WZXFt)OU$Qr{~VzP{Fv>?02zGtg6CXGFktXaku zvMaKTU1QDKL{I0P^UnL@y>rjK_uS7tpZodm-WzLTq{|8t0098Ns;{SQdYUi%bw=9L z_?vIN@NeOyXKDxl!IA(F8UX;mPNC2h0Pu$bz?uU9sAK^EuXpap+iIr`2INg$ZQ##e zd(lWpJw=$j^{g-ez|8U2X@;W8Ae0)HjGBxua1SKS#9p|KKS7TLkSK z`3e9)!ur~p=6apiQ;rhtP&84^dz6FR`p?0x4+wept*kFa%9)gKXv-Kr|2PYOu;OvUQS)U8_D>|7AegQdNgHWq)%&4p&m268Ole2WVKpS?3`n+%w}wj zT$J5To~rJMXaU6Bf#D%Re9#NszSq?aRpGZHpIHvnxX>c&+V^Sh^t`kdr5k1Wp{VEB zdaIV;8y7ChgfjxSdrnuToQX0!*CNQbPmgLz67`jQyA!@EN* z#M!L6d~tN4=)i@j zc1v@EVsEFnBg2=&LvoW6L)LpT`G7-^ISv5q{?Of3C59Oxi@nPmkYvtjSpQUkT5o?EcO_;0ZSJL4;Ba&z+w>v7Et#NT%Y`OyHcb~i+DJ8GGCBcpgyK`U&h!5urS+%d?AX3Brc-gK7CsJ zu@1rT)Q|ovrOHKp7&7-h!PAX>Kw7yg=zt@K*bul>(Dpq98ED7svWifrglZ-;p}9+J zOKq*O=uyJp!dc4dbEo*QmSp|#?XW?7GXH3_U~gaGl`?z;^S5RS;c=_f|E_U=0NhDG!N=qt|L zK`p{G!^KJ`36EP#L^?(9o$I6q1lN-cg!hX%!74r4@{9b4eGe_{W~X443U8g}7(B;D zREG?g+Fi*V+1q?v#6>1I%f7yfp0POp&T6Xv16xeJ{U&&Y=V=V{ph%d7?i^a8$>TZq zO%7^8SLvrDK2urCp0mW2L8s|#)@p*wxjyBYrg#>$qopdic|5KORgUpaobrsT;+q8L zG;jpJ84=#KQ-2Xt;S2yGEbo3TB{?wT)rhsJ4XNxVG({R`5{93YDph7JD)JQXFAdY8 zyi}#9=LS|Ft9N?wKbQMP3^%@MG{1}Qv&z`BSI81TI3eByO+Da_ajVI32SKBPo=j<7 zufcX#b4oh~zOiQE*M^5Ziy`(ks9Tu2D(&t-^{Q}ln(U0m{Yt~Hmu8PGKVZr%_g|iQ zi8PcZ!E4ehnIGbC^}sAd>yLYHFiKd5uzH?dGB- zbwnY@^&3!P%Kmsti(TJOCJGXx$yy@QWUV!k4A#GC(3f>)qS(tNi7N(N*N$k}^?Nzh z(Pq%CIl(7|1G8tldcAkyopPtz4T8qj$9~BPf2s{caGC{By$EQVtDC+>+ySslHPsS-S)2G697l(Q2GYmji>tn3HWtWe9187Oz0X zYO(OB{Bo-W8nF za_MGTfWL{U4S#e)Q+99=SpF3aLq%Gf!~IT5vbcylWVHO_nwCn>$yQGDwHsDMuSewl zLV{5v`N&l7y7IhP;gFgln5(UopnhBzEpmc#&&?1EIk@wXRLgr+R%xBX3cG&1Oy*@Z zR^*5f>%lBU-?&gXFoShF?mO9S@Au{jncE+D^do2Hq57(Qy(?Mw;CQ3o`0?Og?&pSb zRQF2_5N5z~qv5D1ob6=6bv`n-;AHEp<-HJ@kzLBy@$$pjCf$%fMBaNhKE-?746Rle z5sz_(j+SLp+8ZA>Va79?5AV>g=&A=?miR;_zm?ni;+m-UM(4WqB&+~$>fybWVSFQm z>SsD_uf6XVNCmZobNysD~0CF+-G?dkQv`6Vp{7`EvE$Nz} znP__~r&OBh)#;#l2WZgm?M{*4m6wr`ky_E`eERQU7r71GGf;5GasNVTP#YL^pA%}Li24JZ zkKI*6Gg8(v*3H9%8PH%ntrMI?wF$%6oo=Z}aE&#qXawv*jWxlzKr*7FtgLC9B#47C z&QU0k2&jI_G4%k`Ul2r&O;6|U$Ci($n%*x>z1UraGcmZ*`_XT8=-02{M*C=RfJ)vl z!B{n+jc?eR4iLsJBzu(Axm**&WQycgV~@qf#DwU zFor+9C>Bv?cXuYZ8?F-a /dev/null diff --git a/lgsm/modules/command_stop.sh b/lgsm/modules/command_stop.sh index 7bc4080650..478db210ce 100755 --- a/lgsm/modules/command_stop.sh +++ b/lgsm/modules/command_stop.sh @@ -333,6 +333,16 @@ fn_stop_graceful_avorion() { fi } +fn_stop_graceful_rwr() { + fn_print_dots "Graceful: save_profiles stop_server" + fn_script_log_info "Graceful: save_profiles stop_server" + TERM=screen tmux -L "${socketname}" send-keys -t "${sessionname}" save_profiles ENTER > /dev/null 2>&1 + fn_sleep_time_5 + TERM=screen tmux -L "${socketname}" send-keys -t "${sessionname}" stop_server ENTER > /dev/null 2>&1 + fn_sleep_time_5 + fn_stop_graceful_ctrlc +} + fn_stop_graceful_select() { if [ "${stopmode}" == "1" ]; then fn_stop_tmux @@ -360,6 +370,8 @@ fn_stop_graceful_select() { fn_stop_graceful_cmd "shutdown" 30 elif [ "${stopmode}" == "13" ]; then fn_stop_graceful_sm + elif [ "${stopmode}" == "14" ]; then + fn_stop_graceful_rwr fi } diff --git a/lgsm/modules/info_game.sh b/lgsm/modules/info_game.sh index 8ce8605c6b..09242877d4 100755 --- a/lgsm/modules/info_game.sh +++ b/lgsm/modules/info_game.sh @@ -1846,6 +1846,27 @@ fn_info_game_rsdw() { worldname="${worldname:-"NOT SET"}" } +# Config Type: AngelScript (start_server command) +# Comment: // +# Example: server_name='SERVERNAME' +# Filetype: as +fn_info_game_rwr() { + local startscriptfile="${serverfiles}/${startpackage:-media/packages/vanilla}/scripts/${startscript}" + if [ ! -f "${startscriptfile}" ]; then + startscriptfile="${servercfgfullpath}" + fi + if [ -f "${startscriptfile}" ]; then + servername="$(sed -n "s/.*server_name='\([^']*\)'.*/\1/p" "${startscriptfile}" | head -1)" + port="$(sed -n "s/.*server_port='\([0-9]*\)'.*/\1/p" "${startscriptfile}" | head -1)" + maxplayers="$(sed -n "s/.*max_players='\([0-9]*\)'.*/\1/p" "${startscriptfile}" | head -1)" + gamemode="$(sed -n "s/.*mode='\([^']*\)'.*/\1/p" "${startscriptfile}" | head -1)" + fi + servername="${servername:-"NOT SET"}" + port="${port:-"0"}" + queryport="${port}" + maxplayers="${maxplayers:-"0"}" + gamemode="${gamemode:-"NOT SET"}" +} # Config Type: QuakeC # Comment: // or /* */ # Example: set sv_hostname "SERVERNAME" @@ -2479,6 +2500,8 @@ elif [ "${shortname}" == "rsdw" ]; then fn_info_game_rsdw elif [ "${shortname}" == "rtcw" ]; then fn_info_game_rtcw +elif [ "${shortname}" == "rwr" ]; then + fn_info_game_rwr elif [ "${shortname}" == "rust" ]; then fn_info_game_rust elif [ "${shortname}" == "rw" ]; then diff --git a/lgsm/modules/info_messages.sh b/lgsm/modules/info_messages.sh old mode 100755 new mode 100644 index 392f810072..dc6d2ef740 --- a/lgsm/modules/info_messages.sh +++ b/lgsm/modules/info_messages.sh @@ -719,7 +719,7 @@ fn_info_messages_ports_edit() { startparameterslocation="${red}UNKNOWN${default}" # engines/games that require editing in the config file. - local ports_edit_array=("ac" "arma3" "armar" "bo" "bt" "ct" "dst" "eco" "idtech2" "idtech3" "idtech3_ql" "jc2" "jc3" "lwjgl2" "mcb" "nec" "pc" "pc2" "prism3d" "pz" "qw" "refractor" "renderware" "rw" "sb" "sdtd" "st" "stn" "ts3" "tw" "terraria" "unreal" "unreal2" "unreal3" "vints" "xnt" "wurm") + local ports_edit_array=("ac" "arma3" "armar" "bo" "bt" "ct" "dst" "eco" "idtech2" "idtech3" "idtech3_ql" "jc2" "jc3" "lwjgl2" "mcb" "nec" "pc" "pc2" "prism3d" "pz" "qw" "refractor" "renderware" "rw" "rwr" "sb" "sdtd" "st" "stn" "ts3" "tw" "terraria" "unreal" "unreal2" "unreal3" "vints" "xnt" "wurm") for port_edit in "${ports_edit_array[@]}"; do if [ "${shortname}" == "ut3" ]; then startparameterslocation="${servercfgdir}/UTWeb.ini" @@ -754,6 +754,8 @@ fn_info_messages_ports() { portcommand="ss -tuplwn | grep enfMain" elif [ "${shortname}" == "q4" ]; then portcommand="ss -tuplwn | grep q4ded.x86" + elif [ "${shortname}" == "rwr" ]; then + portcommand="ss -tuplwn | grep rwr_server" elif [ "${shortname}" == "hyt" ] || [ "${shortname}" == "mc" ] || [ "${shortname}" == "nec" ] || [ "${shortname}" == "pmc" ] || [ "${shortname}" == "vpmc" ] || [ "${shortname}" == "wmc" ]; then portcommand="ss -tuplwn | grep java" elif [ "${shortname}" == "terraria" ]; then @@ -1433,6 +1435,21 @@ fn_info_messages_rsdw() { } | column -s $'\t' -t } +fn_info_messages_rwr() { + { + fn_port "header" + fn_port "Game" port udp + } | column -s $'\t' -t + echo -e "" + echo -e "${bold}${lightgreen}${gamename} Game Settings${default}" + fn_messages_separator + { + echo -e "${lightblue}Start package:\t${default}${startpackage}" + echo -e "${lightblue}Start script:\t${default}${startscript}" + echo -e "${lightblue}Game mode:\t${default}${gamemode}" + } | column -s $'\t' -t +} + fn_info_messages_rtcw() { { fn_port "header" @@ -1938,6 +1955,8 @@ fn_info_messages_select_engine() { fn_info_messages_ro elif [ "${shortname}" == "rsdw" ]; then fn_info_messages_rsdw + elif [ "${shortname}" == "rwr" ]; then + fn_info_messages_rwr elif [ "${shortname}" == "rtcw" ]; then fn_info_messages_rtcw elif [ "${shortname}" == "samp" ]; then diff --git a/lgsm/modules/install_config.sh b/lgsm/modules/install_config.sh index 6c5019a227..0e22806540 100755 --- a/lgsm/modules/install_config.sh +++ b/lgsm/modules/install_config.sh @@ -715,6 +715,9 @@ elif [ "${shortname}" == "squad" ]; then fn_default_config_remote fn_set_config_vars fn_list_config_locations +elif [ "${shortname}" == "rwr" ]; then + fn_default_config_local + fn_list_config_locations elif [ "${shortname}" == "sb" ]; then array_configs+=(starbound_server.config) fn_default_config_remote From 973badf7fe46a5fbadfbc13f55f557c96939d699 Mon Sep 17 00:00:00 2001 From: Daniel Gibbs Date: Sun, 11 Oct 2026 20:49:01 +0100 Subject: [PATCH 054/164] fix(config): correct console interaction, stop modes and SCP:SL EULA (#5022) * fix(config): correct consoleinteract for servers that do or don't read console input * fix(config): correct stop modes and accept the SCP:SL EULA on install --- lgsm/config-default/config-lgsm/cod2server/_default.cfg | 2 +- lgsm/config-default/config-lgsm/cod4server/_default.cfg | 2 +- lgsm/config-default/config-lgsm/codserver/_default.cfg | 2 +- lgsm/config-default/config-lgsm/coduoserver/_default.cfg | 2 +- lgsm/config-default/config-lgsm/codwawserver/_default.cfg | 2 +- lgsm/config-default/config-lgsm/l4dserver/_default.cfg | 2 +- lgsm/config-default/config-lgsm/mohaaserver/_default.cfg | 2 +- lgsm/config-default/config-lgsm/ns2cserver/_default.cfg | 2 +- lgsm/config-default/config-lgsm/ns2server/_default.cfg | 2 +- lgsm/config-default/config-lgsm/onsetserver/_default.cfg | 2 +- lgsm/config-default/config-lgsm/rtcwserver/_default.cfg | 2 +- lgsm/config-default/config-lgsm/rustserver/_default.cfg | 4 ++-- lgsm/config-default/config-lgsm/rwrserver/_default.cfg | 2 +- lgsm/config-default/config-lgsm/scpslserver/_default.cfg | 2 +- lgsm/config-default/config-lgsm/scpslsmserver/_default.cfg | 2 +- lgsm/config-default/config-lgsm/stserver/_default.cfg | 4 ++-- lgsm/config-default/config-lgsm/wetserver/_default.cfg | 2 +- lgsm/modules/install_eula.sh | 2 ++ lgsm/modules/install_server_files.sh | 2 +- 19 files changed, 22 insertions(+), 20 deletions(-) diff --git a/lgsm/config-default/config-lgsm/cod2server/_default.cfg b/lgsm/config-default/config-lgsm/cod2server/_default.cfg index 45abeb251a..6a71c82e16 100644 --- a/lgsm/config-default/config-lgsm/cod2server/_default.cfg +++ b/lgsm/config-default/config-lgsm/cod2server/_default.cfg @@ -151,7 +151,7 @@ querytype="protocol-quake3" ## Console type consoleverbose="yes" -consoleinteract="no" +consoleinteract="yes" ## Game Server Details # Do not edit diff --git a/lgsm/config-default/config-lgsm/cod4server/_default.cfg b/lgsm/config-default/config-lgsm/cod4server/_default.cfg index 0d007db4e5..5c6f94cadd 100644 --- a/lgsm/config-default/config-lgsm/cod4server/_default.cfg +++ b/lgsm/config-default/config-lgsm/cod4server/_default.cfg @@ -151,7 +151,7 @@ querytype="protocol-quake3" ## Console type consoleverbose="yes" -consoleinteract="no" +consoleinteract="yes" ## Game Server Details # Do not edit diff --git a/lgsm/config-default/config-lgsm/codserver/_default.cfg b/lgsm/config-default/config-lgsm/codserver/_default.cfg index de3fc8c237..f00600e40c 100644 --- a/lgsm/config-default/config-lgsm/codserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/codserver/_default.cfg @@ -151,7 +151,7 @@ querytype="protocol-quake3" ## Console type consoleverbose="yes" -consoleinteract="no" +consoleinteract="yes" ## Game Server Details # Do not edit diff --git a/lgsm/config-default/config-lgsm/coduoserver/_default.cfg b/lgsm/config-default/config-lgsm/coduoserver/_default.cfg index 2e52c6b244..5fc7d9816d 100644 --- a/lgsm/config-default/config-lgsm/coduoserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/coduoserver/_default.cfg @@ -151,7 +151,7 @@ querytype="protocol-quake3" ## Console type consoleverbose="yes" -consoleinteract="no" +consoleinteract="yes" ## Game Server Details # Do not edit diff --git a/lgsm/config-default/config-lgsm/codwawserver/_default.cfg b/lgsm/config-default/config-lgsm/codwawserver/_default.cfg index 438c1b785b..337787fdec 100644 --- a/lgsm/config-default/config-lgsm/codwawserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/codwawserver/_default.cfg @@ -151,7 +151,7 @@ querytype="protocol-quake3" ## Console type consoleverbose="yes" -consoleinteract="no" +consoleinteract="yes" ## Game Server Details # Do not edit diff --git a/lgsm/config-default/config-lgsm/l4dserver/_default.cfg b/lgsm/config-default/config-lgsm/l4dserver/_default.cfg index 354bb9b194..88c45c1baf 100644 --- a/lgsm/config-default/config-lgsm/l4dserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/l4dserver/_default.cfg @@ -152,7 +152,7 @@ steammaster="false" # 9: GoldSrc # 10: Avorion # 11: end -stopmode="2" +stopmode="3" ## Query mode # 1: session only diff --git a/lgsm/config-default/config-lgsm/mohaaserver/_default.cfg b/lgsm/config-default/config-lgsm/mohaaserver/_default.cfg index df8e01fe07..9aab77c7a6 100644 --- a/lgsm/config-default/config-lgsm/mohaaserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/mohaaserver/_default.cfg @@ -150,7 +150,7 @@ querytype="" ## Console type consoleverbose="yes" -consoleinteract="no" +consoleinteract="yes" ## Game Server Details # Do not edit diff --git a/lgsm/config-default/config-lgsm/ns2cserver/_default.cfg b/lgsm/config-default/config-lgsm/ns2cserver/_default.cfg index fdd809dff1..d08afa02ff 100644 --- a/lgsm/config-default/config-lgsm/ns2cserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/ns2cserver/_default.cfg @@ -160,7 +160,7 @@ steammaster="true" # 9: GoldSrc # 10: Avorion # 11: end -stopmode="6" +stopmode="2" ## Query mode # 1: session only diff --git a/lgsm/config-default/config-lgsm/ns2server/_default.cfg b/lgsm/config-default/config-lgsm/ns2server/_default.cfg index d8da66429e..e0c11a4bf9 100644 --- a/lgsm/config-default/config-lgsm/ns2server/_default.cfg +++ b/lgsm/config-default/config-lgsm/ns2server/_default.cfg @@ -161,7 +161,7 @@ steammaster="true" # 9: GoldSrc # 10: Avorion # 11: end -stopmode="6" +stopmode="2" ## Query mode # 1: session only diff --git a/lgsm/config-default/config-lgsm/onsetserver/_default.cfg b/lgsm/config-default/config-lgsm/onsetserver/_default.cfg index 12cabe90da..5fd642a04e 100644 --- a/lgsm/config-default/config-lgsm/onsetserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/onsetserver/_default.cfg @@ -159,7 +159,7 @@ querytype="" ## Console type consoleverbose="yes" -consoleinteract="no" +consoleinteract="yes" ## Game Server Details # Do not edit diff --git a/lgsm/config-default/config-lgsm/rtcwserver/_default.cfg b/lgsm/config-default/config-lgsm/rtcwserver/_default.cfg index f2ba06a62a..16b2877330 100644 --- a/lgsm/config-default/config-lgsm/rtcwserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/rtcwserver/_default.cfg @@ -150,7 +150,7 @@ querytype="protocol-quake3" ## Console type consoleverbose="yes" -consoleinteract="no" +consoleinteract="yes" ## Game Server Details # Do not edit diff --git a/lgsm/config-default/config-lgsm/rustserver/_default.cfg b/lgsm/config-default/config-lgsm/rustserver/_default.cfg index 418aad9468..75e1dba897 100644 --- a/lgsm/config-default/config-lgsm/rustserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/rustserver/_default.cfg @@ -165,7 +165,7 @@ steammaster="false" # 9: GoldSrc # 10: Avorion # 11: end -stopmode="2" +stopmode="4" ## Query mode # 1: session only @@ -178,7 +178,7 @@ querytype="protocol-valve" ## Console type consoleverbose="yes" -consoleinteract="no" +consoleinteract="yes" ## Game Server Details # Do not edit diff --git a/lgsm/config-default/config-lgsm/rwrserver/_default.cfg b/lgsm/config-default/config-lgsm/rwrserver/_default.cfg index a3f15d0074..5831be8972 100644 --- a/lgsm/config-default/config-lgsm/rwrserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/rwrserver/_default.cfg @@ -166,7 +166,7 @@ querytype="" ## Console type consoleverbose="yes" -consoleinteract="no" +consoleinteract="yes" ## Game Server Details # Do not edit diff --git a/lgsm/config-default/config-lgsm/scpslserver/_default.cfg b/lgsm/config-default/config-lgsm/scpslserver/_default.cfg index 2ad4b566ca..4ce7f2fb99 100644 --- a/lgsm/config-default/config-lgsm/scpslserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/scpslserver/_default.cfg @@ -14,7 +14,7 @@ port="7777" ## Server Parameters | https://docs.linuxgsm.com/configuration/start-parameters#additional-parameters -startparameters="${port}" +startparameters="${port} --acceptEULA" #### LinuxGSM Settings #### diff --git a/lgsm/config-default/config-lgsm/scpslsmserver/_default.cfg b/lgsm/config-default/config-lgsm/scpslsmserver/_default.cfg index eca5c43e6f..464ef0feed 100644 --- a/lgsm/config-default/config-lgsm/scpslsmserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/scpslsmserver/_default.cfg @@ -14,7 +14,7 @@ port="7777" ## Server Parameters | https://docs.linuxgsm.com/configuration/start-parameters#additional-parameters -startparameters="${port}" +startparameters="${port} --acceptEULA" #### LinuxGSM Settings #### diff --git a/lgsm/config-default/config-lgsm/stserver/_default.cfg b/lgsm/config-default/config-lgsm/stserver/_default.cfg index a14fc812a6..9fd5172017 100644 --- a/lgsm/config-default/config-lgsm/stserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/stserver/_default.cfg @@ -155,7 +155,7 @@ steammaster="false" # 9: GoldSrc # 10: Avorion # 11: end -stopmode="3" +stopmode="2" ## Query mode # 1: session only @@ -168,7 +168,7 @@ querytype="" ## Console type consoleverbose="yes" -consoleinteract="yes" +consoleinteract="no" ## Game Server Details # Do not edit diff --git a/lgsm/config-default/config-lgsm/wetserver/_default.cfg b/lgsm/config-default/config-lgsm/wetserver/_default.cfg index 819390dc04..246b41a194 100644 --- a/lgsm/config-default/config-lgsm/wetserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/wetserver/_default.cfg @@ -145,7 +145,7 @@ querytype="protocol-quake3" ## Console type consoleverbose="yes" -consoleinteract="no" +consoleinteract="yes" ## Game Server Details # Do not edit diff --git a/lgsm/modules/install_eula.sh b/lgsm/modules/install_eula.sh index f32a1931e1..ff94a39a28 100755 --- a/lgsm/modules/install_eula.sh +++ b/lgsm/modules/install_eula.sh @@ -11,6 +11,8 @@ if [ "${shortname}" == "ts3" ]; then eulaurl="https://www.teamspeak.com/en/privacy-and-terms" elif [ "${shortname}" == "mc" ] || [ "${shortname}" == "pmc" ]; then eulaurl="https://account.mojang.com/documents/minecraft_eula" +elif [ "${shortname}" == "scpsl" ] || [ "${shortname}" == "scpslsm" ]; then + eulaurl="https://link.scpslgame.com/eula" elif [ "${shortname}" == "ut" ]; then eulaurl="https://www.epicgames.com/unrealtournament/unreal-tournament-pre-alpha-test-development-build-eula" fi diff --git a/lgsm/modules/install_server_files.sh b/lgsm/modules/install_server_files.sh index c860ac1e1a..eceeed9ba1 100755 --- a/lgsm/modules/install_server_files.sh +++ b/lgsm/modules/install_server_files.sh @@ -227,7 +227,7 @@ fn_install_server_files() { fn_clear_tmp } -if [ "${shortname}" == "mc" ] || [ "${shortname}" == "pmc" ] || [ "${shortname}" == "ut" ]; then +if [ "${shortname}" == "mc" ] || [ "${shortname}" == "pmc" ] || [ "${shortname}" == "scpsl" ] || [ "${shortname}" == "scpslsm" ] || [ "${shortname}" == "ut" ]; then install_eula.sh fi From e712367221349a9a1c36b9d00220994724b793dc Mon Sep 17 00:00:00 2001 From: Daniel Gibbs Date: Wed, 14 Oct 2026 15:30:44 +0100 Subject: [PATCH 055/164] fix(ios): use 64-bit server and stop map reload loop (#5024) IOSoccer moved to a 64-bit server (srcds_run_64) on 7 October 2026. The new engine executes the server cfg on every map load, so the map line in the default cfg caused an endless map reload. Add fix_ios.sh to comment it out on existing installs, and bump glibc to 2.29. Fixes #5023 --- .../config-lgsm/iosserver/_default.cfg | 4 ++-- lgsm/modules/core_modules.sh | 5 +++++ lgsm/modules/fix.sh | 2 +- lgsm/modules/fix_ios.sh | 16 ++++++++++++++++ 4 files changed, 24 insertions(+), 3 deletions(-) create mode 100755 lgsm/modules/fix_ios.sh diff --git a/lgsm/config-default/config-lgsm/iosserver/_default.cfg b/lgsm/config-default/config-lgsm/iosserver/_default.cfg index 9286669841..f091c4f48e 100644 --- a/lgsm/config-default/config-lgsm/iosserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/iosserver/_default.cfg @@ -172,7 +172,7 @@ consoleinteract="yes" # Do not edit gamename="IOSoccer" engine="source" -glibc="2.3.6" +glibc="2.29" #### Directories #### # Edit with care @@ -180,7 +180,7 @@ glibc="2.3.6" ## Game Server Directories systemdir="${serverfiles}/iosoccer" executabledir="${serverfiles}" -executable="./srcds_run" +executable="./srcds_run_64" servercfgdir="${systemdir}/cfg" servercfg="${selfname}.cfg" servercfgdefault="server.cfg" diff --git a/lgsm/modules/core_modules.sh b/lgsm/modules/core_modules.sh index c0975bb60e..9d8c99bc2c 100755 --- a/lgsm/modules/core_modules.sh +++ b/lgsm/modules/core_modules.sh @@ -413,6 +413,11 @@ fix_ins.sh() { fn_fetch_module } +fix_ios.sh() { + modulefile="${FUNCNAME[0]}" + fn_fetch_module +} + fix_kf.sh() { modulefile="${FUNCNAME[0]}" fn_fetch_module diff --git a/lgsm/modules/fix.sh b/lgsm/modules/fix.sh index f31030779c..8a0a4c39a3 100755 --- a/lgsm/modules/fix.sh +++ b/lgsm/modules/fix.sh @@ -53,7 +53,7 @@ fn_apply_fix() { fi } -apply_pre_start_fix=(arma3 armar ark av bt bo csgo cmw dst hw ins kf nmrih onset pvr ro rust rw samp sdtd sfc sm sof2 squad st tf2 terraria ts3 mcb mta unt vh wurm xnt zmr) +apply_pre_start_fix=(arma3 armar ark av bt bo csgo cmw dst hw ins ios kf nmrih onset pvr ro rust rw samp sdtd sfc sm sof2 squad st tf2 terraria ts3 mcb mta unt vh wurm xnt zmr) apply_post_install_fix=(av kf kf2 ro ut2k4 ut ut3) # validate registered fixes for safe development diff --git a/lgsm/modules/fix_ios.sh b/lgsm/modules/fix_ios.sh new file mode 100755 index 0000000000..efb3c28831 --- /dev/null +++ b/lgsm/modules/fix_ios.sh @@ -0,0 +1,16 @@ +#!/bin/bash +# LinuxGSM fix_ios.sh module +# Author: Daniel Gibbs +# Contributors: https://linuxgsm.com/contrib +# Website: https://linuxgsm.com +# Description: Resolves issues with IOSoccer. + +moduleselfname="$(basename "$(readlink -f "${BASH_SOURCE[0]}")")" + +# Fixes: IOSoccer 64-bit server stuck reloading the map #5023. +if [ -f "${servercfgfullpath}" ] && grep -qE '^\s*map\s' "${servercfgfullpath}"; then + fixname="remove map from ${servercfg}" + fn_fix_msg_start + sed -i -E 's|^(\s*map\s.*)$|// \1|' "${servercfgfullpath}" + fn_fix_msg_end +fi From 6e8b9c0e296fa0bcf1e4656311bab69ae38f5bd6 Mon Sep 17 00:00:00 2001 From: Daniel Gibbs Date: Wed, 14 Oct 2026 20:42:31 +0100 Subject: [PATCH 056/164] feat(stop): warn players in-game before stop, restart and update, and retry postponed updates (#5025) * feat(stop): warn players in-game before stop, restart and update, and retry postponed updates * fix(stop): exit when players prevent a stop during update or backup, keep module modes * fix(stop): mark variables shared between modules for shellcheck * refactor(stop): shorten check_players_online module description * refactor(stop): keep chat commands out of the config, clean up locks when a stop is cancelled, exit on CTRL-C * feat(stop): say why the player count is unavailable * fix(monitor): run postponed updates in the background, keep a long update's lockfile, retry forced updates as forced * fix(monitor): mark exitcode as used by core_exit for shellcheck --- .../config-lgsm/acserver/_default.cfg | 9 + .../config-lgsm/ahl2server/_default.cfg | 5 + .../config-lgsm/ahlserver/_default.cfg | 5 + .../config-lgsm/arkserver/_default.cfg | 5 + .../config-lgsm/arma3server/_default.cfg | 5 + .../config-lgsm/armarserver/_default.cfg | 5 + .../config-lgsm/atsserver/_default.cfg | 5 + .../config-lgsm/avserver/_default.cfg | 5 + .../config-lgsm/bb2server/_default.cfg | 5 + .../config-lgsm/bbserver/_default.cfg | 5 + .../config-lgsm/bdserver/_default.cfg | 5 + .../config-lgsm/bf1942server/_default.cfg | 5 + .../config-lgsm/bfvserver/_default.cfg | 5 + .../config-lgsm/bmdmserver/_default.cfg | 5 + .../config-lgsm/boserver/_default.cfg | 5 + .../config-lgsm/bsserver/_default.cfg | 5 + .../config-lgsm/btlserver/_default.cfg | 5 + .../config-lgsm/btserver/_default.cfg | 5 + .../config-lgsm/ccserver/_default.cfg | 5 + .../config-lgsm/ckserver/_default.cfg | 5 + .../config-lgsm/cmwserver/_default.cfg | 5 + .../config-lgsm/cod2server/_default.cfg | 5 + .../config-lgsm/cod4server/_default.cfg | 5 + .../config-lgsm/codserver/_default.cfg | 5 + .../config-lgsm/coduoserver/_default.cfg | 5 + .../config-lgsm/codwawserver/_default.cfg | 5 + .../config-lgsm/colserver/_default.cfg | 5 + .../config-lgsm/cs2server/_default.cfg | 5 + .../config-lgsm/csczserver/_default.cfg | 5 + .../config-lgsm/csgoserver/_default.cfg | 5 + .../config-lgsm/csserver/_default.cfg | 5 + .../config-lgsm/cssserver/_default.cfg | 5 + .../config-lgsm/ctserver/_default.cfg | 5 + .../config-lgsm/dabserver/_default.cfg | 5 + .../config-lgsm/dayzserver/_default.cfg | 5 + .../config-lgsm/dmcserver/_default.cfg | 5 + .../config-lgsm/dodrserver/_default.cfg | 5 + .../config-lgsm/dodserver/_default.cfg | 5 + .../config-lgsm/dodsserver/_default.cfg | 5 + .../config-lgsm/doiserver/_default.cfg | 5 + .../config-lgsm/dstserver/_default.cfg | 5 + .../config-lgsm/dysserver/_default.cfg | 5 + .../config-lgsm/ecoserver/_default.cfg | 5 + .../config-lgsm/emserver/_default.cfg | 5 + .../config-lgsm/etlserver/_default.cfg | 5 + .../config-lgsm/ets2server/_default.cfg | 5 + .../config-lgsm/fctrserver/_default.cfg | 5 + .../config-lgsm/fofserver/_default.cfg | 5 + .../config-lgsm/gmodserver/_default.cfg | 5 + .../config-lgsm/hcuserver/_default.cfg | 5 + .../config-lgsm/hl2dmserver/_default.cfg | 5 + .../config-lgsm/hldmserver/_default.cfg | 5 + .../config-lgsm/hldmsserver/_default.cfg | 5 + .../config-lgsm/hwserver/_default.cfg | 5 + .../config-lgsm/hytserver/_default.cfg | 9 + .../config-lgsm/hzserver/_default.cfg | 5 + .../config-lgsm/insserver/_default.cfg | 5 + .../config-lgsm/inssserver/_default.cfg | 5 + .../config-lgsm/iosserver/_default.cfg | 5 + .../config-lgsm/jbep3server/_default.cfg | 9 + .../config-lgsm/jc2server/_default.cfg | 5 + .../config-lgsm/jc3server/_default.cfg | 5 + .../config-lgsm/jk2server/_default.cfg | 5 + .../config-lgsm/kf2server/_default.cfg | 5 + .../config-lgsm/kfserver/_default.cfg | 5 + .../config-lgsm/l4d2server/_default.cfg | 5 + .../config-lgsm/l4dserver/_default.cfg | 5 + .../config-lgsm/mcbserver/_default.cfg | 5 + .../config-lgsm/mcserver/_default.cfg | 5 + .../config-lgsm/mcvserver/_default.cfg | 9 + .../config-lgsm/mhserver/_default.cfg | 5 + .../config-lgsm/mohaaserver/_default.cfg | 5 + .../config-lgsm/momserver/_default.cfg | 5 + .../config-lgsm/mtaserver/_default.cfg | 5 + .../config-lgsm/ndserver/_default.cfg | 5 + .../config-lgsm/necserver/_default.cfg | 5 + .../config-lgsm/nmrihserver/_default.cfg | 5 + .../config-lgsm/ns2cserver/_default.cfg | 5 + .../config-lgsm/ns2server/_default.cfg | 5 + .../config-lgsm/nsserver/_default.cfg | 5 + .../config-lgsm/ohdserver/_default.cfg | 5 + .../config-lgsm/onsetserver/_default.cfg | 5 + .../config-lgsm/opforserver/_default.cfg | 5 + .../config-lgsm/pc2server/_default.cfg | 5 + .../config-lgsm/pcserver/_default.cfg | 5 + .../config-lgsm/pmcserver/_default.cfg | 5 + .../config-lgsm/pvkiiserver/_default.cfg | 5 + .../config-lgsm/pvrserver/_default.cfg | 9 + .../config-lgsm/pwserver/_default.cfg | 5 + .../config-lgsm/pzserver/_default.cfg | 5 + .../config-lgsm/q2server/_default.cfg | 5 + .../config-lgsm/q3server/_default.cfg | 5 + .../config-lgsm/q4server/_default.cfg | 5 + .../config-lgsm/qlserver/_default.cfg | 5 + .../config-lgsm/qwserver/_default.cfg | 5 + .../config-lgsm/ricochetserver/_default.cfg | 5 + .../config-lgsm/roserver/_default.cfg | 5 + .../config-lgsm/rsdwserver/_default.cfg | 9 + .../config-lgsm/rtcwserver/_default.cfg | 5 + .../config-lgsm/rustserver/_default.cfg | 5 + .../config-lgsm/rwrserver/_default.cfg | 9 + .../config-lgsm/rwserver/_default.cfg | 5 + .../config-lgsm/sampserver/_default.cfg | 5 + .../config-lgsm/sbotsserver/_default.cfg | 5 + .../config-lgsm/sbserver/_default.cfg | 5 + .../config-lgsm/scpslserver/_default.cfg | 5 + .../config-lgsm/scpslsmserver/_default.cfg | 5 + .../config-lgsm/sdtdserver/_default.cfg | 5 + .../config-lgsm/sfcserver/_default.cfg | 5 + .../config-lgsm/sfserver/_default.cfg | 5 + .../config-lgsm/smserver/_default.cfg | 9 + .../config-lgsm/sof2server/_default.cfg | 5 + .../config-lgsm/solserver/_default.cfg | 5 + .../config-lgsm/squad44server/_default.cfg | 5 + .../config-lgsm/squadserver/_default.cfg | 5 + .../config-lgsm/stnserver/_default.cfg | 5 + .../config-lgsm/stserver/_default.cfg | 5 + .../config-lgsm/svenserver/_default.cfg | 5 + .../config-lgsm/terrariaserver/_default.cfg | 5 + .../config-lgsm/tf2cserver/_default.cfg | 9 + .../config-lgsm/tf2server/_default.cfg | 5 + .../config-lgsm/tfcserver/_default.cfg | 5 + .../config-lgsm/tfserver/_default.cfg | 5 + .../config-lgsm/tiserver/_default.cfg | 5 + .../config-lgsm/ts3server/_default.cfg | 5 + .../config-lgsm/tsserver/_default.cfg | 5 + .../config-lgsm/tuserver/_default.cfg | 5 + .../config-lgsm/twserver/_default.cfg | 5 + .../config-lgsm/untserver/_default.cfg | 5 + .../config-lgsm/ut2k4server/_default.cfg | 5 + .../config-lgsm/ut3server/_default.cfg | 5 + .../config-lgsm/ut99server/_default.cfg | 5 + .../config-lgsm/utserver/_default.cfg | 5 + .../config-lgsm/vhserver/_default.cfg | 5 + .../config-lgsm/vintsserver/_default.cfg | 5 + .../config-lgsm/vpmcserver/_default.cfg | 5 + .../config-lgsm/vsserver/_default.cfg | 5 + .../config-lgsm/wetserver/_default.cfg | 5 + .../config-lgsm/wfserver/_default.cfg | 5 + .../config-lgsm/wmcserver/_default.cfg | 5 + .../config-lgsm/wurmserver/_default.cfg | 5 + .../config-lgsm/xntserver/_default.cfg | 9 + .../config-lgsm/zmrserver/_default.cfg | 5 + .../config-lgsm/zpsserver/_default.cfg | 5 + lgsm/modules/check_players_online.sh | 33 ++-- lgsm/modules/command_backup.sh | 3 + lgsm/modules/command_monitor.sh | 38 +++- lgsm/modules/command_stop.sh | 185 +++++++++++++++++- lgsm/modules/command_update.sh | 4 + lgsm/modules/core_trap.sh | 5 + 150 files changed, 1010 insertions(+), 18 deletions(-) diff --git a/lgsm/config-default/config-lgsm/acserver/_default.cfg b/lgsm/config-default/config-lgsm/acserver/_default.cfg index 7ccebf181b..46453984b3 100644 --- a/lgsm/config-default/config-lgsm/acserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/acserver/_default.cfg @@ -99,6 +99,15 @@ telegramthreadid="" telegramsilentnotification="false" curlcustomstring="" +## Stop | https://docs.linuxgsm.com/commands/start-stop-restart +stoponlyifnoplayers="off" +stoponlyifnoplayersallcommands="on" + +## Player Warnings | https://docs.linuxgsm.com/features/player-warnings +# Minutes to warn players in-game before a stop, restart or update. 0 to disable. +# e.g. 15 warns at 15, 10, 5, 3 and 1 minutes. +warnplayerstimer="0" + ## Updating | https://docs.linuxgsm.com/commands/update updateonstart="off" diff --git a/lgsm/config-default/config-lgsm/ahl2server/_default.cfg b/lgsm/config-default/config-lgsm/ahl2server/_default.cfg index b955c4180d..81d68fa19a 100644 --- a/lgsm/config-default/config-lgsm/ahl2server/_default.cfg +++ b/lgsm/config-default/config-lgsm/ahl2server/_default.cfg @@ -111,6 +111,11 @@ curlcustomstring="" stoponlyifnoplayers="off" stoponlyifnoplayersallcommands="on" +## Player Warnings | https://docs.linuxgsm.com/features/player-warnings +# Minutes to warn players in-game before a stop, restart or update. 0 to disable. +# e.g. 15 warns at 15, 10, 5, 3 and 1 minutes. +warnplayerstimer="0" + ## Updating | https://docs.linuxgsm.com/commands/update updateonstart="off" diff --git a/lgsm/config-default/config-lgsm/ahlserver/_default.cfg b/lgsm/config-default/config-lgsm/ahlserver/_default.cfg index 6854d55cfc..4558e9f257 100644 --- a/lgsm/config-default/config-lgsm/ahlserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/ahlserver/_default.cfg @@ -106,6 +106,11 @@ curlcustomstring="" stoponlyifnoplayers="off" stoponlyifnoplayersallcommands="on" +## Player Warnings | https://docs.linuxgsm.com/features/player-warnings +# Minutes to warn players in-game before a stop, restart or update. 0 to disable. +# e.g. 15 warns at 15, 10, 5, 3 and 1 minutes. +warnplayerstimer="0" + ## Updating | https://docs.linuxgsm.com/commands/update updateonstart="off" diff --git a/lgsm/config-default/config-lgsm/arkserver/_default.cfg b/lgsm/config-default/config-lgsm/arkserver/_default.cfg index cc492f7b56..583f7e8bd9 100644 --- a/lgsm/config-default/config-lgsm/arkserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/arkserver/_default.cfg @@ -108,6 +108,11 @@ curlcustomstring="" stoponlyifnoplayers="off" stoponlyifnoplayersallcommands="on" +## Player Warnings | https://docs.linuxgsm.com/features/player-warnings +# Minutes to warn players in-game before a stop, restart or update. 0 to disable. +# e.g. 15 warns at 15, 10, 5, 3 and 1 minutes. +warnplayerstimer="0" + ## Updating | https://docs.linuxgsm.com/commands/update updateonstart="off" diff --git a/lgsm/config-default/config-lgsm/arma3server/_default.cfg b/lgsm/config-default/config-lgsm/arma3server/_default.cfg index 5351c46aab..31f9111108 100644 --- a/lgsm/config-default/config-lgsm/arma3server/_default.cfg +++ b/lgsm/config-default/config-lgsm/arma3server/_default.cfg @@ -129,6 +129,11 @@ curlcustomstring="" stoponlyifnoplayers="off" stoponlyifnoplayersallcommands="on" +## Player Warnings | https://docs.linuxgsm.com/features/player-warnings +# Minutes to warn players in-game before a stop, restart or update. 0 to disable. +# e.g. 15 warns at 15, 10, 5, 3 and 1 minutes. +warnplayerstimer="0" + ## Updating | https://docs.linuxgsm.com/commands/update updateonstart="off" diff --git a/lgsm/config-default/config-lgsm/armarserver/_default.cfg b/lgsm/config-default/config-lgsm/armarserver/_default.cfg index a6532146ff..a17fdf978b 100644 --- a/lgsm/config-default/config-lgsm/armarserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/armarserver/_default.cfg @@ -107,6 +107,11 @@ curlcustomstring="" stoponlyifnoplayers="off" stoponlyifnoplayersallcommands="on" +## Player Warnings | https://docs.linuxgsm.com/features/player-warnings +# Minutes to warn players in-game before a stop, restart or update. 0 to disable. +# e.g. 15 warns at 15, 10, 5, 3 and 1 minutes. +warnplayerstimer="0" + ## Updating | https://docs.linuxgsm.com/commands/update updateonstart="off" diff --git a/lgsm/config-default/config-lgsm/atsserver/_default.cfg b/lgsm/config-default/config-lgsm/atsserver/_default.cfg index 6b4b0807b1..04b2290861 100644 --- a/lgsm/config-default/config-lgsm/atsserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/atsserver/_default.cfg @@ -99,6 +99,11 @@ curlcustomstring="" stoponlyifnoplayers="off" stoponlyifnoplayersallcommands="on" +## Player Warnings | https://docs.linuxgsm.com/features/player-warnings +# Minutes to warn players in-game before a stop, restart or update. 0 to disable. +# e.g. 15 warns at 15, 10, 5, 3 and 1 minutes. +warnplayerstimer="0" + ## Updating | https://docs.linuxgsm.com/commands/update updateonstart="off" diff --git a/lgsm/config-default/config-lgsm/avserver/_default.cfg b/lgsm/config-default/config-lgsm/avserver/_default.cfg index 5668c8be3f..9319196511 100644 --- a/lgsm/config-default/config-lgsm/avserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/avserver/_default.cfg @@ -99,6 +99,11 @@ curlcustomstring="" stoponlyifnoplayers="off" stoponlyifnoplayersallcommands="on" +## Player Warnings | https://docs.linuxgsm.com/features/player-warnings +# Minutes to warn players in-game before a stop, restart or update. 0 to disable. +# e.g. 15 warns at 15, 10, 5, 3 and 1 minutes. +warnplayerstimer="0" + ## Updating | https://docs.linuxgsm.com/commands/update updateonstart="off" diff --git a/lgsm/config-default/config-lgsm/bb2server/_default.cfg b/lgsm/config-default/config-lgsm/bb2server/_default.cfg index ec113ed99f..1348d86905 100644 --- a/lgsm/config-default/config-lgsm/bb2server/_default.cfg +++ b/lgsm/config-default/config-lgsm/bb2server/_default.cfg @@ -112,6 +112,11 @@ curlcustomstring="" stoponlyifnoplayers="off" stoponlyifnoplayersallcommands="on" +## Player Warnings | https://docs.linuxgsm.com/features/player-warnings +# Minutes to warn players in-game before a stop, restart or update. 0 to disable. +# e.g. 15 warns at 15, 10, 5, 3 and 1 minutes. +warnplayerstimer="0" + ## Updating | https://docs.linuxgsm.com/commands/update updateonstart="off" diff --git a/lgsm/config-default/config-lgsm/bbserver/_default.cfg b/lgsm/config-default/config-lgsm/bbserver/_default.cfg index b3d7b75135..789853f747 100644 --- a/lgsm/config-default/config-lgsm/bbserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/bbserver/_default.cfg @@ -106,6 +106,11 @@ curlcustomstring="" stoponlyifnoplayers="off" stoponlyifnoplayersallcommands="on" +## Player Warnings | https://docs.linuxgsm.com/features/player-warnings +# Minutes to warn players in-game before a stop, restart or update. 0 to disable. +# e.g. 15 warns at 15, 10, 5, 3 and 1 minutes. +warnplayerstimer="0" + ## Updating | https://docs.linuxgsm.com/commands/update updateonstart="off" diff --git a/lgsm/config-default/config-lgsm/bdserver/_default.cfg b/lgsm/config-default/config-lgsm/bdserver/_default.cfg index 5144fd2586..83fc499e0c 100644 --- a/lgsm/config-default/config-lgsm/bdserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/bdserver/_default.cfg @@ -106,6 +106,11 @@ curlcustomstring="" stoponlyifnoplayers="off" stoponlyifnoplayersallcommands="on" +## Player Warnings | https://docs.linuxgsm.com/features/player-warnings +# Minutes to warn players in-game before a stop, restart or update. 0 to disable. +# e.g. 15 warns at 15, 10, 5, 3 and 1 minutes. +warnplayerstimer="0" + ## Updating | https://docs.linuxgsm.com/commands/update updateonstart="off" diff --git a/lgsm/config-default/config-lgsm/bf1942server/_default.cfg b/lgsm/config-default/config-lgsm/bf1942server/_default.cfg index 86363ccc53..158770c5a7 100644 --- a/lgsm/config-default/config-lgsm/bf1942server/_default.cfg +++ b/lgsm/config-default/config-lgsm/bf1942server/_default.cfg @@ -99,6 +99,11 @@ curlcustomstring="" stoponlyifnoplayers="off" stoponlyifnoplayersallcommands="on" +## Player Warnings | https://docs.linuxgsm.com/features/player-warnings +# Minutes to warn players in-game before a stop, restart or update. 0 to disable. +# e.g. 15 warns at 15, 10, 5, 3 and 1 minutes. +warnplayerstimer="0" + ## Updating | https://docs.linuxgsm.com/commands/update updateonstart="off" diff --git a/lgsm/config-default/config-lgsm/bfvserver/_default.cfg b/lgsm/config-default/config-lgsm/bfvserver/_default.cfg index 7fcfdd5ace..bb5e000970 100644 --- a/lgsm/config-default/config-lgsm/bfvserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/bfvserver/_default.cfg @@ -99,6 +99,11 @@ curlcustomstring="" stoponlyifnoplayers="off" stoponlyifnoplayersallcommands="on" +## Player Warnings | https://docs.linuxgsm.com/features/player-warnings +# Minutes to warn players in-game before a stop, restart or update. 0 to disable. +# e.g. 15 warns at 15, 10, 5, 3 and 1 minutes. +warnplayerstimer="0" + ## Updating | https://docs.linuxgsm.com/commands/update updateonstart="off" diff --git a/lgsm/config-default/config-lgsm/bmdmserver/_default.cfg b/lgsm/config-default/config-lgsm/bmdmserver/_default.cfg index 3bcdd5cb95..b3c738528e 100644 --- a/lgsm/config-default/config-lgsm/bmdmserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/bmdmserver/_default.cfg @@ -112,6 +112,11 @@ curlcustomstring="" stoponlyifnoplayers="off" stoponlyifnoplayersallcommands="on" +## Player Warnings | https://docs.linuxgsm.com/features/player-warnings +# Minutes to warn players in-game before a stop, restart or update. 0 to disable. +# e.g. 15 warns at 15, 10, 5, 3 and 1 minutes. +warnplayerstimer="0" + ## Updating | https://docs.linuxgsm.com/commands/update updateonstart="off" diff --git a/lgsm/config-default/config-lgsm/boserver/_default.cfg b/lgsm/config-default/config-lgsm/boserver/_default.cfg index 9d3110ccad..9246898ba2 100644 --- a/lgsm/config-default/config-lgsm/boserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/boserver/_default.cfg @@ -104,6 +104,11 @@ curlcustomstring="" stoponlyifnoplayers="off" stoponlyifnoplayersallcommands="on" +## Player Warnings | https://docs.linuxgsm.com/features/player-warnings +# Minutes to warn players in-game before a stop, restart or update. 0 to disable. +# e.g. 15 warns at 15, 10, 5, 3 and 1 minutes. +warnplayerstimer="0" + ## Updating | https://docs.linuxgsm.com/commands/update updateonstart="off" diff --git a/lgsm/config-default/config-lgsm/bsserver/_default.cfg b/lgsm/config-default/config-lgsm/bsserver/_default.cfg index 3ef7574a0e..599965e5af 100644 --- a/lgsm/config-default/config-lgsm/bsserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/bsserver/_default.cfg @@ -116,6 +116,11 @@ curlcustomstring="" stoponlyifnoplayers="off" stoponlyifnoplayersallcommands="on" +## Player Warnings | https://docs.linuxgsm.com/features/player-warnings +# Minutes to warn players in-game before a stop, restart or update. 0 to disable. +# e.g. 15 warns at 15, 10, 5, 3 and 1 minutes. +warnplayerstimer="0" + ## Updating | https://docs.linuxgsm.com/commands/update updateonstart="off" diff --git a/lgsm/config-default/config-lgsm/btlserver/_default.cfg b/lgsm/config-default/config-lgsm/btlserver/_default.cfg index 7e936b1f77..59d68eb51a 100644 --- a/lgsm/config-default/config-lgsm/btlserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/btlserver/_default.cfg @@ -104,6 +104,11 @@ curlcustomstring="" stoponlyifnoplayers="off" stoponlyifnoplayersallcommands="on" +## Player Warnings | https://docs.linuxgsm.com/features/player-warnings +# Minutes to warn players in-game before a stop, restart or update. 0 to disable. +# e.g. 15 warns at 15, 10, 5, 3 and 1 minutes. +warnplayerstimer="0" + ## Updating | https://docs.linuxgsm.com/commands/update updateonstart="off" diff --git a/lgsm/config-default/config-lgsm/btserver/_default.cfg b/lgsm/config-default/config-lgsm/btserver/_default.cfg index a950676e71..f7dc2a116c 100644 --- a/lgsm/config-default/config-lgsm/btserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/btserver/_default.cfg @@ -105,6 +105,11 @@ curlcustomstring="" stoponlyifnoplayers="off" stoponlyifnoplayersallcommands="on" +## Player Warnings | https://docs.linuxgsm.com/features/player-warnings +# Minutes to warn players in-game before a stop, restart or update. 0 to disable. +# e.g. 15 warns at 15, 10, 5, 3 and 1 minutes. +warnplayerstimer="0" + ## Updating | https://docs.linuxgsm.com/commands/update updateonstart="off" diff --git a/lgsm/config-default/config-lgsm/ccserver/_default.cfg b/lgsm/config-default/config-lgsm/ccserver/_default.cfg index 86eaa9d155..f55339bffa 100644 --- a/lgsm/config-default/config-lgsm/ccserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/ccserver/_default.cfg @@ -107,6 +107,11 @@ curlcustomstring="" stoponlyifnoplayers="off" stoponlyifnoplayersallcommands="on" +## Player Warnings | https://docs.linuxgsm.com/features/player-warnings +# Minutes to warn players in-game before a stop, restart or update. 0 to disable. +# e.g. 15 warns at 15, 10, 5, 3 and 1 minutes. +warnplayerstimer="0" + ## Updating | https://docs.linuxgsm.com/commands/update updateonstart="off" diff --git a/lgsm/config-default/config-lgsm/ckserver/_default.cfg b/lgsm/config-default/config-lgsm/ckserver/_default.cfg index b238c21480..de6b248f91 100644 --- a/lgsm/config-default/config-lgsm/ckserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/ckserver/_default.cfg @@ -103,6 +103,11 @@ curlcustomstring="" stoponlyifnoplayers="off" stoponlyifnoplayersallcommands="on" +## Player Warnings | https://docs.linuxgsm.com/features/player-warnings +# Minutes to warn players in-game before a stop, restart or update. 0 to disable. +# e.g. 15 warns at 15, 10, 5, 3 and 1 minutes. +warnplayerstimer="0" + ## Updating | https://docs.linuxgsm.com/commands/update updateonstart="off" diff --git a/lgsm/config-default/config-lgsm/cmwserver/_default.cfg b/lgsm/config-default/config-lgsm/cmwserver/_default.cfg index 110013f89a..f6812662c1 100644 --- a/lgsm/config-default/config-lgsm/cmwserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/cmwserver/_default.cfg @@ -105,6 +105,11 @@ curlcustomstring="" stoponlyifnoplayers="off" stoponlyifnoplayersallcommands="on" +## Player Warnings | https://docs.linuxgsm.com/features/player-warnings +# Minutes to warn players in-game before a stop, restart or update. 0 to disable. +# e.g. 15 warns at 15, 10, 5, 3 and 1 minutes. +warnplayerstimer="0" + ## Updating | https://docs.linuxgsm.com/commands/update updateonstart="off" diff --git a/lgsm/config-default/config-lgsm/cod2server/_default.cfg b/lgsm/config-default/config-lgsm/cod2server/_default.cfg index 6a71c82e16..199907018e 100644 --- a/lgsm/config-default/config-lgsm/cod2server/_default.cfg +++ b/lgsm/config-default/config-lgsm/cod2server/_default.cfg @@ -105,6 +105,11 @@ curlcustomstring="" stoponlyifnoplayers="off" stoponlyifnoplayersallcommands="on" +## Player Warnings | https://docs.linuxgsm.com/features/player-warnings +# Minutes to warn players in-game before a stop, restart or update. 0 to disable. +# e.g. 15 warns at 15, 10, 5, 3 and 1 minutes. +warnplayerstimer="0" + ## Backup | https://docs.linuxgsm.com/commands/backup maxbackups="4" maxbackupdays="30" diff --git a/lgsm/config-default/config-lgsm/cod4server/_default.cfg b/lgsm/config-default/config-lgsm/cod4server/_default.cfg index 5c6f94cadd..4476697f97 100644 --- a/lgsm/config-default/config-lgsm/cod4server/_default.cfg +++ b/lgsm/config-default/config-lgsm/cod4server/_default.cfg @@ -105,6 +105,11 @@ curlcustomstring="" stoponlyifnoplayers="off" stoponlyifnoplayersallcommands="on" +## Player Warnings | https://docs.linuxgsm.com/features/player-warnings +# Minutes to warn players in-game before a stop, restart or update. 0 to disable. +# e.g. 15 warns at 15, 10, 5, 3 and 1 minutes. +warnplayerstimer="0" + ## Backup | https://docs.linuxgsm.com/commands/backup maxbackups="4" maxbackupdays="30" diff --git a/lgsm/config-default/config-lgsm/codserver/_default.cfg b/lgsm/config-default/config-lgsm/codserver/_default.cfg index f00600e40c..07568a3356 100644 --- a/lgsm/config-default/config-lgsm/codserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/codserver/_default.cfg @@ -105,6 +105,11 @@ curlcustomstring="" stoponlyifnoplayers="off" stoponlyifnoplayersallcommands="on" +## Player Warnings | https://docs.linuxgsm.com/features/player-warnings +# Minutes to warn players in-game before a stop, restart or update. 0 to disable. +# e.g. 15 warns at 15, 10, 5, 3 and 1 minutes. +warnplayerstimer="0" + ## Backup | https://docs.linuxgsm.com/commands/backup maxbackups="4" maxbackupdays="30" diff --git a/lgsm/config-default/config-lgsm/coduoserver/_default.cfg b/lgsm/config-default/config-lgsm/coduoserver/_default.cfg index 5fc7d9816d..97107dcbe1 100644 --- a/lgsm/config-default/config-lgsm/coduoserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/coduoserver/_default.cfg @@ -105,6 +105,11 @@ curlcustomstring="" stoponlyifnoplayers="off" stoponlyifnoplayersallcommands="on" +## Player Warnings | https://docs.linuxgsm.com/features/player-warnings +# Minutes to warn players in-game before a stop, restart or update. 0 to disable. +# e.g. 15 warns at 15, 10, 5, 3 and 1 minutes. +warnplayerstimer="0" + ## Backup | https://docs.linuxgsm.com/commands/backup maxbackups="4" maxbackupdays="30" diff --git a/lgsm/config-default/config-lgsm/codwawserver/_default.cfg b/lgsm/config-default/config-lgsm/codwawserver/_default.cfg index 337787fdec..b5b7519601 100644 --- a/lgsm/config-default/config-lgsm/codwawserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/codwawserver/_default.cfg @@ -105,6 +105,11 @@ curlcustomstring="" stoponlyifnoplayers="off" stoponlyifnoplayersallcommands="on" +## Player Warnings | https://docs.linuxgsm.com/features/player-warnings +# Minutes to warn players in-game before a stop, restart or update. 0 to disable. +# e.g. 15 warns at 15, 10, 5, 3 and 1 minutes. +warnplayerstimer="0" + ## Backup | https://docs.linuxgsm.com/commands/backup maxbackups="4" maxbackupdays="30" diff --git a/lgsm/config-default/config-lgsm/colserver/_default.cfg b/lgsm/config-default/config-lgsm/colserver/_default.cfg index 45287684ad..1afd55b028 100644 --- a/lgsm/config-default/config-lgsm/colserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/colserver/_default.cfg @@ -112,6 +112,11 @@ curlcustomstring="" stoponlyifnoplayers="off" stoponlyifnoplayersallcommands="on" +## Player Warnings | https://docs.linuxgsm.com/features/player-warnings +# Minutes to warn players in-game before a stop, restart or update. 0 to disable. +# e.g. 15 warns at 15, 10, 5, 3 and 1 minutes. +warnplayerstimer="0" + ## Updating | https://docs.linuxgsm.com/commands/update updateonstart="off" diff --git a/lgsm/config-default/config-lgsm/cs2server/_default.cfg b/lgsm/config-default/config-lgsm/cs2server/_default.cfg index 81d1cb7edb..4a0a0fc4c9 100644 --- a/lgsm/config-default/config-lgsm/cs2server/_default.cfg +++ b/lgsm/config-default/config-lgsm/cs2server/_default.cfg @@ -111,6 +111,11 @@ curlcustomstring="" stoponlyifnoplayers="off" stoponlyifnoplayersallcommands="on" +## Player Warnings | https://docs.linuxgsm.com/features/player-warnings +# Minutes to warn players in-game before a stop, restart or update. 0 to disable. +# e.g. 15 warns at 15, 10, 5, 3 and 1 minutes. +warnplayerstimer="0" + ## Updating | https://docs.linuxgsm.com/commands/update updateonstart="off" diff --git a/lgsm/config-default/config-lgsm/csczserver/_default.cfg b/lgsm/config-default/config-lgsm/csczserver/_default.cfg index 531e897adc..184b72104d 100644 --- a/lgsm/config-default/config-lgsm/csczserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/csczserver/_default.cfg @@ -106,6 +106,11 @@ curlcustomstring="" stoponlyifnoplayers="off" stoponlyifnoplayersallcommands="on" +## Player Warnings | https://docs.linuxgsm.com/features/player-warnings +# Minutes to warn players in-game before a stop, restart or update. 0 to disable. +# e.g. 15 warns at 15, 10, 5, 3 and 1 minutes. +warnplayerstimer="0" + ## Updating | https://docs.linuxgsm.com/commands/update updateonstart="off" diff --git a/lgsm/config-default/config-lgsm/csgoserver/_default.cfg b/lgsm/config-default/config-lgsm/csgoserver/_default.cfg index d7d32cc025..0b459fba5f 100644 --- a/lgsm/config-default/config-lgsm/csgoserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/csgoserver/_default.cfg @@ -144,6 +144,11 @@ curlcustomstring="" stoponlyifnoplayers="off" stoponlyifnoplayersallcommands="on" +## Player Warnings | https://docs.linuxgsm.com/features/player-warnings +# Minutes to warn players in-game before a stop, restart or update. 0 to disable. +# e.g. 15 warns at 15, 10, 5, 3 and 1 minutes. +warnplayerstimer="0" + ## Updating | https://docs.linuxgsm.com/commands/update updateonstart="off" diff --git a/lgsm/config-default/config-lgsm/csserver/_default.cfg b/lgsm/config-default/config-lgsm/csserver/_default.cfg index 4e598cd164..61bf0c040c 100644 --- a/lgsm/config-default/config-lgsm/csserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/csserver/_default.cfg @@ -106,6 +106,11 @@ curlcustomstring="" stoponlyifnoplayers="off" stoponlyifnoplayersallcommands="on" +## Player Warnings | https://docs.linuxgsm.com/features/player-warnings +# Minutes to warn players in-game before a stop, restart or update. 0 to disable. +# e.g. 15 warns at 15, 10, 5, 3 and 1 minutes. +warnplayerstimer="0" + ## Updating | https://docs.linuxgsm.com/commands/update updateonstart="off" diff --git a/lgsm/config-default/config-lgsm/cssserver/_default.cfg b/lgsm/config-default/config-lgsm/cssserver/_default.cfg index ce79d31474..1a2aefc10d 100644 --- a/lgsm/config-default/config-lgsm/cssserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/cssserver/_default.cfg @@ -112,6 +112,11 @@ curlcustomstring="" stoponlyifnoplayers="off" stoponlyifnoplayersallcommands="on" +## Player Warnings | https://docs.linuxgsm.com/features/player-warnings +# Minutes to warn players in-game before a stop, restart or update. 0 to disable. +# e.g. 15 warns at 15, 10, 5, 3 and 1 minutes. +warnplayerstimer="0" + ## Updating | https://docs.linuxgsm.com/commands/update updateonstart="off" diff --git a/lgsm/config-default/config-lgsm/ctserver/_default.cfg b/lgsm/config-default/config-lgsm/ctserver/_default.cfg index e32f65fa4b..c56a7bf481 100644 --- a/lgsm/config-default/config-lgsm/ctserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/ctserver/_default.cfg @@ -99,6 +99,11 @@ curlcustomstring="" stoponlyifnoplayers="off" stoponlyifnoplayersallcommands="on" +## Player Warnings | https://docs.linuxgsm.com/features/player-warnings +# Minutes to warn players in-game before a stop, restart or update. 0 to disable. +# e.g. 15 warns at 15, 10, 5, 3 and 1 minutes. +warnplayerstimer="0" + ## Updating | https://docs.linuxgsm.com/commands/update updateonstart="off" diff --git a/lgsm/config-default/config-lgsm/dabserver/_default.cfg b/lgsm/config-default/config-lgsm/dabserver/_default.cfg index 575c163cfd..a14c5cafb5 100644 --- a/lgsm/config-default/config-lgsm/dabserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/dabserver/_default.cfg @@ -107,6 +107,11 @@ curlcustomstring="" stoponlyifnoplayers="off" stoponlyifnoplayersallcommands="on" +## Player Warnings | https://docs.linuxgsm.com/features/player-warnings +# Minutes to warn players in-game before a stop, restart or update. 0 to disable. +# e.g. 15 warns at 15, 10, 5, 3 and 1 minutes. +warnplayerstimer="0" + ## Updating | https://docs.linuxgsm.com/commands/update updateonstart="off" diff --git a/lgsm/config-default/config-lgsm/dayzserver/_default.cfg b/lgsm/config-default/config-lgsm/dayzserver/_default.cfg index 4fc6307594..20f2132072 100644 --- a/lgsm/config-default/config-lgsm/dayzserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/dayzserver/_default.cfg @@ -129,6 +129,11 @@ curlcustomstring="" stoponlyifnoplayers="off" stoponlyifnoplayersallcommands="on" +## Player Warnings | https://docs.linuxgsm.com/features/player-warnings +# Minutes to warn players in-game before a stop, restart or update. 0 to disable. +# e.g. 15 warns at 15, 10, 5, 3 and 1 minutes. +warnplayerstimer="0" + ## Updating | https://docs.linuxgsm.com/commands/update updateonstart="off" diff --git a/lgsm/config-default/config-lgsm/dmcserver/_default.cfg b/lgsm/config-default/config-lgsm/dmcserver/_default.cfg index b7f80ade0b..910c83b9bc 100644 --- a/lgsm/config-default/config-lgsm/dmcserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/dmcserver/_default.cfg @@ -106,6 +106,11 @@ curlcustomstring="" stoponlyifnoplayers="off" stoponlyifnoplayersallcommands="on" +## Player Warnings | https://docs.linuxgsm.com/features/player-warnings +# Minutes to warn players in-game before a stop, restart or update. 0 to disable. +# e.g. 15 warns at 15, 10, 5, 3 and 1 minutes. +warnplayerstimer="0" + ## Updating | https://docs.linuxgsm.com/commands/update updateonstart="off" diff --git a/lgsm/config-default/config-lgsm/dodrserver/_default.cfg b/lgsm/config-default/config-lgsm/dodrserver/_default.cfg index 947ee2dab4..655611e6f3 100644 --- a/lgsm/config-default/config-lgsm/dodrserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/dodrserver/_default.cfg @@ -105,6 +105,11 @@ curlcustomstring="" stoponlyifnoplayers="off" stoponlyifnoplayersallcommands="on" +## Player Warnings | https://docs.linuxgsm.com/features/player-warnings +# Minutes to warn players in-game before a stop, restart or update. 0 to disable. +# e.g. 15 warns at 15, 10, 5, 3 and 1 minutes. +warnplayerstimer="0" + ## Updating | https://docs.linuxgsm.com/commands/update updateonstart="off" diff --git a/lgsm/config-default/config-lgsm/dodserver/_default.cfg b/lgsm/config-default/config-lgsm/dodserver/_default.cfg index 6d1f1e28e3..cf0d03a7c2 100644 --- a/lgsm/config-default/config-lgsm/dodserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/dodserver/_default.cfg @@ -106,6 +106,11 @@ curlcustomstring="" stoponlyifnoplayers="off" stoponlyifnoplayersallcommands="on" +## Player Warnings | https://docs.linuxgsm.com/features/player-warnings +# Minutes to warn players in-game before a stop, restart or update. 0 to disable. +# e.g. 15 warns at 15, 10, 5, 3 and 1 minutes. +warnplayerstimer="0" + ## Updating | https://docs.linuxgsm.com/commands/update updateonstart="off" diff --git a/lgsm/config-default/config-lgsm/dodsserver/_default.cfg b/lgsm/config-default/config-lgsm/dodsserver/_default.cfg index dc1e162e1f..aa9f24e872 100644 --- a/lgsm/config-default/config-lgsm/dodsserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/dodsserver/_default.cfg @@ -107,6 +107,11 @@ curlcustomstring="" stoponlyifnoplayers="off" stoponlyifnoplayersallcommands="on" +## Player Warnings | https://docs.linuxgsm.com/features/player-warnings +# Minutes to warn players in-game before a stop, restart or update. 0 to disable. +# e.g. 15 warns at 15, 10, 5, 3 and 1 minutes. +warnplayerstimer="0" + ## Updating | https://docs.linuxgsm.com/commands/update updateonstart="off" diff --git a/lgsm/config-default/config-lgsm/doiserver/_default.cfg b/lgsm/config-default/config-lgsm/doiserver/_default.cfg index 58b31c2066..b38c33cf28 100644 --- a/lgsm/config-default/config-lgsm/doiserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/doiserver/_default.cfg @@ -108,6 +108,11 @@ curlcustomstring="" stoponlyifnoplayers="off" stoponlyifnoplayersallcommands="on" +## Player Warnings | https://docs.linuxgsm.com/features/player-warnings +# Minutes to warn players in-game before a stop, restart or update. 0 to disable. +# e.g. 15 warns at 15, 10, 5, 3 and 1 minutes. +warnplayerstimer="0" + ## Updating | https://docs.linuxgsm.com/commands/update updateonstart="off" diff --git a/lgsm/config-default/config-lgsm/dstserver/_default.cfg b/lgsm/config-default/config-lgsm/dstserver/_default.cfg index 489f748c79..c0d0882ba9 100644 --- a/lgsm/config-default/config-lgsm/dstserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/dstserver/_default.cfg @@ -109,6 +109,11 @@ curlcustomstring="" stoponlyifnoplayers="off" stoponlyifnoplayersallcommands="on" +## Player Warnings | https://docs.linuxgsm.com/features/player-warnings +# Minutes to warn players in-game before a stop, restart or update. 0 to disable. +# e.g. 15 warns at 15, 10, 5, 3 and 1 minutes. +warnplayerstimer="0" + ## Updating | https://docs.linuxgsm.com/commands/update updateonstart="off" diff --git a/lgsm/config-default/config-lgsm/dysserver/_default.cfg b/lgsm/config-default/config-lgsm/dysserver/_default.cfg index 0c7fe66e3f..03bec8e5c8 100644 --- a/lgsm/config-default/config-lgsm/dysserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/dysserver/_default.cfg @@ -112,6 +112,11 @@ curlcustomstring="" stoponlyifnoplayers="off" stoponlyifnoplayersallcommands="on" +## Player Warnings | https://docs.linuxgsm.com/features/player-warnings +# Minutes to warn players in-game before a stop, restart or update. 0 to disable. +# e.g. 15 warns at 15, 10, 5, 3 and 1 minutes. +warnplayerstimer="0" + ## Updating | https://docs.linuxgsm.com/commands/update updateonstart="off" diff --git a/lgsm/config-default/config-lgsm/ecoserver/_default.cfg b/lgsm/config-default/config-lgsm/ecoserver/_default.cfg index af9bde4591..522b8f8f6e 100644 --- a/lgsm/config-default/config-lgsm/ecoserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/ecoserver/_default.cfg @@ -102,6 +102,11 @@ curlcustomstring="" stoponlyifnoplayers="off" stoponlyifnoplayersallcommands="on" +## Player Warnings | https://docs.linuxgsm.com/features/player-warnings +# Minutes to warn players in-game before a stop, restart or update. 0 to disable. +# e.g. 15 warns at 15, 10, 5, 3 and 1 minutes. +warnplayerstimer="0" + ## Updating | https://docs.linuxgsm.com/commands/update updateonstart="off" diff --git a/lgsm/config-default/config-lgsm/emserver/_default.cfg b/lgsm/config-default/config-lgsm/emserver/_default.cfg index fe02f4434e..144e58a494 100644 --- a/lgsm/config-default/config-lgsm/emserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/emserver/_default.cfg @@ -112,6 +112,11 @@ curlcustomstring="" stoponlyifnoplayers="off" stoponlyifnoplayersallcommands="on" +## Player Warnings | https://docs.linuxgsm.com/features/player-warnings +# Minutes to warn players in-game before a stop, restart or update. 0 to disable. +# e.g. 15 warns at 15, 10, 5, 3 and 1 minutes. +warnplayerstimer="0" + ## Updating | https://docs.linuxgsm.com/commands/update updateonstart="off" diff --git a/lgsm/config-default/config-lgsm/etlserver/_default.cfg b/lgsm/config-default/config-lgsm/etlserver/_default.cfg index 6dd1ccb1ef..2bf1eb3dba 100644 --- a/lgsm/config-default/config-lgsm/etlserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/etlserver/_default.cfg @@ -99,6 +99,11 @@ curlcustomstring="" stoponlyifnoplayers="off" stoponlyifnoplayersallcommands="on" +## Player Warnings | https://docs.linuxgsm.com/features/player-warnings +# Minutes to warn players in-game before a stop, restart or update. 0 to disable. +# e.g. 15 warns at 15, 10, 5, 3 and 1 minutes. +warnplayerstimer="0" + ## Backup | https://docs.linuxgsm.com/commands/backup maxbackups="4" maxbackupdays="30" diff --git a/lgsm/config-default/config-lgsm/ets2server/_default.cfg b/lgsm/config-default/config-lgsm/ets2server/_default.cfg index 4b8095c87a..c65803e5dd 100644 --- a/lgsm/config-default/config-lgsm/ets2server/_default.cfg +++ b/lgsm/config-default/config-lgsm/ets2server/_default.cfg @@ -99,6 +99,11 @@ curlcustomstring="" stoponlyifnoplayers="off" stoponlyifnoplayersallcommands="on" +## Player Warnings | https://docs.linuxgsm.com/features/player-warnings +# Minutes to warn players in-game before a stop, restart or update. 0 to disable. +# e.g. 15 warns at 15, 10, 5, 3 and 1 minutes. +warnplayerstimer="0" + ## Updating | https://docs.linuxgsm.com/commands/update updateonstart="off" diff --git a/lgsm/config-default/config-lgsm/fctrserver/_default.cfg b/lgsm/config-default/config-lgsm/fctrserver/_default.cfg index 34d86d3ac0..08f751b8f0 100644 --- a/lgsm/config-default/config-lgsm/fctrserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/fctrserver/_default.cfg @@ -106,6 +106,11 @@ curlcustomstring="" stoponlyifnoplayers="off" stoponlyifnoplayersallcommands="on" +## Player Warnings | https://docs.linuxgsm.com/features/player-warnings +# Minutes to warn players in-game before a stop, restart or update. 0 to disable. +# e.g. 15 warns at 15, 10, 5, 3 and 1 minutes. +warnplayerstimer="0" + ## Updating | https://docs.linuxgsm.com/commands/update updateonstart="off" diff --git a/lgsm/config-default/config-lgsm/fofserver/_default.cfg b/lgsm/config-default/config-lgsm/fofserver/_default.cfg index 926b95b050..86087fbf3e 100644 --- a/lgsm/config-default/config-lgsm/fofserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/fofserver/_default.cfg @@ -107,6 +107,11 @@ curlcustomstring="" stoponlyifnoplayers="off" stoponlyifnoplayersallcommands="on" +## Player Warnings | https://docs.linuxgsm.com/features/player-warnings +# Minutes to warn players in-game before a stop, restart or update. 0 to disable. +# e.g. 15 warns at 15, 10, 5, 3 and 1 minutes. +warnplayerstimer="0" + ## Updating | https://docs.linuxgsm.com/commands/update updateonstart="off" diff --git a/lgsm/config-default/config-lgsm/gmodserver/_default.cfg b/lgsm/config-default/config-lgsm/gmodserver/_default.cfg index ca2ad6be72..eebbe366a5 100644 --- a/lgsm/config-default/config-lgsm/gmodserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/gmodserver/_default.cfg @@ -117,6 +117,11 @@ curlcustomstring="" stoponlyifnoplayers="off" stoponlyifnoplayersallcommands="on" +## Player Warnings | https://docs.linuxgsm.com/features/player-warnings +# Minutes to warn players in-game before a stop, restart or update. 0 to disable. +# e.g. 15 warns at 15, 10, 5, 3 and 1 minutes. +warnplayerstimer="0" + ## Updating | https://docs.linuxgsm.com/commands/update updateonstart="off" diff --git a/lgsm/config-default/config-lgsm/hcuserver/_default.cfg b/lgsm/config-default/config-lgsm/hcuserver/_default.cfg index c0fdcc630d..c389135246 100644 --- a/lgsm/config-default/config-lgsm/hcuserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/hcuserver/_default.cfg @@ -114,6 +114,11 @@ curlcustomstring="" stoponlyifnoplayers="off" stoponlyifnoplayersallcommands="on" +## Player Warnings | https://docs.linuxgsm.com/features/player-warnings +# Minutes to warn players in-game before a stop, restart or update. 0 to disable. +# e.g. 15 warns at 15, 10, 5, 3 and 1 minutes. +warnplayerstimer="0" + ## Updating | https://docs.linuxgsm.com/commands/update updateonstart="off" diff --git a/lgsm/config-default/config-lgsm/hl2dmserver/_default.cfg b/lgsm/config-default/config-lgsm/hl2dmserver/_default.cfg index 2e9afaec11..45ed3b7eb0 100644 --- a/lgsm/config-default/config-lgsm/hl2dmserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/hl2dmserver/_default.cfg @@ -109,6 +109,11 @@ curlcustomstring="" stoponlyifnoplayers="off" stoponlyifnoplayersallcommands="on" +## Player Warnings | https://docs.linuxgsm.com/features/player-warnings +# Minutes to warn players in-game before a stop, restart or update. 0 to disable. +# e.g. 15 warns at 15, 10, 5, 3 and 1 minutes. +warnplayerstimer="0" + ## Updating | https://docs.linuxgsm.com/commands/update updateonstart="off" diff --git a/lgsm/config-default/config-lgsm/hldmserver/_default.cfg b/lgsm/config-default/config-lgsm/hldmserver/_default.cfg index 697341250d..f917bcdb17 100644 --- a/lgsm/config-default/config-lgsm/hldmserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/hldmserver/_default.cfg @@ -106,6 +106,11 @@ curlcustomstring="" stoponlyifnoplayers="off" stoponlyifnoplayersallcommands="on" +## Player Warnings | https://docs.linuxgsm.com/features/player-warnings +# Minutes to warn players in-game before a stop, restart or update. 0 to disable. +# e.g. 15 warns at 15, 10, 5, 3 and 1 minutes. +warnplayerstimer="0" + ## Updating | https://docs.linuxgsm.com/commands/update updateonstart="off" diff --git a/lgsm/config-default/config-lgsm/hldmsserver/_default.cfg b/lgsm/config-default/config-lgsm/hldmsserver/_default.cfg index 6f2d90fb42..52436737b9 100644 --- a/lgsm/config-default/config-lgsm/hldmsserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/hldmsserver/_default.cfg @@ -107,6 +107,11 @@ curlcustomstring="" stoponlyifnoplayers="off" stoponlyifnoplayersallcommands="on" +## Player Warnings | https://docs.linuxgsm.com/features/player-warnings +# Minutes to warn players in-game before a stop, restart or update. 0 to disable. +# e.g. 15 warns at 15, 10, 5, 3 and 1 minutes. +warnplayerstimer="0" + ## Updating | https://docs.linuxgsm.com/commands/update updateonstart="off" diff --git a/lgsm/config-default/config-lgsm/hwserver/_default.cfg b/lgsm/config-default/config-lgsm/hwserver/_default.cfg index 56d455910e..2dab091f68 100644 --- a/lgsm/config-default/config-lgsm/hwserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/hwserver/_default.cfg @@ -124,6 +124,11 @@ curlcustomstring="" stoponlyifnoplayers="off" stoponlyifnoplayersallcommands="on" +## Player Warnings | https://docs.linuxgsm.com/features/player-warnings +# Minutes to warn players in-game before a stop, restart or update. 0 to disable. +# e.g. 15 warns at 15, 10, 5, 3 and 1 minutes. +warnplayerstimer="0" + ## Updating | https://docs.linuxgsm.com/commands/update updateonstart="off" diff --git a/lgsm/config-default/config-lgsm/hytserver/_default.cfg b/lgsm/config-default/config-lgsm/hytserver/_default.cfg index 16ff695d50..074e24b3bd 100644 --- a/lgsm/config-default/config-lgsm/hytserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/hytserver/_default.cfg @@ -104,6 +104,15 @@ telegramthreadid="" telegramsilentnotification="false" curlcustomstring="" +## Stop | https://docs.linuxgsm.com/commands/start-stop-restart +stoponlyifnoplayers="off" +stoponlyifnoplayersallcommands="on" + +## Player Warnings | https://docs.linuxgsm.com/features/player-warnings +# Minutes to warn players in-game before a stop, restart or update. 0 to disable. +# e.g. 15 warns at 15, 10, 5, 3 and 1 minutes. +warnplayerstimer="0" + ## Updating | https://docs.linuxgsm.com/commands/update updateonstart="off" diff --git a/lgsm/config-default/config-lgsm/hzserver/_default.cfg b/lgsm/config-default/config-lgsm/hzserver/_default.cfg index 32fb9d6cd2..9653944b75 100644 --- a/lgsm/config-default/config-lgsm/hzserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/hzserver/_default.cfg @@ -102,6 +102,11 @@ curlcustomstring="" stoponlyifnoplayers="off" stoponlyifnoplayersallcommands="on" +## Player Warnings | https://docs.linuxgsm.com/features/player-warnings +# Minutes to warn players in-game before a stop, restart or update. 0 to disable. +# e.g. 15 warns at 15, 10, 5, 3 and 1 minutes. +warnplayerstimer="0" + ## Updating | https://docs.linuxgsm.com/commands/update updateonstart="off" diff --git a/lgsm/config-default/config-lgsm/insserver/_default.cfg b/lgsm/config-default/config-lgsm/insserver/_default.cfg index afa7f7f270..335e7a99b2 100644 --- a/lgsm/config-default/config-lgsm/insserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/insserver/_default.cfg @@ -113,6 +113,11 @@ curlcustomstring="" stoponlyifnoplayers="off" stoponlyifnoplayersallcommands="on" +## Player Warnings | https://docs.linuxgsm.com/features/player-warnings +# Minutes to warn players in-game before a stop, restart or update. 0 to disable. +# e.g. 15 warns at 15, 10, 5, 3 and 1 minutes. +warnplayerstimer="0" + ## Updating | https://docs.linuxgsm.com/commands/update updateonstart="off" diff --git a/lgsm/config-default/config-lgsm/inssserver/_default.cfg b/lgsm/config-default/config-lgsm/inssserver/_default.cfg index 27974e8a0c..d854cbc0db 100644 --- a/lgsm/config-default/config-lgsm/inssserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/inssserver/_default.cfg @@ -116,6 +116,11 @@ curlcustomstring="" stoponlyifnoplayers="off" stoponlyifnoplayersallcommands="on" +## Player Warnings | https://docs.linuxgsm.com/features/player-warnings +# Minutes to warn players in-game before a stop, restart or update. 0 to disable. +# e.g. 15 warns at 15, 10, 5, 3 and 1 minutes. +warnplayerstimer="0" + ## Updating | https://docs.linuxgsm.com/commands/update updateonstart="off" diff --git a/lgsm/config-default/config-lgsm/iosserver/_default.cfg b/lgsm/config-default/config-lgsm/iosserver/_default.cfg index f091c4f48e..7c844ddf53 100644 --- a/lgsm/config-default/config-lgsm/iosserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/iosserver/_default.cfg @@ -107,6 +107,11 @@ curlcustomstring="" stoponlyifnoplayers="off" stoponlyifnoplayersallcommands="on" +## Player Warnings | https://docs.linuxgsm.com/features/player-warnings +# Minutes to warn players in-game before a stop, restart or update. 0 to disable. +# e.g. 15 warns at 15, 10, 5, 3 and 1 minutes. +warnplayerstimer="0" + ## Updating | https://docs.linuxgsm.com/commands/update updateonstart="off" diff --git a/lgsm/config-default/config-lgsm/jbep3server/_default.cfg b/lgsm/config-default/config-lgsm/jbep3server/_default.cfg index 2036d3522a..9894833644 100644 --- a/lgsm/config-default/config-lgsm/jbep3server/_default.cfg +++ b/lgsm/config-default/config-lgsm/jbep3server/_default.cfg @@ -97,6 +97,15 @@ telegramthreadid="" telegramsilentnotification="false" curlcustomstring="" +## Stop | https://docs.linuxgsm.com/commands/start-stop-restart +stoponlyifnoplayers="off" +stoponlyifnoplayersallcommands="on" + +## Player Warnings | https://docs.linuxgsm.com/features/player-warnings +# Minutes to warn players in-game before a stop, restart or update. 0 to disable. +# e.g. 15 warns at 15, 10, 5, 3 and 1 minutes. +warnplayerstimer="0" + ## Updating | https://docs.linuxgsm.com/commands/update updateonstart="off" diff --git a/lgsm/config-default/config-lgsm/jc2server/_default.cfg b/lgsm/config-default/config-lgsm/jc2server/_default.cfg index afe6d4e83a..7ffde3756b 100644 --- a/lgsm/config-default/config-lgsm/jc2server/_default.cfg +++ b/lgsm/config-default/config-lgsm/jc2server/_default.cfg @@ -99,6 +99,11 @@ curlcustomstring="" stoponlyifnoplayers="off" stoponlyifnoplayersallcommands="on" +## Player Warnings | https://docs.linuxgsm.com/features/player-warnings +# Minutes to warn players in-game before a stop, restart or update. 0 to disable. +# e.g. 15 warns at 15, 10, 5, 3 and 1 minutes. +warnplayerstimer="0" + ## Updating | https://docs.linuxgsm.com/commands/update updateonstart="off" diff --git a/lgsm/config-default/config-lgsm/jc3server/_default.cfg b/lgsm/config-default/config-lgsm/jc3server/_default.cfg index 7d45d966ed..66a54035af 100644 --- a/lgsm/config-default/config-lgsm/jc3server/_default.cfg +++ b/lgsm/config-default/config-lgsm/jc3server/_default.cfg @@ -99,6 +99,11 @@ curlcustomstring="" stoponlyifnoplayers="off" stoponlyifnoplayersallcommands="on" +## Player Warnings | https://docs.linuxgsm.com/features/player-warnings +# Minutes to warn players in-game before a stop, restart or update. 0 to disable. +# e.g. 15 warns at 15, 10, 5, 3 and 1 minutes. +warnplayerstimer="0" + ## Updating | https://docs.linuxgsm.com/commands/update updateonstart="off" diff --git a/lgsm/config-default/config-lgsm/jk2server/_default.cfg b/lgsm/config-default/config-lgsm/jk2server/_default.cfg index 1749c3dd59..de036f81c0 100644 --- a/lgsm/config-default/config-lgsm/jk2server/_default.cfg +++ b/lgsm/config-default/config-lgsm/jk2server/_default.cfg @@ -108,6 +108,11 @@ curlcustomstring="" stoponlyifnoplayers="off" stoponlyifnoplayersallcommands="on" +## Player Warnings | https://docs.linuxgsm.com/features/player-warnings +# Minutes to warn players in-game before a stop, restart or update. 0 to disable. +# e.g. 15 warns at 15, 10, 5, 3 and 1 minutes. +warnplayerstimer="0" + ## Updating | https://docs.linuxgsm.com/commands/update updateonstart="off" diff --git a/lgsm/config-default/config-lgsm/kf2server/_default.cfg b/lgsm/config-default/config-lgsm/kf2server/_default.cfg index 832cc8cfd4..1dbea1f6e6 100644 --- a/lgsm/config-default/config-lgsm/kf2server/_default.cfg +++ b/lgsm/config-default/config-lgsm/kf2server/_default.cfg @@ -105,6 +105,11 @@ curlcustomstring="" stoponlyifnoplayers="off" stoponlyifnoplayersallcommands="on" +## Player Warnings | https://docs.linuxgsm.com/features/player-warnings +# Minutes to warn players in-game before a stop, restart or update. 0 to disable. +# e.g. 15 warns at 15, 10, 5, 3 and 1 minutes. +warnplayerstimer="0" + ## Updating | https://docs.linuxgsm.com/commands/update updateonstart="off" diff --git a/lgsm/config-default/config-lgsm/kfserver/_default.cfg b/lgsm/config-default/config-lgsm/kfserver/_default.cfg index 323142d690..90d4f0e066 100644 --- a/lgsm/config-default/config-lgsm/kfserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/kfserver/_default.cfg @@ -111,6 +111,11 @@ curlcustomstring="" stoponlyifnoplayers="off" stoponlyifnoplayersallcommands="on" +## Player Warnings | https://docs.linuxgsm.com/features/player-warnings +# Minutes to warn players in-game before a stop, restart or update. 0 to disable. +# e.g. 15 warns at 15, 10, 5, 3 and 1 minutes. +warnplayerstimer="0" + ## Updating | https://docs.linuxgsm.com/commands/update updateonstart="off" diff --git a/lgsm/config-default/config-lgsm/l4d2server/_default.cfg b/lgsm/config-default/config-lgsm/l4d2server/_default.cfg index eea3b160b2..e0fbf03682 100644 --- a/lgsm/config-default/config-lgsm/l4d2server/_default.cfg +++ b/lgsm/config-default/config-lgsm/l4d2server/_default.cfg @@ -112,6 +112,11 @@ curlcustomstring="" stoponlyifnoplayers="off" stoponlyifnoplayersallcommands="on" +## Player Warnings | https://docs.linuxgsm.com/features/player-warnings +# Minutes to warn players in-game before a stop, restart or update. 0 to disable. +# e.g. 15 warns at 15, 10, 5, 3 and 1 minutes. +warnplayerstimer="0" + ## Updating | https://docs.linuxgsm.com/commands/update updateonstart="off" diff --git a/lgsm/config-default/config-lgsm/l4dserver/_default.cfg b/lgsm/config-default/config-lgsm/l4dserver/_default.cfg index 88c45c1baf..73962c0fb7 100644 --- a/lgsm/config-default/config-lgsm/l4dserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/l4dserver/_default.cfg @@ -106,6 +106,11 @@ curlcustomstring="" stoponlyifnoplayers="off" stoponlyifnoplayersallcommands="on" +## Player Warnings | https://docs.linuxgsm.com/features/player-warnings +# Minutes to warn players in-game before a stop, restart or update. 0 to disable. +# e.g. 15 warns at 15, 10, 5, 3 and 1 minutes. +warnplayerstimer="0" + ## Updating | https://docs.linuxgsm.com/commands/update updateonstart="off" diff --git a/lgsm/config-default/config-lgsm/mcbserver/_default.cfg b/lgsm/config-default/config-lgsm/mcbserver/_default.cfg index 5714bd328b..1f79054791 100644 --- a/lgsm/config-default/config-lgsm/mcbserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/mcbserver/_default.cfg @@ -102,6 +102,11 @@ curlcustomstring="" stoponlyifnoplayers="off" stoponlyifnoplayersallcommands="on" +## Player Warnings | https://docs.linuxgsm.com/features/player-warnings +# Minutes to warn players in-game before a stop, restart or update. 0 to disable. +# e.g. 15 warns at 15, 10, 5, 3 and 1 minutes. +warnplayerstimer="0" + ## Updating | https://docs.linuxgsm.com/commands/update updateonstart="off" diff --git a/lgsm/config-default/config-lgsm/mcserver/_default.cfg b/lgsm/config-default/config-lgsm/mcserver/_default.cfg index 1ae68b8e32..daf0ef423b 100644 --- a/lgsm/config-default/config-lgsm/mcserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/mcserver/_default.cfg @@ -108,6 +108,11 @@ curlcustomstring="" stoponlyifnoplayers="off" stoponlyifnoplayersallcommands="on" +## Player Warnings | https://docs.linuxgsm.com/features/player-warnings +# Minutes to warn players in-game before a stop, restart or update. 0 to disable. +# e.g. 15 warns at 15, 10, 5, 3 and 1 minutes. +warnplayerstimer="0" + ## Updating | https://docs.linuxgsm.com/commands/update updateonstart="off" diff --git a/lgsm/config-default/config-lgsm/mcvserver/_default.cfg b/lgsm/config-default/config-lgsm/mcvserver/_default.cfg index 3d822892a2..9048f68342 100644 --- a/lgsm/config-default/config-lgsm/mcvserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/mcvserver/_default.cfg @@ -88,6 +88,15 @@ telegramtoken="accesstoken" telegramchatid="" curlcustomstring="" +## Stop | https://docs.linuxgsm.com/commands/start-stop-restart +stoponlyifnoplayers="off" +stoponlyifnoplayersallcommands="on" + +## Player Warnings | https://docs.linuxgsm.com/features/player-warnings +# Minutes to warn players in-game before a stop, restart or update. 0 to disable. +# e.g. 15 warns at 15, 10, 5, 3 and 1 minutes. +warnplayerstimer="0" + ## Updating | https://docs.linuxgsm.com/commands/update updateonstart="off" diff --git a/lgsm/config-default/config-lgsm/mhserver/_default.cfg b/lgsm/config-default/config-lgsm/mhserver/_default.cfg index a8a86b4464..04d50aeb03 100644 --- a/lgsm/config-default/config-lgsm/mhserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/mhserver/_default.cfg @@ -108,6 +108,11 @@ curlcustomstring="" stoponlyifnoplayers="off" stoponlyifnoplayersallcommands="on" +## Player Warnings | https://docs.linuxgsm.com/features/player-warnings +# Minutes to warn players in-game before a stop, restart or update. 0 to disable. +# e.g. 15 warns at 15, 10, 5, 3 and 1 minutes. +warnplayerstimer="0" + ## Updating | https://docs.linuxgsm.com/commands/update updateonstart="off" diff --git a/lgsm/config-default/config-lgsm/mohaaserver/_default.cfg b/lgsm/config-default/config-lgsm/mohaaserver/_default.cfg index 9aab77c7a6..69ae5b81d6 100644 --- a/lgsm/config-default/config-lgsm/mohaaserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/mohaaserver/_default.cfg @@ -104,6 +104,11 @@ curlcustomstring="" stoponlyifnoplayers="off" stoponlyifnoplayersallcommands="on" +## Player Warnings | https://docs.linuxgsm.com/features/player-warnings +# Minutes to warn players in-game before a stop, restart or update. 0 to disable. +# e.g. 15 warns at 15, 10, 5, 3 and 1 minutes. +warnplayerstimer="0" + ## Backup | https://docs.linuxgsm.com/commands/backup maxbackups="4" maxbackupdays="30" diff --git a/lgsm/config-default/config-lgsm/momserver/_default.cfg b/lgsm/config-default/config-lgsm/momserver/_default.cfg index ec376c3610..3b92ccbfbe 100644 --- a/lgsm/config-default/config-lgsm/momserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/momserver/_default.cfg @@ -105,6 +105,11 @@ curlcustomstring="" stoponlyifnoplayers="off" stoponlyifnoplayersallcommands="on" +## Player Warnings | https://docs.linuxgsm.com/features/player-warnings +# Minutes to warn players in-game before a stop, restart or update. 0 to disable. +# e.g. 15 warns at 15, 10, 5, 3 and 1 minutes. +warnplayerstimer="0" + ## Updating | https://docs.linuxgsm.com/commands/update updateonstart="off" diff --git a/lgsm/config-default/config-lgsm/mtaserver/_default.cfg b/lgsm/config-default/config-lgsm/mtaserver/_default.cfg index 835b4c4e0a..eedd83fbd5 100644 --- a/lgsm/config-default/config-lgsm/mtaserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/mtaserver/_default.cfg @@ -102,6 +102,11 @@ curlcustomstring="" stoponlyifnoplayers="off" stoponlyifnoplayersallcommands="on" +## Player Warnings | https://docs.linuxgsm.com/features/player-warnings +# Minutes to warn players in-game before a stop, restart or update. 0 to disable. +# e.g. 15 warns at 15, 10, 5, 3 and 1 minutes. +warnplayerstimer="0" + ## Backup | https://docs.linuxgsm.com/commands/backup maxbackups="4" maxbackupdays="30" diff --git a/lgsm/config-default/config-lgsm/ndserver/_default.cfg b/lgsm/config-default/config-lgsm/ndserver/_default.cfg index f41567bfff..2c9083482a 100644 --- a/lgsm/config-default/config-lgsm/ndserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/ndserver/_default.cfg @@ -107,6 +107,11 @@ curlcustomstring="" stoponlyifnoplayers="off" stoponlyifnoplayersallcommands="on" +## Player Warnings | https://docs.linuxgsm.com/features/player-warnings +# Minutes to warn players in-game before a stop, restart or update. 0 to disable. +# e.g. 15 warns at 15, 10, 5, 3 and 1 minutes. +warnplayerstimer="0" + ## Updating | https://docs.linuxgsm.com/commands/update updateonstart="off" diff --git a/lgsm/config-default/config-lgsm/necserver/_default.cfg b/lgsm/config-default/config-lgsm/necserver/_default.cfg index 1b3ae48f34..03aa886301 100644 --- a/lgsm/config-default/config-lgsm/necserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/necserver/_default.cfg @@ -102,6 +102,11 @@ curlcustomstring="" stoponlyifnoplayers="off" stoponlyifnoplayersallcommands="on" +## Player Warnings | https://docs.linuxgsm.com/features/player-warnings +# Minutes to warn players in-game before a stop, restart or update. 0 to disable. +# e.g. 15 warns at 15, 10, 5, 3 and 1 minutes. +warnplayerstimer="0" + ## Updating | https://docs.linuxgsm.com/commands/update updateonstart="off" diff --git a/lgsm/config-default/config-lgsm/nmrihserver/_default.cfg b/lgsm/config-default/config-lgsm/nmrihserver/_default.cfg index 106658818b..3600221ab7 100644 --- a/lgsm/config-default/config-lgsm/nmrihserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/nmrihserver/_default.cfg @@ -112,6 +112,11 @@ curlcustomstring="" stoponlyifnoplayers="off" stoponlyifnoplayersallcommands="on" +## Player Warnings | https://docs.linuxgsm.com/features/player-warnings +# Minutes to warn players in-game before a stop, restart or update. 0 to disable. +# e.g. 15 warns at 15, 10, 5, 3 and 1 minutes. +warnplayerstimer="0" + ## Updating | https://docs.linuxgsm.com/commands/update updateonstart="off" diff --git a/lgsm/config-default/config-lgsm/ns2cserver/_default.cfg b/lgsm/config-default/config-lgsm/ns2cserver/_default.cfg index d08afa02ff..75236bf2a4 100644 --- a/lgsm/config-default/config-lgsm/ns2cserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/ns2cserver/_default.cfg @@ -114,6 +114,11 @@ curlcustomstring="" stoponlyifnoplayers="off" stoponlyifnoplayersallcommands="on" +## Player Warnings | https://docs.linuxgsm.com/features/player-warnings +# Minutes to warn players in-game before a stop, restart or update. 0 to disable. +# e.g. 15 warns at 15, 10, 5, 3 and 1 minutes. +warnplayerstimer="0" + ## Updating | https://docs.linuxgsm.com/commands/update updateonstart="off" diff --git a/lgsm/config-default/config-lgsm/ns2server/_default.cfg b/lgsm/config-default/config-lgsm/ns2server/_default.cfg index e0c11a4bf9..4e9e83cb16 100644 --- a/lgsm/config-default/config-lgsm/ns2server/_default.cfg +++ b/lgsm/config-default/config-lgsm/ns2server/_default.cfg @@ -115,6 +115,11 @@ curlcustomstring="" stoponlyifnoplayers="off" stoponlyifnoplayersallcommands="on" +## Player Warnings | https://docs.linuxgsm.com/features/player-warnings +# Minutes to warn players in-game before a stop, restart or update. 0 to disable. +# e.g. 15 warns at 15, 10, 5, 3 and 1 minutes. +warnplayerstimer="0" + ## Updating | https://docs.linuxgsm.com/commands/update updateonstart="off" diff --git a/lgsm/config-default/config-lgsm/nsserver/_default.cfg b/lgsm/config-default/config-lgsm/nsserver/_default.cfg index 7c981081f9..8ad8c16a2b 100644 --- a/lgsm/config-default/config-lgsm/nsserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/nsserver/_default.cfg @@ -106,6 +106,11 @@ curlcustomstring="" stoponlyifnoplayers="off" stoponlyifnoplayersallcommands="on" +## Player Warnings | https://docs.linuxgsm.com/features/player-warnings +# Minutes to warn players in-game before a stop, restart or update. 0 to disable. +# e.g. 15 warns at 15, 10, 5, 3 and 1 minutes. +warnplayerstimer="0" + ## Updating | https://docs.linuxgsm.com/commands/update updateonstart="off" diff --git a/lgsm/config-default/config-lgsm/ohdserver/_default.cfg b/lgsm/config-default/config-lgsm/ohdserver/_default.cfg index f3b3510708..68b0f3bb60 100644 --- a/lgsm/config-default/config-lgsm/ohdserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/ohdserver/_default.cfg @@ -116,6 +116,11 @@ curlcustomstring="" stoponlyifnoplayers="off" stoponlyifnoplayersallcommands="on" +## Player Warnings | https://docs.linuxgsm.com/features/player-warnings +# Minutes to warn players in-game before a stop, restart or update. 0 to disable. +# e.g. 15 warns at 15, 10, 5, 3 and 1 minutes. +warnplayerstimer="0" + ## Updating | https://docs.linuxgsm.com/commands/update updateonstart="off" diff --git a/lgsm/config-default/config-lgsm/onsetserver/_default.cfg b/lgsm/config-default/config-lgsm/onsetserver/_default.cfg index 5fd642a04e..d6ed8626f0 100644 --- a/lgsm/config-default/config-lgsm/onsetserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/onsetserver/_default.cfg @@ -100,6 +100,11 @@ curlcustomstring="" stoponlyifnoplayers="off" stoponlyifnoplayersallcommands="on" +## Player Warnings | https://docs.linuxgsm.com/features/player-warnings +# Minutes to warn players in-game before a stop, restart or update. 0 to disable. +# e.g. 15 warns at 15, 10, 5, 3 and 1 minutes. +warnplayerstimer="0" + ## Updating | https://docs.linuxgsm.com/commands/update updateonstart="off" diff --git a/lgsm/config-default/config-lgsm/opforserver/_default.cfg b/lgsm/config-default/config-lgsm/opforserver/_default.cfg index 5501fc6517..c8fd40c857 100644 --- a/lgsm/config-default/config-lgsm/opforserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/opforserver/_default.cfg @@ -106,6 +106,11 @@ curlcustomstring="" stoponlyifnoplayers="off" stoponlyifnoplayersallcommands="on" +## Player Warnings | https://docs.linuxgsm.com/features/player-warnings +# Minutes to warn players in-game before a stop, restart or update. 0 to disable. +# e.g. 15 warns at 15, 10, 5, 3 and 1 minutes. +warnplayerstimer="0" + ## Updating | https://docs.linuxgsm.com/commands/update updateonstart="off" diff --git a/lgsm/config-default/config-lgsm/pc2server/_default.cfg b/lgsm/config-default/config-lgsm/pc2server/_default.cfg index 3ac6eeb77b..dc39d4f908 100644 --- a/lgsm/config-default/config-lgsm/pc2server/_default.cfg +++ b/lgsm/config-default/config-lgsm/pc2server/_default.cfg @@ -103,6 +103,11 @@ curlcustomstring="" stoponlyifnoplayers="off" stoponlyifnoplayersallcommands="on" +## Player Warnings | https://docs.linuxgsm.com/features/player-warnings +# Minutes to warn players in-game before a stop, restart or update. 0 to disable. +# e.g. 15 warns at 15, 10, 5, 3 and 1 minutes. +warnplayerstimer="0" + ## Updating | https://docs.linuxgsm.com/commands/update updateonstart="off" diff --git a/lgsm/config-default/config-lgsm/pcserver/_default.cfg b/lgsm/config-default/config-lgsm/pcserver/_default.cfg index 601ffed3bc..3417df9a86 100644 --- a/lgsm/config-default/config-lgsm/pcserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/pcserver/_default.cfg @@ -99,6 +99,11 @@ curlcustomstring="" stoponlyifnoplayers="off" stoponlyifnoplayersallcommands="on" +## Player Warnings | https://docs.linuxgsm.com/features/player-warnings +# Minutes to warn players in-game before a stop, restart or update. 0 to disable. +# e.g. 15 warns at 15, 10, 5, 3 and 1 minutes. +warnplayerstimer="0" + ## Updating | https://docs.linuxgsm.com/commands/update updateonstart="off" diff --git a/lgsm/config-default/config-lgsm/pmcserver/_default.cfg b/lgsm/config-default/config-lgsm/pmcserver/_default.cfg index db456dbf7b..4da2891aec 100644 --- a/lgsm/config-default/config-lgsm/pmcserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/pmcserver/_default.cfg @@ -106,6 +106,11 @@ curlcustomstring="" stoponlyifnoplayers="off" stoponlyifnoplayersallcommands="on" +## Player Warnings | https://docs.linuxgsm.com/features/player-warnings +# Minutes to warn players in-game before a stop, restart or update. 0 to disable. +# e.g. 15 warns at 15, 10, 5, 3 and 1 minutes. +warnplayerstimer="0" + ## Updating | https://docs.linuxgsm.com/commands/update updateonstart="off" diff --git a/lgsm/config-default/config-lgsm/pvkiiserver/_default.cfg b/lgsm/config-default/config-lgsm/pvkiiserver/_default.cfg index 7f27e32a0a..c8e39c7375 100644 --- a/lgsm/config-default/config-lgsm/pvkiiserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/pvkiiserver/_default.cfg @@ -107,6 +107,11 @@ curlcustomstring="" stoponlyifnoplayers="off" stoponlyifnoplayersallcommands="on" +## Player Warnings | https://docs.linuxgsm.com/features/player-warnings +# Minutes to warn players in-game before a stop, restart or update. 0 to disable. +# e.g. 15 warns at 15, 10, 5, 3 and 1 minutes. +warnplayerstimer="0" + ## Updating | https://docs.linuxgsm.com/commands/update updateonstart="off" diff --git a/lgsm/config-default/config-lgsm/pvrserver/_default.cfg b/lgsm/config-default/config-lgsm/pvrserver/_default.cfg index 85deb664f5..ebf0ae8697 100644 --- a/lgsm/config-default/config-lgsm/pvrserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/pvrserver/_default.cfg @@ -104,6 +104,15 @@ telegramthreadid="" telegramsilentnotification="false" curlcustomstring="" +## Stop | https://docs.linuxgsm.com/commands/start-stop-restart +stoponlyifnoplayers="off" +stoponlyifnoplayersallcommands="on" + +## Player Warnings | https://docs.linuxgsm.com/features/player-warnings +# Minutes to warn players in-game before a stop, restart or update. 0 to disable. +# e.g. 15 warns at 15, 10, 5, 3 and 1 minutes. +warnplayerstimer="0" + ## Updating | https://docs.linuxgsm.com/commands/update updateonstart="off" diff --git a/lgsm/config-default/config-lgsm/pwserver/_default.cfg b/lgsm/config-default/config-lgsm/pwserver/_default.cfg index c58ce087f2..9ee1461acd 100644 --- a/lgsm/config-default/config-lgsm/pwserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/pwserver/_default.cfg @@ -107,6 +107,11 @@ curlcustomstring="" stoponlyifnoplayers="off" stoponlyifnoplayersallcommands="on" +## Player Warnings | https://docs.linuxgsm.com/features/player-warnings +# Minutes to warn players in-game before a stop, restart or update. 0 to disable. +# e.g. 15 warns at 15, 10, 5, 3 and 1 minutes. +warnplayerstimer="0" + ## Updating | https://docs.linuxgsm.com/commands/update updateonstart="off" diff --git a/lgsm/config-default/config-lgsm/pzserver/_default.cfg b/lgsm/config-default/config-lgsm/pzserver/_default.cfg index e8e139f8a5..1f430c776b 100644 --- a/lgsm/config-default/config-lgsm/pzserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/pzserver/_default.cfg @@ -103,6 +103,11 @@ curlcustomstring="" stoponlyifnoplayers="off" stoponlyifnoplayersallcommands="on" +## Player Warnings | https://docs.linuxgsm.com/features/player-warnings +# Minutes to warn players in-game before a stop, restart or update. 0 to disable. +# e.g. 15 warns at 15, 10, 5, 3 and 1 minutes. +warnplayerstimer="0" + ## Updating | https://docs.linuxgsm.com/commands/update updateonstart="off" diff --git a/lgsm/config-default/config-lgsm/q2server/_default.cfg b/lgsm/config-default/config-lgsm/q2server/_default.cfg index 2fe85ea3cb..bac93bb137 100644 --- a/lgsm/config-default/config-lgsm/q2server/_default.cfg +++ b/lgsm/config-default/config-lgsm/q2server/_default.cfg @@ -104,6 +104,11 @@ curlcustomstring="" stoponlyifnoplayers="off" stoponlyifnoplayersallcommands="on" +## Player Warnings | https://docs.linuxgsm.com/features/player-warnings +# Minutes to warn players in-game before a stop, restart or update. 0 to disable. +# e.g. 15 warns at 15, 10, 5, 3 and 1 minutes. +warnplayerstimer="0" + ## Backup | https://docs.linuxgsm.com/commands/backup maxbackups="4" maxbackupdays="30" diff --git a/lgsm/config-default/config-lgsm/q3server/_default.cfg b/lgsm/config-default/config-lgsm/q3server/_default.cfg index 24a3604fcc..e21dc0fdb4 100644 --- a/lgsm/config-default/config-lgsm/q3server/_default.cfg +++ b/lgsm/config-default/config-lgsm/q3server/_default.cfg @@ -104,6 +104,11 @@ curlcustomstring="" stoponlyifnoplayers="off" stoponlyifnoplayersallcommands="on" +## Player Warnings | https://docs.linuxgsm.com/features/player-warnings +# Minutes to warn players in-game before a stop, restart or update. 0 to disable. +# e.g. 15 warns at 15, 10, 5, 3 and 1 minutes. +warnplayerstimer="0" + ## Backup | https://docs.linuxgsm.com/commands/backup maxbackups="4" maxbackupdays="30" diff --git a/lgsm/config-default/config-lgsm/q4server/_default.cfg b/lgsm/config-default/config-lgsm/q4server/_default.cfg index f4f8f4655c..0be2a39066 100644 --- a/lgsm/config-default/config-lgsm/q4server/_default.cfg +++ b/lgsm/config-default/config-lgsm/q4server/_default.cfg @@ -106,6 +106,11 @@ curlcustomstring="" stoponlyifnoplayers="off" stoponlyifnoplayersallcommands="on" +## Player Warnings | https://docs.linuxgsm.com/features/player-warnings +# Minutes to warn players in-game before a stop, restart or update. 0 to disable. +# e.g. 15 warns at 15, 10, 5, 3 and 1 minutes. +warnplayerstimer="0" + ## Updating | https://docs.linuxgsm.com/commands/update updateonstart="off" diff --git a/lgsm/config-default/config-lgsm/qlserver/_default.cfg b/lgsm/config-default/config-lgsm/qlserver/_default.cfg index 057b0f09d7..05ff7a340a 100644 --- a/lgsm/config-default/config-lgsm/qlserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/qlserver/_default.cfg @@ -99,6 +99,11 @@ curlcustomstring="" stoponlyifnoplayers="off" stoponlyifnoplayersallcommands="on" +## Player Warnings | https://docs.linuxgsm.com/features/player-warnings +# Minutes to warn players in-game before a stop, restart or update. 0 to disable. +# e.g. 15 warns at 15, 10, 5, 3 and 1 minutes. +warnplayerstimer="0" + ## Updating | https://docs.linuxgsm.com/commands/update updateonstart="off" diff --git a/lgsm/config-default/config-lgsm/qwserver/_default.cfg b/lgsm/config-default/config-lgsm/qwserver/_default.cfg index b637f7d074..1b9d9d1cb0 100644 --- a/lgsm/config-default/config-lgsm/qwserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/qwserver/_default.cfg @@ -103,6 +103,11 @@ curlcustomstring="" stoponlyifnoplayers="off" stoponlyifnoplayersallcommands="on" +## Player Warnings | https://docs.linuxgsm.com/features/player-warnings +# Minutes to warn players in-game before a stop, restart or update. 0 to disable. +# e.g. 15 warns at 15, 10, 5, 3 and 1 minutes. +warnplayerstimer="0" + ## Backup | https://docs.linuxgsm.com/commands/backup maxbackups="4" maxbackupdays="30" diff --git a/lgsm/config-default/config-lgsm/ricochetserver/_default.cfg b/lgsm/config-default/config-lgsm/ricochetserver/_default.cfg index a1d05ac95a..7ee7763b0b 100644 --- a/lgsm/config-default/config-lgsm/ricochetserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/ricochetserver/_default.cfg @@ -106,6 +106,11 @@ curlcustomstring="" stoponlyifnoplayers="off" stoponlyifnoplayersallcommands="on" +## Player Warnings | https://docs.linuxgsm.com/features/player-warnings +# Minutes to warn players in-game before a stop, restart or update. 0 to disable. +# e.g. 15 warns at 15, 10, 5, 3 and 1 minutes. +warnplayerstimer="0" + ## Updating | https://docs.linuxgsm.com/commands/update updateonstart="off" diff --git a/lgsm/config-default/config-lgsm/roserver/_default.cfg b/lgsm/config-default/config-lgsm/roserver/_default.cfg index 9d28637358..b4c92d66c8 100644 --- a/lgsm/config-default/config-lgsm/roserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/roserver/_default.cfg @@ -107,6 +107,11 @@ curlcustomstring="" stoponlyifnoplayers="off" stoponlyifnoplayersallcommands="on" +## Player Warnings | https://docs.linuxgsm.com/features/player-warnings +# Minutes to warn players in-game before a stop, restart or update. 0 to disable. +# e.g. 15 warns at 15, 10, 5, 3 and 1 minutes. +warnplayerstimer="0" + ## Updating | https://docs.linuxgsm.com/commands/update updateonstart="off" diff --git a/lgsm/config-default/config-lgsm/rsdwserver/_default.cfg b/lgsm/config-default/config-lgsm/rsdwserver/_default.cfg index 1b428f7025..081d8dee48 100644 --- a/lgsm/config-default/config-lgsm/rsdwserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/rsdwserver/_default.cfg @@ -98,6 +98,15 @@ telegramthreadid="" telegramsilentnotification="false" curlcustomstring="" +## Stop | https://docs.linuxgsm.com/commands/start-stop-restart +stoponlyifnoplayers="off" +stoponlyifnoplayersallcommands="on" + +## Player Warnings | https://docs.linuxgsm.com/features/player-warnings +# Minutes to warn players in-game before a stop, restart or update. 0 to disable. +# e.g. 15 warns at 15, 10, 5, 3 and 1 minutes. +warnplayerstimer="0" + ## Updating | https://docs.linuxgsm.com/commands/update updateonstart="off" diff --git a/lgsm/config-default/config-lgsm/rtcwserver/_default.cfg b/lgsm/config-default/config-lgsm/rtcwserver/_default.cfg index 16b2877330..2241a144bf 100644 --- a/lgsm/config-default/config-lgsm/rtcwserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/rtcwserver/_default.cfg @@ -104,6 +104,11 @@ curlcustomstring="" stoponlyifnoplayers="off" stoponlyifnoplayersallcommands="on" +## Player Warnings | https://docs.linuxgsm.com/features/player-warnings +# Minutes to warn players in-game before a stop, restart or update. 0 to disable. +# e.g. 15 warns at 15, 10, 5, 3 and 1 minutes. +warnplayerstimer="0" + ## Backup | https://docs.linuxgsm.com/commands/backup maxbackups="4" maxbackupdays="30" diff --git a/lgsm/config-default/config-lgsm/rustserver/_default.cfg b/lgsm/config-default/config-lgsm/rustserver/_default.cfg index 75e1dba897..f6dab1f4fa 100644 --- a/lgsm/config-default/config-lgsm/rustserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/rustserver/_default.cfg @@ -119,6 +119,11 @@ curlcustomstring="" stoponlyifnoplayers="off" stoponlyifnoplayersallcommands="on" +## Player Warnings | https://docs.linuxgsm.com/features/player-warnings +# Minutes to warn players in-game before a stop, restart or update. 0 to disable. +# e.g. 15 warns at 15, 10, 5, 3 and 1 minutes. +warnplayerstimer="0" + ## Updating | https://docs.linuxgsm.com/commands/update updateonstart="off" diff --git a/lgsm/config-default/config-lgsm/rwrserver/_default.cfg b/lgsm/config-default/config-lgsm/rwrserver/_default.cfg index 5831be8972..cf01d2b0b9 100644 --- a/lgsm/config-default/config-lgsm/rwrserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/rwrserver/_default.cfg @@ -104,6 +104,15 @@ telegramthreadid="" telegramsilentnotification="false" curlcustomstring="" +## Stop | https://docs.linuxgsm.com/commands/start-stop-restart +stoponlyifnoplayers="off" +stoponlyifnoplayersallcommands="on" + +## Player Warnings | https://docs.linuxgsm.com/features/player-warnings +# Minutes to warn players in-game before a stop, restart or update. 0 to disable. +# e.g. 15 warns at 15, 10, 5, 3 and 1 minutes. +warnplayerstimer="0" + ## Updating | https://docs.linuxgsm.com/commands/update updateonstart="off" diff --git a/lgsm/config-default/config-lgsm/rwserver/_default.cfg b/lgsm/config-default/config-lgsm/rwserver/_default.cfg index fe8c9f842e..200a37ed13 100644 --- a/lgsm/config-default/config-lgsm/rwserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/rwserver/_default.cfg @@ -99,6 +99,11 @@ curlcustomstring="" stoponlyifnoplayers="off" stoponlyifnoplayersallcommands="on" +## Player Warnings | https://docs.linuxgsm.com/features/player-warnings +# Minutes to warn players in-game before a stop, restart or update. 0 to disable. +# e.g. 15 warns at 15, 10, 5, 3 and 1 minutes. +warnplayerstimer="0" + ## Updating | https://docs.linuxgsm.com/commands/update updateonstart="off" diff --git a/lgsm/config-default/config-lgsm/sampserver/_default.cfg b/lgsm/config-default/config-lgsm/sampserver/_default.cfg index af548a639a..ab2ae30364 100644 --- a/lgsm/config-default/config-lgsm/sampserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/sampserver/_default.cfg @@ -103,6 +103,11 @@ curlcustomstring="" stoponlyifnoplayers="off" stoponlyifnoplayersallcommands="on" +## Player Warnings | https://docs.linuxgsm.com/features/player-warnings +# Minutes to warn players in-game before a stop, restart or update. 0 to disable. +# e.g. 15 warns at 15, 10, 5, 3 and 1 minutes. +warnplayerstimer="0" + ## Backup | https://docs.linuxgsm.com/commands/backup maxbackups="4" maxbackupdays="30" diff --git a/lgsm/config-default/config-lgsm/sbotsserver/_default.cfg b/lgsm/config-default/config-lgsm/sbotsserver/_default.cfg index 93644efe5b..ad73ede403 100644 --- a/lgsm/config-default/config-lgsm/sbotsserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/sbotsserver/_default.cfg @@ -105,6 +105,11 @@ curlcustomstring="" stoponlyifnoplayers="off" stoponlyifnoplayersallcommands="on" +## Player Warnings | https://docs.linuxgsm.com/features/player-warnings +# Minutes to warn players in-game before a stop, restart or update. 0 to disable. +# e.g. 15 warns at 15, 10, 5, 3 and 1 minutes. +warnplayerstimer="0" + ## Updating | https://docs.linuxgsm.com/commands/update updateonstart="off" diff --git a/lgsm/config-default/config-lgsm/sbserver/_default.cfg b/lgsm/config-default/config-lgsm/sbserver/_default.cfg index a10b42f7a8..c61d87fc56 100644 --- a/lgsm/config-default/config-lgsm/sbserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/sbserver/_default.cfg @@ -112,6 +112,11 @@ curlcustomstring="" stoponlyifnoplayers="off" stoponlyifnoplayersallcommands="on" +## Player Warnings | https://docs.linuxgsm.com/features/player-warnings +# Minutes to warn players in-game before a stop, restart or update. 0 to disable. +# e.g. 15 warns at 15, 10, 5, 3 and 1 minutes. +warnplayerstimer="0" + ## Updating | https://docs.linuxgsm.com/commands/update updateonstart="off" diff --git a/lgsm/config-default/config-lgsm/scpslserver/_default.cfg b/lgsm/config-default/config-lgsm/scpslserver/_default.cfg index 4ce7f2fb99..9c82bc9528 100644 --- a/lgsm/config-default/config-lgsm/scpslserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/scpslserver/_default.cfg @@ -104,6 +104,11 @@ curlcustomstring="" stoponlyifnoplayers="off" stoponlyifnoplayersallcommands="on" +## Player Warnings | https://docs.linuxgsm.com/features/player-warnings +# Minutes to warn players in-game before a stop, restart or update. 0 to disable. +# e.g. 15 warns at 15, 10, 5, 3 and 1 minutes. +warnplayerstimer="0" + ## Updating | https://docs.linuxgsm.com/commands/update updateonstart="off" diff --git a/lgsm/config-default/config-lgsm/scpslsmserver/_default.cfg b/lgsm/config-default/config-lgsm/scpslsmserver/_default.cfg index 464ef0feed..921d11944c 100644 --- a/lgsm/config-default/config-lgsm/scpslsmserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/scpslsmserver/_default.cfg @@ -104,6 +104,11 @@ curlcustomstring="" stoponlyifnoplayers="off" stoponlyifnoplayersallcommands="on" +## Player Warnings | https://docs.linuxgsm.com/features/player-warnings +# Minutes to warn players in-game before a stop, restart or update. 0 to disable. +# e.g. 15 warns at 15, 10, 5, 3 and 1 minutes. +warnplayerstimer="0" + ## Updating | https://docs.linuxgsm.com/commands/update updateonstart="off" diff --git a/lgsm/config-default/config-lgsm/sdtdserver/_default.cfg b/lgsm/config-default/config-lgsm/sdtdserver/_default.cfg index 383b51d231..f4cc7c1146 100644 --- a/lgsm/config-default/config-lgsm/sdtdserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/sdtdserver/_default.cfg @@ -102,6 +102,11 @@ curlcustomstring="" stoponlyifnoplayers="off" stoponlyifnoplayersallcommands="on" +## Player Warnings | https://docs.linuxgsm.com/features/player-warnings +# Minutes to warn players in-game before a stop, restart or update. 0 to disable. +# e.g. 15 warns at 15, 10, 5, 3 and 1 minutes. +warnplayerstimer="0" + ## Updating | https://docs.linuxgsm.com/commands/update updateonstart="off" diff --git a/lgsm/config-default/config-lgsm/sfcserver/_default.cfg b/lgsm/config-default/config-lgsm/sfcserver/_default.cfg index 856b172dfe..2be02488b4 100644 --- a/lgsm/config-default/config-lgsm/sfcserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/sfcserver/_default.cfg @@ -107,6 +107,11 @@ curlcustomstring="" stoponlyifnoplayers="off" stoponlyifnoplayersallcommands="on" +## Player Warnings | https://docs.linuxgsm.com/features/player-warnings +# Minutes to warn players in-game before a stop, restart or update. 0 to disable. +# e.g. 15 warns at 15, 10, 5, 3 and 1 minutes. +warnplayerstimer="0" + ## Updating | https://docs.linuxgsm.com/commands/update updateonstart="off" diff --git a/lgsm/config-default/config-lgsm/sfserver/_default.cfg b/lgsm/config-default/config-lgsm/sfserver/_default.cfg index 778a04ddf5..ed51b6e8ea 100644 --- a/lgsm/config-default/config-lgsm/sfserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/sfserver/_default.cfg @@ -106,6 +106,11 @@ curlcustomstring="" stoponlyifnoplayers="off" stoponlyifnoplayersallcommands="on" +## Player Warnings | https://docs.linuxgsm.com/features/player-warnings +# Minutes to warn players in-game before a stop, restart or update. 0 to disable. +# e.g. 15 warns at 15, 10, 5, 3 and 1 minutes. +warnplayerstimer="0" + ## Updating | https://docs.linuxgsm.com/commands/update updateonstart="off" diff --git a/lgsm/config-default/config-lgsm/smserver/_default.cfg b/lgsm/config-default/config-lgsm/smserver/_default.cfg index 029b33306f..b70c383a94 100644 --- a/lgsm/config-default/config-lgsm/smserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/smserver/_default.cfg @@ -106,6 +106,15 @@ telegramthreadid="" telegramsilentnotification="false" curlcustomstring="" +## Stop | https://docs.linuxgsm.com/commands/start-stop-restart +stoponlyifnoplayers="off" +stoponlyifnoplayersallcommands="on" + +## Player Warnings | https://docs.linuxgsm.com/features/player-warnings +# Minutes to warn players in-game before a stop, restart or update. 0 to disable. +# e.g. 15 warns at 15, 10, 5, 3 and 1 minutes. +warnplayerstimer="0" + ## Updating | https://docs.linuxgsm.com/commands/update updateonstart="off" diff --git a/lgsm/config-default/config-lgsm/sof2server/_default.cfg b/lgsm/config-default/config-lgsm/sof2server/_default.cfg index 88fdfd2391..d2dfc2e508 100644 --- a/lgsm/config-default/config-lgsm/sof2server/_default.cfg +++ b/lgsm/config-default/config-lgsm/sof2server/_default.cfg @@ -104,6 +104,11 @@ curlcustomstring="" stoponlyifnoplayers="off" stoponlyifnoplayersallcommands="on" +## Player Warnings | https://docs.linuxgsm.com/features/player-warnings +# Minutes to warn players in-game before a stop, restart or update. 0 to disable. +# e.g. 15 warns at 15, 10, 5, 3 and 1 minutes. +warnplayerstimer="0" + ## Backup | https://docs.linuxgsm.com/commands/backup maxbackups="4" maxbackupdays="30" diff --git a/lgsm/config-default/config-lgsm/solserver/_default.cfg b/lgsm/config-default/config-lgsm/solserver/_default.cfg index bdf677e805..f934703942 100644 --- a/lgsm/config-default/config-lgsm/solserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/solserver/_default.cfg @@ -110,6 +110,11 @@ curlcustomstring="" stoponlyifnoplayers="off" stoponlyifnoplayersallcommands="on" +## Player Warnings | https://docs.linuxgsm.com/features/player-warnings +# Minutes to warn players in-game before a stop, restart or update. 0 to disable. +# e.g. 15 warns at 15, 10, 5, 3 and 1 minutes. +warnplayerstimer="0" + ## Updating | https://docs.linuxgsm.com/commands/update updateonstart="off" diff --git a/lgsm/config-default/config-lgsm/squad44server/_default.cfg b/lgsm/config-default/config-lgsm/squad44server/_default.cfg index 99cf2a4bd4..8483e308e7 100644 --- a/lgsm/config-default/config-lgsm/squad44server/_default.cfg +++ b/lgsm/config-default/config-lgsm/squad44server/_default.cfg @@ -110,6 +110,11 @@ curlcustomstring="" stoponlyifnoplayers="off" stoponlyifnoplayersallcommands="on" +## Player Warnings | https://docs.linuxgsm.com/features/player-warnings +# Minutes to warn players in-game before a stop, restart or update. 0 to disable. +# e.g. 15 warns at 15, 10, 5, 3 and 1 minutes. +warnplayerstimer="0" + ## Updating | https://docs.linuxgsm.com/commands/update updateonstart="off" diff --git a/lgsm/config-default/config-lgsm/squadserver/_default.cfg b/lgsm/config-default/config-lgsm/squadserver/_default.cfg index 18045e3f57..ae14cf30e2 100644 --- a/lgsm/config-default/config-lgsm/squadserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/squadserver/_default.cfg @@ -110,6 +110,11 @@ curlcustomstring="" stoponlyifnoplayers="off" stoponlyifnoplayersallcommands="on" +## Player Warnings | https://docs.linuxgsm.com/features/player-warnings +# Minutes to warn players in-game before a stop, restart or update. 0 to disable. +# e.g. 15 warns at 15, 10, 5, 3 and 1 minutes. +warnplayerstimer="0" + ## Updating | https://docs.linuxgsm.com/commands/update updateonstart="off" diff --git a/lgsm/config-default/config-lgsm/stnserver/_default.cfg b/lgsm/config-default/config-lgsm/stnserver/_default.cfg index d245e780d6..50c7753578 100644 --- a/lgsm/config-default/config-lgsm/stnserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/stnserver/_default.cfg @@ -103,6 +103,11 @@ curlcustomstring="" stoponlyifnoplayers="off" stoponlyifnoplayersallcommands="on" +## Player Warnings | https://docs.linuxgsm.com/features/player-warnings +# Minutes to warn players in-game before a stop, restart or update. 0 to disable. +# e.g. 15 warns at 15, 10, 5, 3 and 1 minutes. +warnplayerstimer="0" + ## Updating | https://docs.linuxgsm.com/commands/update updateonstart="off" diff --git a/lgsm/config-default/config-lgsm/stserver/_default.cfg b/lgsm/config-default/config-lgsm/stserver/_default.cfg index 9fd5172017..60e26ffe23 100644 --- a/lgsm/config-default/config-lgsm/stserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/stserver/_default.cfg @@ -109,6 +109,11 @@ curlcustomstring="" stoponlyifnoplayers="off" stoponlyifnoplayersallcommands="on" +## Player Warnings | https://docs.linuxgsm.com/features/player-warnings +# Minutes to warn players in-game before a stop, restart or update. 0 to disable. +# e.g. 15 warns at 15, 10, 5, 3 and 1 minutes. +warnplayerstimer="0" + ## Updating | https://docs.linuxgsm.com/commands/update updateonstart="off" diff --git a/lgsm/config-default/config-lgsm/svenserver/_default.cfg b/lgsm/config-default/config-lgsm/svenserver/_default.cfg index 60a1e8c7aa..e591fbc057 100644 --- a/lgsm/config-default/config-lgsm/svenserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/svenserver/_default.cfg @@ -106,6 +106,11 @@ curlcustomstring="" stoponlyifnoplayers="off" stoponlyifnoplayersallcommands="on" +## Player Warnings | https://docs.linuxgsm.com/features/player-warnings +# Minutes to warn players in-game before a stop, restart or update. 0 to disable. +# e.g. 15 warns at 15, 10, 5, 3 and 1 minutes. +warnplayerstimer="0" + ## Updating | https://docs.linuxgsm.com/commands/update updateonstart="off" diff --git a/lgsm/config-default/config-lgsm/terrariaserver/_default.cfg b/lgsm/config-default/config-lgsm/terrariaserver/_default.cfg index 3694c63ba8..19aa0dc5ef 100644 --- a/lgsm/config-default/config-lgsm/terrariaserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/terrariaserver/_default.cfg @@ -106,6 +106,11 @@ curlcustomstring="" stoponlyifnoplayers="off" stoponlyifnoplayersallcommands="on" +## Player Warnings | https://docs.linuxgsm.com/features/player-warnings +# Minutes to warn players in-game before a stop, restart or update. 0 to disable. +# e.g. 15 warns at 15, 10, 5, 3 and 1 minutes. +warnplayerstimer="0" + ## Updating | https://docs.linuxgsm.com/commands/update updateonstart="off" diff --git a/lgsm/config-default/config-lgsm/tf2cserver/_default.cfg b/lgsm/config-default/config-lgsm/tf2cserver/_default.cfg index e17cb3cd72..592d1aba28 100644 --- a/lgsm/config-default/config-lgsm/tf2cserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/tf2cserver/_default.cfg @@ -110,6 +110,15 @@ telegramthreadid="" telegramsilentnotification="false" curlcustomstring="" +## Stop | https://docs.linuxgsm.com/commands/start-stop-restart +stoponlyifnoplayers="off" +stoponlyifnoplayersallcommands="on" + +## Player Warnings | https://docs.linuxgsm.com/features/player-warnings +# Minutes to warn players in-game before a stop, restart or update. 0 to disable. +# e.g. 15 warns at 15, 10, 5, 3 and 1 minutes. +warnplayerstimer="0" + ## Updating | https://docs.linuxgsm.com/commands/update updateonstart="off" diff --git a/lgsm/config-default/config-lgsm/tf2server/_default.cfg b/lgsm/config-default/config-lgsm/tf2server/_default.cfg index 3bd74259a8..00b1aeb1a0 100644 --- a/lgsm/config-default/config-lgsm/tf2server/_default.cfg +++ b/lgsm/config-default/config-lgsm/tf2server/_default.cfg @@ -114,6 +114,11 @@ curlcustomstring="" stoponlyifnoplayers="off" stoponlyifnoplayersallcommands="on" +## Player Warnings | https://docs.linuxgsm.com/features/player-warnings +# Minutes to warn players in-game before a stop, restart or update. 0 to disable. +# e.g. 15 warns at 15, 10, 5, 3 and 1 minutes. +warnplayerstimer="0" + ## Updating | https://docs.linuxgsm.com/commands/update updateonstart="off" diff --git a/lgsm/config-default/config-lgsm/tfcserver/_default.cfg b/lgsm/config-default/config-lgsm/tfcserver/_default.cfg index 123fe1b0b5..35e3d98c8c 100644 --- a/lgsm/config-default/config-lgsm/tfcserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/tfcserver/_default.cfg @@ -106,6 +106,11 @@ curlcustomstring="" stoponlyifnoplayers="off" stoponlyifnoplayersallcommands="on" +## Player Warnings | https://docs.linuxgsm.com/features/player-warnings +# Minutes to warn players in-game before a stop, restart or update. 0 to disable. +# e.g. 15 warns at 15, 10, 5, 3 and 1 minutes. +warnplayerstimer="0" + ## Updating | https://docs.linuxgsm.com/commands/update updateonstart="off" diff --git a/lgsm/config-default/config-lgsm/tfserver/_default.cfg b/lgsm/config-default/config-lgsm/tfserver/_default.cfg index 43026b5d19..04af34bbab 100644 --- a/lgsm/config-default/config-lgsm/tfserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/tfserver/_default.cfg @@ -123,6 +123,11 @@ curlcustomstring="" stoponlyifnoplayers="off" stoponlyifnoplayersallcommands="on" +## Player Warnings | https://docs.linuxgsm.com/features/player-warnings +# Minutes to warn players in-game before a stop, restart or update. 0 to disable. +# e.g. 15 warns at 15, 10, 5, 3 and 1 minutes. +warnplayerstimer="0" + ## Updating | https://docs.linuxgsm.com/commands/update updateonstart="off" diff --git a/lgsm/config-default/config-lgsm/tiserver/_default.cfg b/lgsm/config-default/config-lgsm/tiserver/_default.cfg index 59384527b0..503c8de1bf 100644 --- a/lgsm/config-default/config-lgsm/tiserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/tiserver/_default.cfg @@ -105,6 +105,11 @@ curlcustomstring="" stoponlyifnoplayers="off" stoponlyifnoplayersallcommands="on" +## Player Warnings | https://docs.linuxgsm.com/features/player-warnings +# Minutes to warn players in-game before a stop, restart or update. 0 to disable. +# e.g. 15 warns at 15, 10, 5, 3 and 1 minutes. +warnplayerstimer="0" + ## Updating | https://docs.linuxgsm.com/commands/update updateonstart="off" diff --git a/lgsm/config-default/config-lgsm/ts3server/_default.cfg b/lgsm/config-default/config-lgsm/ts3server/_default.cfg index 8b6f0bc339..8c5738d73a 100644 --- a/lgsm/config-default/config-lgsm/ts3server/_default.cfg +++ b/lgsm/config-default/config-lgsm/ts3server/_default.cfg @@ -99,6 +99,11 @@ curlcustomstring="" stoponlyifnoplayers="off" stoponlyifnoplayersallcommands="on" +## Player Warnings | https://docs.linuxgsm.com/features/player-warnings +# Minutes to warn players in-game before a stop, restart or update. 0 to disable. +# e.g. 15 warns at 15, 10, 5, 3 and 1 minutes. +warnplayerstimer="0" + ## Updating | https://docs.linuxgsm.com/commands/update updateonstart="off" diff --git a/lgsm/config-default/config-lgsm/tsserver/_default.cfg b/lgsm/config-default/config-lgsm/tsserver/_default.cfg index 8ade847bd8..25987d7d63 100644 --- a/lgsm/config-default/config-lgsm/tsserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/tsserver/_default.cfg @@ -106,6 +106,11 @@ curlcustomstring="" stoponlyifnoplayers="off" stoponlyifnoplayersallcommands="on" +## Player Warnings | https://docs.linuxgsm.com/features/player-warnings +# Minutes to warn players in-game before a stop, restart or update. 0 to disable. +# e.g. 15 warns at 15, 10, 5, 3 and 1 minutes. +warnplayerstimer="0" + ## Updating | https://docs.linuxgsm.com/commands/update updateonstart="off" diff --git a/lgsm/config-default/config-lgsm/tuserver/_default.cfg b/lgsm/config-default/config-lgsm/tuserver/_default.cfg index 3597cac15d..102b948b41 100644 --- a/lgsm/config-default/config-lgsm/tuserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/tuserver/_default.cfg @@ -109,6 +109,11 @@ curlcustomstring="" stoponlyifnoplayers="off" stoponlyifnoplayersallcommands="on" +## Player Warnings | https://docs.linuxgsm.com/features/player-warnings +# Minutes to warn players in-game before a stop, restart or update. 0 to disable. +# e.g. 15 warns at 15, 10, 5, 3 and 1 minutes. +warnplayerstimer="0" + ## Updating | https://docs.linuxgsm.com/commands/update updateonstart="off" diff --git a/lgsm/config-default/config-lgsm/twserver/_default.cfg b/lgsm/config-default/config-lgsm/twserver/_default.cfg index d423126ab8..4923f24392 100644 --- a/lgsm/config-default/config-lgsm/twserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/twserver/_default.cfg @@ -106,6 +106,11 @@ curlcustomstring="" stoponlyifnoplayers="off" stoponlyifnoplayersallcommands="on" +## Player Warnings | https://docs.linuxgsm.com/features/player-warnings +# Minutes to warn players in-game before a stop, restart or update. 0 to disable. +# e.g. 15 warns at 15, 10, 5, 3 and 1 minutes. +warnplayerstimer="0" + ## Updating | https://docs.linuxgsm.com/commands/update updateonstart="off" diff --git a/lgsm/config-default/config-lgsm/untserver/_default.cfg b/lgsm/config-default/config-lgsm/untserver/_default.cfg index 5ae3612fe1..a2a0308208 100644 --- a/lgsm/config-default/config-lgsm/untserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/untserver/_default.cfg @@ -113,6 +113,11 @@ curlcustomstring="" stoponlyifnoplayers="off" stoponlyifnoplayersallcommands="on" +## Player Warnings | https://docs.linuxgsm.com/features/player-warnings +# Minutes to warn players in-game before a stop, restart or update. 0 to disable. +# e.g. 15 warns at 15, 10, 5, 3 and 1 minutes. +warnplayerstimer="0" + ## Updating | https://docs.linuxgsm.com/commands/update updateonstart="off" diff --git a/lgsm/config-default/config-lgsm/ut2k4server/_default.cfg b/lgsm/config-default/config-lgsm/ut2k4server/_default.cfg index 40803ef4d9..00cf8ad5ae 100644 --- a/lgsm/config-default/config-lgsm/ut2k4server/_default.cfg +++ b/lgsm/config-default/config-lgsm/ut2k4server/_default.cfg @@ -103,6 +103,11 @@ curlcustomstring="" stoponlyifnoplayers="off" stoponlyifnoplayersallcommands="on" +## Player Warnings | https://docs.linuxgsm.com/features/player-warnings +# Minutes to warn players in-game before a stop, restart or update. 0 to disable. +# e.g. 15 warns at 15, 10, 5, 3 and 1 minutes. +warnplayerstimer="0" + ## Backup | https://docs.linuxgsm.com/commands/backup maxbackups="4" maxbackupdays="30" diff --git a/lgsm/config-default/config-lgsm/ut3server/_default.cfg b/lgsm/config-default/config-lgsm/ut3server/_default.cfg index 031a2b0472..9a77eeadd9 100644 --- a/lgsm/config-default/config-lgsm/ut3server/_default.cfg +++ b/lgsm/config-default/config-lgsm/ut3server/_default.cfg @@ -119,6 +119,11 @@ curlcustomstring="" stoponlyifnoplayers="off" stoponlyifnoplayersallcommands="on" +## Player Warnings | https://docs.linuxgsm.com/features/player-warnings +# Minutes to warn players in-game before a stop, restart or update. 0 to disable. +# e.g. 15 warns at 15, 10, 5, 3 and 1 minutes. +warnplayerstimer="0" + ## Backup | https://docs.linuxgsm.com/commands/backup maxbackups="4" maxbackupdays="30" diff --git a/lgsm/config-default/config-lgsm/ut99server/_default.cfg b/lgsm/config-default/config-lgsm/ut99server/_default.cfg index c1506ad38b..c61d542f49 100644 --- a/lgsm/config-default/config-lgsm/ut99server/_default.cfg +++ b/lgsm/config-default/config-lgsm/ut99server/_default.cfg @@ -103,6 +103,11 @@ curlcustomstring="" stoponlyifnoplayers="off" stoponlyifnoplayersallcommands="on" +## Player Warnings | https://docs.linuxgsm.com/features/player-warnings +# Minutes to warn players in-game before a stop, restart or update. 0 to disable. +# e.g. 15 warns at 15, 10, 5, 3 and 1 minutes. +warnplayerstimer="0" + ## Backup | https://docs.linuxgsm.com/commands/backup maxbackups="4" maxbackupdays="30" diff --git a/lgsm/config-default/config-lgsm/utserver/_default.cfg b/lgsm/config-default/config-lgsm/utserver/_default.cfg index e26b79e6e2..59341032e7 100644 --- a/lgsm/config-default/config-lgsm/utserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/utserver/_default.cfg @@ -107,6 +107,11 @@ curlcustomstring="" stoponlyifnoplayers="off" stoponlyifnoplayersallcommands="on" +## Player Warnings | https://docs.linuxgsm.com/features/player-warnings +# Minutes to warn players in-game before a stop, restart or update. 0 to disable. +# e.g. 15 warns at 15, 10, 5, 3 and 1 minutes. +warnplayerstimer="0" + ## Backup | https://docs.linuxgsm.com/commands/backup maxbackups="4" maxbackupdays="30" diff --git a/lgsm/config-default/config-lgsm/vhserver/_default.cfg b/lgsm/config-default/config-lgsm/vhserver/_default.cfg index e4d498768a..7506613fcc 100644 --- a/lgsm/config-default/config-lgsm/vhserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/vhserver/_default.cfg @@ -143,6 +143,11 @@ curlcustomstring="" stoponlyifnoplayers="off" stoponlyifnoplayersallcommands="on" +## Player Warnings | https://docs.linuxgsm.com/features/player-warnings +# Minutes to warn players in-game before a stop, restart or update. 0 to disable. +# e.g. 15 warns at 15, 10, 5, 3 and 1 minutes. +warnplayerstimer="0" + ## Updating | https://docs.linuxgsm.com/commands/update updateonstart="off" diff --git a/lgsm/config-default/config-lgsm/vintsserver/_default.cfg b/lgsm/config-default/config-lgsm/vintsserver/_default.cfg index 47dcfb3d03..fb44ecefb5 100644 --- a/lgsm/config-default/config-lgsm/vintsserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/vintsserver/_default.cfg @@ -103,6 +103,11 @@ curlcustomstring="" stoponlyifnoplayers="off" stoponlyifnoplayersallcommands="on" +## Player Warnings | https://docs.linuxgsm.com/features/player-warnings +# Minutes to warn players in-game before a stop, restart or update. 0 to disable. +# e.g. 15 warns at 15, 10, 5, 3 and 1 minutes. +warnplayerstimer="0" + ## Updating | https://docs.linuxgsm.com/commands/update updateonstart="off" diff --git a/lgsm/config-default/config-lgsm/vpmcserver/_default.cfg b/lgsm/config-default/config-lgsm/vpmcserver/_default.cfg index 67715860f8..488a412cd0 100644 --- a/lgsm/config-default/config-lgsm/vpmcserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/vpmcserver/_default.cfg @@ -106,6 +106,11 @@ curlcustomstring="" stoponlyifnoplayers="off" stoponlyifnoplayersallcommands="on" +## Player Warnings | https://docs.linuxgsm.com/features/player-warnings +# Minutes to warn players in-game before a stop, restart or update. 0 to disable. +# e.g. 15 warns at 15, 10, 5, 3 and 1 minutes. +warnplayerstimer="0" + ## Updating | https://docs.linuxgsm.com/commands/update updateonstart="off" diff --git a/lgsm/config-default/config-lgsm/vsserver/_default.cfg b/lgsm/config-default/config-lgsm/vsserver/_default.cfg index d640347acc..bb212d398f 100644 --- a/lgsm/config-default/config-lgsm/vsserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/vsserver/_default.cfg @@ -106,6 +106,11 @@ curlcustomstring="" stoponlyifnoplayers="off" stoponlyifnoplayersallcommands="on" +## Player Warnings | https://docs.linuxgsm.com/features/player-warnings +# Minutes to warn players in-game before a stop, restart or update. 0 to disable. +# e.g. 15 warns at 15, 10, 5, 3 and 1 minutes. +warnplayerstimer="0" + ## Updating | https://docs.linuxgsm.com/commands/update updateonstart="off" diff --git a/lgsm/config-default/config-lgsm/wetserver/_default.cfg b/lgsm/config-default/config-lgsm/wetserver/_default.cfg index 246b41a194..6f1e1446ed 100644 --- a/lgsm/config-default/config-lgsm/wetserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/wetserver/_default.cfg @@ -99,6 +99,11 @@ curlcustomstring="" stoponlyifnoplayers="off" stoponlyifnoplayersallcommands="on" +## Player Warnings | https://docs.linuxgsm.com/features/player-warnings +# Minutes to warn players in-game before a stop, restart or update. 0 to disable. +# e.g. 15 warns at 15, 10, 5, 3 and 1 minutes. +warnplayerstimer="0" + ## Backup | https://docs.linuxgsm.com/commands/backup maxbackups="4" maxbackupdays="30" diff --git a/lgsm/config-default/config-lgsm/wfserver/_default.cfg b/lgsm/config-default/config-lgsm/wfserver/_default.cfg index ab0c88e305..bd8fc55c3e 100644 --- a/lgsm/config-default/config-lgsm/wfserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/wfserver/_default.cfg @@ -104,6 +104,11 @@ curlcustomstring="" stoponlyifnoplayers="off" stoponlyifnoplayersallcommands="on" +## Player Warnings | https://docs.linuxgsm.com/features/player-warnings +# Minutes to warn players in-game before a stop, restart or update. 0 to disable. +# e.g. 15 warns at 15, 10, 5, 3 and 1 minutes. +warnplayerstimer="0" + ## Updating | https://docs.linuxgsm.com/commands/update updateonstart="off" diff --git a/lgsm/config-default/config-lgsm/wmcserver/_default.cfg b/lgsm/config-default/config-lgsm/wmcserver/_default.cfg index 4b2a258065..d54aa9897e 100644 --- a/lgsm/config-default/config-lgsm/wmcserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/wmcserver/_default.cfg @@ -106,6 +106,11 @@ curlcustomstring="" stoponlyifnoplayers="off" stoponlyifnoplayersallcommands="on" +## Player Warnings | https://docs.linuxgsm.com/features/player-warnings +# Minutes to warn players in-game before a stop, restart or update. 0 to disable. +# e.g. 15 warns at 15, 10, 5, 3 and 1 minutes. +warnplayerstimer="0" + ## Updating | https://docs.linuxgsm.com/commands/update updateonstart="off" diff --git a/lgsm/config-default/config-lgsm/wurmserver/_default.cfg b/lgsm/config-default/config-lgsm/wurmserver/_default.cfg index a57da3c364..b8c2736d17 100644 --- a/lgsm/config-default/config-lgsm/wurmserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/wurmserver/_default.cfg @@ -143,6 +143,11 @@ curlcustomstring="" stoponlyifnoplayers="off" stoponlyifnoplayersallcommands="on" +## Player Warnings | https://docs.linuxgsm.com/features/player-warnings +# Minutes to warn players in-game before a stop, restart or update. 0 to disable. +# e.g. 15 warns at 15, 10, 5, 3 and 1 minutes. +warnplayerstimer="0" + ## Updating | https://docs.linuxgsm.com/commands/update updateonstart="off" diff --git a/lgsm/config-default/config-lgsm/xntserver/_default.cfg b/lgsm/config-default/config-lgsm/xntserver/_default.cfg index da371512e9..6d362f5d45 100644 --- a/lgsm/config-default/config-lgsm/xntserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/xntserver/_default.cfg @@ -97,6 +97,15 @@ telegramthreadid="" telegramsilentnotification="false" curlcustomstring="" +## Stop | https://docs.linuxgsm.com/commands/start-stop-restart +stoponlyifnoplayers="off" +stoponlyifnoplayersallcommands="on" + +## Player Warnings | https://docs.linuxgsm.com/features/player-warnings +# Minutes to warn players in-game before a stop, restart or update. 0 to disable. +# e.g. 15 warns at 15, 10, 5, 3 and 1 minutes. +warnplayerstimer="0" + ## Backup | https://docs.linuxgsm.com/commands/backup maxbackups="4" maxbackupdays="30" diff --git a/lgsm/config-default/config-lgsm/zmrserver/_default.cfg b/lgsm/config-default/config-lgsm/zmrserver/_default.cfg index 262487bdba..8bdeb2fbf5 100644 --- a/lgsm/config-default/config-lgsm/zmrserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/zmrserver/_default.cfg @@ -107,6 +107,11 @@ curlcustomstring="" stoponlyifnoplayers="off" stoponlyifnoplayersallcommands="on" +## Player Warnings | https://docs.linuxgsm.com/features/player-warnings +# Minutes to warn players in-game before a stop, restart or update. 0 to disable. +# e.g. 15 warns at 15, 10, 5, 3 and 1 minutes. +warnplayerstimer="0" + ## Updating | https://docs.linuxgsm.com/commands/update updateonstart="off" diff --git a/lgsm/config-default/config-lgsm/zpsserver/_default.cfg b/lgsm/config-default/config-lgsm/zpsserver/_default.cfg index 456a617659..fc4b50fb92 100644 --- a/lgsm/config-default/config-lgsm/zpsserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/zpsserver/_default.cfg @@ -112,6 +112,11 @@ curlcustomstring="" stoponlyifnoplayers="off" stoponlyifnoplayersallcommands="on" +## Player Warnings | https://docs.linuxgsm.com/features/player-warnings +# Minutes to warn players in-game before a stop, restart or update. 0 to disable. +# e.g. 15 warns at 15, 10, 5, 3 and 1 minutes. +warnplayerstimer="0" + ## Updating | https://docs.linuxgsm.com/commands/update updateonstart="off" diff --git a/lgsm/modules/check_players_online.sh b/lgsm/modules/check_players_online.sh index b38de1f704..4034d35f01 100755 --- a/lgsm/modules/check_players_online.sh +++ b/lgsm/modules/check_players_online.sh @@ -3,32 +3,39 @@ # Author: Daniel Gibbs # Contributors: https://linuxgsm.com/contrib # Website: https://linuxgsm.com -# Description: Queries the server with gamedig and sets ${playersonline} to the -# current player count when players are connected (empty otherwise). -# Used by the stoponlyifnoplayers feature to postpone stop/restart. +# Description: Checks if players are on the server. moduleselfname="$(basename "$(readlink -f "${BASH_SOURCE[0]}")")" playersonline="" -if [ "${stoponlyifnoplayers}" == "on" ]; then - if [ "${querymode}" == "2" ] || [ "${querymode}" == "3" ]; then - querysucceeded="0" +playerscounted="" +playercountunavailable="" +if [ "${stoponlyifnoplayers}" == "on" ] || [ "${playercheckforce}" == "1" ]; then + if [ "${querymode}" != "2" ] && [ "${querymode}" != "3" ]; then + playercountunavailable="querymode ${querymode} cannot count players" + elif [ ! -f "${lgsmdir}/node_modules/gamedig/bin/gamedig.js" ] && [ ! "$(command -v gamedig 2> /dev/null)" ]; then + playercountunavailable="gamedig is not installed" + elif [ ! "$(command -v jq 2> /dev/null)" ]; then + playercountunavailable="jq is not installed" + else for queryip in "${queryips[@]}"; do query_gamedig.sh if [ "${querystatus}" == "0" ]; then - querysucceeded="1" + playerscounted="1" if [ -n "${gdplayers}" ] && [ "${gdplayers}" -ne 0 ]; then playersonline="${gdplayers}" break fi fi done - # The query failed for every configured IP, so the player count could not be - # determined. Fail open (proceed as if empty) rather than block the server - # indefinitely, but warn clearly since the safety check did not actually run. - if [ "${querysucceeded}" == "0" ]; then - fn_print_warn_nl "Unable to determine player count: stoponlyifnoplayers check skipped" - fn_script_log_warn "Unable to determine player count via gamedig: stoponlyifnoplayers check skipped" + if [ "${playerscounted}" != "1" ]; then + playercountunavailable="query failed" fi fi + # The player count could not be determined. Fail open (proceed as if empty) rather than + # block the server indefinitely, but warn clearly since the check did not actually run. + if [ -n "${playercountunavailable}" ] && [ "${playercheckforce}" != "1" ]; then + fn_print_warn_nl "Unable to determine player count (${playercountunavailable}): stoponlyifnoplayers check skipped" + fn_script_log_warn "Unable to determine player count (${playercountunavailable}): stoponlyifnoplayers check skipped" + fi fi diff --git a/lgsm/modules/command_backup.sh b/lgsm/modules/command_backup.sh index 5892a81eb2..cb1de84152 100755 --- a/lgsm/modules/command_backup.sh +++ b/lgsm/modules/command_backup.sh @@ -12,6 +12,9 @@ fn_firstcommand_set # Trap to remove lockfile on quit. fn_backup_trap() { + if [ "$(type -t fn_stop_warn_players_cancel)" == "function" ]; then + fn_stop_warn_players_cancel + fi echo -e "" echo -en "backup ${backupname}.${compressext}..." fn_print_canceled_eol_nl diff --git a/lgsm/modules/command_monitor.sh b/lgsm/modules/command_monitor.sh index cc39f0ca34..ef375b3ed5 100755 --- a/lgsm/modules/command_monitor.sh +++ b/lgsm/modules/command_monitor.sh @@ -135,6 +135,37 @@ fn_monitor_check_restart_request() { fi } +# An update postponed because players were online runs once the server is empty. +# It runs in the background as its own update command, so monitor returns straight away +# (e.g. a healthcheck timeout can't stop it) and other monitor runs see the update in progress. +fn_monitor_check_update_request() { + local updaterequest="${lockdir}/${selfname}-update-request.lock" + if [ -f "${updaterequest}" ]; then + fn_print_dots "Checking update: " + fn_print_checking_eol + fn_print_info "Checking update: Update requested: " + fn_print_info_eol_nl + fn_script_log_info "Checking update: Update requested" + check_players_online.sh + if [ -n "${playersonline}" ]; then + fn_print_info_nl "${playersonline} players are on the server: update postponed" + fn_script_log_info "${playersonline} players are on the server: update postponed" + echo "${playersonline}" > "${lockdir:?}/${selfname}-player-numbers.lock" + else + local requestforce="" + if grep -qx "force" "${updaterequest}"; then + requestforce="1" + fi + fn_print_info_nl "Checking update: Running requested update" + fn_script_log_info "Checking update: Running requested update" + forceupdate="${requestforce}" setsid "${rootdir}/${selfname}" update > /dev/null 2>&1 < /dev/null & + # shellcheck disable=SC2034 # Used by core_exit.sh. + exitcode=0 + core_exit.sh + fi + fi +} + fn_monitor_check_backup() { # Remove stale lockfile. if [ -f "${lockdir}/backup.lock" ]; then @@ -159,8 +190,8 @@ fn_monitor_check_backup() { } fn_monitor_check_update() { - # Remove stale lockfile. - if [ -f "${lockdir}/update.lock" ]; then + # Remove stale lockfile, unless a long update is still running. + if [ -f "${lockdir}/update.lock" ] && ! fn_monitor_command_running "update|u|validate|v|force-update|fu|update-restart|ur|workshop-update|wu"; then if [ "$(find "${lockdir}/update.lock" -mmin +15)" ]; then fn_print_dots "Checking update" fn_print_checking_eol @@ -171,7 +202,7 @@ fn_monitor_check_update() { fi fi - if [ -f "${lockdir}/update.lock" ] && fn_monitor_command_running "update|u|validate|v|force-update|fu|update-restart|ur"; then + if [ -f "${lockdir}/update.lock" ] && fn_monitor_command_running "update|u|validate|v|force-update|fu|update-restart|ur|workshop-update|wu"; then fn_print_dots "Checking update" fn_print_checking_eol fn_print_info "Checking update: LinuxGSM is updating the game server" @@ -432,6 +463,7 @@ fn_monitor_check_starting fn_monitor_check_stopping fn_monitor_check_session fn_monitor_check_restart_request +fn_monitor_check_update_request # Monitor will not continue if session only check. if [ "${querymode}" != "1" ]; then diff --git a/lgsm/modules/command_stop.sh b/lgsm/modules/command_stop.sh index 478db210ce..96406ad3ec 100755 --- a/lgsm/modules/command_stop.sh +++ b/lgsm/modules/command_stop.sh @@ -21,11 +21,185 @@ fn_stop_players_online() { fn_print_info_nl "${playersonline} players are on the server: stop prevented" fn_script_log_info "${playersonline} players are on the server: stop prevented" echo "${playersonline}" > "${lockdir:?}/${selfname}-player-numbers.lock" + # Monitor runs the update once the server is empty. + if [ "${firstcommandname}" == "UPDATE" ]; then + date '+%s' > "${lockdir:?}/${selfname}-update-request.lock" + if [ "${forceupdate}" == "1" ]; then + echo "force" >> "${lockdir:?}/${selfname}-update-request.lock" + fi + fn_print_info_nl "Update postponed until the server is empty" + fn_script_log_info "Update postponed until the server is empty" + fi + fn_stop_cancel_locks + # Exit the whole command, including when called by another command (e.g. update) with exitbypass. + unset exitbypass core_exit.sh fi fi } +# Removes the lockfiles of the command that called stop when it ends without stopping the server. +fn_stop_cancel_locks() { + if [ "${firstcommandname}" == "UPDATE" ] || [ "${firstcommandname}" == "WORKSHOP-UPDATE" ]; then + rm -f "${lockdir:?}/update.lock" "${lockdir:?}/last-updated.lock" + elif [ "${firstcommandname}" == "VALIDATE" ]; then + rm -f "${lockdir:?}/update.lock" + elif [ "${firstcommandname}" == "BACKUP" ]; then + rm -f "${lockdir:?}/backup.lock" + fi +} + +# Tells players a warning countdown was cancelled, used when CTRL-C is pressed. +fn_stop_warn_players_cancel() { + if [ "$(cat "${lockdir}/${selfname}-warning.lock" 2> /dev/null)" == "$$" ]; then + fn_stop_warn_players_send "${warnplayersaction}" "0" + rm -f "${lockdir:?}/${selfname}-warning.lock" + fn_stop_cancel_locks + fi +} + +# Sets the game's chat command used to warn players, %s is replaced by the message. +fn_stop_warn_players_command() { + warncommand="" + if [ "${shortname}" == "pz" ]; then + warncommand='servermsg "%s"' + elif [ "${shortname}" == "dst" ]; then + warncommand='c_announce("%s")' + elif [ "${shortname}" == "scpsl" ] || [ "${shortname}" == "scpslsm" ]; then + warncommand="/bc 10 %s" + elif [ "${shortname}" == "vints" ]; then + warncommand="/announce %s" + elif [ "${shortname}" == "wmc" ]; then + warncommand="alert %s" + elif [ "${shortname}" == "fctr" ]; then + warncommand="%s" + elif [ "${engine}" == "source" ] || [ "${engine}" == "source2" ] || [ "${engine}" == "goldsrc" ]; then + warncommand="say %s" + else + local saygames=(bt cod cod2 cod4 coduo codwaw etl hyt jk2 mc mcb mohaa pmc q2 q3 q4 ql qw rtcw sof2 terraria unt wet wf xnt) + local game + for game in "${saygames[@]}"; do + if [ "${shortname}" == "${game}" ]; then + warncommand="say %s" + fi + done + fi +} + +# Sends a warning message to players using the game's own chat command. +# A minutes value of 0 sends a cancelled message. +fn_stop_warn_players_send() { + local message="Server ${1} in ${2} minute" + if [ "${2}" != "1" ]; then + message+="s" + fi + if [ "${2}" == "0" ]; then + message="Server ${1} cancelled" + fi + local warnmessage="${warncommand//%s/${message}}" + TERM=screen tmux -L "${socketname}" send-keys -t "${sessionname}" -l "${warnmessage}" > /dev/null 2>&1 + TERM=screen tmux -L "${socketname}" send-keys -t "${sessionname}" ENTER > /dev/null 2>&1 +} + +# Waits for another LinuxGSM command that is already warning players on this server. +fn_stop_warn_players_wait() { + local warnlock="${lockdir}/${selfname}-warning.lock" + local warnpid + while [ -f "${warnlock}" ]; do + warnpid="$(cat "${warnlock}" 2> /dev/null)" + if [ -z "${warnpid}" ] || ! kill -0 "${warnpid}" 2> /dev/null; then + rm -f "${warnlock:?}" + break + fi + fn_print_info_nl "Warning players: another command is already warning players: waiting" + fn_script_log_info "Warning players: another command is already warning players: waiting" + sleep 30 + done +} + +# Counts down to the stop with in-game warnings, e.g. warnplayerstimer="15" warns at 15, 10, 5, 3 and 1 minutes. +# Skipped when the server is empty, and ends early if the server empties during the countdown. +fn_stop_warn_players() { + if [ "${firstcommandname}" == "STOP" ]; then + warnplayersaction="stopping" + elif [ "${firstcommandname}" == "RESTART" ] || [ "${firstcommandname}" == "BACKUP" ]; then + warnplayersaction="restarting" + elif [ "${firstcommandname}" == "UPDATE" ] || [ "${firstcommandname}" == "WORKSHOP-UPDATE" ]; then + warnplayersaction="updating" + else + return + fi + if [ -z "${warnplayerstimer}" ] || [ "${forceupdate}" == "1" ]; then + return + fi + if ! [[ "${warnplayerstimer}" =~ ^[0-9]+$ ]]; then + fn_print_warn_nl "Warning players: warnplayerstimer must be a number of minutes: skipped" + fn_script_log_warn "Warning players: warnplayerstimer \"${warnplayerstimer}\" is not a number of minutes: skipped" + return + fi + local timer="$((10#${warnplayerstimer}))" + if [ "${timer}" -eq 0 ]; then + return + fi + fn_stop_warn_players_command + if [ "${consoleinteract}" != "yes" ] || [ -z "${warncommand}" ]; then + fn_print_info_nl "Warning players: not supported by ${gamename}: skipped" + fn_script_log_info "Warning players: not supported by ${gamename}: skipped" + return + fi + + fn_stop_warn_players_wait + check_status.sh + if [ "${status}" == "0" ]; then + return + fi + + local steps=("${timer}") + local step + for step in 60 30 15 10 5 3 1; do + if [ "${step}" -lt "${timer}" ]; then + steps+=("${step}") + fi + done + + echo "$$" > "${lockdir:?}/${selfname}-warning.lock" + local i next + for i in "${!steps[@]}"; do + check_status.sh + if [ "${status}" == "0" ]; then + break + fi + # shellcheck disable=SC2034 # Used by check_players_online.sh. + playercheckforce=1 + check_players_online.sh + unset playercheckforce + if [ "${playerscounted}" == "1" ] && [ -z "${playersonline}" ]; then + fn_print_info_nl "Warning players: no players on the server" + fn_script_log_info "Warning players: no players on the server" + break + fi + if [ "${i}" == "0" ] && [ -n "${playercountunavailable}" ]; then + fn_print_info_nl "Warning players: unable to check for players (${playercountunavailable}): warning anyway" + fn_script_log_info "Warning players: unable to check for players (${playercountunavailable}): warning anyway" + fi + fn_stop_warn_players_send "${warnplayersaction}" "${steps[i]}" + fn_print_info_nl "Warning players: ${warnplayersaction} in ${steps[i]} minute(s)" + fn_script_log_info "Warning players: ${warnplayersaction} in ${steps[i]} minute(s)" + next="${steps[i + 1]:-0}" + local waitseconds=$(((steps[i] - next) * 60)) + while [ "${waitseconds}" -gt 0 ]; do + sleep 10 + waitseconds=$((waitseconds - 10)) + check_status.sh + if [ "${status}" == "0" ]; then + break 2 + fi + done + done + unset warnplayersaction + rm -f "${lockdir:?}/${selfname}-warning.lock" +} + # Attempts graceful shutdown by sending 'CTRL+c'. fn_stop_graceful_ctrlc() { fn_print_dots "Graceful: CTRL+c" @@ -401,7 +575,6 @@ fn_stop_pre_check() { fn_print_skip_nl "${servername} is already stopped" fn_script_log_info "${servername} is already stopped" else - fn_stop_players_online # Select graceful shutdown. fn_stop_graceful_select # Check status again, a kill tmux session if graceful shutdown failed. @@ -414,13 +587,21 @@ fn_stop_pre_check() { fn_print_dots "" check.sh +info_game.sh + +# Players are checked and warned before the stopping lockfile is created, +# as a warning countdown can outlast monitor's stale lockfile check. +if [ "${status}" != "0" ]; then + fn_stop_players_online + fn_stop_warn_players + check_status.sh +fi # Create a stopping lockfile that only exists while the stop command is running. date '+%s' > "${lockdir:?}/${selfname}-stopping.lock" fn_print_dots "${servername}" -info_game.sh fn_stop_pre_check # Remove started lockfile. diff --git a/lgsm/modules/command_update.sh b/lgsm/modules/command_update.sh index 7d135c7a56..1726901761 100755 --- a/lgsm/modules/command_update.sh +++ b/lgsm/modules/command_update.sh @@ -13,6 +13,10 @@ fn_firstcommand_set fn_print_dots "" check.sh core_logs.sh + +# A postponed update is requested again if players are still online. +rm -f "${lockdir:?}/${selfname}-update-request.lock" + check_last_update.sh if [ "${shortname}" == "ts3" ]; then diff --git a/lgsm/modules/core_trap.sh b/lgsm/modules/core_trap.sh index f9ff17ff16..c17a5894cd 100755 --- a/lgsm/modules/core_trap.sh +++ b/lgsm/modules/core_trap.sh @@ -17,6 +17,11 @@ fn_exit_trap() { if [ -z "${exitcode}" ]; then exitcode=0 fi + if [ "$(type -t fn_stop_warn_players_cancel)" == "function" ]; then + fn_stop_warn_players_cancel + fi + # CTRL-C exits LinuxGSM, including while one command is running another (e.g. restart running stop). + unset exitbypass core_exit.sh } From fcc337fc668e9ee858f046fec4fa09cb0bcae25a Mon Sep 17 00:00:00 2001 From: Daniel Gibbs Date: Wed, 14 Oct 2026 20:57:04 +0100 Subject: [PATCH 057/164] feat(backup): run backups postponed by players once the server is empty (#5029) * feat(stop): warn players in-game before stop, restart and update, and retry postponed updates * fix(stop): exit when players prevent a stop during update or backup, keep module modes * fix(stop): mark variables shared between modules for shellcheck * refactor(stop): shorten check_players_online module description * refactor(stop): keep chat commands out of the config, clean up locks when a stop is cancelled, exit on CTRL-C * feat(backup): run backups postponed by players once the server is empty, and keep long backups' lockfile * feat(stop): say why the player count is unavailable * fix(monitor): run postponed updates in the background, keep a long update's lockfile, retry forced updates as forced * fix(monitor): run postponed backups in the background * fix(monitor): mark exitcode as used by core_exit for shellcheck * fix(monitor): mark exitcode as used by core_exit for shellcheck --- lgsm/modules/alert.sh | 13 +++++++++++ lgsm/modules/command_backup.sh | 8 +++++-- lgsm/modules/command_monitor.sh | 38 +++++++++++++++++++++++++++++++-- lgsm/modules/command_stop.sh | 6 ++++++ 4 files changed, 61 insertions(+), 4 deletions(-) diff --git a/lgsm/modules/alert.sh b/lgsm/modules/alert.sh index 8b5adfda35..c9e9d2ef34 100755 --- a/lgsm/modules/alert.sh +++ b/lgsm/modules/alert.sh @@ -169,6 +169,17 @@ fn_alert_backup() { alertcolourdec="52480" } +fn_alert_backup_postponed() { + fn_script_log_warn "Sending alert: ${selfname} backup postponed for over 24 hours" + alertaction="Backup Postponed" + alertemoji="⏳" + alertsound="1" + alertmessage="${selfname} has not been backed up for over 24 hours as players are online. The backup will run once the server is empty." + # Amber + alertcolourhex="#cd8b00" + alertcolourdec="13470464" +} + fn_alert_hytale_login() { fn_script_log_info "Sending alert: ${selfname} needs a Hytale server login" alertaction="Login Required" @@ -261,6 +272,8 @@ elif [ "${alert}" == "update-linuxgsm" ]; then fn_alert_update_linuxgsm elif [ "${alert}" == "backup" ]; then fn_alert_backup +elif [ "${alert}" == "backup-postponed" ]; then + fn_alert_backup_postponed elif [ "${alert}" == "hytale-login" ]; then fn_alert_hytale_login else diff --git a/lgsm/modules/command_backup.sh b/lgsm/modules/command_backup.sh index cb1de84152..91c34fbd06 100755 --- a/lgsm/modules/command_backup.sh +++ b/lgsm/modules/command_backup.sh @@ -32,8 +32,10 @@ fn_backup_trap() { # Check if a backup is pending or has been aborted using backup.lock. fn_backup_check_lockfile() { - # Remove stale lockfile. - if [ -f "${lockdir}/backup.lock" ]; then + # Remove stale lockfile, unless a long backup is still running. + local backupsrunning + backupsrunning="$(pgrep -fc -u "$(id -u)" "^([^ ]*/)?bash ([^ ]*/)?${selfname} (backup|b)( |$)")" + if [ -f "${lockdir}/backup.lock" ] && [ "${backupsrunning:-0}" -le 1 ]; then if [ "$(find "${lockdir}/backup.lock" -mmin +60)" ]; then fn_print_dots "Lockfile found: " fn_print_checking_eol @@ -167,6 +169,8 @@ fn_backup_compression() { fn_script_log_pass "Backup created: ${backupname}.${compressext}, total size $(du -sh "${backupdir}/${backupname}.${compressext}" | awk '{print $1}')" alert="backup" alert.sh + # A postponed backup is complete. + rm -f "${lockdir:?}/${selfname}-backup-request.lock" fi } diff --git a/lgsm/modules/command_monitor.sh b/lgsm/modules/command_monitor.sh index ef375b3ed5..887e194190 100755 --- a/lgsm/modules/command_monitor.sh +++ b/lgsm/modules/command_monitor.sh @@ -166,9 +166,42 @@ fn_monitor_check_update_request() { fi } +# A backup postponed because players were online runs once the server is empty, in the background +# like a requested update. An alert is sent once if it has been postponed for over 24 hours. +fn_monitor_check_backup_request() { + local backuprequest="${lockdir}/${selfname}-backup-request.lock" + if [ -f "${backuprequest}" ]; then + fn_print_dots "Checking backup: " + fn_print_checking_eol + fn_print_info "Checking backup: Backup requested: " + fn_print_info_eol_nl + fn_script_log_info "Checking backup: Backup requested" + check_players_online.sh + if [ -n "${playersonline}" ]; then + fn_print_info_nl "${playersonline} players are on the server: backup postponed" + fn_script_log_info "${playersonline} players are on the server: backup postponed" + echo "${playersonline}" > "${lockdir:?}/${selfname}-player-numbers.lock" + local requested + requested="$(head -n 1 "${backuprequest}")" + if [[ "${requested}" =~ ^[0-9]+$ ]] && [ "$(($(date '+%s') - requested))" -gt 86400 ] && ! grep -q "alerted" "${backuprequest}"; then + alert="backup-postponed" + alert.sh + echo "alerted" >> "${backuprequest}" + fi + else + fn_print_info_nl "Checking backup: Running requested backup" + fn_script_log_info "Checking backup: Running requested backup" + setsid "${rootdir}/${selfname}" backup > /dev/null 2>&1 < /dev/null & + # shellcheck disable=SC2034 # Used by core_exit.sh. + exitcode=0 + core_exit.sh + fi + fi +} + fn_monitor_check_backup() { - # Remove stale lockfile. - if [ -f "${lockdir}/backup.lock" ]; then + # Remove stale lockfile, unless a long backup is still running. + if [ -f "${lockdir}/backup.lock" ] && ! fn_monitor_command_running "backup|b"; then if [ "$(find "${lockdir}/backup.lock" -mmin +60)" ]; then fn_print_dots "Checking backup" fn_print_checking_eol @@ -464,6 +497,7 @@ fn_monitor_check_stopping fn_monitor_check_session fn_monitor_check_restart_request fn_monitor_check_update_request +fn_monitor_check_backup_request # Monitor will not continue if session only check. if [ "${querymode}" != "1" ]; then diff --git a/lgsm/modules/command_stop.sh b/lgsm/modules/command_stop.sh index 96406ad3ec..80d8268a9b 100755 --- a/lgsm/modules/command_stop.sh +++ b/lgsm/modules/command_stop.sh @@ -29,6 +29,12 @@ fn_stop_players_online() { fi fn_print_info_nl "Update postponed until the server is empty" fn_script_log_info "Update postponed until the server is empty" + elif [ "${firstcommandname}" == "BACKUP" ]; then + if [ ! -f "${lockdir}/${selfname}-backup-request.lock" ]; then + date '+%s' > "${lockdir:?}/${selfname}-backup-request.lock" + fi + fn_print_info_nl "Backup postponed until the server is empty" + fn_script_log_info "Backup postponed until the server is empty" fi fn_stop_cancel_locks # Exit the whole command, including when called by another command (e.g. update) with exitbypass. From f6454dcfc34bd5ffc7dbf7a6ea1892f55a869b5e Mon Sep 17 00:00:00 2001 From: Daniel Gibbs Date: Wed, 14 Oct 2026 21:15:57 +0100 Subject: [PATCH 058/164] fix(modules): make info_messages.sh executable (#5030) --- lgsm/modules/info_messages.sh | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 lgsm/modules/info_messages.sh diff --git a/lgsm/modules/info_messages.sh b/lgsm/modules/info_messages.sh old mode 100644 new mode 100755 From 5714958bd60f421c5c14df76eefead1b406cfdd7 Mon Sep 17 00:00:00 2001 From: Daniel Gibbs Date: Wed, 14 Oct 2026 22:42:52 +0100 Subject: [PATCH 059/164] fix(vints): remove old assets before extracting an update (#5032) --- lgsm/modules/update_vints.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/lgsm/modules/update_vints.sh b/lgsm/modules/update_vints.sh index 5bf3df25d0..d9480501a7 100755 --- a/lgsm/modules/update_vints.sh +++ b/lgsm/modules/update_vints.sh @@ -10,6 +10,7 @@ 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" "${remotebuildhash}" + rm -rf "${serverfiles:?}/assets" fn_dl_extract "${tmpdir}" "${remotebuildfilename}" "${serverfiles}" fn_clear_tmp } From b42436ada3cd32888a65b3110599ab29b50038ad Mon Sep 17 00:00:00 2001 From: Daniel Gibbs Date: Wed, 14 Oct 2026 22:45:41 +0100 Subject: [PATCH 060/164] fix(rwserver): stop Rising World gracefully with shutdown (#5031) --- .../config-lgsm/rwserver/_default.cfg | 4 ++- lgsm/modules/command_send.sh | 3 +- lgsm/modules/command_stop.sh | 36 +++++++++++++++++++ 3 files changed, 41 insertions(+), 2 deletions(-) diff --git a/lgsm/config-default/config-lgsm/rwserver/_default.cfg b/lgsm/config-default/config-lgsm/rwserver/_default.cfg index 200a37ed13..5536e1a686 100644 --- a/lgsm/config-default/config-lgsm/rwserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/rwserver/_default.cfg @@ -150,7 +150,9 @@ steammaster="false" # 9: GoldSrc # 10: Avorion # 11: end -stopmode="3" +# 12: shutdown +# 15: Rising World +stopmode="15" ## Query mode # 1: session only diff --git a/lgsm/modules/command_send.sh b/lgsm/modules/command_send.sh index 8b8a1a2525..71c1e43426 100755 --- a/lgsm/modules/command_send.sh +++ b/lgsm/modules/command_send.sh @@ -27,7 +27,8 @@ if [ "${status}" != "0" ]; then echo "" fn_print_dots "Sending command to console: \"${commandtosend}\"" fn_print_ok_nl "Sending command to console: \"${commandtosend}\"" - TERM=screen tmux -L "${socketname}" send-keys -t "${sessionname}" "${commandtosend}" ENTER + TERM=screen tmux -L "${socketname}" send-keys -t "${sessionname}" -l "${commandtosend}" + TERM=screen tmux -L "${socketname}" send-keys -t "${sessionname}" ENTER fn_script_log_pass "Command \"${commandtosend}\" sent to console" else fn_print_error_nl "Unable to send command to console. Server not running" diff --git a/lgsm/modules/command_stop.sh b/lgsm/modules/command_stop.sh index 80d8268a9b..2abd520031 100755 --- a/lgsm/modules/command_stop.sh +++ b/lgsm/modules/command_stop.sh @@ -523,6 +523,40 @@ fn_stop_graceful_rwr() { fn_stop_graceful_ctrlc } +# Attempts graceful shutdown of Rising World using 'shutdown'. +# Its console can miss input, so the command is sent again every 10 seconds until the server stops. +fn_stop_graceful_rw() { + fn_print_dots "Graceful: sending \"shutdown\"" + fn_script_log_info "Graceful: sending \"shutdown\"" + for ((seconds = 1; seconds <= 120; seconds++)); do + if [ $((seconds % 10)) -eq 1 ]; then + TERM=screen tmux -L "${socketname}" send-keys -t "${sessionname}" ENTER > /dev/null 2>&1 + sleep 1 + TERM=screen tmux -L "${socketname}" send-keys -t "${sessionname}" -l "shutdown" > /dev/null 2>&1 + TERM=screen tmux -L "${socketname}" send-keys -t "${sessionname}" ENTER > /dev/null 2>&1 + fi + check_status.sh + if [ "${status}" == "0" ]; then + fn_print_ok "Graceful: sending \"shutdown\": ${seconds}" + fn_print_ok_eol_nl + fn_script_log_pass "Graceful: sending \"shutdown\": OK: ${seconds} seconds" + if [ "${statusalert}" == "on" ] && [ "${firstcommandname}" == "STOP" ]; then + alert="stopped" + alert.sh + fi + break + fi + fn_sleep_time_1 + fn_print_dots "Graceful: sending \"shutdown\": ${seconds}" + done + check_status.sh + if [ "${status}" != "0" ]; then + fn_print_error "Graceful: sending \"shutdown\": " + fn_print_fail_eol_nl + fn_script_log_error "Graceful: sending \"shutdown\": FAIL" + fi +} + fn_stop_graceful_select() { if [ "${stopmode}" == "1" ]; then fn_stop_tmux @@ -552,6 +586,8 @@ fn_stop_graceful_select() { fn_stop_graceful_sm elif [ "${stopmode}" == "14" ]; then fn_stop_graceful_rwr + elif [ "${stopmode}" == "15" ]; then + fn_stop_graceful_rw fi } From c753a690516400f515f28d9cc6ecc10676a5af2b Mon Sep 17 00:00:00 2001 From: Daniel Gibbs Date: Wed, 14 Oct 2026 22:48:53 +0100 Subject: [PATCH 061/164] feat(stop): add warning chat commands for Avorion, Craftopia, MTA, Necesse and Rising World (#5033) --- lgsm/config-default/config-lgsm/necserver/_default.cfg | 2 +- lgsm/modules/command_stop.sh | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/lgsm/config-default/config-lgsm/necserver/_default.cfg b/lgsm/config-default/config-lgsm/necserver/_default.cfg index 03aa886301..555d0cf008 100644 --- a/lgsm/config-default/config-lgsm/necserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/necserver/_default.cfg @@ -166,7 +166,7 @@ querytype="" ## Console type consoleverbose="yes" -consoleinteract="no" +consoleinteract="yes" ## Game Server Details # Do not edit diff --git a/lgsm/modules/command_stop.sh b/lgsm/modules/command_stop.sh index 2abd520031..41412bec4e 100755 --- a/lgsm/modules/command_stop.sh +++ b/lgsm/modules/command_stop.sh @@ -77,12 +77,14 @@ fn_stop_warn_players_command() { warncommand="/announce %s" elif [ "${shortname}" == "wmc" ]; then warncommand="alert %s" + elif [ "${shortname}" == "av" ]; then + warncommand="/say %s" elif [ "${shortname}" == "fctr" ]; then warncommand="%s" elif [ "${engine}" == "source" ] || [ "${engine}" == "source2" ] || [ "${engine}" == "goldsrc" ]; then warncommand="say %s" else - local saygames=(bt cod cod2 cod4 coduo codwaw etl hyt jk2 mc mcb mohaa pmc q2 q3 q4 ql qw rtcw sof2 terraria unt wet wf xnt) + local saygames=(bt cod cod2 cod4 coduo codwaw ct etl hyt jk2 mc mcb mohaa mta nec pmc q2 q3 q4 ql qw rtcw rw sof2 terraria unt wet wf xnt) local game for game in "${saygames[@]}"; do if [ "${shortname}" == "${game}" ]; then From 2a494011fb636642b9a5d1332a79e359586c54f8 Mon Sep 17 00:00:00 2001 From: Daniel Gibbs Date: Wed, 14 Oct 2026 22:59:44 +0100 Subject: [PATCH 062/164] fix(ut99): use System directory for patch 469f and later (#5034) Patch 469f no longer ships System64 and puts the 64-bit ucc-bin in System, so fresh installs failed with Executable was not found. --- lgsm/config-default/config-lgsm/ut99server/_default.cfg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lgsm/config-default/config-lgsm/ut99server/_default.cfg b/lgsm/config-default/config-lgsm/ut99server/_default.cfg index c61d542f49..e23a6d51b5 100644 --- a/lgsm/config-default/config-lgsm/ut99server/_default.cfg +++ b/lgsm/config-default/config-lgsm/ut99server/_default.cfg @@ -166,7 +166,7 @@ glibc="2.1" # Edit with care ## Game Server Directories -systemdir="${serverfiles}/System64" +systemdir="${serverfiles}/System" executabledir="${systemdir}" executable="./ucc-bin" servercfgdir="${systemdir}" From 4d3e1ec3a1cab60709080e8d6a129d83afcf2e8f Mon Sep 17 00:00:00 2001 From: Daniel Gibbs Date: Wed, 14 Oct 2026 23:20:26 +0100 Subject: [PATCH 063/164] fix(postdetails): remove shared temporary status file (#5035) --- lgsm/modules/command_postdetails.sh | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/lgsm/modules/command_postdetails.sh b/lgsm/modules/command_postdetails.sh index d029093b5f..b62834ffcb 100755 --- a/lgsm/modules/command_postdetails.sh +++ b/lgsm/modules/command_postdetails.sh @@ -58,11 +58,12 @@ else fi fn_print_dots "termbin.com" -link=$(cat "${postdetailslog}" | { - nc -w 10 termbin.com 9999 - echo $? > /tmp/nc_exit_status -} | tr -d '\n\0') -nc_exit_status=$(cat /tmp/nc_exit_status) +# Keep the upload status without sharing a temporary file between invocations. +link=$( + set -o pipefail + nc -w 10 termbin.com 9999 < "${postdetailslog}" | tr -d '\n\0' +) +nc_exit_status=$? if [ "${nc_exit_status}" -ne 0 ]; then fn_print_error_nl "Failed to post to termbin.com" fn_script_log_error "Failed to post to termbin.com" From 8dcb527a749d2eb827714f1976b3e31c4c43e44e Mon Sep 17 00:00:00 2001 From: Daniel Gibbs Date: Thu, 15 Oct 2026 19:19:21 +0100 Subject: [PATCH 064/164] feat(docker): move game server images to Ubuntu 26.04 (#5028) Moves 134 docker-gameserver images from ubuntu-24.04 to ubuntu-26.04 by changing the os column of lgsm/data/serverlist.csv. Every server was installed fresh and checked with monitor on both 24.04 and 26.04; full results are in #5027. Staying on 24.04: cod, cod2, coduo and mohaa (libstdc++5:i386, #5026) and scpslsm (retired Steam app, #5038). ios, ut99 and rwr also need #5024, #5034 and #5021, which ship in the same release. Refs #5027 --- lgsm/data/serverlist.csv | 268 +++++++++++++++++++-------------------- 1 file changed, 134 insertions(+), 134 deletions(-) diff --git a/lgsm/data/serverlist.csv b/lgsm/data/serverlist.csv index 9c03abb0e4..82c478c088 100644 --- a/lgsm/data/serverlist.csv +++ b/lgsm/data/serverlist.csv @@ -1,144 +1,144 @@ shortname,gameservername,gamename,os -ac,acserver,Assetto Corsa,ubuntu-24.04 -ahl,ahlserver,Action Half-Life,ubuntu-24.04 -ahl2,ahl2server,Action: Source,ubuntu-24.04 -ark,arkserver,ARK: Survival Evolved,ubuntu-24.04 -arma3,arma3server,ARMA 3,ubuntu-24.04 -armar,armarserver,Arma Reforger,ubuntu-24.04 -ats,atsserver,American Truck Simulator,ubuntu-24.04 -av,avserver,Avorion,ubuntu-24.04 -bb,bbserver,BrainBread,ubuntu-24.04 -bb2,bb2server,BrainBread 2,ubuntu-24.04 -bd,bdserver,Base Defense,ubuntu-24.04 +ac,acserver,Assetto Corsa,ubuntu-26.04 +ahl,ahlserver,Action Half-Life,ubuntu-26.04 +ahl2,ahl2server,Action: Source,ubuntu-26.04 +ark,arkserver,ARK: Survival Evolved,ubuntu-26.04 +arma3,arma3server,ARMA 3,ubuntu-26.04 +armar,armarserver,Arma Reforger,ubuntu-26.04 +ats,atsserver,American Truck Simulator,ubuntu-26.04 +av,avserver,Avorion,ubuntu-26.04 +bb,bbserver,BrainBread,ubuntu-26.04 +bb2,bb2server,BrainBread 2,ubuntu-26.04 +bd,bdserver,Base Defense,ubuntu-26.04 bf1942,bf1942server,Battlefield 1942,ubuntu-22.04 bfv,bfvserver,Battlefield: Vietnam,ubuntu-22.04 -bmdm,bmdmserver,Black Mesa: Deathmatch,ubuntu-24.04 -bo,boserver,Ballistic Overkill,ubuntu-24.04 -bs,bsserver,Blade Symphony,ubuntu-24.04 -bt,btserver,Barotrauma,ubuntu-24.04 +bmdm,bmdmserver,Black Mesa: Deathmatch,ubuntu-26.04 +bo,boserver,Ballistic Overkill,ubuntu-26.04 +bs,bsserver,Blade Symphony,ubuntu-26.04 +bt,btserver,Barotrauma,ubuntu-26.04 btl,btlserver,BATTALION: Legacy,ubuntu-20.04 -cc,ccserver,Codename CURE,ubuntu-24.04 -ck,ckserver,Core Keeper,ubuntu-24.04 -cmw,cmwserver,Chivalry: Medieval Warfare,ubuntu-24.04 +cc,ccserver,Codename CURE,ubuntu-26.04 +ck,ckserver,Core Keeper,ubuntu-26.04 +cmw,cmwserver,Chivalry: Medieval Warfare,ubuntu-26.04 cod,codserver,Call of Duty,ubuntu-24.04 cod2,cod2server,Call of Duty 2,ubuntu-24.04 -cod4,cod4server,Call of Duty 4,ubuntu-24.04 +cod4,cod4server,Call of Duty 4,ubuntu-26.04 coduo,coduoserver,Call of Duty: United Offensive,ubuntu-24.04 -codwaw,codwawserver,Call of Duty: World at War,ubuntu-24.04 -col,colserver,Colony Survival,ubuntu-24.04 -cs,csserver,Counter-Strike 1.6,ubuntu-24.04 -cs2,cs2server,Counter-Strike 2,ubuntu-24.04 -cscz,csczserver,Counter-Strike: Condition Zero,ubuntu-24.04 -csgo,csgoserver,Counter-Strike: Global Offensive,ubuntu-24.04 -css,cssserver,Counter-Strike: Source,ubuntu-24.04 -ct,ctserver,Craftopia,ubuntu-24.04 -dab,dabserver,Double Action: Boogaloo,ubuntu-24.04 -dayz,dayzserver,DayZ,ubuntu-24.04 -dmc,dmcserver,Deathmatch Classic,ubuntu-24.04 -dod,dodserver,Day of Defeat,ubuntu-24.04 -dodr,dodrserver,Day of Dragons,ubuntu-24.04 -dods,dodsserver,Day of Defeat: Source,ubuntu-24.04 -doi,doiserver,Day of Infamy,ubuntu-24.04 -dst,dstserver,Don't Starve Together,ubuntu-24.04 -dys,dysserver,Dystopia,ubuntu-24.04 -eco,ecoserver,Eco,ubuntu-24.04 -em,emserver,Empires Mod,ubuntu-24.04 -etl,etlserver,ET: Legacy,ubuntu-24.04 -ets2,ets2server,Euro Truck Simulator 2,ubuntu-24.04 -fctr,fctrserver,Factorio,ubuntu-24.04 -fof,fofserver,Fistful of Frags,ubuntu-24.04 -gmod,gmodserver,Garrys Mod,ubuntu-24.04 -hcu,hcuserver,HYPERCHARGE: Unboxed,ubuntu-24.04 -hl2dm,hl2dmserver,Half-Life 2: Deathmatch,ubuntu-24.04 -hldm,hldmserver,Half-Life: Deathmatch,ubuntu-24.04 -hldms,hldmsserver,Half-Life Deathmatch: Source,ubuntu-24.04 -hw,hwserver,Hurtworld,ubuntu-24.04 -hyt,hytserver,Hytale,ubuntu-24.04 -hz,hzserver,Humanitz,ubuntu-24.04 -ins,insserver,Insurgency,ubuntu-24.04 -inss,inssserver,Insurgency: Sandstorm,ubuntu-24.04 -ios,iosserver,IOSoccer,ubuntu-24.04 -jbep3,jbep3server,Jabroni Brawl: Episode 3,ubuntu-24.04 -jc2,jc2server,Just Cause 2,ubuntu-24.04 -jc3,jc3server,Just Cause 3,ubuntu-24.04 -jk2,jk2server,Jedi Knight II: Jedi Outcast,ubuntu-24.04 -kf,kfserver,Killing Floor,ubuntu-24.04 -kf2,kf2server,Killing Floor 2,ubuntu-24.04 -l4d,l4dserver,Left 4 Dead,ubuntu-24.04 -l4d2,l4d2server,Left 4 Dead 2,ubuntu-24.04 -mc,mcserver,Minecraft,ubuntu-24.04 -mcb,mcbserver,Minecraft Bedrock,ubuntu-24.04 -mcv,mcvserver,Military Conflict: Vietnam,ubuntu-24.04 -mh,mhserver,MORDHAU,ubuntu-24.04 +codwaw,codwawserver,Call of Duty: World at War,ubuntu-26.04 +col,colserver,Colony Survival,ubuntu-26.04 +cs,csserver,Counter-Strike 1.6,ubuntu-26.04 +cs2,cs2server,Counter-Strike 2,ubuntu-26.04 +cscz,csczserver,Counter-Strike: Condition Zero,ubuntu-26.04 +csgo,csgoserver,Counter-Strike: Global Offensive,ubuntu-26.04 +css,cssserver,Counter-Strike: Source,ubuntu-26.04 +ct,ctserver,Craftopia,ubuntu-26.04 +dab,dabserver,Double Action: Boogaloo,ubuntu-26.04 +dayz,dayzserver,DayZ,ubuntu-26.04 +dmc,dmcserver,Deathmatch Classic,ubuntu-26.04 +dod,dodserver,Day of Defeat,ubuntu-26.04 +dodr,dodrserver,Day of Dragons,ubuntu-26.04 +dods,dodsserver,Day of Defeat: Source,ubuntu-26.04 +doi,doiserver,Day of Infamy,ubuntu-26.04 +dst,dstserver,Don't Starve Together,ubuntu-26.04 +dys,dysserver,Dystopia,ubuntu-26.04 +eco,ecoserver,Eco,ubuntu-26.04 +em,emserver,Empires Mod,ubuntu-26.04 +etl,etlserver,ET: Legacy,ubuntu-26.04 +ets2,ets2server,Euro Truck Simulator 2,ubuntu-26.04 +fctr,fctrserver,Factorio,ubuntu-26.04 +fof,fofserver,Fistful of Frags,ubuntu-26.04 +gmod,gmodserver,Garrys Mod,ubuntu-26.04 +hcu,hcuserver,HYPERCHARGE: Unboxed,ubuntu-26.04 +hl2dm,hl2dmserver,Half-Life 2: Deathmatch,ubuntu-26.04 +hldm,hldmserver,Half-Life: Deathmatch,ubuntu-26.04 +hldms,hldmsserver,Half-Life Deathmatch: Source,ubuntu-26.04 +hw,hwserver,Hurtworld,ubuntu-26.04 +hyt,hytserver,Hytale,ubuntu-26.04 +hz,hzserver,Humanitz,ubuntu-26.04 +ins,insserver,Insurgency,ubuntu-26.04 +inss,inssserver,Insurgency: Sandstorm,ubuntu-26.04 +ios,iosserver,IOSoccer,ubuntu-26.04 +jbep3,jbep3server,Jabroni Brawl: Episode 3,ubuntu-26.04 +jc2,jc2server,Just Cause 2,ubuntu-26.04 +jc3,jc3server,Just Cause 3,ubuntu-26.04 +jk2,jk2server,Jedi Knight II: Jedi Outcast,ubuntu-26.04 +kf,kfserver,Killing Floor,ubuntu-26.04 +kf2,kf2server,Killing Floor 2,ubuntu-26.04 +l4d,l4dserver,Left 4 Dead,ubuntu-26.04 +l4d2,l4d2server,Left 4 Dead 2,ubuntu-26.04 +mc,mcserver,Minecraft,ubuntu-26.04 +mcb,mcbserver,Minecraft Bedrock,ubuntu-26.04 +mcv,mcvserver,Military Conflict: Vietnam,ubuntu-26.04 +mh,mhserver,MORDHAU,ubuntu-26.04 mohaa,mohaaserver,Medal of Honor: Allied Assault,ubuntu-24.04 -mta,mtaserver,Multi Theft Auto,ubuntu-24.04 -nd,ndserver,Nuclear Dawn,ubuntu-24.04 -nec,necserver,Necesse,ubuntu-24.04 -nmrih,nmrihserver,No More Room in Hell,ubuntu-24.04 -ns,nsserver,Natural Selection,ubuntu-24.04 -ns2,ns2server,Natural Selection 2,ubuntu-24.04 -ns2c,ns2cserver,NS2: Combat,ubuntu-24.04 -ohd,ohdserver,Operation: Harsh Doorstop,ubuntu-24.04 +mta,mtaserver,Multi Theft Auto,ubuntu-26.04 +nd,ndserver,Nuclear Dawn,ubuntu-26.04 +nec,necserver,Necesse,ubuntu-26.04 +nmrih,nmrihserver,No More Room in Hell,ubuntu-26.04 +ns,nsserver,Natural Selection,ubuntu-26.04 +ns2,ns2server,Natural Selection 2,ubuntu-26.04 +ns2c,ns2cserver,NS2: Combat,ubuntu-26.04 +ohd,ohdserver,Operation: Harsh Doorstop,ubuntu-26.04 onset,onsetserver,Onset,ubuntu-20.04 -opfor,opforserver,Opposing Force,ubuntu-24.04 -pc,pcserver,Project Cars,ubuntu-24.04 -pc2,pc2server,Project Cars 2,ubuntu-24.04 -pmc,pmcserver,PaperMC,ubuntu-24.04 -pvkii,pvkiiserver,Pirates Vikings & Knights II,ubuntu-24.04 -pvr,pvrserver,Pavlov VR,ubuntu-24.04 -pw,pwserver,Palworld,ubuntu-24.04 -pz,pzserver,Project Zomboid,ubuntu-24.04 -q2,q2server,Quake 2,ubuntu-24.04 -q3,q3server,Quake 3: Arena,ubuntu-24.04 -q4,q4server,Quake 4,ubuntu-24.04 -ql,qlserver,Quake Live,ubuntu-24.04 -qw,qwserver,Quake World,ubuntu-24.04 -ricochet,ricochetserver,Ricochet,ubuntu-24.04 -ro,roserver,Red Orchestra: Ostfront 41-45,ubuntu-24.04 -rsdw,rsdwserver,RuneScape: Dragonwilds,ubuntu-24.04 -rtcw,rtcwserver,Return to Castle Wolfenstein,ubuntu-24.04 -rust,rustserver,Rust,ubuntu-24.04 -rw,rwserver,Rising World,ubuntu-24.04 -rwr,rwrserver,Running With Rifles,ubuntu-24.04 -samp,sampserver,San Andreas Multiplayer,ubuntu-24.04 -sb,sbserver,Starbound,ubuntu-24.04 -sbots,sbotsserver,StickyBots,ubuntu-24.04 -scpsl,scpslserver,SCP: Secret Laboratory,ubuntu-24.04 +opfor,opforserver,Opposing Force,ubuntu-26.04 +pc,pcserver,Project Cars,ubuntu-26.04 +pc2,pc2server,Project Cars 2,ubuntu-26.04 +pmc,pmcserver,PaperMC,ubuntu-26.04 +pvkii,pvkiiserver,Pirates Vikings & Knights II,ubuntu-26.04 +pvr,pvrserver,Pavlov VR,ubuntu-26.04 +pw,pwserver,Palworld,ubuntu-26.04 +pz,pzserver,Project Zomboid,ubuntu-26.04 +q2,q2server,Quake 2,ubuntu-26.04 +q3,q3server,Quake 3: Arena,ubuntu-26.04 +q4,q4server,Quake 4,ubuntu-26.04 +ql,qlserver,Quake Live,ubuntu-26.04 +qw,qwserver,Quake World,ubuntu-26.04 +ricochet,ricochetserver,Ricochet,ubuntu-26.04 +ro,roserver,Red Orchestra: Ostfront 41-45,ubuntu-26.04 +rsdw,rsdwserver,RuneScape: Dragonwilds,ubuntu-26.04 +rtcw,rtcwserver,Return to Castle Wolfenstein,ubuntu-26.04 +rust,rustserver,Rust,ubuntu-26.04 +rw,rwserver,Rising World,ubuntu-26.04 +rwr,rwrserver,Running With Rifles,ubuntu-26.04 +samp,sampserver,San Andreas Multiplayer,ubuntu-26.04 +sb,sbserver,Starbound,ubuntu-26.04 +sbots,sbotsserver,StickyBots,ubuntu-26.04 +scpsl,scpslserver,SCP: Secret Laboratory,ubuntu-26.04 scpslsm,scpslsmserver,SCP: Secret Laboratory ServerMod,ubuntu-24.04 -sdtd,sdtdserver,7 Days to Die,ubuntu-24.04 -sf,sfserver,Satisfactory,ubuntu-24.04 -sfc,sfcserver,SourceForts Classic,ubuntu-24.04 -sm,smserver,Soulmask,ubuntu-24.04 -sof2,sof2server,Soldier Of Fortune 2: Gold Edition,ubuntu-24.04 -sol,solserver,Soldat,ubuntu-24.04 -squad,squadserver,Squad,ubuntu-24.04 -squad44,squad44server,Squad 44,ubuntu-24.04 -st,stserver,Stationeers,ubuntu-24.04 -stn,stnserver,Survive the Nights,ubuntu-24.04 -sven,svenserver,Sven Co-op,ubuntu-24.04 -terraria,terrariaserver,Terraria,ubuntu-24.04 -tf,tfserver,The Front,ubuntu-24.04 -tf2,tf2server,Team Fortress 2,ubuntu-24.04 -tf2c,tf2cserver,Team Fortress 2 Classified,ubuntu-24.04 -tfc,tfcserver,Team Fortress Classic,ubuntu-24.04 -ti,tiserver,The Isle,ubuntu-24.04 -ts,tsserver,The Specialists,ubuntu-24.04 -ts3,ts3server,Teamspeak 3,ubuntu-24.04 -tu,tuserver,Tower Unite,ubuntu-24.04 -tw,twserver,Teeworlds,ubuntu-24.04 -unt,untserver,Unturned,ubuntu-24.04 -ut,utserver,Unreal Tournament,ubuntu-24.04 -ut2k4,ut2k4server,Unreal Tournament 2004,ubuntu-24.04 -ut3,ut3server,Unreal Tournament 3,ubuntu-24.04 -ut99,ut99server,Unreal Tournament 99,ubuntu-24.04 -vh,vhserver,Valheim,ubuntu-24.04 -vints,vintsserver,Vintage Story,ubuntu-24.04 -vpmc,vpmcserver,Velocity Proxy MC,ubuntu-24.04 -vs,vsserver,Vampire Slayer,ubuntu-24.04 -wet,wetserver,Wolfenstein: Enemy Territory,ubuntu-24.04 -wf,wfserver,Warfork,ubuntu-24.04 -wmc,wmcserver,WaterfallMC,ubuntu-24.04 -wurm,wurmserver,Wurm Unlimited,ubuntu-24.04 -xnt,xntserver,Xonotic,ubuntu-24.04 -zmr,zmrserver,Zombie Master: Reborn,ubuntu-24.04 -zps,zpsserver,Zombie Panic! Source,ubuntu-24.04 +sdtd,sdtdserver,7 Days to Die,ubuntu-26.04 +sf,sfserver,Satisfactory,ubuntu-26.04 +sfc,sfcserver,SourceForts Classic,ubuntu-26.04 +sm,smserver,Soulmask,ubuntu-26.04 +sof2,sof2server,Soldier Of Fortune 2: Gold Edition,ubuntu-26.04 +sol,solserver,Soldat,ubuntu-26.04 +squad,squadserver,Squad,ubuntu-26.04 +squad44,squad44server,Squad 44,ubuntu-26.04 +st,stserver,Stationeers,ubuntu-26.04 +stn,stnserver,Survive the Nights,ubuntu-26.04 +sven,svenserver,Sven Co-op,ubuntu-26.04 +terraria,terrariaserver,Terraria,ubuntu-26.04 +tf,tfserver,The Front,ubuntu-26.04 +tf2,tf2server,Team Fortress 2,ubuntu-26.04 +tf2c,tf2cserver,Team Fortress 2 Classified,ubuntu-26.04 +tfc,tfcserver,Team Fortress Classic,ubuntu-26.04 +ti,tiserver,The Isle,ubuntu-26.04 +ts,tsserver,The Specialists,ubuntu-26.04 +ts3,ts3server,Teamspeak 3,ubuntu-26.04 +tu,tuserver,Tower Unite,ubuntu-26.04 +tw,twserver,Teeworlds,ubuntu-26.04 +unt,untserver,Unturned,ubuntu-26.04 +ut,utserver,Unreal Tournament,ubuntu-26.04 +ut2k4,ut2k4server,Unreal Tournament 2004,ubuntu-26.04 +ut3,ut3server,Unreal Tournament 3,ubuntu-26.04 +ut99,ut99server,Unreal Tournament 99,ubuntu-26.04 +vh,vhserver,Valheim,ubuntu-26.04 +vints,vintsserver,Vintage Story,ubuntu-26.04 +vpmc,vpmcserver,Velocity Proxy MC,ubuntu-26.04 +vs,vsserver,Vampire Slayer,ubuntu-26.04 +wet,wetserver,Wolfenstein: Enemy Territory,ubuntu-26.04 +wf,wfserver,Warfork,ubuntu-26.04 +wmc,wmcserver,WaterfallMC,ubuntu-26.04 +wurm,wurmserver,Wurm Unlimited,ubuntu-26.04 +xnt,xntserver,Xonotic,ubuntu-26.04 +zmr,zmrserver,Zombie Master: Reborn,ubuntu-26.04 +zps,zpsserver,Zombie Panic! Source,ubuntu-26.04 From 05bae92651a1791ae486a8a6b31c755e55ee0c1b Mon Sep 17 00:00:00 2001 From: Daniel Gibbs Date: Thu, 15 Oct 2026 19:28:37 +0100 Subject: [PATCH 065/164] fix(ndserver): download Nuclear Dawn game content from app 17710 (#5040) App 111710 only ships the Linux server binaries. Its content depot 17711 is a shared install from the Nuclear Dawn game app (17710), which SteamCMD records under SharedDepots and never downloads, so servers fail with "Unable to find gameinfo.txt". app_update 17710 does not work either, as SteamCMD treats it as shared only. Require a Steam account that owns Nuclear Dawn and add fix_nd.sh, run post install and pre start, which downloads depot 17711 with download_depot when gameinfo.txt is missing and merges it into serverfiles without overwriting the server files. app_info_print is run first as download_depot fails with "missing app info" on a cold cache. Fixes #5039 --- .../config-lgsm/ndserver/_default.cfg | 5 +++ lgsm/modules/core_modules.sh | 5 +++ lgsm/modules/fix.sh | 4 +- lgsm/modules/fix_nd.sh | 38 +++++++++++++++++++ 4 files changed, 50 insertions(+), 2 deletions(-) create mode 100755 lgsm/modules/fix_nd.sh diff --git a/lgsm/config-default/config-lgsm/ndserver/_default.cfg b/lgsm/config-default/config-lgsm/ndserver/_default.cfg index 2c9083482a..8009fe1a3c 100644 --- a/lgsm/config-default/config-lgsm/ndserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/ndserver/_default.cfg @@ -8,6 +8,11 @@ #### Game Server Settings #### +## SteamCMD Login | https://docs.linuxgsm.com/steamcmd#steamcmd-login +# The Steam account must own Nuclear Dawn. The server game content is part of the game. +steamuser="username" +steampass='password' + ## Predefined Parameters | https://docs.linuxgsm.com/configuration/start-parameters ip="0.0.0.0" port="27015" diff --git a/lgsm/modules/core_modules.sh b/lgsm/modules/core_modules.sh index 9d8c99bc2c..d02a828b56 100755 --- a/lgsm/modules/core_modules.sh +++ b/lgsm/modules/core_modules.sh @@ -438,6 +438,11 @@ fix_mta.sh() { fn_fetch_module } +fix_nd.sh() { + modulefile="${FUNCNAME[0]}" + fn_fetch_module +} + fix_nmrih.sh() { modulefile="${FUNCNAME[0]}" fn_fetch_module diff --git a/lgsm/modules/fix.sh b/lgsm/modules/fix.sh index 8a0a4c39a3..505a8628d3 100755 --- a/lgsm/modules/fix.sh +++ b/lgsm/modules/fix.sh @@ -53,8 +53,8 @@ fn_apply_fix() { fi } -apply_pre_start_fix=(arma3 armar ark av bt bo csgo cmw dst hw ins ios kf nmrih onset pvr ro rust rw samp sdtd sfc sm sof2 squad st tf2 terraria ts3 mcb mta unt vh wurm xnt zmr) -apply_post_install_fix=(av kf kf2 ro ut2k4 ut ut3) +apply_pre_start_fix=(arma3 armar ark av bt bo csgo cmw dst hw ins ios kf nd nmrih onset pvr ro rust rw samp sdtd sfc sm sof2 squad st tf2 terraria ts3 mcb mta unt vh wurm xnt zmr) +apply_post_install_fix=(av kf kf2 nd ro ut2k4 ut ut3) # validate registered fixes for safe development for fix in "${apply_pre_start_fix[@]}" "${apply_post_install_fix[@]}"; do diff --git a/lgsm/modules/fix_nd.sh b/lgsm/modules/fix_nd.sh new file mode 100755 index 0000000000..5d305348eb --- /dev/null +++ b/lgsm/modules/fix_nd.sh @@ -0,0 +1,38 @@ +#!/bin/bash +# LinuxGSM fix_nd.sh module +# Author: Daniel Gibbs +# Contributors: https://linuxgsm.com/contrib +# Website: https://linuxgsm.com +# Description: Resolves issues with Nuclear Dawn. + +moduleselfname="$(basename "$(readlink -f "${BASH_SOURCE[0]}")")" + +if [ ! -f "${serverfiles}/nucleardawn/gameinfo.txt" ]; then + fixname="game content" + fn_fix_msg_start_nl + steamcmdlog="${lgsmlogdir}/${selfname}-steamcmd.log" + rm -f "${steamcmdlog:?}" + if [ -d "${steamcmddir}" ]; then + cd "${steamcmddir}" || exit + fi + "${steamcmdcommand}" +login "${steamuser}" "${steampass}" +app_info_print 17710 +quit > /dev/null 2>&1 + "${steamcmdcommand}" +login "${steamuser}" "${steampass}" +download_depot 17710 17711 +quit | uniq | tee -a "${lgsmlog}" "${steamcmdlog}" + ndcontentdepot="$(grep -o 'Depot download complete : "[^"]*"' "${steamcmdlog}" | tail -1 | cut -d'"' -f2 | tr '\134' '/')" + if [[ "${ndcontentdepot}" == */depot_17711 ]]; then + if [ -f "${ndcontentdepot}/nucleardawn/gameinfo.txt" ]; then + tar -C "${ndcontentdepot}" -cf - . | tar -C "${serverfiles}" -xf - --skip-old-files + fi + rm -rf "${ndcontentdepot:?}" "${ndcontentdepot%/*}/state_17710_17711.patch" + fi + if [ -f "${serverfiles}/nucleardawn/gameinfo.txt" ]; then + exitcode=0 + else + exitcode=1 + fi + fn_fix_msg_end + if [ "${exitcode}" -ne 0 ]; then + fn_print_nl "* Nuclear Dawn game content requires a Steam account that owns Nuclear Dawn." + fn_print_nl "* Set steamuser and steampass in ${configdirserver}" + core_exit.sh + fi +fi From 05e61dc3650f1d6f5d23623f04861c207fe1a555 Mon Sep 17 00:00:00 2001 From: Daniel Gibbs Date: Thu, 15 Oct 2026 19:41:56 +0100 Subject: [PATCH 066/164] feat: remove SCP: Secret Laboratory ServerMod (scpslsm) (#5038) Removes SCP: Secret Laboratory ServerMod (scpslsm). Steam app 786920 has been retired by the publisher, so SteamCMD returns "No subscription" for every account and the server can no longer be installed. Modded SCP:SL servers are covered by scpsl with LabAPI or EXILED. --- .../config-lgsm/scpslsmserver/_default.cfg | 210 ------------------ lgsm/data/almalinux-8.csv | 1 - lgsm/data/almalinux-9.csv | 1 - lgsm/data/centos-7.csv | 1 - lgsm/data/centos-8.csv | 1 - lgsm/data/centos-9.csv | 1 - lgsm/data/debian-10.csv | 1 - lgsm/data/debian-11.csv | 1 - lgsm/data/debian-12.csv | 1 - lgsm/data/debian-13.csv | 1 - lgsm/data/debian-9.csv | 1 - lgsm/data/gameicons/scpslsm-icon.png | Bin 3090 -> 0 bytes lgsm/data/rhel-7.csv | 1 - lgsm/data/rhel-8.csv | 1 - lgsm/data/rhel-9.csv | 1 - lgsm/data/rocky-8.csv | 1 - lgsm/data/rocky-9.csv | 1 - lgsm/data/serverlist.csv | 1 - lgsm/data/ubuntu-16.04.csv | 1 - lgsm/data/ubuntu-18.04.csv | 1 - lgsm/data/ubuntu-20.04.csv | 1 - lgsm/data/ubuntu-22.04.csv | 1 - lgsm/data/ubuntu-23.04.csv | 1 - lgsm/data/ubuntu-23.10.csv | 1 - lgsm/data/ubuntu-24.04.csv | 1 - lgsm/data/ubuntu-26.04.csv | 1 - lgsm/modules/command_stop.sh | 2 +- lgsm/modules/info_game.sh | 2 +- lgsm/modules/info_messages.sh | 4 +- lgsm/modules/install_config.sh | 2 +- lgsm/modules/install_eula.sh | 2 +- lgsm/modules/install_server_files.sh | 2 +- 32 files changed, 7 insertions(+), 241 deletions(-) delete mode 100644 lgsm/config-default/config-lgsm/scpslsmserver/_default.cfg delete mode 100644 lgsm/data/gameicons/scpslsm-icon.png diff --git a/lgsm/config-default/config-lgsm/scpslsmserver/_default.cfg b/lgsm/config-default/config-lgsm/scpslsmserver/_default.cfg deleted file mode 100644 index 921d11944c..0000000000 --- a/lgsm/config-default/config-lgsm/scpslsmserver/_default.cfg +++ /dev/null @@ -1,210 +0,0 @@ -################################## -######## Default Settings ######## -################################## -# DO NOT EDIT, ANY CHANGES WILL BE OVERWRITTEN! -# Copy settings from here and use them in either: -# common.cfg - applies settings to every instance. -# [instance].cfg - applies settings to a specific instance. - -#### Game Server Settings #### - -## Predefined Parameters | https://docs.linuxgsm.com/configuration/start-parameters -## All server settings except the server port are done in the config file: -## Docs: https://en.scpslgame.com/index.php?title=Docs:Server_Config -port="7777" - -## Server Parameters | https://docs.linuxgsm.com/configuration/start-parameters#additional-parameters -startparameters="${port} --acceptEULA" - -#### LinuxGSM Settings #### - -## LinuxGSM Stats -# Send useful stats to LinuxGSM developers. -# https://docs.linuxgsm.com/configuration/linuxgsm-stats -# (on|off) -stats="off" - -## Notification Alerts -# (on|off) - -# Display IP | https://docs.linuxgsm.com/alerts#display-ip -displayip="" - -# More info | https://docs.linuxgsm.com/alerts#more-info -postalert="off" - -# Alert on Start/Stop/Restart -statusalert="off" - -# Discord Alerts | https://docs.linuxgsm.com/alerts/discord -discordalert="off" -discordwebhook="webhook" - -# Email Alerts | https://docs.linuxgsm.com/alerts/email -emailalert="off" -email="email@example.com" -emailfrom="" - -# Gotify Alerts | https://docs.linuxgsm.com/alerts/gotify -gotifyalert="off" -gotifytoken="token" -gotifywebhook="webhook" - -# IFTTT Alerts | https://docs.linuxgsm.com/alerts/ifttt -iftttalert="off" -ifttttoken="accesstoken" -iftttevent="linuxgsm_alert" - -# ntfy Alerts | https://docs.linuxgsm.com/alerts/ntfy -ntfyalert="off" -ntfytopic="LinuxGSM" -ntfyserver="https://ntfy.sh" -ntfytoken="" -ntfyusername="" -ntfypassword="" -ntfypriority="" -ntfytags="" - -# Matrix Alerts | https://docs.linuxgsm.com/alerts/matrix -matrixalert="off" -matrixhomeserver="matrix.org" -matrixtoken="accesstoken" -matrixroom="" - -# Pushbullet Alerts | https://docs.linuxgsm.com/alerts/pushbullet -pushbulletalert="off" -pushbullettoken="accesstoken" -channeltag="" - -# Pushover Alerts | https://docs.linuxgsm.com/alerts/pushover -pushoveralert="off" -pushovertoken="accesstoken" -pushoveruserkey="userkey" - -# Rocket.Chat Alerts | https://docs.linuxgsm.com/alerts/rocket.chat -rocketchatalert="off" -rocketchatwebhook="webhook" - -# Slack Alerts | https://docs.linuxgsm.com/alerts/slack -slackalert="off" -slackwebhook="webhook" - -# Telegram Alerts | https://docs.linuxgsm.com/alerts/telegram -# You can add a custom cURL string eg proxy (useful in Russia) in "curlcustomstring". -# For example "--socks5 ipaddr:port" for socks5 proxy see more in "curl --help all". -telegramapi="api.telegram.org" -telegramalert="off" -telegramtoken="accesstoken" -telegramchatid="" -telegramthreadid="" -telegramsilentnotification="false" -curlcustomstring="" - -## Stop | https://docs.linuxgsm.com/commands/start-stop-restart -stoponlyifnoplayers="off" -stoponlyifnoplayersallcommands="on" - -## Player Warnings | https://docs.linuxgsm.com/features/player-warnings -# Minutes to warn players in-game before a stop, restart or update. 0 to disable. -# e.g. 15 warns at 15, 10, 5, 3 and 1 minutes. -warnplayerstimer="0" - -## Updating | https://docs.linuxgsm.com/commands/update -updateonstart="off" - -## Backup | https://docs.linuxgsm.com/commands/backup -maxbackups="4" -maxbackupdays="30" -stoponbackup="on" - -## Logging | https://docs.linuxgsm.com/features/logging -consolelogging="on" -logdays="7" - -## Monitor | https://docs.linuxgsm.com/commands/monitor -# Query delay time -querydelay="1" - -## ANSI Colors | https://docs.linuxgsm.com/features/ansi-colors -ansi="on" - -#### Advanced Settings #### - -## Message Display Time | https://docs.linuxgsm.com/features/message-display-time -sleeptime="0.5" - -## SteamCMD Settings | https://docs.linuxgsm.com/steamcmd -# Server appid -appid="786920" -steamcmdforcewindows="no" -# SteamCMD Branch | https://docs.linuxgsm.com/steamcmd/branch -branch="" -betapassword="" -# Master Server | https://docs.linuxgsm.com/steamcmd/steam-master-server -steammaster="false" - -## Stop Mode | https://docs.linuxgsm.com/features/stop-mode -# 1: tmux kill -# 2: CTRL+c -# 3: quit -# 4: quit 120s -# 5: stop -# 6: q -# 7: exit -# 8: 7 Days to Die -# 9: GoldSrc -# 10: Avorion -# 11: end -stopmode="7" - -## Query mode -# 1: session only -# 2: gamedig (gsquery fallback) -# 3: gamedig -# 4: gsquery -# 5: tcp -querymode="1" -querytype="" - -## Console type -consoleverbose="yes" -consoleinteract="yes" - -## Game Server Details -# Do not edit -gamename="SCP: Secret Laboratory ServerMod" -engine="unity3d" -glibc="2.27" - -#### Directories #### -# Edit with care - -## Game Server Directories -systemdir="${serverfiles}" -executabledir="${systemdir}" -executable="./LocalAdmin" -servercfg="config_gameplay.txt" -servercfgdefault="config_gameplay.txt" -servercfgdir="${HOME}/.config/SCP Secret Laboratory/config/${port}" -servercfgfullpath="${servercfgdir}/${servercfg}" - -## Backup Directory -backupdir="${lgsmdir}/backup" - -## Logging Directories -[ -n "${LGSM_LOGDIR}" ] && logdir="${LGSM_LOGDIR}" || logdir="${rootdir}/log" -gamelogdir="${HOME}/.config/SCP Secret Laboratory/LocalAdminLogs/${port}" -lgsmlogdir="${logdir}/script" -consolelogdir="${logdir}/console" -lgsmlog="${lgsmlogdir}/${selfname}-script.log" -consolelog="${consolelogdir}/${selfname}-console.log" -alertlog="${lgsmlogdir}/${selfname}-alert.log" -postdetailslog="${lgsmlogdir}/${selfname}-postdetails.log" - -## Logs Naming -lgsmlogdate="${lgsmlogdir}/${selfname}-script-$(date '+%Y-%m-%d-%H:%M:%S').log" -consolelogdate="${consolelogdir}/${selfname}-console-$(date '+%Y-%m-%d-%H:%M:%S').log" - -## Log Parameters -logtimestamp="off" -logtimestampformat="%Y-%m-%d %H:%M:%S" diff --git a/lgsm/data/almalinux-8.csv b/lgsm/data/almalinux-8.csv index 519bf0cd0f..5ad1d630a0 100644 --- a/lgsm/data/almalinux-8.csv +++ b/lgsm/data/almalinux-8.csv @@ -105,7 +105,6 @@ samp sb sbots scpsl -scpslsm sdtd,telnet,expect,libxml2 sf sfc,ncurses-libs.i686 diff --git a/lgsm/data/almalinux-9.csv b/lgsm/data/almalinux-9.csv index c6834b24c3..6222163b7a 100644 --- a/lgsm/data/almalinux-9.csv +++ b/lgsm/data/almalinux-9.csv @@ -105,7 +105,6 @@ samp sb sbots scpsl -scpslsm sdtd,telnet,expect,libxml2 sf sfc,ncurses-libs.i686 diff --git a/lgsm/data/centos-7.csv b/lgsm/data/centos-7.csv index bb068562b4..423f359622 100644 --- a/lgsm/data/centos-7.csv +++ b/lgsm/data/centos-7.csv @@ -105,7 +105,6 @@ samp sb sbots scpsl -scpslsm sdtd,telnet,expect,libxml2 sf sfc,ncurses-libs.i686 diff --git a/lgsm/data/centos-8.csv b/lgsm/data/centos-8.csv index 3dca174c79..13dbb15282 100644 --- a/lgsm/data/centos-8.csv +++ b/lgsm/data/centos-8.csv @@ -105,7 +105,6 @@ samp sb sbots scpsl -scpslsm sdtd,telnet,expect,libxml2 sf sfc,ncurses-libs.i686 diff --git a/lgsm/data/centos-9.csv b/lgsm/data/centos-9.csv index f385b0f95d..8b6f7e3fd6 100644 --- a/lgsm/data/centos-9.csv +++ b/lgsm/data/centos-9.csv @@ -105,7 +105,6 @@ samp sb sbots scpsl -scpslsm sdtd,telnet,expect,libxml2 sf sfc,ncurses-libs.i686 diff --git a/lgsm/data/debian-10.csv b/lgsm/data/debian-10.csv index 8750c676b8..e36ca3b36d 100644 --- a/lgsm/data/debian-10.csv +++ b/lgsm/data/debian-10.csv @@ -105,7 +105,6 @@ samp sb sbots scpsl,mono-complete -scpslsm,mono-complete sdtd,telnet,expect,libxml2-utils sf sfc,libtinfo5:i386 diff --git a/lgsm/data/debian-11.csv b/lgsm/data/debian-11.csv index 30e4bdbd21..38b615f612 100644 --- a/lgsm/data/debian-11.csv +++ b/lgsm/data/debian-11.csv @@ -106,7 +106,6 @@ samp sb sbots scpsl,mono-complete -scpslsm,mono-complete sdtd,telnet,expect,libxml2-utils sf sfc,libtinfo5:i386 diff --git a/lgsm/data/debian-12.csv b/lgsm/data/debian-12.csv index 40aafa29b1..add6fbbaf7 100644 --- a/lgsm/data/debian-12.csv +++ b/lgsm/data/debian-12.csv @@ -106,7 +106,6 @@ samp sb sbots scpsl,mono-complete -scpslsm,mono-complete sdtd,telnet,expect,libxml2-utils sf sfc,libtinfo5:i386 diff --git a/lgsm/data/debian-13.csv b/lgsm/data/debian-13.csv index c5029d353a..401d75324e 100644 --- a/lgsm/data/debian-13.csv +++ b/lgsm/data/debian-13.csv @@ -106,7 +106,6 @@ samp sb sbots scpsl,mono-complete,libicu76 -scpslsm,mono-complete sdtd,telnet,expect,libxml2 sf sfc diff --git a/lgsm/data/debian-9.csv b/lgsm/data/debian-9.csv index f5b3cac230..e4eda6f6dc 100644 --- a/lgsm/data/debian-9.csv +++ b/lgsm/data/debian-9.csv @@ -106,7 +106,6 @@ samp sb sbots scpsl,mono-complete -scpslsm,mono-complete sdtd,telnet,expect,libxml2-utils sf sfc,libtinfo5:i386 diff --git a/lgsm/data/gameicons/scpslsm-icon.png b/lgsm/data/gameicons/scpslsm-icon.png deleted file mode 100644 index 2872a78412197e19dbfc9d427bb1ef27f51a2510..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3090 zcmV+t4DIuYP)004R>004l5008;`004mK004C`008P>0026e000+ooVrmw00006 zVoOIv0RI600RN!9r;`8x010qNS#tmY4%h$y4%h()NRg%h000McNliru=L!%J3Lm#W z;+y~g3js+)K~zY`CDHkxRaF51@N>@Hmv`U0Z=E+YZ}t@i*#`=j8o?#P3^K%|6my9! zl-x*MFeCC4shN~1g$6EQhK7K+Fd{XI1fs|)3=Fd{GjG59z2}^M==(2xVO?Ea5Cjav zP)Y#+48s6Kecwlb;Rt8SjE6?_(IzO2IAXy0m}1G75#tzP0!yxn6bupesLDYHW6VGh z5DXziEJFee0AL9r9LHgdA%q;q5kiWEQam2FU4v(dSvG4yqI!M}7_BrJU*w_4GC|G? zqAAxMWV6UTb1Yjnqg<}!g?Pl^fIx&W0=y^~g`&*ztnd4xC}NBWA)e=9jCEZ%P1DDU zfN&Huw|D%k>fTIYht121YvcfL10w_#rCo}@Gj89DHy%=iSRSL83_TLKzAuYn;Q7Ui zqhURQDPeh@cN_;HWLcK3>$d5*w#RdV#|IAb9f-rtsn>VE)V=NiHb7KWp%E!YZLv6f zNu+b}M=PJlTf#*fg`klwV})lmrBE_8%BI87oMi?QizuZCAxf#DD30Yq2vt=r7K<^% zV=TI0!7W#=ob&a8en;|c)*o=pW9-3_KV+2A0r%w8cP2mn!aeY6Xu2M+hgg=ivjv4^ z0|ZXtVndPUd5@0@&*Id+vdN&@Qt6qnBv)16bg(_9F7dQWk%p5l!J}U4MxcnMbWiARaFs1 zxm<4X;>DfUOkDQR{e^+iqV1+A=lFrdFga`?pHp!);0D-0E+!+;wwhS{$Ty!*S2jGb z?Cy)beR4?4yA~&iAy)7U7Ne-LBua!3ffr5Fq=c?mv7)uPb;Yt3MyVj=?Wh|ku1Rn> zSy7oDS6h*coQw3SMb@DL@1Dh6AY`@Ia{IlZfmOeH?5+JDW($QV6ciVD1eaI}GnENR zi`s@y>;P-v-i{^g!{Q(2KRaxXdae`U)VLE_bnl&4-Z;0uJ{`g$<^XW5gXGg4Z-4dL z3#(2XbsD{R7P&GK)=pbD`q0qRH>@jgeAGq~Oy=3IVQXWPVH+L`IV4PRI+nh*@)r-? z*7sjq^srBuIjysw`Ntob8f=`&{cG&y+#S8_~haVi=2Pc5~V-gd8gJOMfGqz8CyE`=Wm?amK>+o zRJYbuXKLyzL1leqbH$kIRMq7AaUXa0)Qk@$Vs(+~$ThKRjUnqRzo%hg*YwSD~FyR)9`0x@t&vSr}!BMvRjSaVe<9j;9!B2}s5YrklDaBOXTyrp)0 zRb>JRK(c_z%5YBOysblj7e+&-SCY!&WA{F$M1(sYeaQT0dCzZm$d{%D_YADP^XYl_ zUo&C+Br_9!x38KxhY+iTEs+rsH4v0t3z%1b zWA4Wvy>r2F!YXbT#&_N|^>61lAAV}zM0=Vvg?;9ewKw0teA9h@4z^NRkMTL22L{L+ zuS)Okd}`-Rb4J_TrUJf*3Fh5Etw4kxRcEE7JM~;+_fRms-H7;K<;yaj1h@M6;MFdgAE@c%W7O>sywim1N zA#CDoI*1R6tN{E%z=|eYh}h)W;s)+o|F=7SW9`=d)wMwa67m#|112;jPdA`20tzAs zhgocckdq$}xd>5#4MsJpvy8`uV{#4`xHF6k7#gz+u2srg6ftU@;$xxAUKB8T^6)z4 z2JrBn-;~!E2nT%Zc^)6tq!J!VGBpV%Qbfbn1qtdV8^i-dB$df|jKpK)v4K@8X5?lm zjS8NN2#yM=?o)dqBXv!lq?x75;mj|-Ix_jm&W-zDh5Nvy)+vk&MBepz&tL-C5iV=K z!fW?GJM>vdic2Ox8geU$q}Mbg1vy8{pz)HLTc`i@?BTwyA5T{rB9-x)M6_yRbfWnQ z*>1g@7%S8%W5{2eJsDU~D;GV>Rm zBU00kwGX!Z8#L9nOs?+Svu*qI<(D?6+G4S)WIB>aR?JXl(A~7`n%6z|133c|T0#J# zETa&RLzOWgYH?JtWX5ggm&IXvx^-@IB9RE|kz^)WmkxKfUUl@P?$#S7G__SSY9vx- z2h(3RPyP9Xp2G*2B0(N>c-M2z9ee-lZ(sI<>*rhtI_$o~y;hj|Wg$>Z$>zqkOnCI3 z`yN=cdayD3y<6w>zCEN08iBURL<5d4zv8x@ai5=f{=YdAz(jLZti&TE{_WvcerZ2= z=(!KHY^5dGCB_F{ai)0vy7jBt=1v@ThW>Nrv*A;{5!i4^x~6(+nnm=>Q|E7b@b=Q) zex9%vOGJ)0s5vY7ou$8DFz?Bml@ly)S1@`s>Wa3@@^EkV`>W<2`r`NnYg8`_K5_^J zL)L|DufKKnKfUdt_GvW}JEwiKt*u4R#6RlkdF0nmJpQZ4M~)2%qT&a{4?)&0RV0%4 z&A#(l_-g-~7Z|8%*oBSh`aEx|zAlJ`O$%P!H15;xwXd{Cn}=(%CwHEuc_7G~eiO;LRh14?yW zzwGkMmo8nJ%xIX%gXiPj@H#IahH#Yt7rumbmPFVHGFS~bb zZ;nmPTwedrU0W;5Q4d%J)s)OMY^`p(APmMpTr!vSU&+vCZ?mzrOV1#?2c8>L~$hm3djSkW#6`k_Get4{;~~ zE9!KKl`)CIQm-A=BCczI2=t3G7s7<}yS);UCvwxrG-f>*pM83; zum1w#kSO!6?=VCK5>`BfsZ@j`J{Hnqr0C>fsxBl1)zB)JVp#Jj@&zJ6*YKc6d4*GG zC Date: Thu, 15 Oct 2026 21:24:04 +0100 Subject: [PATCH 067/164] fix(bf1942,bfv): run on Ubuntu 24.04+ by providing 32-bit ncurses 5 (#5043) * fix(bf1942,bfv): provide 32-bit ncurses 5 libraries on newer distros Ubuntu 24.04+, Debian 13 and RHEL 9 no longer package the i386 libncurses.so.5 and libtinfo.so.5 that the Battlefield 1942 and Battlefield: Vietnam server binaries need. The new fix modules download them into serverfiles when the system does not provide them, and add serverfiles to LD_LIBRARY_PATH. The static binaries only need ncurses 5 and the 32-bit libc, so the libstdc++5 dependency and the Ubuntu 22.04 / Debian 12 support block in check_deps are removed. * feat(bf1942,bfv): move Docker images to Ubuntu 26.04 * fix(bf1942,bfv): install the LinuxGSM default serversettings.con The server archives ship their own serversettings.con with gameSpyPort 0. install_config skips copying the LinuxGSM default when the file already exists, so a fresh install had no query port and monitor failed with "queryport is not set". The bundled file is removed first so the default config is copied. install_config only runs on install, right after the archive has been extracted, so no user settings are lost. * fix(bf1942,bfv): preserve configs by repacking server archives * fix(bf1942,bfv): document shared module variables for ShellCheck --- lgsm/data/almalinux-8.csv | 2 +- lgsm/data/almalinux-9.csv | 2 +- lgsm/data/centos-7.csv | 2 +- lgsm/data/centos-8.csv | 2 +- lgsm/data/centos-9.csv | 2 +- lgsm/data/debian-10.csv | 4 ++-- lgsm/data/debian-11.csv | 4 ++-- lgsm/data/debian-12.csv | 4 ++-- lgsm/data/debian-13.csv | 4 ++-- lgsm/data/debian-9.csv | 4 ++-- lgsm/data/rhel-7.csv | 2 +- lgsm/data/rhel-8.csv | 2 +- lgsm/data/rhel-9.csv | 2 +- lgsm/data/rocky-8.csv | 2 +- lgsm/data/rocky-9.csv | 2 +- lgsm/data/serverlist.csv | 4 ++-- lgsm/data/ubuntu-16.04.csv | 4 ++-- lgsm/data/ubuntu-18.04.csv | 4 ++-- lgsm/data/ubuntu-20.04.csv | 4 ++-- lgsm/data/ubuntu-22.04.csv | 4 ++-- lgsm/data/ubuntu-23.04.csv | 4 ++-- lgsm/data/ubuntu-23.10.csv | 4 ++-- lgsm/data/ubuntu-24.04.csv | 4 ++-- lgsm/data/ubuntu-26.04.csv | 4 ++-- lgsm/modules/check_deps.sh | 9 --------- lgsm/modules/core_modules.sh | 10 ++++++++++ lgsm/modules/fix.sh | 2 +- lgsm/modules/fix_bf1942.sh | 21 +++++++++++++++++++++ lgsm/modules/fix_bfv.sh | 21 +++++++++++++++++++++ lgsm/modules/install_server_files.sh | 12 ++++++------ 30 files changed, 97 insertions(+), 54 deletions(-) create mode 100755 lgsm/modules/fix_bf1942.sh create mode 100755 lgsm/modules/fix_bfv.sh diff --git a/lgsm/data/almalinux-8.csv b/lgsm/data/almalinux-8.csv index 5ad1d630a0..88a11800ee 100644 --- a/lgsm/data/almalinux-8.csv +++ b/lgsm/data/almalinux-8.csv @@ -12,7 +12,7 @@ bb bb2,libcurl.i686 bd bf1942,ncurses-libs.i686 -bfv,compat-libstdc++-33.i686,glibc.i686 +bfv,glibc.i686 bmdm,ncurses-libs.i686 bo bs diff --git a/lgsm/data/almalinux-9.csv b/lgsm/data/almalinux-9.csv index 6222163b7a..7e3c49766c 100644 --- a/lgsm/data/almalinux-9.csv +++ b/lgsm/data/almalinux-9.csv @@ -12,7 +12,7 @@ bb bb2,libcurl.i686 bd bf1942,ncurses-libs.i686 -bfv,compat-libstdc++-33.i686,glibc.i686 +bfv,glibc.i686 bmdm,ncurses-libs.i686 bo bs diff --git a/lgsm/data/centos-7.csv b/lgsm/data/centos-7.csv index 423f359622..8a93a6091c 100644 --- a/lgsm/data/centos-7.csv +++ b/lgsm/data/centos-7.csv @@ -12,7 +12,7 @@ bb bb2,libcurl.i686 bd bf1942,ncurses-libs.i686 -bfv,compat-libstdc++-33.i686,glibc.i686 +bfv,glibc.i686 bmdm,ncurses-libs.i686 bo bs diff --git a/lgsm/data/centos-8.csv b/lgsm/data/centos-8.csv index 13dbb15282..284b88628f 100644 --- a/lgsm/data/centos-8.csv +++ b/lgsm/data/centos-8.csv @@ -12,7 +12,7 @@ bb bb2,libcurl.i686 bd bf1942,ncurses-libs.i686 -bfv,compat-libstdc++-33.i686,glibc.i686 +bfv,glibc.i686 bmdm,ncurses-libs.i686 bo bs diff --git a/lgsm/data/centos-9.csv b/lgsm/data/centos-9.csv index 8b6f7e3fd6..3dd1739626 100644 --- a/lgsm/data/centos-9.csv +++ b/lgsm/data/centos-9.csv @@ -12,7 +12,7 @@ bb bb2,libcurl.i686 bd bf1942,ncurses-libs.i686 -bfv,compat-libstdc++-33.i686,glibc.i686 +bfv,glibc.i686 bmdm,ncurses-libs.i686 bo bs diff --git a/lgsm/data/debian-10.csv b/lgsm/data/debian-10.csv index e36ca3b36d..8fc0403c9f 100644 --- a/lgsm/data/debian-10.csv +++ b/lgsm/data/debian-10.csv @@ -10,8 +10,8 @@ av bb bb2,libcurl4-gnutls-dev:i386 bd -bf1942,libncurses5:i386,libtinfo5:i386 -bfv,libncurses5:i386,libstdc++5:i386 +bf1942,libc6:i386 +bfv,libc6:i386 bmdm,libncurses5:i386 bo bs diff --git a/lgsm/data/debian-11.csv b/lgsm/data/debian-11.csv index 38b615f612..0b0168c791 100644 --- a/lgsm/data/debian-11.csv +++ b/lgsm/data/debian-11.csv @@ -11,8 +11,8 @@ av bb bb2,libcurl4-gnutls-dev:i386 bd -bf1942,libncurses5:i386,libtinfo5:i386 -bfv,libncurses5:i386,libstdc++5:i386 +bf1942,libc6:i386 +bfv,libc6:i386 bmdm,libncurses5:i386 bo bs diff --git a/lgsm/data/debian-12.csv b/lgsm/data/debian-12.csv index add6fbbaf7..1260899298 100644 --- a/lgsm/data/debian-12.csv +++ b/lgsm/data/debian-12.csv @@ -11,8 +11,8 @@ av bb bb2,libcurl4-gnutls-dev:i386 bd -bf1942,libncurses5:i386,libtinfo5:i386 -bfv,libncurses5:i386,libstdc++5:i386 +bf1942,libc6:i386 +bfv,libc6:i386 bmdm,libncurses5:i386 bo bs diff --git a/lgsm/data/debian-13.csv b/lgsm/data/debian-13.csv index 401d75324e..6a62b041f3 100644 --- a/lgsm/data/debian-13.csv +++ b/lgsm/data/debian-13.csv @@ -11,8 +11,8 @@ av bb bb2,libcurl4-gnutls-dev:i386 bd -bf1942,libncurses5:i386 -bfv,libncurses5:i386,libstdc++5:i386 +bf1942,libc6:i386 +bfv,libc6:i386 bmdm,libncurses5:i386 bo bs diff --git a/lgsm/data/debian-9.csv b/lgsm/data/debian-9.csv index e4eda6f6dc..ac8715d532 100644 --- a/lgsm/data/debian-9.csv +++ b/lgsm/data/debian-9.csv @@ -11,8 +11,8 @@ av bb bb2,libcurl4-gnutls-dev:i386 bd -bf1942,libncurses5:i386,libtinfo5:i386 -bfv,libncurses5:i386,libstdc++5:i386 +bf1942,libc6:i386 +bfv,libc6:i386 bmdm,libncurses5:i386 bo bs diff --git a/lgsm/data/rhel-7.csv b/lgsm/data/rhel-7.csv index ed65045128..7fe790d296 100644 --- a/lgsm/data/rhel-7.csv +++ b/lgsm/data/rhel-7.csv @@ -13,7 +13,7 @@ pw bb2,libcurl.i686 bd bf1942,ncurses-libs.i686 -bfv,compat-libstdc++-33.i686,glibc.i686 +bfv,glibc.i686 bmdm,ncurses-libs.i686 bo bs diff --git a/lgsm/data/rhel-8.csv b/lgsm/data/rhel-8.csv index 313c5928d5..ac207c625f 100644 --- a/lgsm/data/rhel-8.csv +++ b/lgsm/data/rhel-8.csv @@ -12,7 +12,7 @@ bb bb2,libcurl.i686 bd bf1942,ncurses-libs.i686 -bfv,compat-libstdc++-33.i686,glibc.i686 +bfv,glibc.i686 bmdm,ncurses-libs.i686 bo bs diff --git a/lgsm/data/rhel-9.csv b/lgsm/data/rhel-9.csv index 6222163b7a..7e3c49766c 100644 --- a/lgsm/data/rhel-9.csv +++ b/lgsm/data/rhel-9.csv @@ -12,7 +12,7 @@ bb bb2,libcurl.i686 bd bf1942,ncurses-libs.i686 -bfv,compat-libstdc++-33.i686,glibc.i686 +bfv,glibc.i686 bmdm,ncurses-libs.i686 bo bs diff --git a/lgsm/data/rocky-8.csv b/lgsm/data/rocky-8.csv index 313c5928d5..ac207c625f 100644 --- a/lgsm/data/rocky-8.csv +++ b/lgsm/data/rocky-8.csv @@ -12,7 +12,7 @@ bb bb2,libcurl.i686 bd bf1942,ncurses-libs.i686 -bfv,compat-libstdc++-33.i686,glibc.i686 +bfv,glibc.i686 bmdm,ncurses-libs.i686 bo bs diff --git a/lgsm/data/rocky-9.csv b/lgsm/data/rocky-9.csv index 6222163b7a..7e3c49766c 100644 --- a/lgsm/data/rocky-9.csv +++ b/lgsm/data/rocky-9.csv @@ -12,7 +12,7 @@ bb bb2,libcurl.i686 bd bf1942,ncurses-libs.i686 -bfv,compat-libstdc++-33.i686,glibc.i686 +bfv,glibc.i686 bmdm,ncurses-libs.i686 bo bs diff --git a/lgsm/data/serverlist.csv b/lgsm/data/serverlist.csv index 061395bbb7..0bbfedbace 100644 --- a/lgsm/data/serverlist.csv +++ b/lgsm/data/serverlist.csv @@ -10,8 +10,8 @@ av,avserver,Avorion,ubuntu-26.04 bb,bbserver,BrainBread,ubuntu-26.04 bb2,bb2server,BrainBread 2,ubuntu-26.04 bd,bdserver,Base Defense,ubuntu-26.04 -bf1942,bf1942server,Battlefield 1942,ubuntu-22.04 -bfv,bfvserver,Battlefield: Vietnam,ubuntu-22.04 +bf1942,bf1942server,Battlefield 1942,ubuntu-26.04 +bfv,bfvserver,Battlefield: Vietnam,ubuntu-26.04 bmdm,bmdmserver,Black Mesa: Deathmatch,ubuntu-26.04 bo,boserver,Ballistic Overkill,ubuntu-26.04 bs,bsserver,Blade Symphony,ubuntu-26.04 diff --git a/lgsm/data/ubuntu-16.04.csv b/lgsm/data/ubuntu-16.04.csv index 7a384f9309..b458ea8175 100644 --- a/lgsm/data/ubuntu-16.04.csv +++ b/lgsm/data/ubuntu-16.04.csv @@ -12,8 +12,8 @@ bb pw bb2,libcurl4-gnutls-dev:i386 bd -bf1942,libncurses5:i386,libtinfo5:i386 -bfv,libncurses5:i386,libstdc++5:i386 +bf1942,libc6:i386 +bfv,libc6:i386 bmdm,libncurses5:i386 bo bs diff --git a/lgsm/data/ubuntu-18.04.csv b/lgsm/data/ubuntu-18.04.csv index 258d74b6ca..b9760326e9 100644 --- a/lgsm/data/ubuntu-18.04.csv +++ b/lgsm/data/ubuntu-18.04.csv @@ -12,8 +12,8 @@ pw bb bb2,libcurl4-gnutls-dev:i386 bd -bf1942,libncurses5:i386,libtinfo5:i386 -bfv,libncurses5:i386,libstdc++5:i386 +bf1942,libc6:i386 +bfv,libc6:i386 bmdm,libncurses5:i386 bo bs diff --git a/lgsm/data/ubuntu-20.04.csv b/lgsm/data/ubuntu-20.04.csv index 70836606fb..397fe8ca1a 100644 --- a/lgsm/data/ubuntu-20.04.csv +++ b/lgsm/data/ubuntu-20.04.csv @@ -11,8 +11,8 @@ av bb bb2,libcurl4-gnutls-dev:i386 bd -bf1942,libncurses5:i386,libtinfo5:i386 -bfv,libncurses5:i386,libstdc++5:i386 +bf1942,libc6:i386 +bfv,libc6:i386 bmdm,libncurses5:i386 bo bs diff --git a/lgsm/data/ubuntu-22.04.csv b/lgsm/data/ubuntu-22.04.csv index 4899014069..8e7aa50794 100644 --- a/lgsm/data/ubuntu-22.04.csv +++ b/lgsm/data/ubuntu-22.04.csv @@ -11,8 +11,8 @@ av bb bb2,libcurl4-gnutls-dev:i386 bd -bf1942,libncurses5:i386,libtinfo5:i386 -bfv,libncurses5:i386,libstdc++5:i386 +bf1942,libc6:i386 +bfv,libc6:i386 bmdm,libncurses5:i386 bo bs diff --git a/lgsm/data/ubuntu-23.04.csv b/lgsm/data/ubuntu-23.04.csv index 13693600b1..815a6a14fc 100644 --- a/lgsm/data/ubuntu-23.04.csv +++ b/lgsm/data/ubuntu-23.04.csv @@ -11,8 +11,8 @@ av bb bb2,libcurl4-gnutls-dev:i386 bd -bf1942,libncurses5:i386,libtinfo5:i386 -bfv,libncurses5:i386,libstdc++5:i386 +bf1942,libc6:i386 +bfv,libc6:i386 bmdm,libncurses5:i386 bo bs diff --git a/lgsm/data/ubuntu-23.10.csv b/lgsm/data/ubuntu-23.10.csv index 13693600b1..815a6a14fc 100644 --- a/lgsm/data/ubuntu-23.10.csv +++ b/lgsm/data/ubuntu-23.10.csv @@ -11,8 +11,8 @@ av bb bb2,libcurl4-gnutls-dev:i386 bd -bf1942,libncurses5:i386,libtinfo5:i386 -bfv,libncurses5:i386,libstdc++5:i386 +bf1942,libc6:i386 +bfv,libc6:i386 bmdm,libncurses5:i386 bo bs diff --git a/lgsm/data/ubuntu-24.04.csv b/lgsm/data/ubuntu-24.04.csv index 9ecc5bd265..05ca25dbd0 100644 --- a/lgsm/data/ubuntu-24.04.csv +++ b/lgsm/data/ubuntu-24.04.csv @@ -11,8 +11,8 @@ av bb bb2,libcurl4-gnutls-dev:i386 bd -bf1942 -bfv,libstdc++5:i386 +bf1942,libc6:i386 +bfv,libc6:i386 bmdm bo bs diff --git a/lgsm/data/ubuntu-26.04.csv b/lgsm/data/ubuntu-26.04.csv index 9ecc5bd265..05ca25dbd0 100644 --- a/lgsm/data/ubuntu-26.04.csv +++ b/lgsm/data/ubuntu-26.04.csv @@ -11,8 +11,8 @@ av bb bb2,libcurl4-gnutls-dev:i386 bd -bf1942 -bfv,libstdc++5:i386 +bf1942,libc6:i386 +bfv,libc6:i386 bmdm bo bs diff --git a/lgsm/modules/check_deps.sh b/lgsm/modules/check_deps.sh index 0f01181318..975540542a 100755 --- a/lgsm/modules/check_deps.sh +++ b/lgsm/modules/check_deps.sh @@ -395,15 +395,6 @@ if [ -n "${distrosupport}" ]; then fi fi -# These titles are only supported up to Ubuntu 22.04 (Jammy) and Debian 12 (Bookworm). -if { [ "${distroid}" == "ubuntu" ] && dpkg --compare-versions "${distroversion}" "gt" "22.04"; } || { [ "${distroid}" == "debian" ] && dpkg --compare-versions "${distroversion}" "gt" "12"; }; then - if [ "${shortname}" == "bf1942" ] || [ "${shortname}" == "bfv" ]; then - fn_print_failure_nl "${gamename} is not supported on ${distroname} (requires Ubuntu <= 22.04 or Debian <= 12)." - fn_script_log_fail "${gamename} is not supported on ${distroname}." - core_exit.sh - fi -fi - # These titles are only supported up to Ubuntu 20.04 and Debian 11. if { [ "${distroid}" == "ubuntu" ] && dpkg --compare-versions "${distroversion}" "gt" "20.04"; } || { [ "${distroid}" == "debian" ] && dpkg --compare-versions "${distroversion}" "gt" "11"; }; then if [ "${shortname}" == "onset" ] || [ "${shortname}" == "btl" ]; then diff --git a/lgsm/modules/core_modules.sh b/lgsm/modules/core_modules.sh index d02a828b56..7284f3c1b6 100755 --- a/lgsm/modules/core_modules.sh +++ b/lgsm/modules/core_modules.sh @@ -378,6 +378,16 @@ fix_av.sh() { fn_fetch_module } +fix_bf1942.sh() { + modulefile="${FUNCNAME[0]}" + fn_fetch_module +} + +fix_bfv.sh() { + modulefile="${FUNCNAME[0]}" + fn_fetch_module +} + fix_bo.sh() { modulefile="${FUNCNAME[0]}" fn_fetch_module diff --git a/lgsm/modules/fix.sh b/lgsm/modules/fix.sh index 505a8628d3..69065a9fcd 100755 --- a/lgsm/modules/fix.sh +++ b/lgsm/modules/fix.sh @@ -53,7 +53,7 @@ fn_apply_fix() { fi } -apply_pre_start_fix=(arma3 armar ark av bt bo csgo cmw dst hw ins ios kf nd nmrih onset pvr ro rust rw samp sdtd sfc sm sof2 squad st tf2 terraria ts3 mcb mta unt vh wurm xnt zmr) +apply_pre_start_fix=(arma3 armar ark av bf1942 bfv bt bo csgo cmw dst hw ins ios kf nd nmrih onset pvr ro rust rw samp sdtd sfc sm sof2 squad st tf2 terraria ts3 mcb mta unt vh wurm xnt zmr) apply_post_install_fix=(av kf kf2 nd ro ut2k4 ut ut3) # validate registered fixes for safe development diff --git a/lgsm/modules/fix_bf1942.sh b/lgsm/modules/fix_bf1942.sh new file mode 100755 index 0000000000..2993d55ed2 --- /dev/null +++ b/lgsm/modules/fix_bf1942.sh @@ -0,0 +1,21 @@ +#!/bin/bash +# LinuxGSM fix_bf1942.sh module +# Author: Daniel Gibbs +# Contributors: https://linuxgsm.com/contrib +# Website: https://linuxgsm.com +# Description: Resolves issues with Battlefield 1942. + +# shellcheck disable=SC2034 # Used by the module loader. +moduleselfname="$(basename "$(readlink -f "${BASH_SOURCE[0]}")")" + +export LD_LIBRARY_PATH="$LD_LIBRARY_PATH:${serverfiles}" + +if ldd "${executabledir}/bf1942_lnxded.static" 2>&1 | grep -qE "lib(ncurses|tinfo)\.so\.5 => not found"; then + # shellcheck disable=SC2034 # Used by fn_fix_msg_start_nl and fn_fix_msg_end. + fixname="libncurses5 i386" + fn_fix_msg_start_nl + fn_fetch_file "http://linuxgsm.download/libraries/libncurses5-i386-6.3-2ubuntu0.3.tar.xz" "" "" "" "${tmpdir}" "libncurses5-i386-6.3-2ubuntu0.3.tar.xz" "nochmodx" "norun" "noforce" "ee141cb3a843e4201786b6f188347666" + fn_dl_extract "${tmpdir}" "libncurses5-i386-6.3-2ubuntu0.3.tar.xz" "${serverfiles}" + fn_clear_tmp + fn_fix_msg_end +fi diff --git a/lgsm/modules/fix_bfv.sh b/lgsm/modules/fix_bfv.sh new file mode 100755 index 0000000000..5397d6e69f --- /dev/null +++ b/lgsm/modules/fix_bfv.sh @@ -0,0 +1,21 @@ +#!/bin/bash +# LinuxGSM fix_bfv.sh module +# Author: Daniel Gibbs +# Contributors: https://linuxgsm.com/contrib +# Website: https://linuxgsm.com +# Description: Resolves issues with Battlefield: Vietnam. + +# shellcheck disable=SC2034 # Used by the module loader. +moduleselfname="$(basename "$(readlink -f "${BASH_SOURCE[0]}")")" + +export LD_LIBRARY_PATH="$LD_LIBRARY_PATH:${serverfiles}" + +if ldd "${executabledir}/bfv_linded.static" 2>&1 | grep -qE "lib(ncurses|tinfo)\.so\.5 => not found"; then + # shellcheck disable=SC2034 # Used by fn_fix_msg_start_nl and fn_fix_msg_end. + fixname="libncurses5 i386" + fn_fix_msg_start_nl + fn_fetch_file "http://linuxgsm.download/libraries/libncurses5-i386-6.3-2ubuntu0.3.tar.xz" "" "" "" "${tmpdir}" "libncurses5-i386-6.3-2ubuntu0.3.tar.xz" "nochmodx" "norun" "noforce" "ee141cb3a843e4201786b6f188347666" + fn_dl_extract "${tmpdir}" "libncurses5-i386-6.3-2ubuntu0.3.tar.xz" "${serverfiles}" + fn_clear_tmp + fn_fix_msg_end +fi diff --git a/lgsm/modules/install_server_files.sh b/lgsm/modules/install_server_files.sh index d7f615462f..1ff3561e97 100755 --- a/lgsm/modules/install_server_files.sh +++ b/lgsm/modules/install_server_files.sh @@ -17,21 +17,21 @@ fn_install_server_files() { force="noforce" md5="61d7b79fd714888b6d65944fdaafa94a" elif [ "${shortname}" == "bf1942" ]; then - remote_fileurl="http://linuxgsm.download/BattleField1942/bf1942_lnxded-1.61-hacked-to-1.612.full.tar.xz" + remote_fileurl="http://linuxgsm.download/BattleField1942/bf1942_lnxded-1.61-hacked-to-1.612.full-linuxgsm.tar.xz" local_filedir="${tmpdir}" - local_filename="bf1942_lnxded-1.61-hacked-to-1.612.full.tar.xz" + local_filename="bf1942_lnxded-1.61-hacked-to-1.612.full-linuxgsm.tar.xz" chmodx="nochmodx" run="norun" force="noforce" - md5="4223bf4ed85f5162c24b2cba51249b9e" + md5="d58016b3c45f86a71bb56c39749ce941" elif [ "${shortname}" == "bfv" ]; then - remote_fileurl="http://linuxgsm.download/BattlefieldVietnam/bfv_linded-v1.21-20041207_patch.tar.xz" + remote_fileurl="http://linuxgsm.download/BattlefieldVietnam/bfv_linded-v1.21-20041207_patch-linuxgsm.tar.xz" local_filedir="${tmpdir}" - local_filename="bfv_linded-v1.21-20041207_patch.tar.xz" + local_filename="bfv_linded-v1.21-20041207_patch-linuxgsm.tar.xz" chmodx="nochmodx" run="norun" force="noforce" - md5="e3b4962cdd9d41e23c6fed65101bccde" + md5="9a8117732b8abd99cc59f1f0fa92adfa" elif [ "${shortname}" == "cod" ]; then remote_fileurl="http://linuxgsm.download/CallOfDuty/cod-lnxded-1.5b-full.tar.xz" From 84ee98e767ab9f4f2d839d970053b670edf49acc Mon Sep 17 00:00:00 2001 From: Daniel Gibbs Date: Thu, 15 Oct 2026 21:33:10 +0100 Subject: [PATCH 068/164] fix(ut3server): read web admin enabled flag and port from UTWeb.ini (#5044) UT3 stores [UWeb.WebServer] bEnabled and ListenPort in UTWeb.ini, not UTGame.ini, so details always showed the web interface as disabled on port 0. Parse both keys from UTWeb.ini, as kf2server does with KFWeb.ini. Fixes #1438 --- lgsm/modules/info_game.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lgsm/modules/info_game.sh b/lgsm/modules/info_game.sh index 01a064493b..baa8604b20 100755 --- a/lgsm/modules/info_game.sh +++ b/lgsm/modules/info_game.sh @@ -834,9 +834,9 @@ fn_info_game_ut3() { fn_info_game_ini "maxplayers" "MaxPlayers" fn_info_game_ini "servername" "ServerName" fn_info_game_ini "serverpassword" "GamePassword" - fn_info_game_ini "httpenabled" "bEnabled" + fn_info_game_ini "httpenabled" "bEnabled" "${servercfgdir}/UTWeb.ini" fn_info_game_ini "httppassword" "AdminPassword" - fn_info_game_ini "httpport" "ListenPort" + fn_info_game_ini "httpport" "ListenPort" "${servercfgdir}/UTWeb.ini" fi adminpassword="${adminpassword:-"NOT SET"}" defaultmap="${defaultmap:-"NOT SET"}" From 80ac7281f8b50c2835caa8b1347d37086018d7e9 Mon Sep 17 00:00:00 2001 From: Daniel Gibbs Date: Thu, 15 Oct 2026 21:36:05 +0100 Subject: [PATCH 069/164] fix(fastdl): collect GoldSrc content with the GoldSrc file layout (#5045) The fastdl command is offered for GoldSrc servers and already copies files instead of compressing them, but it gathered files using the Source layout (materials, particles, resource and Source file types). GoldSrc custom content was therefore left out: wad files in the mod root, map .res files, sprites, sky and detail textures in gfx, and overviews. When the engine is goldsrc, the preview and build steps now use a GoldSrc directory list and per-directory file types from a single shared function: - mod root: *.wad (top level only) - maps: *.bsp *.res *.txt - models: *.mdl - sound: *.wav - sprites: *.spr *.txt - gfx: *.tga *.bmp - overviews: *.bmp *.tga *.txt Source and Garry's Mod behaviour is unchanged. Fixes #1778 --- lgsm/modules/command_fastdl.sh | 41 +++++++++++++++++++++++++++++----- 1 file changed, 35 insertions(+), 6 deletions(-) diff --git a/lgsm/modules/command_fastdl.sh b/lgsm/modules/command_fastdl.sh index c73fe175a7..93dc87d262 100755 --- a/lgsm/modules/command_fastdl.sh +++ b/lgsm/modules/command_fastdl.sh @@ -132,6 +132,27 @@ fn_human_readable_file_size() { fi } +# Sets the GoldSrc file types to include for the current directory. +fn_fastdl_goldsrc_extensions() { + fastdl_find_maxdepth=() + if [ "${directory}" == "." ]; then + allowed_extentions_array=("*.wad") + fastdl_find_maxdepth=("-maxdepth" "1") + elif [ "${directory}" == "maps" ]; then + allowed_extentions_array=("*.bsp" "*.res" "*.txt") + elif [ "${directory}" == "models" ]; then + allowed_extentions_array=("*.mdl") + elif [ "${directory}" == "sound" ]; then + allowed_extentions_array=("*.wav") + elif [ "${directory}" == "sprites" ]; then + allowed_extentions_array=("*.spr" "*.txt") + elif [ "${directory}" == "gfx" ]; then + allowed_extentions_array=("*.tga" "*.bmp") + elif [ "${directory}" == "overviews" ]; then + allowed_extentions_array=("*.bmp" "*.tga" "*.txt") + fi +} + # Provides info about the fastdl directory content and prompts for confirmation. fn_fastdl_preview() { # Remove any file list. @@ -160,12 +181,18 @@ fn_fastdl_preview() { fn_print_skip_eol_nl fi done - # Source engine + # Source and GoldSrc engines else - fastdl_directories_array=("maps" "materials" "models" "particles" "sound" "resource") + if [ "${engine}" == "goldsrc" ]; then + fastdl_directories_array=("." "maps" "models" "sound" "sprites" "gfx" "overviews") + else + fastdl_directories_array=("maps" "materials" "models" "particles" "sound" "resource") + fi for directory in "${fastdl_directories_array[@]}"; do if [ -d "${systemdir}/${directory}" ]; then - if [ "${directory}" == "maps" ]; then + if [ "${engine}" == "goldsrc" ]; then + fn_fastdl_goldsrc_extensions + elif [ "${directory}" == "maps" ]; then local allowed_extentions_array=("*.bsp" "*.ain" "*.nav" "*.jpg" "*.txt") elif [ "${directory}" == "materials" ]; then local allowed_extentions_array=("*.vtf" "*.vmt" "*.vbf" "*.png" "*.svg") @@ -187,7 +214,7 @@ fn_fastdl_preview() { tput el fn_print "gathering ${directory} ${allowed_extention} : ${fileswc}" echo -e "${ext}" >> "${tmpdir}/fastdl_files_to_compress.txt" - done < <(find "${systemdir}/${directory}" -type f -iname "${allowed_extention}") + done < <(find "${systemdir}/${directory}" "${fastdl_find_maxdepth[@]}" -type f -iname "${allowed_extention}") tput rc tput el fn_print "gathering ${directory} ${allowed_extention} : ${fileswc}" @@ -315,7 +342,9 @@ fn_fastdl_gmod() { fn_fastdl_source() { for directory in "${fastdl_directories_array[@]}"; do if [ -d "${systemdir}/${directory}" ]; then - if [ "${directory}" == "maps" ]; then + if [ "${engine}" == "goldsrc" ]; then + fn_fastdl_goldsrc_extensions + elif [ "${directory}" == "maps" ]; then local allowed_extentions_array=("*.bsp" "*.ain" "*.nav" "*.jpg" "*.txt") elif [ "${directory}" == "materials" ]; then local allowed_extentions_array=("*.vtf" "*.vmt" "*.vbf" "*.png" "*.svg") @@ -353,7 +382,7 @@ fn_fastdl_source() { else fn_script_log_pass "Copying ${fastdlfile} > ${fastdldir}/${copytodir}" fi - done < <(find "${systemdir}/${directory}" -type f -iname "${allowed_extention}") + done < <(find "${systemdir}/${directory}" "${fastdl_find_maxdepth[@]}" -type f -iname "${allowed_extention}") if [ ${fileswc} != 0 ]; then fn_print_ok_eol_nl fi From 8ef06ff6aca595c388d8e309e76bd3e7c8ccf184 Mon Sep 17 00:00:00 2001 From: Daniel Gibbs Date: Thu, 15 Oct 2026 21:41:13 +0100 Subject: [PATCH 070/164] fix(core): stop prompts looping forever when no input is available (#5042) * fix(core): stop prompts looping forever when no input is available fn_prompt_yn read the answer in an endless loop. When stdin is not a terminal (cron, piped input, a container started without -it), read hits EOF, the answer stays empty and "Please answer yes or no." is printed forever at full CPU. Running ./vhserver install with stdin from /dev/null wrote over 3 million lines (83 MB) in 60 seconds at the server directory prompt. Without a terminal bash also ignores read -e, -i and -p, so the prefilled default is never applied and taking the default is not an option. Several prompts default to Y on actions that must not happen unattended (accept EULA, enable stats, delete all modules, overwrite the fastdl directory, remove a mod), and treating no input as "no" would exit 0 on an aborted install. Prompts now check the read return code. If read fails with no answer, the command prints an error and exits with code 2. Scripted answers such as "yes |" or "printf 'y\n' |" keep working, including an answer with no trailing newline. The same check is added to: - fn_prompt_message, which returns 1, and command_send, which exits with an error because core_exit.sh inside $() only ends the subshell. - the mods-install and mods-remove selection loops, which looped forever on "is not a valid addon/mod" in the same way. * fix(core): document shared prompt exit codes for ShellCheck --- lgsm/modules/command_mods_install.sh | 8 +++++++- lgsm/modules/command_mods_remove.sh | 8 +++++++- lgsm/modules/command_send.sh | 9 ++++++++- lgsm/modules/core_messages.sh | 13 +++++++++++-- 4 files changed, 33 insertions(+), 5 deletions(-) diff --git a/lgsm/modules/command_mods_install.sh b/lgsm/modules/command_mods_install.sh index 77dfd017e3..09bc4ce270 100755 --- a/lgsm/modules/command_mods_install.sh +++ b/lgsm/modules/command_mods_install.sh @@ -64,7 +64,13 @@ echo -e "" while :; do echo -en "Enter an ${cyan}addon/mod${default} to ${green}install${default} (or exit to abort): " - read -r usermodselect + if ! read -r usermodselect && [ -z "${usermodselect}" ]; then + echo -e "" + fn_print_error_nl "Unable to read an addon/mod: no input available" + fn_script_log_error "Unable to read an addon/mod: no input available" + exitcode=2 + core_exit.sh + fi # Exit if user says exit or abort. if [ "${usermodselect}" == "exit" ] || [ "${usermodselect}" == "abort" ]; then core_exit.sh diff --git a/lgsm/modules/command_mods_remove.sh b/lgsm/modules/command_mods_remove.sh index c9c06b15f0..821451dab9 100755 --- a/lgsm/modules/command_mods_remove.sh +++ b/lgsm/modules/command_mods_remove.sh @@ -35,7 +35,13 @@ echo -e "" while :; do echo -en "Enter an ${cyan}addon/mod${default} to ${red}remove${default} (or exit to abort): " - read -r usermodselect + if ! read -r usermodselect && [ -z "${usermodselect}" ]; then + echo -e "" + fn_print_error_nl "Unable to read an addon/mod: no input available" + fn_script_log_error "Unable to read an addon/mod: no input available" + exitcode=2 + core_exit.sh + fi # Exit if user says exit or abort. if [ "${usermodselect}" == "exit" ] || [ "${usermodselect}" == "abort" ]; then core_exit.sh diff --git a/lgsm/modules/command_send.sh b/lgsm/modules/command_send.sh index 71c1e43426..f2197421a1 100755 --- a/lgsm/modules/command_send.sh +++ b/lgsm/modules/command_send.sh @@ -22,7 +22,14 @@ if [ "${status}" != "0" ]; then commandtosend="${userinput2}" else echo "" - commandtosend=$(fn_prompt_message "send: ") + if ! commandtosend=$(fn_prompt_message "send: "); then + echo -e "" + fn_print_error_nl "Unable to read a command to send: no input available" + fn_script_log_error "Unable to read a command to send: no input available" + # shellcheck disable=SC2034 # Used by core_exit.sh. + exitcode=2 + core_exit.sh + fi fi echo "" fn_print_dots "Sending command to console: \"${commandtosend}\"" diff --git a/lgsm/modules/core_messages.sh b/lgsm/modules/core_messages.sh index f00a44984e..bcf3abe2ca 100755 --- a/lgsm/modules/core_messages.sh +++ b/lgsm/modules/core_messages.sh @@ -320,7 +320,14 @@ fn_prompt_yn() { fi while true; do - read -e -i "${initial}" -p "${prompt}" -r yn + if ! read -e -i "${initial}" -p "${prompt}" -r yn && [ -z "${yn}" ]; then + echo -e "" + fn_print_error_nl "Unable to read an answer: no input available" + fn_script_log_error "Unable to read an answer to \"${1}\": no input available" + # shellcheck disable=SC2034 # Used by core_exit.sh. + exitcode=2 + core_exit.sh + fi case "${yn}" in [Yy] | [Yy][Ee][Ss]) return 0 ;; [Nn] | [Nn][Oo]) return 1 ;; @@ -334,7 +341,9 @@ fn_prompt_message() { while true; do unset prompt local prompt="$1" - read -e -p "${prompt}" -r answer + if ! read -e -p "${prompt}" -r answer && [ -z "${answer}" ]; then + return 1 + fi if fn_prompt_yn "Continue" Y; then break fi From d9079242a3f2a9aa029ec8fccd2bb1a2967da5af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E3=82=A2=E3=83=AC=E3=83=83=E3=82=AF=E3=82=B9?= Date: Fri, 16 Oct 2026 07:46:53 +1000 Subject: [PATCH 071/164] feat(jk3server): add Jedi Academy with OpenJK (#3891) * Update port number for jk2server * Add jk3server LinuxGSM configuration This adds Jedi Knight: Jedi Academy configuation to LinuxGSM Similar to jk2server configuration but with minor differences. * Update port number and defaultmap for jk3server * feat(new server): Jedi Knight: Jedi Academy * fix(jk3): misplaced number * Update serverlist.csv Try to add new server to serverlist * add update jk3 module also added jk3 to serverlistmenu * update jk3s lgsm config * remove serverlistmenu.csv not meant to be there * Update missing info for lgsm modules - jk3server * fix typos * add condition for starting jk3server in tmux * fix(jk3server): select Academy app and bound release lookups * fix(jk3server): omit unavailable config version from details * refactor(jk3server): follow shared updater conventions --------- Co-authored-by: Alexander Silva Co-authored-by: Daniel Gibbs --- .../config-lgsm/jk3server/_default.cfg | 215 ++++++++++++++++++ lgsm/data/almalinux-8.csv | 1 + lgsm/data/almalinux-9.csv | 1 + lgsm/data/centos-7.csv | 1 + lgsm/data/centos-8.csv | 1 + lgsm/data/centos-9.csv | 1 + lgsm/data/debian-10.csv | 1 + lgsm/data/debian-11.csv | 1 + lgsm/data/debian-12.csv | 1 + lgsm/data/debian-13.csv | 1 + lgsm/data/debian-9.csv | 1 + lgsm/data/gameicons/jk3-icon.png | Bin 0 -> 2805 bytes lgsm/data/rhel-7.csv | 1 + lgsm/data/rhel-8.csv | 1 + lgsm/data/rhel-9.csv | 1 + lgsm/data/rocky-8.csv | 1 + lgsm/data/rocky-9.csv | 1 + lgsm/data/serverlist.csv | 1 + lgsm/data/ubuntu-16.04.csv | 1 + lgsm/data/ubuntu-18.04.csv | 1 + lgsm/data/ubuntu-20.04.csv | 1 + lgsm/data/ubuntu-22.04.csv | 1 + lgsm/data/ubuntu-23.04.csv | 1 + lgsm/data/ubuntu-23.10.csv | 1 + lgsm/data/ubuntu-24.04.csv | 1 + lgsm/data/ubuntu-26.04.csv | 1 + lgsm/modules/command_check_update.sh | 2 + lgsm/modules/command_update.sh | 2 + lgsm/modules/core_getopt.sh | 2 +- lgsm/modules/core_modules.sh | 5 + lgsm/modules/info_game.sh | 23 ++ lgsm/modules/info_messages.sh | 9 + lgsm/modules/install_config.sh | 5 + lgsm/modules/install_server_files.sh | 2 + lgsm/modules/update_jk3.sh | 175 ++++++++++++++ 35 files changed, 463 insertions(+), 1 deletion(-) create mode 100644 lgsm/config-default/config-lgsm/jk3server/_default.cfg create mode 100644 lgsm/data/gameicons/jk3-icon.png create mode 100755 lgsm/modules/update_jk3.sh diff --git a/lgsm/config-default/config-lgsm/jk3server/_default.cfg b/lgsm/config-default/config-lgsm/jk3server/_default.cfg new file mode 100644 index 0000000000..576b1e0a33 --- /dev/null +++ b/lgsm/config-default/config-lgsm/jk3server/_default.cfg @@ -0,0 +1,215 @@ +################################## +######## Default Settings ######## +################################## +# DO NOT EDIT, ANY CHANGES WILL BE OVERWRITTEN! +# Copy settings from here and use them in either: +# common.cfg - applies settings to every instance. +# [instance].cfg - applies settings to a specific instance. + +#### Game Server Settings #### + +## SteamCMD Login | https://docs.linuxgsm.com/steamcmd#steamcmd-login +# Requires a Steam account that owns Jedi Academy. +steamuser="username" +steampass='password' + +## Predefined Parameters | https://docs.linuxgsm.com/configuration/start-parameters +ip="0.0.0.0" +port="29070" +defaultmap="mp/ffa3" + +## Server Parameters | https://docs.linuxgsm.com/configuration/start-parameters#additional-parameters +startparameters="+set dedicated 2 +set fs_basepath \"${systemdir}\" +set fs_homepath \"${systemdir}\" +set net_ip ${ip} +set net_port ${port} +exec ${servercfg} +map ${defaultmap}" + +#### LinuxGSM Settings #### + +## LinuxGSM Stats +# Send useful stats to LinuxGSM developers. +# https://docs.linuxgsm.com/configuration/linuxgsm-stats +# (on|off) +stats="off" + +## Notification Alerts +# (on|off) + +# Display IP | https://docs.linuxgsm.com/alerts#display-ip +displayip="" + +# More info | https://docs.linuxgsm.com/alerts#more-info +postalert="off" + +# Alert on Start/Stop/Restart +statusalert="off" + +# Discord Alerts | https://docs.linuxgsm.com/alerts/discord +discordalert="off" +discordwebhook="webhook" + +# Email Alerts | https://docs.linuxgsm.com/alerts/email +emailalert="off" +email="email@example.com" +emailfrom="" + +# Gotify Alerts | https://docs.linuxgsm.com/alerts/gotify +gotifyalert="off" +gotifytoken="token" +gotifywebhook="webhook" + +# IFTTT Alerts | https://docs.linuxgsm.com/alerts/ifttt +iftttalert="off" +ifttttoken="accesstoken" +iftttevent="linuxgsm_alert" + +# ntfy Alerts | https://docs.linuxgsm.com/alerts/ntfy +ntfyalert="off" +ntfytopic="LinuxGSM" +ntfyserver="https://ntfy.sh" +ntfytoken="" +ntfyusername="" +ntfypassword="" +ntfypriority="" +ntfytags="" + +# Matrix Alerts | https://docs.linuxgsm.com/alerts/matrix +matrixalert="off" +matrixhomeserver="matrix.org" +matrixtoken="accesstoken" +matrixroom="" + +# Pushbullet Alerts | https://docs.linuxgsm.com/alerts/pushbullet +pushbulletalert="off" +pushbullettoken="accesstoken" +channeltag="" + +# Pushover Alerts | https://docs.linuxgsm.com/alerts/pushover +pushoveralert="off" +pushovertoken="accesstoken" +pushoveruserkey="userkey" + +# Rocket.Chat Alerts | https://docs.linuxgsm.com/alerts/rocket.chat +rocketchatalert="off" +rocketchatwebhook="webhook" + +# Slack Alerts | https://docs.linuxgsm.com/alerts/slack +slackalert="off" +slackwebhook="webhook" + +# Telegram Alerts | https://docs.linuxgsm.com/alerts/telegram +# You can add a custom cURL string eg proxy (useful in Russia) in "curlcustomstring". +# For example "--socks5 ipaddr:port" for socks5 proxy see more in "curl --help all". +telegramapi="api.telegram.org" +telegramalert="off" +telegramtoken="accesstoken" +telegramchatid="" +telegramthreadid="" +telegramsilentnotification="false" +curlcustomstring="" + +## Stop | https://docs.linuxgsm.com/commands/start-stop-restart +stoponlyifnoplayers="off" +stoponlyifnoplayersallcommands="on" + +## Player Warnings | https://docs.linuxgsm.com/features/player-warnings +# Minutes to warn players in-game before a stop, restart or update. 0 to disable. +# e.g. 15 warns at 15, 10, 5, 3 and 1 minutes. +warnplayerstimer="0" + +## Updating | https://docs.linuxgsm.com/commands/update +updateonstart="off" + +## Backup | https://docs.linuxgsm.com/commands/backup +maxbackups="4" +maxbackupdays="30" +stoponbackup="on" + +## Logging | https://docs.linuxgsm.com/features/logging +consolelogging="on" +logdays="7" + +## Monitor | https://docs.linuxgsm.com/commands/monitor +# Query delay time +querydelay="1" + +## ANSI Colors | https://docs.linuxgsm.com/features/ansi-colors +ansi="on" + +#### Advanced Settings #### + +## Message Display Time | https://docs.linuxgsm.com/features/message-display-time +sleeptime="0.5" + +## SteamCMD Settings | https://docs.linuxgsm.com/steamcmd +# Server appid +appid="6020" +steamcmdforcewindows="yes" +# SteamCMD Branch | https://docs.linuxgsm.com/steamcmd/branch +branch="" +betapassword="" +# Master Server | https://docs.linuxgsm.com/steamcmd/steam-master-server +steammaster="false" + +## Stop Mode | https://docs.linuxgsm.com/features/stop-mode +# 1: tmux kill +# 2: CTRL+c +# 3: quit +# 4: quit 120s +# 5: stop +# 6: q +# 7: exit +# 8: 7 Days to Die +# 9: GoldSrc +# 10: Avorion +# 11: end +stopmode="3" + +## Query mode +# 1: session only +# 2: gamedig (gsquery fallback) +# 3: gamedig +# 4: gsquery +# 5: tcp +querymode="2" +querytype="protocol-quake3" + +## Console type +consoleverbose="yes" +consoleinteract="yes" + +## Game Server Details +# Do not edit +gamename="Jedi Knight: Jedi Academy" +engine="idtech3" +glibc="2.34" + +#### Directories #### +# Edit with care + +## Game Server Directories +systemdir="${serverfiles}/GameData" +executabledir="${systemdir}" +executable="./openjkded.x86_64" +servercfg="${selfname}.cfg" +servercfgdefault="server.cfg" +servercfgdir="${systemdir}/base" +servercfgfullpath="${servercfgdir}/${servercfg}" + +## Backup Directory +backupdir="${lgsmdir}/backups" + +## Logging Directories +[ -n "${LGSM_LOGDIR}" ] && logdir="${LGSM_LOGDIR}" || logdir="${rootdir}/log" +gamelogdir="${systemdir}/logs" +lgsmlogdir="${logdir}/script" +consolelogdir="${logdir}/console" +lgsmlog="${lgsmlogdir}/${selfname}-script.log" +consolelog="${consolelogdir}/${selfname}-console.log" +alertlog="${lgsmlogdir}/${selfname}-alert.log" +postdetailslog="${lgsmlogdir}/${selfname}-postdetails.log" + +## Logs Naming +lgsmlogdate="${lgsmlogdir}/${selfname}-script-$(date '+%Y-%m-%d-%H:%M:%S').log" +consolelogdate="${consolelogdir}/${selfname}-console-$(date '+%Y-%m-%d-%H:%M:%S').log" + +## Log Parameters +logtimestamp="off" +logtimestampformat="%Y-%m-%d %H:%M:%S" diff --git a/lgsm/data/almalinux-8.csv b/lgsm/data/almalinux-8.csv index 88a11800ee..ef1168a11b 100644 --- a/lgsm/data/almalinux-8.csv +++ b/lgsm/data/almalinux-8.csv @@ -63,6 +63,7 @@ jbep3 jc2 jc3 jk2 +jk3,libstdc++,zlib kf kf2 l4d diff --git a/lgsm/data/almalinux-9.csv b/lgsm/data/almalinux-9.csv index 7e3c49766c..51d249bf3f 100644 --- a/lgsm/data/almalinux-9.csv +++ b/lgsm/data/almalinux-9.csv @@ -63,6 +63,7 @@ jbep3 jc2 jc3 jk2 +jk3,libstdc++,zlib kf kf2 l4d diff --git a/lgsm/data/centos-7.csv b/lgsm/data/centos-7.csv index 8a93a6091c..a1ba04eca8 100644 --- a/lgsm/data/centos-7.csv +++ b/lgsm/data/centos-7.csv @@ -63,6 +63,7 @@ jbep3 jc2 jc3 jk2 +jk3,libstdc++,zlib kf kf2 l4d diff --git a/lgsm/data/centos-8.csv b/lgsm/data/centos-8.csv index 284b88628f..5528c18daf 100644 --- a/lgsm/data/centos-8.csv +++ b/lgsm/data/centos-8.csv @@ -63,6 +63,7 @@ jbep3 jc2 jc3 jk2 +jk3,libstdc++,zlib kf kf2 l4d diff --git a/lgsm/data/centos-9.csv b/lgsm/data/centos-9.csv index 3dd1739626..96ffff9a3c 100644 --- a/lgsm/data/centos-9.csv +++ b/lgsm/data/centos-9.csv @@ -63,6 +63,7 @@ jbep3 jc2 jc3 jk2 +jk3,libstdc++,zlib kf kf2 l4d diff --git a/lgsm/data/debian-10.csv b/lgsm/data/debian-10.csv index 8fc0403c9f..0ad2140d7b 100644 --- a/lgsm/data/debian-10.csv +++ b/lgsm/data/debian-10.csv @@ -62,6 +62,7 @@ jbep3 jc2 jc3 jk2 +jk3,libstdc++6,zlib1g kf kf2 l4d diff --git a/lgsm/data/debian-11.csv b/lgsm/data/debian-11.csv index 0b0168c791..66604e5dd6 100644 --- a/lgsm/data/debian-11.csv +++ b/lgsm/data/debian-11.csv @@ -63,6 +63,7 @@ jbep3 jc2 jc3 jk2 +jk3,libstdc++6,zlib1g kf kf2 l4d diff --git a/lgsm/data/debian-12.csv b/lgsm/data/debian-12.csv index 1260899298..f9f4c286b8 100644 --- a/lgsm/data/debian-12.csv +++ b/lgsm/data/debian-12.csv @@ -63,6 +63,7 @@ jbep3 jc2 jc3 jk2 +jk3,libstdc++6,zlib1g kf kf2 l4d diff --git a/lgsm/data/debian-13.csv b/lgsm/data/debian-13.csv index 6a62b041f3..c7b5e4e941 100644 --- a/lgsm/data/debian-13.csv +++ b/lgsm/data/debian-13.csv @@ -63,6 +63,7 @@ jbep3 jc2 jc3 jk2 +jk3,libstdc++6,zlib1g kf kf2 l4d diff --git a/lgsm/data/debian-9.csv b/lgsm/data/debian-9.csv index ac8715d532..7124d6c451 100644 --- a/lgsm/data/debian-9.csv +++ b/lgsm/data/debian-9.csv @@ -63,6 +63,7 @@ jbep3 jc2 jc3 jk2 +jk3,libstdc++6,zlib1g kf kf2 l4d diff --git a/lgsm/data/gameicons/jk3-icon.png b/lgsm/data/gameicons/jk3-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..8c480a205e7544d61ede62b163768a2402748dff GIT binary patch literal 2805 zcmZ{mcRbXOAICr6GVX9zR)k8CeME}vlNA{`oUL;r4&m%QN><$2drS7nI9pwI_U07v zb9Ud5vwr&X_s8$?e!SkV$K&;SKmUJ6>FKINXgFyA0Dx#}zzi<^=3jxXT<%kj?Sf0A zuvgYm27sD)+EW|KzvT-J104YHsXGAB&-~Rt)EWuJmm#%>rj8o*It?Qe4R533kIc)nRZW=k zbB(W*U79f#v&z7TT)Q9fbSY;uD8=H_0Qzx*gBPAv)peXZKUq&D8eqo5Y`d;ZiJ0Cj zge5TgO=&2{zTCt}(io-W*w+~&c+W7Uz%NLwr9@IyOLEFWk{7TekTlj6wNs*i4 zc0WM(iz;Tz(i#RT%6iGpt*kgV+o56V;k<3)=EdG`*}bH>x^|8&$)GQgG2=g-)kewh9U03h4l52n31M@1?g=~jNocl00`u9EcV3k;M=kkxS zh!7^|=+KqS4Nl{hBs z5vgWbCo;^zSAEsBp!%Ow1}+7G0|LpR5Pe@gRUr8G3TKlqBR z*5eQsAHP95SnyDIIi$yqe{b93t29JRkfajI`k`jDu|f>=@OhR3A+Z~#nq-V{eBN6; z$yq{)V^TW5#qoV8CvwQgBW)Gb6*;B?%RU1WtfG1;hMeL@g{6YBBk5P z>qHPuX?`U2o80}_5hv?;?1Zudw%7a_SrneU@!~E>DLTJ;A_GfCVdH_P`d@2=A~Bh~ z^r-^olLXgQw5?Bs(A(u!sA&VLv+u_?_w^?%uPLJ0Qo>osO>r|df&E(P!M5;7D~0#>CTjSw8M@ye4d z-}B34I>B}kG}EdOOaOZx+MtMbUx3n;rR}prjAzLP6>&pe=qaj!+#iA8wGzS*j9Vk2 zJ{~>E^6RcH{~C4tVXP;7gQtfVYt%TMH1*k>Cidse-!Sqn%8ih2Pk4@wXgRnkabjLZ zlmC&GwB_+*@zFs0dh1z3PI{)+)eSMiqf%ypow%{CdsCt-n&@O%67XQhi2-^(9|U z*d3cEB6*zPoqD-p{2_S=f8=&BFVJ!F=s=A8DQGD_zz=yH{$*yoiQp`N2&}g}`|_Xj z3VXkt$G7G4IJtS9vY-ovk!`~;Y4u0l-FgODxex->t2VP_4qe{8_E~|}Kk5;4`RbBhC=N?Ocyq?eK%C^lYo*V*!)d}11Ss(3NlaTLoY z6)ckE*Oy`z)^9QCCGvW~5G?`c1Tz-8n#cUh z^lf?haK&{f_B|IyzI;utG^dJ9R>dtspzM6i8yva#Fl*&hMJe=22>T>&RP488pU#e$ zW2+a;6i+A~xW#hS#NrgqvMB1bn~?FJso6zIS~4HdSPv(r8e$H z%2Pn;4u3GndI>Nq;hzyyiJ5ZEMxIlZ+ay>9!f#)&%@hqfnvcwfV(NTJt|#KVH>7EF z*X^gblk^^H6-1a2J9s8yD?G|W70uD72>mKi1hud}Md;|SsbNvoB}bUQtfDWF%Ew`dlZ!J=gSFB*x2Do@1F0Ph|rD^UI43< zRF?BtY+6cJn#`9B_P;o2)+F?e9v>~K#@)|q(~mtAHwnQ!hGagFGqsOri?{P~TEfHq z{}cobNc+6EV2svE5fp)&ZQXo^f{cI|7u2<`7lP&)W%QXe5VTasjvvz=9&LQ^KfHD{ zY9Pm_I1V`ME1TSM7&juoI~a z?FwWP!ZqC08nlOcIZ1P?uGmJCqdzNS9n+O4(qw0c5=e>)T#BmuDxiN3Rgg1_{zDwt z7vF~^v4|%A+6#Hf9$Z;-Bh_{i$0R|wb>yGfU}Thn@#S=O8=cs1DT-XfGKQ9GA(iDmY%y8L+P-ex<#etTd$S`S10yMb&C%U0Oj+Sil%1D^?WQyZ`hw$%|+K z8=vdTLQ;roYl~%0soCi08<$Js77p3$=XSD;?j8@xwtsr$*WQ~g6J4L)(J6Z3v{BED7kFlDby9EgD2Qkg{JJW*@D~jCnzFxk DlL1HN literal 0 HcmV?d00001 diff --git a/lgsm/data/rhel-7.csv b/lgsm/data/rhel-7.csv index 7fe790d296..028aae14e5 100644 --- a/lgsm/data/rhel-7.csv +++ b/lgsm/data/rhel-7.csv @@ -64,6 +64,7 @@ jbep3 jc2 jc3 jk2 +jk3,libstdc++,zlib kf kf2 l4d diff --git a/lgsm/data/rhel-8.csv b/lgsm/data/rhel-8.csv index ac207c625f..3b95056e6c 100644 --- a/lgsm/data/rhel-8.csv +++ b/lgsm/data/rhel-8.csv @@ -63,6 +63,7 @@ jbep3 jc2 jc3 jk2 +jk3,libstdc++,zlib kf kf2 l4d diff --git a/lgsm/data/rhel-9.csv b/lgsm/data/rhel-9.csv index 7e3c49766c..51d249bf3f 100644 --- a/lgsm/data/rhel-9.csv +++ b/lgsm/data/rhel-9.csv @@ -63,6 +63,7 @@ jbep3 jc2 jc3 jk2 +jk3,libstdc++,zlib kf kf2 l4d diff --git a/lgsm/data/rocky-8.csv b/lgsm/data/rocky-8.csv index ac207c625f..3b95056e6c 100644 --- a/lgsm/data/rocky-8.csv +++ b/lgsm/data/rocky-8.csv @@ -63,6 +63,7 @@ jbep3 jc2 jc3 jk2 +jk3,libstdc++,zlib kf kf2 l4d diff --git a/lgsm/data/rocky-9.csv b/lgsm/data/rocky-9.csv index 7e3c49766c..51d249bf3f 100644 --- a/lgsm/data/rocky-9.csv +++ b/lgsm/data/rocky-9.csv @@ -63,6 +63,7 @@ jbep3 jc2 jc3 jk2 +jk3,libstdc++,zlib kf kf2 l4d diff --git a/lgsm/data/serverlist.csv b/lgsm/data/serverlist.csv index 0bbfedbace..752029b185 100644 --- a/lgsm/data/serverlist.csv +++ b/lgsm/data/serverlist.csv @@ -62,6 +62,7 @@ jbep3,jbep3server,Jabroni Brawl: Episode 3,ubuntu-26.04 jc2,jc2server,Just Cause 2,ubuntu-26.04 jc3,jc3server,Just Cause 3,ubuntu-26.04 jk2,jk2server,Jedi Knight II: Jedi Outcast,ubuntu-26.04 +jk3,jk3server,Jedi Knight: Jedi Academy,ubuntu-26.04 kf,kfserver,Killing Floor,ubuntu-26.04 kf2,kf2server,Killing Floor 2,ubuntu-26.04 l4d,l4dserver,Left 4 Dead,ubuntu-26.04 diff --git a/lgsm/data/ubuntu-16.04.csv b/lgsm/data/ubuntu-16.04.csv index b458ea8175..e38f636567 100644 --- a/lgsm/data/ubuntu-16.04.csv +++ b/lgsm/data/ubuntu-16.04.csv @@ -64,6 +64,7 @@ jbep3 jc2 jc3 jk2 +jk3,libstdc++6,zlib1g kf kf2 l4d diff --git a/lgsm/data/ubuntu-18.04.csv b/lgsm/data/ubuntu-18.04.csv index b9760326e9..d3a5de623f 100644 --- a/lgsm/data/ubuntu-18.04.csv +++ b/lgsm/data/ubuntu-18.04.csv @@ -64,6 +64,7 @@ jbep3 jc2 jc3 jk2 +jk3,libstdc++6,zlib1g kf kf2 l4d diff --git a/lgsm/data/ubuntu-20.04.csv b/lgsm/data/ubuntu-20.04.csv index 397fe8ca1a..461ba650d5 100644 --- a/lgsm/data/ubuntu-20.04.csv +++ b/lgsm/data/ubuntu-20.04.csv @@ -63,6 +63,7 @@ jbep3 jc2 jc3 jk2 +jk3,libstdc++6,zlib1g kf kf2 l4d diff --git a/lgsm/data/ubuntu-22.04.csv b/lgsm/data/ubuntu-22.04.csv index 8e7aa50794..d974282fb0 100644 --- a/lgsm/data/ubuntu-22.04.csv +++ b/lgsm/data/ubuntu-22.04.csv @@ -63,6 +63,7 @@ jbep3 jc2 jc3 jk2 +jk3,libstdc++6,zlib1g kf kf2 l4d diff --git a/lgsm/data/ubuntu-23.04.csv b/lgsm/data/ubuntu-23.04.csv index 815a6a14fc..d3981877a6 100644 --- a/lgsm/data/ubuntu-23.04.csv +++ b/lgsm/data/ubuntu-23.04.csv @@ -63,6 +63,7 @@ jbep3 jc2 jc3 jk2 +jk3,libstdc++6,zlib1g kf kf2 l4d diff --git a/lgsm/data/ubuntu-23.10.csv b/lgsm/data/ubuntu-23.10.csv index 815a6a14fc..d3981877a6 100644 --- a/lgsm/data/ubuntu-23.10.csv +++ b/lgsm/data/ubuntu-23.10.csv @@ -63,6 +63,7 @@ jbep3 jc2 jc3 jk2 +jk3,libstdc++6,zlib1g kf kf2 l4d diff --git a/lgsm/data/ubuntu-24.04.csv b/lgsm/data/ubuntu-24.04.csv index 05ca25dbd0..0aad356933 100644 --- a/lgsm/data/ubuntu-24.04.csv +++ b/lgsm/data/ubuntu-24.04.csv @@ -63,6 +63,7 @@ jbep3 jc2 jc3 jk2 +jk3,libstdc++6,zlib1g kf kf2 l4d diff --git a/lgsm/data/ubuntu-26.04.csv b/lgsm/data/ubuntu-26.04.csv index 05ca25dbd0..0aad356933 100644 --- a/lgsm/data/ubuntu-26.04.csv +++ b/lgsm/data/ubuntu-26.04.csv @@ -63,6 +63,7 @@ jbep3 jc2 jc3 jk2 +jk3,libstdc++6,zlib1g kf kf2 l4d diff --git a/lgsm/modules/command_check_update.sh b/lgsm/modules/command_check_update.sh index 9b6a8a319a..5fdf404a18 100755 --- a/lgsm/modules/command_check_update.sh +++ b/lgsm/modules/command_check_update.sh @@ -30,6 +30,8 @@ elif [ "${shortname}" == "mta" ]; then update_mta.sh elif [ "${shortname}" == "jk2" ]; then update_jk2.sh +elif [ "${shortname}" == "jk3" ]; then + update_jk3.sh elif [ "${shortname}" == "vints" ]; then update_vints.sh elif [ "${shortname}" == "bb" ]; then diff --git a/lgsm/modules/command_update.sh b/lgsm/modules/command_update.sh index 1726901761..80bcca1700 100755 --- a/lgsm/modules/command_update.sh +++ b/lgsm/modules/command_update.sh @@ -35,6 +35,8 @@ elif [ "${shortname}" == "mta" ]; then update_mta.sh elif [ "${shortname}" == "jk2" ]; then update_jk2.sh +elif [ "${shortname}" == "jk3" ]; then + update_jk3.sh elif [ "${shortname}" == "vints" ]; then update_vints.sh elif [ "${shortname}" == "bb" ]; then diff --git a/lgsm/modules/core_getopt.sh b/lgsm/modules/core_getopt.sh index d0e0679c5a..c42324ae0d 100755 --- a/lgsm/modules/core_getopt.sh +++ b/lgsm/modules/core_getopt.sh @@ -68,7 +68,7 @@ currentopt=("${cmd_start[@]}" "${cmd_stop[@]}" "${cmd_restart[@]}" "${cmd_monito currentopt+=("${cmd_update_linuxgsm[@]}") # Exclude noupdate games here. -if [ "${shortname}" == "jk2" ] || [ "${shortname}" == "etl" ] || [ "${engine}" != "idtech3" ]; then +if [ "${shortname}" == "jk2" ] || [ "${shortname}" == "jk3" ] || [ "${shortname}" == "etl" ] || [ "${engine}" != "idtech3" ]; then if [ "${shortname}" != "bf1942" ] && [ "${shortname}" != "bfv" ] && [ "${engine}" != "idtech2" ] && [ "${engine}" != "iw2.0" ] && [ "${engine}" != "iw3.0" ] && [ "${engine}" != "quake" ] && [ "${shortname}" != "samp" ] && [ "${shortname}" != "ut2k4" ]; then currentopt+=("${cmd_update[@]}" "${cmd_check_update[@]}") # force update for SteamCMD, Multi Theft Auto or Hytale only. diff --git a/lgsm/modules/core_modules.sh b/lgsm/modules/core_modules.sh index 7284f3c1b6..81ec05473e 100755 --- a/lgsm/modules/core_modules.sh +++ b/lgsm/modules/core_modules.sh @@ -722,6 +722,11 @@ update_jk2.sh() { fn_fetch_module } +update_jk3.sh() { + modulefile="${FUNCNAME[0]}" + fn_fetch_module +} + update_mc.sh() { modulefile="${FUNCNAME[0]}" fn_fetch_module diff --git a/lgsm/modules/info_game.sh b/lgsm/modules/info_game.sh index baa8604b20..3c39fea864 100755 --- a/lgsm/modules/info_game.sh +++ b/lgsm/modules/info_game.sh @@ -1467,6 +1467,27 @@ fn_info_game_jk2() { serverversion="${serverversion:-"NOT SET"}" } +# Config Type: QuakeC +# Parameters: true +# Comment: // or /* */ +# Example: set sv_hostname "SERVERNAME" +# Filetype: cfg +fn_info_game_jk3() { + if [ -f "${servercfgfullpath}" ]; then + fn_info_game_quakec "maxplayers" "sv_maxclients" + fn_info_game_quakec "rconpassword" "rconpassword" + fn_info_game_quakec "servername" "sv_hostname" + fn_info_game_quakec "serverpassword" "g_password" + fi + defaultmap="${defaultmap:-"NOT SET"}" + maxplayers="${maxplayers:-"0"}" + port="${port:-"0"}" + queryport="${port}" + rconpassword="${rconpassword:-"NOT SET"}" + servername="${servername:-"NOT SET"}" + serverpassword="${serverpassword:-"NOT SET"}" +} + # Config Type: Java properties # Comment: # or ! # Example: motd=SERVERNAME @@ -2452,6 +2473,8 @@ elif [ "${shortname}" == "jc3" ]; then fn_info_game_jc3 elif [ "${shortname}" == "jk2" ]; then fn_info_game_jk2 +elif [ "${shortname}" == "jk3" ]; then + fn_info_game_jk3 elif [ "${shortname}" == "kf" ]; then fn_info_game_kf elif [ "${shortname}" == "kf2" ]; then diff --git a/lgsm/modules/info_messages.sh b/lgsm/modules/info_messages.sh index 3fdee99f69..668aab744d 100755 --- a/lgsm/modules/info_messages.sh +++ b/lgsm/modules/info_messages.sh @@ -1185,6 +1185,13 @@ fn_info_messages_jk2() { } | column -s $'\t' -t } +fn_info_messages_jk3() { + { + fn_port "header" + fn_port "Game" port udp + } | column -s $'\t' -t +} + fn_info_messages_kf() { { fn_port "header" @@ -1909,6 +1916,8 @@ fn_info_messages_select_engine() { fn_info_messages_jc3 elif [ "${shortname}" == "jk2" ]; then fn_info_messages_jk2 + elif [ "${shortname}" == "jk3" ]; then + fn_info_messages_jk3 elif [ "${shortname}" == "kf" ]; then fn_info_messages_kf elif [ "${shortname}" == "kf2" ]; then diff --git a/lgsm/modules/install_config.sh b/lgsm/modules/install_config.sh index 8d47079218..e144c52c3d 100755 --- a/lgsm/modules/install_config.sh +++ b/lgsm/modules/install_config.sh @@ -661,6 +661,11 @@ elif [ "${shortname}" == "jk2" ]; then array_configs+=(server.cfg) fn_default_config_remote fn_set_config_vars +elif [ "${shortname}" == "jk3" ]; then + array_configs+=(server.cfg) + fn_default_config_remote + fn_set_config_vars + fn_list_config_locations elif [ "${shortname}" == "qw" ]; then array_configs+=(server.cfg) fn_default_config_remote diff --git a/lgsm/modules/install_server_files.sh b/lgsm/modules/install_server_files.sh index 1ff3561e97..a7550cf784 100755 --- a/lgsm/modules/install_server_files.sh +++ b/lgsm/modules/install_server_files.sh @@ -261,6 +261,8 @@ elif [ "${shortname}" == "hyt" ]; then update_hyt.sh elif [ "${shortname}" == "jk2" ]; then update_jk2.sh +elif [ "${shortname}" == "jk3" ]; then + update_jk3.sh elif [ "${shortname}" == "vints" ]; then update_vints.sh elif [ "${shortname}" == "bb" ]; then diff --git a/lgsm/modules/update_jk3.sh b/lgsm/modules/update_jk3.sh new file mode 100755 index 0000000000..e9cd792c1c --- /dev/null +++ b/lgsm/modules/update_jk3.sh @@ -0,0 +1,175 @@ +#!/bin/bash +# LinuxGSM update_jk3.sh module +# Author: Daniel Gibbs +# Contributors: https://linuxgsm.com/contrib +# Website: https://linuxgsm.com +# Description: Handles updating of Jedi Academy OpenJK servers. + +# shellcheck disable=SC2034 # Used by the module loader. +moduleselfname="$(basename "$(readlink -f "${BASH_SOURCE[0]}")")" + +fn_update_dl() { + # Download and extract files to GameData. + fn_fetch_file "${remotebuildurl}" "" "" "" "${tmpdir}" "${remotebuildfilename}" "nochmodx" "norun" "forcedl" "${remotebuildhash:-nohash}" + # OpenJK archives already have the executable and base/ at their root. + fn_dl_extract "${tmpdir}" "${remotebuildfilename}" "${systemdir}" + if [ ! -x "${executabledir}/openjkded.x86_64" ] || [ ! -f "${systemdir}/base/jampgamex86_64.so" ]; then + fn_print_fail_nl "OpenJK server files are missing after extraction" + fn_script_log_fail "OpenJK server files are missing after extraction" + # shellcheck disable=SC2034 # Used by core_exit.sh. + exitcode=1 + core_exit.sh + fi + if ! echo "${remotebuild}" > "${systemdir}/openjk-build.txt"; then + fn_print_fail_nl "Unable to save the OpenJK build ID" + fn_script_log_fail "Unable to save the OpenJK build ID" + # shellcheck disable=SC2034 # Used by core_exit.sh. + exitcode=1 + core_exit.sh + fi + fn_clear_tmp +} + +fn_update_localbuild() { + # Gets local build info. + fn_print_dots "Checking local build: ${remotelocation}" + # Uses build file to get local build. + localbuild=$(head -n 1 "${systemdir}/openjk-build.txt" 2> /dev/null) + if [ -z "${localbuild}" ]; then + fn_print_error "Checking local build: ${remotelocation}: missing local build info" + 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}" + fn_script_log_pass "Checking local build" + fi +} + +fn_update_remotebuild() { + # Gets remote build info. + apiurl="https://api.github.com/repos/JACoders/OpenJK/releases/latest" + remotebuildfilename="OpenJK-linux-x86_64.tar.gz" + remotebuildresponse=$(curl --connect-timeout 10 --max-time 30 --retry 2 --fail --silent --show-error --location "${apiurl}") || remotebuildresponse="" + # Select exactly one dedicated Linux x86_64 asset. + remotebuildasset=$(echo "${remotebuildresponse}" | jq -er --arg filename "${remotebuildfilename}" '[.assets[]? | select(.name == $filename)] | select(length == 1) | .[0] | select((.id | type) == "number" and (.browser_download_url | type) == "string")') || remotebuildasset="" + remotebuildurl=$(echo "${remotebuildasset}" | jq -r '.browser_download_url') + # The rolling latest tag is reused; replacing its asset changes the asset ID. + remotebuild=$(echo "${remotebuildasset}" | jq -r '.id') + remotebuildhash=$(echo "${remotebuildasset}" | jq -r '.digest // empty' | sed -n 's/^sha256://p') + + if [ "${firstcommandname}" != "INSTALL" ]; then + fn_print_dots "Checking remote build: ${remotelocation}" + fi + # Checks if the remote build and download URL have been set. + if [ -z "${remotebuild}" ] || [ "${remotebuild}" == "null" ] || [ -z "${remotebuildurl}" ] || [ "${remotebuildurl}" == "null" ]; then + if [ "${firstcommandname}" != "INSTALL" ]; then + fn_print_fail "Checking remote build: ${remotelocation}" + fn_script_log_fail "Checking remote build" + else + fn_print_fail_nl "Unable to get remote build" + fn_script_log_fail "Unable to get remote build" + fi + # shellcheck disable=SC2034 # Used by core_exit.sh. + exitcode=1 + core_exit.sh + elif [ "${firstcommandname}" != "INSTALL" ]; then + fn_print_ok "Checking remote build: ${remotelocation}" + fn_script_log_pass "Checking remote build" + fi +} + +fn_update_compare() { + fn_print_dots "Checking for update: ${remotelocation}" + # Update has been found or force update. + 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}${remotebuild}${default}" + if [ -n "${branch}" ]; then + fn_print_nl "* Branch: ${branch}" + fi + if [ -f "${rootdir}/.dev-debug" ]; then + 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 + fn_print "\n" + fn_script_log_info "Update available" + fn_script_log_info "Local build: ${localbuild}" + fn_script_log_info "Remote build: ${remotebuild}" + if [ -n "${branch}" ]; then + fn_script_log_info "Branch: ${branch}" + fi + fn_script_log_info "${localbuild} > ${remotebuild}" + + if [ "${commandname}" == "UPDATE" ]; then + unset updateonstart + check_status.sh + # If server stopped. + if [ "${status}" == "0" ]; then + fn_update_dl + # If server started. + else + fn_print_restart_warning + exitbypass=1 + command_stop.sh + fn_firstcommand_reset + fn_update_dl + exitbypass=1 + command_start.sh + fn_firstcommand_reset + fi + unset exitbypass + date +%s > "${lockdir:?}/last-updated.lock" + alert="update" + elif [ "${commandname}" == "CHECK-UPDATE" ]; then + alert="check-update" + fi + alert.sh + else + fn_print_ok_nl "Checking for update: ${remotelocation}" + 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 + fn_print_nl "* Branch: ${branch}" + fi + fn_print "\n" + fn_script_log_info "No update available" + fn_script_log_info "Local build: ${localbuild}" + fn_script_log_info "Remote build: ${remotebuild}" + if [ -n "${branch}" ]; then + fn_script_log_info "Branch: ${branch}" + fi + if [ -f "${rootdir}/.dev-debug" ]; then + 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 +} + +# The location where the builds are checked and downloaded. +remotelocation="github.com" + +if [ "${firstcommandname}" == "INSTALL" ]; then + fn_update_remotebuild + fn_update_dl +else + fn_print_dots "Checking for update" + fn_print_dots "Checking for update: ${remotelocation}" + fn_script_log_info "Checking for update: ${remotelocation}" + fn_update_localbuild + fn_update_remotebuild + fn_update_compare +fi From 5d625d995a4bc7c5e69813ef9b0c5a3e24d03d2d Mon Sep 17 00:00:00 2001 From: Daniel Gibbs Date: Fri, 16 Oct 2026 09:05:47 +0100 Subject: [PATCH 072/164] fix(details): detect and display Source Steam ports (#5046) --- lgsm/modules/info_game.sh | 8 ++++---- lgsm/modules/info_messages.sh | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/lgsm/modules/info_game.sh b/lgsm/modules/info_game.sh index 3c39fea864..7f026821ac 100755 --- a/lgsm/modules/info_game.sh +++ b/lgsm/modules/info_game.sh @@ -2149,10 +2149,10 @@ fn_info_game_source() { fn_info_game_valve_keyvalues "servername" "hostname" fn_info_game_valve_keyvalues "serverpassword" "sv_password" fi - # Steamport can be between 26901-26910 and is normally automatically set. - # Some servers might support -steamport parameter to set - if [ "${steamport}" == "0" ] || [ -v "${steamport}" ]; then - steamport="$(echo "${ssinfo}" | grep "${srcdslinuxpid}" | awk '{print $5}' | grep ":269" | cut -d ":" -f2)" + # Detect the optional Steam port from this server's UDP sockets in the 269xx range. + # Keep an explicitly configured port, including ports outside the default range. + if { [ -z "${steamport}" ] || [ "${steamport}" == "0" ]; } && [ -n "${srcdslinuxpid}" ]; then + steamport="$(echo "${ssinfo}" | awk -v pid="${srcdslinuxpid}" '$1 == "udp" && $0 ~ ("pid=" pid ",") { port = $5; sub(/^.*:/, "", port); if (port ~ /^269[0-9][0-9]$/) { print port; exit } }')" fi clientport="${clientport:-"0"}" defaultmap="${defaultmap:-"NOT SET"}" diff --git a/lgsm/modules/info_messages.sh b/lgsm/modules/info_messages.sh index 668aab744d..9f664c70c5 100755 --- a/lgsm/modules/info_messages.sh +++ b/lgsm/modules/info_messages.sh @@ -1603,7 +1603,7 @@ fn_info_messages_source() { fn_port "RCON" rconport tcp fn_port "SourceTV" sourcetvport udp # Will not show if unavailable - if [ "${steamport}" == "0" ] || [ -v "${steamport}" ]; then + if [ -n "${steamport}" ] && [ "${steamport}" != "0" ]; then fn_port "Steam" steamport udp fi fn_port "Client" clientport udp From 1c17f031944403269c653269b2608b4d1bb1b13f Mon Sep 17 00:00:00 2001 From: Daniel Gibbs Date: Fri, 16 Oct 2026 10:34:35 +0100 Subject: [PATCH 073/164] fix(deps): sudo handling and messages when auto-install cannot prompt (#5050) * fix(deps): clarify sudo message when auto-install cannot prompt During auto-install, passwordless sudo is checked with `sudo -n true` and the password prompt is skipped if it fails. The warning then claimed the user does not have sudo access, which is misleading when the user has sudo but it requires a password. The auto-install path now says sudo cannot run without a password during auto-install. The interactive path keeps the existing "does not have sudo access" wording, since `sudo -v` has actually prompted there. The Mono repository warning and log line use the same message. Closes #2307 * fix(deps): skip Microsoft repo install without usable sudo fn_install_dotnet_repo ran `sudo dpkg -i` whenever the required .NET package was missing from the distro repos, without checking whether sudo was usable. During auto-install without passwordless sudo this could block on a password prompt. The Microsoft repository is now only added when automatic dependency installation is available. Otherwise a warning with the reason and a link to Microsoft's install instructions is shown and logged, matching the Mono repository behaviour. The identical Ubuntu and Debian branches are merged, using the distro id in the repository URL. --- lgsm/modules/check_deps.sh | 32 ++++++++++++++++++-------------- 1 file changed, 18 insertions(+), 14 deletions(-) mode change 100755 => 100644 lgsm/modules/check_deps.sh diff --git a/lgsm/modules/check_deps.sh b/lgsm/modules/check_deps.sh old mode 100755 new mode 100644 index 975540542a..46cf989a05 --- a/lgsm/modules/check_deps.sh +++ b/lgsm/modules/check_deps.sh @@ -18,17 +18,19 @@ fn_install_dotnet_repo() { fi done - if [ "${distroid}" == "ubuntu" ]; then - # If the required .NET package is unavailable in Ubuntu repos, add the Microsoft repo. + if [ "${distroid}" == "ubuntu" ] || [ "${distroid}" == "debian" ]; then + # If the required .NET package is unavailable in Ubuntu/Debian repos, add the Microsoft repo. if ! apt-cache show "${dotnetpackage}" > /dev/null 2>&1; then - fn_fetch_file "https://packages.microsoft.com/config/ubuntu/${distroversion}/packages-microsoft-prod.deb" "" "" "" "/tmp" "packages-microsoft-prod.deb" "" "" "" "" - sudo dpkg -i /tmp/packages-microsoft-prod.deb - fi - elif [ "${distroid}" == "debian" ]; then - # If the required .NET package is unavailable in Debian repos, add the Microsoft repo. - if ! apt-cache show "${dotnetpackage}" > /dev/null 2>&1; then - fn_fetch_file "https://packages.microsoft.com/config/debian/${distroversion}/packages-microsoft-prod.deb" "" "" "" "/tmp" "packages-microsoft-prod.deb" "" "" "" "" - sudo dpkg -i /tmp/packages-microsoft-prod.deb + if [ "${autodepinstall}" == "0" ]; then + fn_fetch_file "https://packages.microsoft.com/config/${distroid}/${distroversion}/packages-microsoft-prod.deb" "" "" "" "/tmp" "packages-microsoft-prod.deb" "" "" "" "" + sudo dpkg -i /tmp/packages-microsoft-prod.deb + else + fn_print_information_nl "Installing Microsoft repository." + fn_print_warning_nl "${nosudomessage}" + echo -e "Follow instructions on Microsoft website to install." + echo -e "https://learn.microsoft.com/en-us/dotnet/core/install/linux" + fn_script_log_warn "Unable to install Microsoft repository. ${nosudomessage}" + fi fi fi } @@ -111,10 +113,10 @@ fn_install_mono_repo() { else fn_print_information_nl "Installing Mono repository." - fn_print_warning_nl "$(whoami) does not have sudo access." + fn_print_warning_nl "${nosudomessage}" echo -e "Follow instructions on Mono website to install." echo -e "https://www.mono-project.com/download/stable/#download-lin" - fn_script_log_warn "Unable to install Mono repository. $(whoami) does not have sudo access." + fn_script_log_warn "Unable to install Mono repository. ${nosudomessage}" fi } @@ -163,9 +165,11 @@ fn_install_missing_deps() { autodepinstall="0" elif [ "${autoinstall}" == "1" ]; then autodepinstall="1" + nosudomessage="sudo cannot run without a password during auto-install." else sudo -v > /dev/null 2>&1 autodepinstall="$?" + nosudomessage="$(whoami) does not have sudo access." fi if [ "${monoinstalled}" == "false" ]; then @@ -181,8 +185,8 @@ fn_install_missing_deps() { fn_print_information_nl "$(whoami) has sudo access." fn_script_log_info "$(whoami) has sudo access." else - fn_print_warning_nl "$(whoami) does not have sudo access. Manually install dependencies or run ./${selfname} install as root." - fn_script_log_warn "$(whoami) does not have sudo access. Manually install dependencies or run ./${selfname} install as root." + fn_print_warning_nl "${nosudomessage} Manually install dependencies or run ./${selfname} install as root." + fn_script_log_warn "${nosudomessage} Manually install dependencies or run ./${selfname} install as root." fi fi From c830bc2c2ac817ed3f6cdd2e13a645eeafa57c54 Mon Sep 17 00:00:00 2001 From: Daniel Gibbs Date: Fri, 16 Oct 2026 11:18:02 +0100 Subject: [PATCH 074/164] fix(info): stop shell-expanding parsed config values (#5052) * fix(info): stop shell-expanding parsed config values Every config parser in info_game.sh assigned its result with eval "${1}=\"$(...)\"", so each value read from a game server config was expanded by the shell a second time. A $var in a password vanished, backticks and $(...) were executed as commands as the LinuxGSM user, backslashes were collapsed, and a value containing a double quote or an unmatched backtick made eval fail with a syntax error and leave the variable empty. For example a 7 Days to Die TelnetPassword of p$w[d]'x\y`id` was shown by details as p[d]'x\yuid=1000(...), and the stop command then sent that corrupted password to the telnet console. Replace each eval with printf -v "${1}" '%s' "$(...)", which assigns the extracted text verbatim. The sed, jq and xmllint extraction in each parser is unchanged. All callers pass a plain variable name as the first argument and none relies on expansion of the parsed value. Checked with a harness feeding values containing $, ${...}, $(...), backticks, quotes and backslashes through all 11 parsers: before, 68 of 88 cases differed from the input (including command execution and eval syntax errors); after, the only differences are existing extraction limits of the sed patterns (double quotes are not captured, and the space-delimited parsers keep only the last word). * fix(info): restore executable bit on info_game.sh --- lgsm/modules/info_game.sh | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/lgsm/modules/info_game.sh b/lgsm/modules/info_game.sh index 7f026821ac..50b0793d97 100755 --- a/lgsm/modules/info_game.sh +++ b/lgsm/modules/info_game.sh @@ -31,7 +31,7 @@ fn_info_game_ini() { else servercfgparse="${servercfgfullpath}" fi - eval "${1}=\"$(sed -n '/^\<'"${2}"'\>/ { s/.*= *\"\?\([^"]*\)\"\?/\1/p;q }' "${servercfgparse}" | tr -d '\r')\"" + printf -v "${1}" '%s' "$(sed -n '/^\<'"${2}"'\>/ { s/.*= *\"\?\([^"]*\)\"\?/\1/p;q }' "${servercfgparse}" | tr -d '\r')" configtype="ini" } @@ -56,7 +56,7 @@ fn_info_game_keyvalue_pairs_equals() { else servercfgparse="${servercfgfullpath}" fi - eval "${1}=\"$(sed -n '/^\<'"${2}"'\>/ { s/.*= *\"\?\([^"]*\)\"\?/\1/p;q }' "${servercfgparse}" | tr -d '\r')\"" + printf -v "${1}" '%s' "$(sed -n '/^\<'"${2}"'\>/ { s/.*= *\"\?\([^"]*\)\"\?/\1/p;q }' "${servercfgparse}" | tr -d '\r')" configtype="keyvalue_pairs" } @@ -81,7 +81,7 @@ fn_info_game_keyvalue_pairs_space() { else servercfgparse="${servercfgfullpath}" fi - eval "${1}=\"$(sed -n '/^\<'"${2}"'\>/ { s/.* *\"\?\([^"]*\)\"\?/\1/p;q }' "${servercfgparse}" | tr -d '\r')\"" + printf -v "${1}" '%s' "$(sed -n '/^\<'"${2}"'\>/ { s/.* *\"\?\([^"]*\)\"\?/\1/p;q }' "${servercfgparse}" | tr -d '\r')" configtype="keyvalue_pairs" } @@ -106,7 +106,7 @@ fn_info_game_quakec() { else servercfgparse="${servercfgfullpath}" fi - eval "${1}=\"$(sed -n '/[[:space:]]\<'"${2}"'\>/ { s/.* *\"\?\([^"]*\)\"\?/\1/p;q }' "${servercfgparse}" | tr -d '\r')\"" + printf -v "${1}" '%s' "$(sed -n '/[[:space:]]\<'"${2}"'\>/ { s/.* *\"\?\([^"]*\)\"\?/\1/p;q }' "${servercfgparse}" | tr -d '\r')" configtype="quakec" } @@ -118,7 +118,7 @@ fn_info_game_json() { else servercfgparse="${servercfgfullpath}" fi - eval "${1}=\"$(jq -r "${2}" "${servercfgparse}")\"" + printf -v "${1}" '%s' "$(jq -r "${2}" "${servercfgparse}")" configtype="json" } @@ -144,7 +144,7 @@ fn_info_game_sqf() { else servercfgparse="${servercfgfullpath}" fi - eval "${1}=\"$(sed -n '/^\<'"${2}"'\>/ { s/.*= *"\?\([^"]*\)"\?/\1/;s/;$//p;q }' "${servercfgparse}" | tr -d '\r')\"" + printf -v "${1}" '%s' "$(sed -n '/^\<'"${2}"'\>/ { s/.*= *"\?\([^"]*\)"\?/\1/;s/;$//p;q }' "${servercfgparse}" | tr -d '\r')" configtype="sqf" } @@ -156,7 +156,7 @@ fn_info_game_xml() { else servercfgparse="${servercfgfullpath}" fi - eval "${1}=\"$(xmllint --xpath "string(${2})" "${servercfgparse}")\"" + printf -v "${1}" '%s' "$(xmllint --xpath "string(${2})" "${servercfgparse}")" configtype="xml" } @@ -182,7 +182,7 @@ fn_info_game_valve_keyvalues() { else servercfgparse="${servercfgfullpath}" fi - eval "${1}=\"$(sed -n '/^\<'"${2}"'\>/ { s/.* *"\([^"]*\)".*/\1/p;q }' "${servercfgparse}" | tr -d '\r')\"" + printf -v "${1}" '%s' "$(sed -n '/^\<'"${2}"'\>/ { s/.* *"\([^"]*\)".*/\1/p;q }' "${servercfgparse}" | tr -d '\r')" configtype="valve_keyvalues" } @@ -207,7 +207,7 @@ fn_info_game_java_properties() { else servercfgparse="${servercfgfullpath}" fi - eval "${1}=\"$(sed -n '/^\<'"${2}"'\>/ { s/.*= *\"\?\([^"]*\)\"\?/\1/p;q }' "${servercfgparse}" | tr -d '\r')\"" + printf -v "${1}" '%s' "$(sed -n '/^\<'"${2}"'\>/ { s/.*= *\"\?\([^"]*\)\"\?/\1/p;q }' "${servercfgparse}" | tr -d '\r')" configtype="java" } @@ -230,7 +230,7 @@ fn_info_game_lua() { else servercfgparse="${servercfgfullpath}" fi - eval "${1}=\"$(sed -n '/^[[:space:]]*\<'"${2}"'\>/ { s/.*= *"\?\([^"]*\)"\?/\1/;s#,.*##;p;q }' "${servercfgparse}" | tr -d '\r')\"" + printf -v "${1}" '%s' "$(sed -n '/^[[:space:]]*\<'"${2}"'\>/ { s/.*= *"\?\([^"]*\)"\?/\1/;s#,.*##;p;q }' "${servercfgparse}" | tr -d '\r')" configtype="lua" } @@ -255,7 +255,7 @@ fn_info_game_pc_config() { else servercfgparse="${servercfgfullpath}" fi - eval "${1}=\"$(sed -n '/^\<'"${2}"'\>/ { s/.*: *\"\?\([^"]*\)\"\?/\1/p;q }' "${servercfgparse}" | tr -d '\r')\"" + printf -v "${1}" '%s' "$(sed -n '/^\<'"${2}"'\>/ { s/.*: *\"\?\([^"]*\)\"\?/\1/p;q }' "${servercfgparse}" | tr -d '\r')" configtype="pc_config" } From 4ebb89f94e4cd01598f8d108699502d53ff33921 Mon Sep 17 00:00:00 2001 From: Daniel Gibbs Date: Fri, 16 Oct 2026 11:18:43 +0100 Subject: [PATCH 075/164] refactor(stop): use bash /dev/tcp for telnet shutdown, drop expect (#5051) 7 Days to Die (stopmode 8) and Soulmask (stopmode 13) stopped the server by spawning telnet inside an expect script. That made expect and telnet hard dependencies for both games and had several problems: - The telnet password was pasted into the Tcl script, so a password containing quotes, brackets, braces, $ or backslashes broke it. - The address loop overwrote the global telnetip. - Success meant "the telnet port closed", not "the server exited". The tmux session was then killed straight away, which could cut off the world save on slow shutdowns. - Each "is it closed yet" check opened a new session and, with a password set, logged in and sent shutdown again. - A 30 second timeout with the port still open ended silently. The conversation now runs over a bash /dev/tcp file descriptor: fn_stop_telnet_open, fn_stop_telnet_expect (wait for text, with a timeout), fn_stop_telnet_send and fn_stop_telnet_close. The password is written with printf, so it is never interpreted. Writes run in a subshell so a connection the server already closed cannot SIGPIPE the script, and the open is wrapped in a function-level stderr redirect because a redirect on the exec line itself would be permanent. fn_stop_graceful_telnet is now shared by both games. It tries 127.0.0.1, then telnetip and ip, without overwriting telnetip. Then it waits on check_status.sh like the other graceful stop methods (60s for 7 Days to Die, 30s for Soulmask) and reports FAIL if the server is still running, so the existing tmux fallback still applies. Text matching ignores case. Soulmask graceful stop was already broken: current builds send no "Hello:" greeting, and saveworld now replies "[WORLD IS SAVED TO:] ... succeed" rather than "the world is saved.", so the old script always timed out and fell through to a tmux kill without saving. The session now sends "saveworld 1" straight away, waits up to 120s for "world is saved", then sends "quit 1". telnet and expect are removed from the sdtd and sm rows in every distro dependency CSV. unbuffer (from expect) is still used for SteamCMD output when present, as for every other game. Tested against a live 7 Days to Die V3.3 server: stop with no password, and stop with the password p[d]'x\y#!{z} (server listening on all interfaces). Both sent shutdown over telnet, the server logged the save and OnApplicationQuit, and LinuxGSM reported OK once the process exited. Tested against a fresh Soulmask server: the develop expect code timed out with no save. With this change the server logged saveworld, the world save and quit 1. An idle server ticks very slowly and had not exited 120s after quit 1, so the stop still finishes with the tmux fallback, but now after the world is saved. Resolves #2201 --- lgsm/data/almalinux-8.csv | 4 +- lgsm/data/almalinux-9.csv | 4 +- lgsm/data/centos-7.csv | 4 +- lgsm/data/centos-8.csv | 4 +- lgsm/data/centos-9.csv | 4 +- lgsm/data/debian-10.csv | 4 +- lgsm/data/debian-11.csv | 4 +- lgsm/data/debian-12.csv | 4 +- lgsm/data/debian-13.csv | 4 +- lgsm/data/debian-9.csv | 4 +- lgsm/data/rhel-7.csv | 4 +- lgsm/data/rhel-8.csv | 4 +- lgsm/data/rhel-9.csv | 4 +- lgsm/data/rocky-8.csv | 4 +- lgsm/data/rocky-9.csv | 4 +- lgsm/data/ubuntu-16.04.csv | 4 +- lgsm/data/ubuntu-18.04.csv | 4 +- lgsm/data/ubuntu-20.04.csv | 4 +- lgsm/data/ubuntu-22.04.csv | 4 +- lgsm/data/ubuntu-23.04.csv | 4 +- lgsm/data/ubuntu-23.10.csv | 4 +- lgsm/data/ubuntu-24.04.csv | 4 +- lgsm/data/ubuntu-26.04.csv | 4 +- lgsm/modules/command_stop.sh | 293 ++++++++++++++--------------------- 24 files changed, 165 insertions(+), 220 deletions(-) diff --git a/lgsm/data/almalinux-8.csv b/lgsm/data/almalinux-8.csv index ef1168a11b..1a465dc920 100644 --- a/lgsm/data/almalinux-8.csv +++ b/lgsm/data/almalinux-8.csv @@ -106,10 +106,10 @@ samp sb sbots scpsl -sdtd,telnet,expect,libxml2 +sdtd,libxml2 sf sfc,ncurses-libs.i686 -sm,telnet,expect +sm sof2 sol squad diff --git a/lgsm/data/almalinux-9.csv b/lgsm/data/almalinux-9.csv index 51d249bf3f..ff2e70637e 100644 --- a/lgsm/data/almalinux-9.csv +++ b/lgsm/data/almalinux-9.csv @@ -106,10 +106,10 @@ samp sb sbots scpsl -sdtd,telnet,expect,libxml2 +sdtd,libxml2 sf sfc,ncurses-libs.i686 -sm,telnet,expect +sm sof2 sol squad diff --git a/lgsm/data/centos-7.csv b/lgsm/data/centos-7.csv index a1ba04eca8..68b9a0e4e1 100644 --- a/lgsm/data/centos-7.csv +++ b/lgsm/data/centos-7.csv @@ -106,10 +106,10 @@ samp sb sbots scpsl -sdtd,telnet,expect,libxml2 +sdtd,libxml2 sf sfc,ncurses-libs.i686 -sm,telnet,expect +sm sof2 sol squad diff --git a/lgsm/data/centos-8.csv b/lgsm/data/centos-8.csv index 5528c18daf..9af0d93841 100644 --- a/lgsm/data/centos-8.csv +++ b/lgsm/data/centos-8.csv @@ -106,10 +106,10 @@ samp sb sbots scpsl -sdtd,telnet,expect,libxml2 +sdtd,libxml2 sf sfc,ncurses-libs.i686 -sm,telnet,expect +sm sof2 sol squad diff --git a/lgsm/data/centos-9.csv b/lgsm/data/centos-9.csv index 96ffff9a3c..65d5f5dc28 100644 --- a/lgsm/data/centos-9.csv +++ b/lgsm/data/centos-9.csv @@ -106,10 +106,10 @@ samp sb sbots scpsl -sdtd,telnet,expect,libxml2 +sdtd,libxml2 sf sfc,ncurses-libs.i686 -sm,telnet,expect +sm sof2 sol squad diff --git a/lgsm/data/debian-10.csv b/lgsm/data/debian-10.csv index 0ad2140d7b..29ac28d999 100644 --- a/lgsm/data/debian-10.csv +++ b/lgsm/data/debian-10.csv @@ -106,10 +106,10 @@ samp sb sbots scpsl,mono-complete -sdtd,telnet,expect,libxml2-utils +sdtd,libxml2-utils sf sfc,libtinfo5:i386 -sm,telnet,expect +sm sof2 sol squad diff --git a/lgsm/data/debian-11.csv b/lgsm/data/debian-11.csv index 66604e5dd6..b205318a4f 100644 --- a/lgsm/data/debian-11.csv +++ b/lgsm/data/debian-11.csv @@ -107,10 +107,10 @@ samp sb sbots scpsl,mono-complete -sdtd,telnet,expect,libxml2-utils +sdtd,libxml2-utils sf sfc,libtinfo5:i386 -sm,telnet,expect +sm sof2 sol squad diff --git a/lgsm/data/debian-12.csv b/lgsm/data/debian-12.csv index f9f4c286b8..9bd2c891d9 100644 --- a/lgsm/data/debian-12.csv +++ b/lgsm/data/debian-12.csv @@ -107,10 +107,10 @@ samp sb sbots scpsl,mono-complete -sdtd,telnet,expect,libxml2-utils +sdtd,libxml2-utils sf sfc,libtinfo5:i386 -sm,telnet,expect +sm sof2 sol squad diff --git a/lgsm/data/debian-13.csv b/lgsm/data/debian-13.csv index c7b5e4e941..1331ca4052 100644 --- a/lgsm/data/debian-13.csv +++ b/lgsm/data/debian-13.csv @@ -107,10 +107,10 @@ samp sb sbots scpsl,mono-complete,libicu76 -sdtd,telnet,expect,libxml2 +sdtd,libxml2 sf sfc -sm,telnet,expect +sm sof2 sol squad diff --git a/lgsm/data/debian-9.csv b/lgsm/data/debian-9.csv index 7124d6c451..1d6102a49c 100644 --- a/lgsm/data/debian-9.csv +++ b/lgsm/data/debian-9.csv @@ -107,10 +107,10 @@ samp sb sbots scpsl,mono-complete -sdtd,telnet,expect,libxml2-utils +sdtd,libxml2-utils sf sfc,libtinfo5:i386 -sm,telnet,expect +sm sof2 sol squad diff --git a/lgsm/data/rhel-7.csv b/lgsm/data/rhel-7.csv index 028aae14e5..a790d1dca7 100644 --- a/lgsm/data/rhel-7.csv +++ b/lgsm/data/rhel-7.csv @@ -106,10 +106,10 @@ samp sb sbots scpsl -sdtd,telnet,expect,libxml2 +sdtd,libxml2 sf sfc,ncurses-libs.i686 -sm,telnet,expect +sm sof2 sol squad diff --git a/lgsm/data/rhel-8.csv b/lgsm/data/rhel-8.csv index 3b95056e6c..719aa040cf 100644 --- a/lgsm/data/rhel-8.csv +++ b/lgsm/data/rhel-8.csv @@ -106,10 +106,10 @@ samp sb sbots scpsl -sdtd,telnet,expect,libxml2 +sdtd,libxml2 sf sfc,ncurses-libs.i686 -sm,telnet,expect +sm sof2 sol squad diff --git a/lgsm/data/rhel-9.csv b/lgsm/data/rhel-9.csv index 51d249bf3f..ff2e70637e 100644 --- a/lgsm/data/rhel-9.csv +++ b/lgsm/data/rhel-9.csv @@ -106,10 +106,10 @@ samp sb sbots scpsl -sdtd,telnet,expect,libxml2 +sdtd,libxml2 sf sfc,ncurses-libs.i686 -sm,telnet,expect +sm sof2 sol squad diff --git a/lgsm/data/rocky-8.csv b/lgsm/data/rocky-8.csv index 3b95056e6c..719aa040cf 100644 --- a/lgsm/data/rocky-8.csv +++ b/lgsm/data/rocky-8.csv @@ -106,10 +106,10 @@ samp sb sbots scpsl -sdtd,telnet,expect,libxml2 +sdtd,libxml2 sf sfc,ncurses-libs.i686 -sm,telnet,expect +sm sof2 sol squad diff --git a/lgsm/data/rocky-9.csv b/lgsm/data/rocky-9.csv index 51d249bf3f..ff2e70637e 100644 --- a/lgsm/data/rocky-9.csv +++ b/lgsm/data/rocky-9.csv @@ -106,10 +106,10 @@ samp sb sbots scpsl -sdtd,telnet,expect,libxml2 +sdtd,libxml2 sf sfc,ncurses-libs.i686 -sm,telnet,expect +sm sof2 sol squad diff --git a/lgsm/data/ubuntu-16.04.csv b/lgsm/data/ubuntu-16.04.csv index e38f636567..111c2e788c 100644 --- a/lgsm/data/ubuntu-16.04.csv +++ b/lgsm/data/ubuntu-16.04.csv @@ -107,10 +107,10 @@ samp sb sbots scpsl,mono-complete -sdtd,telnet,expect,libxml2-utils +sdtd,libxml2-utils sf sfc,libtinfo5:i386 -sm,telnet,expect +sm sof2 sol squad diff --git a/lgsm/data/ubuntu-18.04.csv b/lgsm/data/ubuntu-18.04.csv index d3a5de623f..a97d455eb3 100644 --- a/lgsm/data/ubuntu-18.04.csv +++ b/lgsm/data/ubuntu-18.04.csv @@ -107,10 +107,10 @@ samp sb sbots scpsl,mono-complete -sdtd,telnet,expect,libxml2-utils +sdtd,libxml2-utils sf sfc,libtinfo5:i386 -sm,telnet,expect +sm sof2 sol squad diff --git a/lgsm/data/ubuntu-20.04.csv b/lgsm/data/ubuntu-20.04.csv index 461ba650d5..42f1f1e920 100644 --- a/lgsm/data/ubuntu-20.04.csv +++ b/lgsm/data/ubuntu-20.04.csv @@ -107,10 +107,10 @@ samp sb sbots scpsl,mono-complete -sdtd,telnet,expect,libxml2-utils +sdtd,libxml2-utils sf sfc,libtinfo5:i386 -sm,telnet,expect +sm sof2 sol squad diff --git a/lgsm/data/ubuntu-22.04.csv b/lgsm/data/ubuntu-22.04.csv index d974282fb0..44e47afe28 100644 --- a/lgsm/data/ubuntu-22.04.csv +++ b/lgsm/data/ubuntu-22.04.csv @@ -107,10 +107,10 @@ samp sb sbots scpsl,mono-complete -sdtd,telnet,expect,libxml2-utils +sdtd,libxml2-utils sf sfc,libtinfo5:i386 -sm,telnet,expect +sm sof2 sol squad diff --git a/lgsm/data/ubuntu-23.04.csv b/lgsm/data/ubuntu-23.04.csv index d3981877a6..c4395d3afd 100644 --- a/lgsm/data/ubuntu-23.04.csv +++ b/lgsm/data/ubuntu-23.04.csv @@ -107,10 +107,10 @@ samp sb sbots scpsl,mono-complete -sdtd,telnet,expect,libxml2-utils +sdtd,libxml2-utils sf sfc,libtinfo5:i386 -sm,telnet,expect +sm sof2 sol squad diff --git a/lgsm/data/ubuntu-23.10.csv b/lgsm/data/ubuntu-23.10.csv index d3981877a6..c4395d3afd 100644 --- a/lgsm/data/ubuntu-23.10.csv +++ b/lgsm/data/ubuntu-23.10.csv @@ -107,10 +107,10 @@ samp sb sbots scpsl,mono-complete -sdtd,telnet,expect,libxml2-utils +sdtd,libxml2-utils sf sfc,libtinfo5:i386 -sm,telnet,expect +sm sof2 sol squad diff --git a/lgsm/data/ubuntu-24.04.csv b/lgsm/data/ubuntu-24.04.csv index 0aad356933..f9fa95981d 100644 --- a/lgsm/data/ubuntu-24.04.csv +++ b/lgsm/data/ubuntu-24.04.csv @@ -106,10 +106,10 @@ samp sb sbots scpsl,mono-complete -sdtd,telnet,expect,libxml2-utils +sdtd,libxml2-utils sf sfc -sm,telnet,expect +sm sof2 sol squad diff --git a/lgsm/data/ubuntu-26.04.csv b/lgsm/data/ubuntu-26.04.csv index 0aad356933..f9fa95981d 100644 --- a/lgsm/data/ubuntu-26.04.csv +++ b/lgsm/data/ubuntu-26.04.csv @@ -106,10 +106,10 @@ samp sb sbots scpsl,mono-complete -sdtd,telnet,expect,libxml2-utils +sdtd,libxml2-utils sf sfc -sm,telnet,expect +sm sof2 sol squad diff --git a/lgsm/modules/command_stop.sh b/lgsm/modules/command_stop.sh index 64df74f807..0bd9843bb0 100755 --- a/lgsm/modules/command_stop.sh +++ b/lgsm/modules/command_stop.sh @@ -292,196 +292,141 @@ fn_stop_graceful_goldsrc() { fi } -# telnet command for sdtd graceful shutdown. -fn_stop_graceful_sdtd_telnet() { - if [ -z "${telnetpassword}" ] || [ "${telnetpassword}" == "NOT SET" ]; then - sdtdtelnetshutdown=$(expect -c ' - proc abort {} { - puts "Timeout or EOF\n" - exit 1 - } - spawn telnet '"${telnetip}"' '"${telnetport}"' - expect { - "session." { send "shutdown\r" } - default abort - } - expect { eof } - puts "Completed.\n" - ') - else - sdtdtelnetshutdown=$(expect -c ' - proc abort {} { - puts "Timeout or EOF\n" - exit 1 - } - spawn telnet '"${telnetip}"' '"${telnetport}"' - expect { - "password:" { send "'"${telnetpassword}"'\r" } - default abort - } - expect { - "session." { send "shutdown\r" } - default abort - } - expect { eof } - puts "Completed.\n" - ') +# Opens a telnet connection using bash /dev/tcp. +# Usage: fn_stop_telnet_open "ip" +fn_stop_telnet_open() { + telnetoutput="" + exec {telnetfd}<> "/dev/tcp/${1}/${telnetport}" +} 2> /dev/null + +# Closes the telnet connection. +fn_stop_telnet_close() { + if [ -n "${telnetfd}" ]; then + exec {telnetfd}>&- + unset telnetfd fi } -# Attempts graceful shutdown of 7 Days To Die using telnet. -fn_stop_graceful_sdtd() { - fn_print_dots "Graceful: telnet" - fn_script_log_info "Graceful: telnet" - if [ "${telnetenabled}" == "false" ]; then - fn_print_info_nl "Graceful: telnet: DISABLED: Enable in ${servercfg}" - elif [ "$(command -v expect 2> /dev/null)" ]; then - # Tries to shutdown with both localhost and server IP. - for telnetip in 127.0.0.1 ${ip}; do - fn_print_dots "Graceful: telnet: ${telnetip}:${telnetport}" - fn_script_log_info "Graceful: telnet: ${telnetip}:${telnetport}" - fn_stop_graceful_sdtd_telnet - completed=$(echo -en "\n ${sdtdtelnetshutdown}" | grep "Completed.") - refused=$(echo -en "\n ${sdtdtelnetshutdown}" | grep "Timeout or EOF") - if [ "${refused}" ]; then - fn_print_error "Graceful: telnet: ${telnetip}:${telnetport} : " - fn_print_fail_eol_nl - fn_script_log_error "Graceful: telnet: ${telnetip}:${telnetport} : FAIL" - elif [ "${completed}" ]; then - break - fi - done +# Reads from the telnet connection until the text is received, ignoring case. +# Fails if the connection closes or nothing is received for the timeout. +# Usage: fn_stop_telnet_expect "text" "timeout_in_seconds" +fn_stop_telnet_expect() { + local char + while IFS= read -r -N 1 -t "${2:-10}" -u "${telnetfd}" char; do + telnetoutput+="${char}" + if [[ "${telnetoutput,,}" == *"${1,,}"* ]]; then + return 0 + fi + done + return 1 +} - # If telnet shutdown was successful will use telnet again to check - # the connection has closed, confirming that the tmux session can now be killed. - if [ "${completed}" ]; then - for seconds in {1..30}; do - fn_stop_graceful_sdtd_telnet - refused=$(echo -en "\n ${sdtdtelnetshutdown}" | grep "Timeout or EOF") - if [ "${refused}" ]; then - fn_print_ok "Graceful: telnet: ${telnetip}:${telnetport} : " - fn_print_ok_eol_nl - fn_script_log_pass "Graceful: telnet: ${telnetip}:${telnetport} : ${seconds} seconds" - if [ "${statusalert}" == "on" ] && [ "${firstcommandname}" == "STOP" ]; then - alert="stopped" - alert.sh - fi - break - fi - fn_sleep_time_1 - fn_print_dots "Graceful: telnet: ${seconds}" - done - # If telnet shutdown fails tmux shutdown will be used, this risks loss of world save. - else - if [ "${refused}" ]; then - fn_print_error "Graceful: telnet: " - fn_print_fail_eol_nl - fn_script_log_error "Graceful: telnet: ${telnetip}:${telnetport} : FAIL" - else - fn_print_error_nl "Graceful: telnet: Unknown error" - fn_script_log_error "Graceful: telnet: Unknown error" - fi - echo -en "\n" | tee -a "${lgsmlog}" - echo -en "Telnet output:" | tee -a "${lgsmlog}" - echo -en "\n ${sdtdtelnetshutdown}" | tee -a "${lgsmlog}" - echo -en "\n\n" | tee -a "${lgsmlog}" +# Reads from the telnet connection until the server closes it. +fn_stop_telnet_read_to_close() { + local char + while IFS= read -r -N 1 -t 10 -u "${telnetfd}" char; do + telnetoutput+="${char}" + done +} + +# Sends a line to the telnet connection. +# Usage: fn_stop_telnet_send "text" +fn_stop_telnet_send() { + (printf '%s\r\n' "${1}" >&"${telnetfd}") 2> /dev/null +} + +# Telnet session for 7 Days to Die graceful shutdown. +# Usage: fn_stop_graceful_sdtd_telnet "ip" +fn_stop_graceful_sdtd_telnet() { + fn_stop_telnet_open "${1}" || return 1 + if [ -n "${telnetpassword}" ] && [ "${telnetpassword}" != "NOT SET" ]; then + if ! fn_stop_telnet_expect "password:" || ! fn_stop_telnet_send "${telnetpassword}"; then + fn_stop_telnet_close + return 1 fi - else - fn_print_warn "Graceful: telnet: expect not installed: " - fn_print_fail_eol_nl - fn_script_log_warn "Graceful: telnet: expect not installed: FAIL" fi + if fn_stop_telnet_expect "session." && fn_stop_telnet_send "shutdown"; then + fn_stop_telnet_read_to_close + fn_stop_telnet_close + return 0 + fi + fn_stop_telnet_close + return 1 } -# Attempts graceful shutdown of Soulmask using telnet. -fn_stop_graceful_sm() { +# Telnet session for Soulmask graceful shutdown. +# Usage: fn_stop_graceful_sm_telnet "ip" +fn_stop_graceful_sm_telnet() { + fn_stop_telnet_open "${1}" || return 1 + if fn_stop_telnet_send "saveworld 1" && fn_stop_telnet_expect "world is saved" 120 && fn_stop_telnet_send "quit 1"; then + fn_stop_telnet_read_to_close + fn_stop_telnet_close + return 0 + fi + fn_stop_telnet_close + return 1 +} + +# Attempts graceful shutdown using a telnet session. +# Tries localhost first, then the telnet and server IPs. +# Usage: fn_stop_graceful_telnet "session_function" "timeout_in_seconds" +# e.g.: fn_stop_graceful_telnet "fn_stop_graceful_sdtd_telnet" "60" +fn_stop_graceful_telnet() { fn_print_dots "Graceful: telnet" fn_script_log_info "Graceful: telnet" if [ "${telnetenabled}" == "false" ]; then fn_print_info_nl "Graceful: telnet: DISABLED: Enable in ${servercfg}" - elif [ "$(command -v expect 2> /dev/null)" ]; then - # Tries to shutdown with both localhost and server IP. - for telnetip in 127.0.0.1 ${ip}; do - fn_print_dots "Graceful: telnet: ${telnetip}:${telnetport}" - fn_script_log_info "Graceful: telnet: ${telnetip}:${telnetport}" - fn_stop_graceful_sm_telnet - completed=$(echo -en "\n ${smtelnetshutdown}" | grep "Completed.") - refused=$(echo -en "\n ${smtelnetshutdown}" | grep "Timeout or EOF") - if [ "${refused}" ]; then - fn_print_error "Graceful: telnet: ${telnetip}:${telnetport} : " - fn_print_fail_eol_nl - fn_script_log_error "Graceful: telnet: ${telnetip}:${telnetport} : FAIL" - elif [ "${completed}" ]; then - break - fi - done - - # If telnet shutdown was successful will use telnet again to check - # the connection has closed, confirming that the tmux session can now be killed. - if [ "${completed}" ]; then - for seconds in {1..30}; do - fn_stop_graceful_sm_telnet - refused=$(echo -en "\n ${smtelnetshutdown}" | grep "Timeout or EOF") - if [ "${refused}" ]; then - fn_print_ok "Graceful: telnet: ${telnetip}:${telnetport} : " - fn_print_ok_eol_nl - fn_script_log_pass "Graceful: telnet: ${telnetip}:${telnetport} : ${seconds} seconds" - if [ "${statusalert}" == "on" ] && [ "${firstcommandname}" == "STOP" ]; then - alert="stopped" - alert.sh - fi - break - fi - fn_sleep_time_1 - fn_print_dots "Graceful: telnet: ${seconds}" - done - # If telnet shutdown fails, show it and stop - else - if [ "${refused}" ]; then - fn_print_error "Graceful: telnet: " - fn_print_fail_eol_nl - fn_script_log_error "Graceful: telnet: ${telnetip}:${telnetport} : FAIL" - else - fn_print_error_nl "Graceful: telnet: Unknown error" - fn_script_log_error "Graceful: telnet: Unknown error" + fn_script_log_info "Graceful: telnet: DISABLED" + return + fi + local telnetaddresses=("127.0.0.1") + local telnetaddress telnetsent + for telnetaddress in "${telnetip[@]}" ${ip}; do + if [ -n "${telnetaddress}" ] && [[ " ${telnetaddresses[*]} " != *" ${telnetaddress} "* ]]; then + telnetaddresses+=("${telnetaddress}") + fi + done + for telnetaddress in "${telnetaddresses[@]}"; do + fn_print_dots "Graceful: telnet: ${telnetaddress}:${telnetport}" + fn_script_log_info "Graceful: telnet: ${telnetaddress}:${telnetport}" + if "${1}" "${telnetaddress}"; then + telnetsent=1 + break + fi + fn_print_error "Graceful: telnet: ${telnetaddress}:${telnetport}: " + fn_print_fail_eol_nl + fn_script_log_error "Graceful: telnet: ${telnetaddress}:${telnetport}: FAIL" + if [ -n "${telnetoutput}" ]; then + fn_script_log_error "Graceful: telnet: output: ${telnetoutput//$'\r'/}" + fi + done + if [ -z "${telnetsent}" ]; then + return + fi + # Waits up to ${seconds} seconds giving the server time to shutdown gracefully. + for ((seconds = 1; seconds <= ${2}; seconds++)); do + check_status.sh + if [ "${status}" == "0" ]; then + fn_print_ok "Graceful: telnet: ${telnetaddress}:${telnetport}: ${seconds}" + fn_print_ok_eol_nl + fn_script_log_pass "Graceful: telnet: ${telnetaddress}:${telnetport}: OK: ${seconds} seconds" + if [ "${statusalert}" == "on" ] && [ "${firstcommandname}" == "STOP" ]; then + alert="stopped" + alert.sh fi - echo -en "\n" | tee -a "${lgsmlog}" - echo -en "Telnet output:" | tee -a "${lgsmlog}" - echo -en "\n ${smtelnetshutdown}" | tee -a "${lgsmlog}" - echo -en "\n\n" | tee -a "${lgsmlog}" + break fi - else - fn_print_warn "Graceful: telnet: expect not installed: " + fn_sleep_time_1 + fn_print_dots "Graceful: telnet: ${telnetaddress}:${telnetport}: ${seconds}" + done + check_status.sh + if [ "${status}" != "0" ]; then + fn_print_error "Graceful: telnet: ${telnetaddress}:${telnetport}: " fn_print_fail_eol_nl - fn_script_log_warn "Graceful: telnet: expect not installed: FAIL" + fn_script_log_error "Graceful: telnet: ${telnetaddress}:${telnetport}: FAIL" fi } -# telnet command for soulmask graceful shutdown. -fn_stop_graceful_sm_telnet() { - smtelnetshutdown=$(expect -c ' - proc abort {} { - puts "Timeout or EOF\n" - exit 1 - } - spawn telnet '"${telnetip}"' '"${telnetport}"' - expect { - "Hello:" { send "saveworld 1\r" } - default abort - } - expect { - "the world is saved." { send "quit 1\r" } - default abort - } - expect { - "World is closing..." {} - default abort - } - expect { eof } - puts "Completed.\n" - ') -} - # Attempts graceful shutdown by sending /save /stop. fn_stop_graceful_avorion() { fn_print_dots "Graceful: /save /stop" @@ -575,7 +520,7 @@ fn_stop_graceful_select() { elif [ "${stopmode}" == "7" ]; then fn_stop_graceful_cmd "exit" 30 elif [ "${stopmode}" == "8" ]; then - fn_stop_graceful_sdtd + fn_stop_graceful_telnet "fn_stop_graceful_sdtd_telnet" "60" elif [ "${stopmode}" == "9" ]; then fn_stop_graceful_goldsrc elif [ "${stopmode}" == "10" ]; then @@ -585,7 +530,7 @@ fn_stop_graceful_select() { elif [ "${stopmode}" == "12" ]; then fn_stop_graceful_cmd "shutdown" 30 elif [ "${stopmode}" == "13" ]; then - fn_stop_graceful_sm + fn_stop_graceful_telnet "fn_stop_graceful_sm_telnet" "30" elif [ "${stopmode}" == "14" ]; then fn_stop_graceful_rwr elif [ "${stopmode}" == "15" ]; then From e68664e888f4e4055d3176056f15cef4fecf6f9b Mon Sep 17 00:00:00 2001 From: Daniel Gibbs Date: Fri, 16 Oct 2026 11:30:39 +0100 Subject: [PATCH 076/164] fix(jc3server): add libatomic dependency (#5053) The Just Cause 3 server binary needs libatomic.so.1 and fails to start on a fresh install without it. Add libatomic1 (Debian/Ubuntu) and libatomic (RHEL family) to the jc3 row of each distro csv. --- lgsm/data/almalinux-8.csv | 2 +- lgsm/data/almalinux-9.csv | 2 +- lgsm/data/centos-7.csv | 2 +- lgsm/data/centos-8.csv | 2 +- lgsm/data/centos-9.csv | 2 +- lgsm/data/debian-10.csv | 2 +- lgsm/data/debian-11.csv | 2 +- lgsm/data/debian-12.csv | 2 +- lgsm/data/debian-13.csv | 2 +- lgsm/data/debian-9.csv | 2 +- lgsm/data/rhel-7.csv | 2 +- lgsm/data/rhel-8.csv | 2 +- lgsm/data/rhel-9.csv | 2 +- lgsm/data/rocky-8.csv | 2 +- lgsm/data/rocky-9.csv | 2 +- lgsm/data/ubuntu-16.04.csv | 2 +- lgsm/data/ubuntu-18.04.csv | 2 +- lgsm/data/ubuntu-20.04.csv | 2 +- lgsm/data/ubuntu-22.04.csv | 2 +- lgsm/data/ubuntu-23.04.csv | 2 +- lgsm/data/ubuntu-23.10.csv | 2 +- lgsm/data/ubuntu-24.04.csv | 2 +- lgsm/data/ubuntu-26.04.csv | 2 +- 23 files changed, 23 insertions(+), 23 deletions(-) diff --git a/lgsm/data/almalinux-8.csv b/lgsm/data/almalinux-8.csv index 1a465dc920..1ebeed9124 100644 --- a/lgsm/data/almalinux-8.csv +++ b/lgsm/data/almalinux-8.csv @@ -61,7 +61,7 @@ inss ios jbep3 jc2 -jc3 +jc3,libatomic jk2 jk3,libstdc++,zlib kf diff --git a/lgsm/data/almalinux-9.csv b/lgsm/data/almalinux-9.csv index ff2e70637e..3e8350a78f 100644 --- a/lgsm/data/almalinux-9.csv +++ b/lgsm/data/almalinux-9.csv @@ -61,7 +61,7 @@ inss ios jbep3 jc2 -jc3 +jc3,libatomic jk2 jk3,libstdc++,zlib kf diff --git a/lgsm/data/centos-7.csv b/lgsm/data/centos-7.csv index 68b9a0e4e1..060e2cf27a 100644 --- a/lgsm/data/centos-7.csv +++ b/lgsm/data/centos-7.csv @@ -61,7 +61,7 @@ inss ios jbep3 jc2 -jc3 +jc3,libatomic jk2 jk3,libstdc++,zlib kf diff --git a/lgsm/data/centos-8.csv b/lgsm/data/centos-8.csv index 9af0d93841..7dd7165cc2 100644 --- a/lgsm/data/centos-8.csv +++ b/lgsm/data/centos-8.csv @@ -61,7 +61,7 @@ inss ios jbep3 jc2 -jc3 +jc3,libatomic jk2 jk3,libstdc++,zlib kf diff --git a/lgsm/data/centos-9.csv b/lgsm/data/centos-9.csv index 65d5f5dc28..935eff7e83 100644 --- a/lgsm/data/centos-9.csv +++ b/lgsm/data/centos-9.csv @@ -61,7 +61,7 @@ inss ios jbep3 jc2 -jc3 +jc3,libatomic jk2 jk3,libstdc++,zlib kf diff --git a/lgsm/data/debian-10.csv b/lgsm/data/debian-10.csv index 29ac28d999..4bb6e3aeab 100644 --- a/lgsm/data/debian-10.csv +++ b/lgsm/data/debian-10.csv @@ -60,7 +60,7 @@ inss ios jbep3 jc2 -jc3 +jc3,libatomic1 jk2 jk3,libstdc++6,zlib1g kf diff --git a/lgsm/data/debian-11.csv b/lgsm/data/debian-11.csv index b205318a4f..830af0721a 100644 --- a/lgsm/data/debian-11.csv +++ b/lgsm/data/debian-11.csv @@ -61,7 +61,7 @@ inss ios jbep3 jc2 -jc3 +jc3,libatomic1 jk2 jk3,libstdc++6,zlib1g kf diff --git a/lgsm/data/debian-12.csv b/lgsm/data/debian-12.csv index 9bd2c891d9..7a281fa139 100644 --- a/lgsm/data/debian-12.csv +++ b/lgsm/data/debian-12.csv @@ -61,7 +61,7 @@ inss ios jbep3 jc2 -jc3 +jc3,libatomic1 jk2 jk3,libstdc++6,zlib1g kf diff --git a/lgsm/data/debian-13.csv b/lgsm/data/debian-13.csv index 1331ca4052..8538e5a911 100644 --- a/lgsm/data/debian-13.csv +++ b/lgsm/data/debian-13.csv @@ -61,7 +61,7 @@ inss ios jbep3 jc2 -jc3 +jc3,libatomic1 jk2 jk3,libstdc++6,zlib1g kf diff --git a/lgsm/data/debian-9.csv b/lgsm/data/debian-9.csv index 1d6102a49c..e190c77d08 100644 --- a/lgsm/data/debian-9.csv +++ b/lgsm/data/debian-9.csv @@ -61,7 +61,7 @@ inss ios jbep3 jc2 -jc3 +jc3,libatomic1 jk2 jk3,libstdc++6,zlib1g kf diff --git a/lgsm/data/rhel-7.csv b/lgsm/data/rhel-7.csv index a790d1dca7..ff3f41901f 100644 --- a/lgsm/data/rhel-7.csv +++ b/lgsm/data/rhel-7.csv @@ -62,7 +62,7 @@ inss ios jbep3 jc2 -jc3 +jc3,libatomic jk2 jk3,libstdc++,zlib kf diff --git a/lgsm/data/rhel-8.csv b/lgsm/data/rhel-8.csv index 719aa040cf..7097fe244c 100644 --- a/lgsm/data/rhel-8.csv +++ b/lgsm/data/rhel-8.csv @@ -61,7 +61,7 @@ inss ios jbep3 jc2 -jc3 +jc3,libatomic jk2 jk3,libstdc++,zlib kf diff --git a/lgsm/data/rhel-9.csv b/lgsm/data/rhel-9.csv index ff2e70637e..3e8350a78f 100644 --- a/lgsm/data/rhel-9.csv +++ b/lgsm/data/rhel-9.csv @@ -61,7 +61,7 @@ inss ios jbep3 jc2 -jc3 +jc3,libatomic jk2 jk3,libstdc++,zlib kf diff --git a/lgsm/data/rocky-8.csv b/lgsm/data/rocky-8.csv index 719aa040cf..7097fe244c 100644 --- a/lgsm/data/rocky-8.csv +++ b/lgsm/data/rocky-8.csv @@ -61,7 +61,7 @@ inss ios jbep3 jc2 -jc3 +jc3,libatomic jk2 jk3,libstdc++,zlib kf diff --git a/lgsm/data/rocky-9.csv b/lgsm/data/rocky-9.csv index ff2e70637e..3e8350a78f 100644 --- a/lgsm/data/rocky-9.csv +++ b/lgsm/data/rocky-9.csv @@ -61,7 +61,7 @@ inss ios jbep3 jc2 -jc3 +jc3,libatomic jk2 jk3,libstdc++,zlib kf diff --git a/lgsm/data/ubuntu-16.04.csv b/lgsm/data/ubuntu-16.04.csv index 111c2e788c..165d81f296 100644 --- a/lgsm/data/ubuntu-16.04.csv +++ b/lgsm/data/ubuntu-16.04.csv @@ -62,7 +62,7 @@ inss ios jbep3 jc2 -jc3 +jc3,libatomic1 jk2 jk3,libstdc++6,zlib1g kf diff --git a/lgsm/data/ubuntu-18.04.csv b/lgsm/data/ubuntu-18.04.csv index a97d455eb3..29ca5089f4 100644 --- a/lgsm/data/ubuntu-18.04.csv +++ b/lgsm/data/ubuntu-18.04.csv @@ -62,7 +62,7 @@ inss ios jbep3 jc2 -jc3 +jc3,libatomic1 jk2 jk3,libstdc++6,zlib1g kf diff --git a/lgsm/data/ubuntu-20.04.csv b/lgsm/data/ubuntu-20.04.csv index 42f1f1e920..a6e1ab5cb2 100644 --- a/lgsm/data/ubuntu-20.04.csv +++ b/lgsm/data/ubuntu-20.04.csv @@ -61,7 +61,7 @@ inss ios jbep3 jc2 -jc3 +jc3,libatomic1 jk2 jk3,libstdc++6,zlib1g kf diff --git a/lgsm/data/ubuntu-22.04.csv b/lgsm/data/ubuntu-22.04.csv index 44e47afe28..def0e20b8f 100644 --- a/lgsm/data/ubuntu-22.04.csv +++ b/lgsm/data/ubuntu-22.04.csv @@ -61,7 +61,7 @@ inss ios jbep3 jc2 -jc3 +jc3,libatomic1 jk2 jk3,libstdc++6,zlib1g kf diff --git a/lgsm/data/ubuntu-23.04.csv b/lgsm/data/ubuntu-23.04.csv index c4395d3afd..98bfd20a56 100644 --- a/lgsm/data/ubuntu-23.04.csv +++ b/lgsm/data/ubuntu-23.04.csv @@ -61,7 +61,7 @@ inss ios jbep3 jc2 -jc3 +jc3,libatomic1 jk2 jk3,libstdc++6,zlib1g kf diff --git a/lgsm/data/ubuntu-23.10.csv b/lgsm/data/ubuntu-23.10.csv index c4395d3afd..98bfd20a56 100644 --- a/lgsm/data/ubuntu-23.10.csv +++ b/lgsm/data/ubuntu-23.10.csv @@ -61,7 +61,7 @@ inss ios jbep3 jc2 -jc3 +jc3,libatomic1 jk2 jk3,libstdc++6,zlib1g kf diff --git a/lgsm/data/ubuntu-24.04.csv b/lgsm/data/ubuntu-24.04.csv index f9fa95981d..f01738c06d 100644 --- a/lgsm/data/ubuntu-24.04.csv +++ b/lgsm/data/ubuntu-24.04.csv @@ -61,7 +61,7 @@ inss ios jbep3 jc2 -jc3 +jc3,libatomic1 jk2 jk3,libstdc++6,zlib1g kf diff --git a/lgsm/data/ubuntu-26.04.csv b/lgsm/data/ubuntu-26.04.csv index f9fa95981d..f01738c06d 100644 --- a/lgsm/data/ubuntu-26.04.csv +++ b/lgsm/data/ubuntu-26.04.csv @@ -61,7 +61,7 @@ inss ios jbep3 jc2 -jc3 +jc3,libatomic1 jk2 jk3,libstdc++6,zlib1g kf From c5297b7364e670325b290356e7f0c2889dd9a498 Mon Sep 17 00:00:00 2001 From: Daniel Gibbs Date: Fri, 16 Oct 2026 11:42:13 +0100 Subject: [PATCH 077/164] fix(security): download SteamCMD and MTA files over HTTPS (#5054) * fix(security): download SteamCMD and MTA files over HTTPS SteamCMD, the MTA server binaries and the MTA default resources were downloaded over plain HTTP with hash checking disabled. Anyone able to alter that traffic could swap in code that LinuxGSM later runs. - Use HTTPS for the SteamCMD tarball, the MTA server tarball (download and build-check URL) and the MTA resources zip. The MTA URLs move to the multitheftauto.com hosts that MTA documents. - When fn_fetch_file starts from an https:// URL, only allow HTTPS redirects, so a download cannot be downgraded to HTTP part way. Neither Valve nor MTA publishes checksums or signatures for these rolling "latest" files, so there is nothing trustworthy to pin yet. Fixes #4954 * fix(mta): show linux.multitheftauto.com as the update source --- lgsm/modules/command_install_resources_mta.sh | 2 +- lgsm/modules/core_dl.sh | 3 +++ lgsm/modules/core_steamcmd.sh | 2 +- lgsm/modules/update_mta.sh | 6 +++--- 4 files changed, 8 insertions(+), 5 deletions(-) diff --git a/lgsm/modules/command_install_resources_mta.sh b/lgsm/modules/command_install_resources_mta.sh index 7eca4fb979..7b1c45d12d 100755 --- a/lgsm/modules/command_install_resources_mta.sh +++ b/lgsm/modules/command_install_resources_mta.sh @@ -14,7 +14,7 @@ fn_install_resources() { echo -e "" echo -e "${bold}${lightyellow}Installing Default Resources${default}" fn_messages_separator - fn_fetch_file "http://mirror.mtasa.com/mtasa/resources/mtasa-resources-latest.zip" "" "" "" "${tmpdir}" "mtasa-resources-latest.zip" "nochmodx" "norun" "noforce" "nohash" + fn_fetch_file "https://mirror.multitheftauto.com/mtasa/resources/mtasa-resources-latest.zip" "" "" "" "${tmpdir}" "mtasa-resources-latest.zip" "nochmodx" "norun" "noforce" "nohash" fn_dl_extract "${tmpdir}" "mtasa-resources-latest.zip" "${resourcesdir}" echo -e "Default Resources Installed." } diff --git a/lgsm/modules/core_dl.sh b/lgsm/modules/core_dl.sh index 00c02d6f2e..752d4871a1 100755 --- a/lgsm/modules/core_dl.sh +++ b/lgsm/modules/core_dl.sh @@ -458,6 +458,9 @@ fn_fetch_file() { # Trap will remove part downloaded files if canceled. trap fn_fetch_trap INT curlcmd=(curl --connect-timeout 3 --fail -L -o "${local_filedir}/${local_filename}" --retry 2 -A "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.${randomint}.212 Safari/537.36") + if [[ "${fileurl}" == https://* ]]; then + curlcmd+=(--proto-redir "=https") + fi # if is large file show progress, else be silent local exitcode="" diff --git a/lgsm/modules/core_steamcmd.sh b/lgsm/modules/core_steamcmd.sh index 463a1f7dac..dc3f19abda 100755 --- a/lgsm/modules/core_steamcmd.sh +++ b/lgsm/modules/core_steamcmd.sh @@ -14,7 +14,7 @@ fn_install_steamcmd() { if [ ! -d "${steamcmddir}" ]; then mkdir -p "${steamcmddir}" fi - fn_fetch_file "http://media.steampowered.com/client/steamcmd_linux.tar.gz" "" "" "" "${tmpdir}" "steamcmd_linux.tar.gz" "nochmodx" "norun" "noforce" "nohash" + fn_fetch_file "https://media.steampowered.com/client/steamcmd_linux.tar.gz" "" "" "" "${tmpdir}" "steamcmd_linux.tar.gz" "nochmodx" "norun" "noforce" "nohash" fn_dl_extract "${tmpdir}" "steamcmd_linux.tar.gz" "${steamcmddir}" chmod +x "${steamcmddir}/steamcmd.sh" } diff --git a/lgsm/modules/update_mta.sh b/lgsm/modules/update_mta.sh index b1ba0459c8..35f7228efd 100755 --- a/lgsm/modules/update_mta.sh +++ b/lgsm/modules/update_mta.sh @@ -9,7 +9,7 @@ moduleselfname="$(basename "$(readlink -f "${BASH_SOURCE[0]}")")" fn_update_dl() { # Download and extract files to tmpdir. - fn_fetch_file "http://linux.mtasa.com/dl/multitheftauto_linux_x64.tar.gz" "" "" "" "${tmpdir}" "multitheftauto_linux_x64.tar.gz" "nochmodx" "norun" "force" "nohash" + fn_fetch_file "https://linux.multitheftauto.com/dl/multitheftauto_linux_x64.tar.gz" "" "" "" "${tmpdir}" "multitheftauto_linux_x64.tar.gz" "nochmodx" "norun" "force" "nohash" fn_dl_extract "${tmpdir}" "multitheftauto_linux_x64.tar.gz" "${serverfiles}" "multitheftauto_linux_x64" fn_clear_tmp } @@ -38,7 +38,7 @@ fn_update_remotebuild() { apiurl="https://linux.multitheftauto.com/revision/latest.txt" remotebuildresponse=$(curl -s "${apiurl}") remotebuildfilename="multitheftauto_linux_x64.tar.gz" - remotebuildurl="http://linux.mtasa.com/dl/multitheftauto_linux_x64.tar.gz" + remotebuildurl="https://linux.multitheftauto.com/dl/multitheftauto_linux_x64.tar.gz" remotebuild="${remotebuildresponse}" if [ "${firstcommandname}" != "INSTALL" ]; then fn_print_dots "Checking remote build: ${remotelocation}" @@ -158,7 +158,7 @@ fn_update_compare() { } # The location where the builds are checked and downloaded. -remotelocation="linux.mtasa.com" +remotelocation="linux.multitheftauto.com" if [ "${firstcommandname}" == "INSTALL" ]; then fn_update_remotebuild From 497e76b7cf37dd0ad5edeafddd367327ae1eda93 Mon Sep 17 00:00:00 2001 From: Daniel Gibbs Date: Fri, 16 Oct 2026 12:36:10 +0100 Subject: [PATCH 078/164] fix(update): continue starting the server after updateonstart applies an update (#5056) With updateonstart enabled, command_start.sh sets exitbypass so that command_update.sh returns to it. When an update was available and the server was stopped, the update modules ran unset exitbypass after the download, so the final core_exit.sh in command_update.sh exited the whole script and the server was never started. This affected start and restart for every update module, not just SteamCMD. command_update.sh now records the caller's exitbypass on entry and restores it before its final core_exit.sh, so a caller that asked to continue always gets control back. Tested on a test server (hl2dmserver, develop modules): - start and restart with an update available: server now starts (was left stopped with exit code 0 before the fix) - start and restart with no update: server starts - start and restart with a failed SteamCMD download: server starts on the installed build - update while running, while stopped, with no update and with a failed download: unchanged behaviour Fixes #4415 Fixes #4703 --- lgsm/modules/command_update.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lgsm/modules/command_update.sh b/lgsm/modules/command_update.sh index 80bcca1700..8afa8f6aec 100755 --- a/lgsm/modules/command_update.sh +++ b/lgsm/modules/command_update.sh @@ -9,6 +9,7 @@ commandname="UPDATE" commandaction="Updating" moduleselfname="$(basename "$(readlink -f "${BASH_SOURCE[0]}")")" fn_firstcommand_set +updateexitbypass="${exitbypass}" fn_print_dots "" check.sh @@ -59,4 +60,5 @@ fi # remove update lockfile. rm -f "${lockdir:?}/update.lock" +exitbypass="${updateexitbypass}" core_exit.sh From ba81fc032451707c13ea4200fd6ee13202c31247 Mon Sep 17 00:00:00 2001 From: Daniel Gibbs Date: Fri, 16 Oct 2026 21:23:56 +0100 Subject: [PATCH 079/164] fix(sven): drop libssl3:i386 dependency on Debian 12 and 13 (#5058) The current Sven Co-op build bundles libcurl.so.4 with OpenSSL statically linked, so server.so no longer needs a system libssl. Verified with fresh installs on Debian 12 and 13 without libssl3:i386. Refs #4668 --- lgsm/data/debian-12.csv | 2 +- lgsm/data/debian-13.csv | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lgsm/data/debian-12.csv b/lgsm/data/debian-12.csv index 7a281fa139..b6347d6881 100644 --- a/lgsm/data/debian-12.csv +++ b/lgsm/data/debian-12.csv @@ -116,7 +116,7 @@ sol squad st,libxml2-utils stn -sven,libssl3:i386,zlib1g:i386 +sven,zlib1g:i386 terraria tf tf2,libcurl4-gnutls-dev:i386 diff --git a/lgsm/data/debian-13.csv b/lgsm/data/debian-13.csv index 8538e5a911..8dee746bf6 100644 --- a/lgsm/data/debian-13.csv +++ b/lgsm/data/debian-13.csv @@ -116,7 +116,7 @@ sol squad st,libxml2 stn -sven,libssl3:i386,zlib1g:i386 +sven,zlib1g:i386 terraria tf tf2,libcurl4-gnutls-dev:i386 From 8c5441022c7fa2722833d75aca82ba29be137dee Mon Sep 17 00:00:00 2001 From: Daniel Gibbs Date: Fri, 16 Oct 2026 22:24:11 +0100 Subject: [PATCH 080/164] feat(details): show missing dependencies in details and post-details (#5041) * feat(details): show missing dependencies in details and post-details details and post-details now list any missing dependencies in the Distro Details section, so they end up in the termbin output shared for support. check_deps.sh gains a check-only mode for DETAILS and POST-DETAILS. In that mode it builds array_deps_missing but never calls fn_install_missing_deps, so neither command will try to install packages or add Mono or .NET repositories via sudo. The unsupported distro warnings and exits are also skipped so a game blocked on the current distro can still produce details for support, and the "dependency checking unavailable" warning and its no-check tmp file are left to the commands that install. When no dependency CSV exists for the distro, details shows that dependency checking is unavailable instead. post-details is added to the commands that run check_deps.sh. Closes #1281 * refactor(details): label missing dependencies line Dependencies * refactor(details): label line Missing dependencies --- lgsm/modules/check.sh | 2 +- lgsm/modules/check_deps.sh | 51 +++++++++++++++++++++-------------- lgsm/modules/info_messages.sh | 6 +++++ 3 files changed, 38 insertions(+), 21 deletions(-) mode change 100755 => 100644 lgsm/modules/info_messages.sh diff --git a/lgsm/modules/check.sh b/lgsm/modules/check.sh index a892dd1a35..8e048a60ca 100755 --- a/lgsm/modules/check.sh +++ b/lgsm/modules/check.sh @@ -54,7 +54,7 @@ for allowed_command in "${allowed_commands_array[@]}"; do fi done -allowed_commands_array=(BACKUP DEBUG DETAILS RESTART START UPDATE WORKSHOP-UPDATE) +allowed_commands_array=(BACKUP DEBUG DETAILS POST-DETAILS RESTART START UPDATE WORKSHOP-UPDATE) for allowed_command in "${allowed_commands_array[@]}"; do if [ "${allowed_command}" == "${commandname}" ]; then check_deps.sh diff --git a/lgsm/modules/check_deps.sh b/lgsm/modules/check_deps.sh index 46cf989a05..ec003ba7e6 100644 --- a/lgsm/modules/check_deps.sh +++ b/lgsm/modules/check_deps.sh @@ -264,7 +264,9 @@ fn_check_loop() { done # user will be informed of any missing dependencies. - fn_install_missing_deps + if [ "${depcheckonly}" != "1" ]; then + fn_install_missing_deps + fi } # Checks if dependency is installed or not. @@ -375,6 +377,10 @@ fn_deps_detector() { fi } +if [ "${commandname}" == "DETAILS" ] || [ "${commandname}" == "POST-DETAILS" ]; then + depcheckonly="1" +fi + if [ "${commandname}" == "INSTALL" ]; then if [ "$(whoami)" == "root" ]; then echo -e "" @@ -391,29 +397,31 @@ fi info_distro.sh -# Will warn user if their distro is no longer supported by the vendor. -if [ -n "${distrosupport}" ]; then - if [ "${distrosupport}" == "unsupported" ]; then - fn_print_warning_nl "${distroname} is no longer supported by the vendor or LinuxGSM. Upgrading is recommended." - fn_script_log_warn "${distroname} is no longer supported by the vendor or LinuxGSM. Upgrading is recommended." +if [ "${depcheckonly}" != "1" ]; then + # Will warn user if their distro is no longer supported by the vendor. + if [ -n "${distrosupport}" ]; then + if [ "${distrosupport}" == "unsupported" ]; then + fn_print_warning_nl "${distroname} is no longer supported by the vendor or LinuxGSM. Upgrading is recommended." + fn_script_log_warn "${distroname} is no longer supported by the vendor or LinuxGSM. Upgrading is recommended." + fi fi -fi -# These titles are only supported up to Ubuntu 20.04 and Debian 11. -if { [ "${distroid}" == "ubuntu" ] && dpkg --compare-versions "${distroversion}" "gt" "20.04"; } || { [ "${distroid}" == "debian" ] && dpkg --compare-versions "${distroversion}" "gt" "11"; }; then - if [ "${shortname}" == "onset" ] || [ "${shortname}" == "btl" ]; then - fn_print_failure_nl "${gamename} is not supported on ${distroname} (requires Ubuntu <= 20.04 or Debian <= 11)." - fn_script_log_fail "${gamename} is not supported on ${distroname}." - core_exit.sh + # These titles are only supported up to Ubuntu 20.04 and Debian 11. + if { [ "${distroid}" == "ubuntu" ] && dpkg --compare-versions "${distroversion}" "gt" "20.04"; } || { [ "${distroid}" == "debian" ] && dpkg --compare-versions "${distroversion}" "gt" "11"; }; then + if [ "${shortname}" == "onset" ] || [ "${shortname}" == "btl" ]; then + fn_print_failure_nl "${gamename} is not supported on ${distroname} (requires Ubuntu <= 20.04 or Debian <= 11)." + fn_script_log_fail "${gamename} is not supported on ${distroname}." + core_exit.sh + fi fi -fi -# Vintage Story tracks newer .NET runtimes; older distro releases may not ship required packages. -if [ "${shortname}" == "vints" ]; then - if { [ "${distroid}" == "ubuntu" ] && dpkg --compare-versions "${distroversion}" "lt" "24.04"; } || { [ "${distroid}" == "debian" ] && dpkg --compare-versions "${distroversion}" "lt" "12"; } || [ "${distroid}" == "centos" ] || [ "${distroid}" == "rhel" ] || [ "${distroid}" == "rocky" ] || [ "${distroid}" == "almalinux" ]; then - fn_print_warning_nl "${gamename} may require newer .NET runtimes than ${distroname} provides." - echo -e "If startup fails due to missing .NET runtime, upgrading to Ubuntu 24.04+ or Debian 12+ is recommended." - fn_script_log_warn "${gamename} may require newer .NET runtimes than ${distroname} provides." + # Vintage Story tracks newer .NET runtimes; older distro releases may not ship required packages. + if [ "${shortname}" == "vints" ]; then + if { [ "${distroid}" == "ubuntu" ] && dpkg --compare-versions "${distroversion}" "lt" "24.04"; } || { [ "${distroid}" == "debian" ] && dpkg --compare-versions "${distroversion}" "lt" "12"; } || [ "${distroid}" == "centos" ] || [ "${distroid}" == "rhel" ] || [ "${distroid}" == "rocky" ] || [ "${distroid}" == "almalinux" ]; then + fn_print_warning_nl "${gamename} may require newer .NET runtimes than ${distroname} provides." + echo -e "If startup fails due to missing .NET runtime, upgrading to Ubuntu 24.04+ or Debian 12+ is recommended." + fn_script_log_warn "${gamename} may require newer .NET runtimes than ${distroname} provides." + fi fi fi @@ -441,6 +449,9 @@ if [ -f "${datadir}/${distroid}-${distroversioncsv}.csv" ]; then IFS=" " read -r -a array_deps_required <<< "$(echo "${array_deps_required[@]}" | tr ' ' '\n' | sort -u | tr '\n' ' ')" fn_check_loop +elif [ "${depcheckonly}" == "1" ]; then + # shellcheck disable=SC2034 # Used by info_messages.sh. + depcheckunavailable="1" # Warn the user that dependency checking is unavailable for their distro. elif [ "${commandname}" == "INSTALL" ] || [ -n "${checkflag}" ] && [ "${checkflag}" != "0" ]; then fn_print_warning_nl "LinuxGSM dependency checking currently unavailable for ${distroname}." diff --git a/lgsm/modules/info_messages.sh b/lgsm/modules/info_messages.sh old mode 100755 new mode 100644 index 9f664c70c5..512e5d3464 --- a/lgsm/modules/info_messages.sh +++ b/lgsm/modules/info_messages.sh @@ -111,6 +111,7 @@ fn_info_messages_distro() { # Uptime: 16d, 5h, 18m # tmux: tmux 3.0a # glibc: 2.31 + # Missing dependencies: lib32gcc-s1 steamcmd echo -e "" echo -e "${bold}${lightyellow}Distro Details${default}" @@ -128,6 +129,11 @@ fn_info_messages_distro() { if [ -n "${javaram}" ]; then echo -e "${lightblue}Java:\t${default}${javaversion}" fi + if [ "${#array_deps_missing[@]}" != "0" ]; then + echo -e "${lightblue}Missing dependencies:\t${red}${array_deps_missing[*]}${default}" + elif [ "${depcheckunavailable}" == "1" ]; then + echo -e "${lightblue}Missing dependencies:\t${default}dependency checking unavailable for ${distroname}" + fi } | column -s $'\t' -t } From cd9db5a5af8b0182773d654b55b08bc5a4c5de38 Mon Sep 17 00:00:00 2001 From: Daniel Gibbs Date: Fri, 16 Oct 2026 22:30:03 +0100 Subject: [PATCH 081/164] feat(tf2): use 64-bit server by default (#5059) Team Fortress 2 has shipped a 64-bit Linux server since April 2024 and SteamCMD already installs srcds_run_64. Start it by default and raise glibc to 2.29, which both the 32-bit and 64-bit binaries require. Add -norestart to startparameters: on 64-bit, quit aborts during Steam shutdown and srcds_run_64 restarted the server, so graceful stop never completed. Keep servers with SourceMod on 32-bit unless executable is set in the user's configs, because DHooks and many third-party extensions have no Linux x64 build yet. Fixes #4841 --- lgsm/config-default/config-lgsm/tf2server/_default.cfg | 6 +++--- lgsm/modules/fix_tf2.sh | 7 +++++++ 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/lgsm/config-default/config-lgsm/tf2server/_default.cfg b/lgsm/config-default/config-lgsm/tf2server/_default.cfg index 00b1aeb1a0..0c1404a937 100644 --- a/lgsm/config-default/config-lgsm/tf2server/_default.cfg +++ b/lgsm/config-default/config-lgsm/tf2server/_default.cfg @@ -24,7 +24,7 @@ maxplayers="16" gslt="" ## Server Parameters | https://docs.linuxgsm.com/configuration/start-parameters#additional-parameters -startparameters="-game tf -strictportbind -ip ${ip} -port ${port} +clientport ${clientport} +tv_port ${sourcetvport} +map ${defaultmap} +sv_setsteamaccount ${gslt} +servercfgfile ${servercfg} -maxplayers ${maxplayers}" +startparameters="-game tf -strictportbind -ip ${ip} -port ${port} +clientport ${clientport} +tv_port ${sourcetvport} +map ${defaultmap} +sv_setsteamaccount ${gslt} +servercfgfile ${servercfg} -maxplayers ${maxplayers} -norestart" #### LinuxGSM Settings #### @@ -184,7 +184,7 @@ consoleinteract="yes" # Do not edit gamename="Team Fortress 2" engine="source" -glibc="2.15" +glibc="2.29" #### Directories #### # Edit with care @@ -192,7 +192,7 @@ glibc="2.15" ## Game Server Directories systemdir="${serverfiles}/tf" executabledir="${serverfiles}" -executable="./srcds_run" +executable="./srcds_run_64" servercfgdir="${systemdir}/cfg" servercfg="${selfname}.cfg" servercfgdefault="server.cfg" diff --git a/lgsm/modules/fix_tf2.sh b/lgsm/modules/fix_tf2.sh index 1050264880..be13d01fdd 100755 --- a/lgsm/modules/fix_tf2.sh +++ b/lgsm/modules/fix_tf2.sh @@ -14,3 +14,10 @@ if [ -f "/etc/redhat-release" ] && [ ! -f "${serverfiles}/bin/libcurl-gnutls.so. ln -s "/usr/lib/libcurl.so.4" "${serverfiles}/bin/libcurl-gnutls.so.4" fn_fix_msg_end fi + +# Fixes: SourceMod extensions without 64-bit builds failing to load #4841. +if [ "${executable}" == "./srcds_run_64" ] && [ -d "${systemdir}/addons/sourcemod" ] && ! grep -qsE "^[[:blank:]]*executable=" "${configdirserver}/common.cfg" "${configdirserver}/secrets-common.cfg" "${configdirserver}/${selfname}.cfg" "${configdirserver}/secrets-${selfname}.cfg"; then + fn_print_info_nl "SourceMod detected, starting 32-bit server. Set executable=\"./srcds_run_64\" in ${selfname}.cfg to use 64-bit" + fn_script_log_info "SourceMod detected, starting 32-bit server. Set executable=\"./srcds_run_64\" in ${selfname}.cfg to use 64-bit" + executable="./srcds_run" +fi From cfda3f6c298d1f8eb808ea3a21dac510726664bc Mon Sep 17 00:00:00 2001 From: Daniel Gibbs Date: Fri, 16 Oct 2026 22:52:10 +0100 Subject: [PATCH 082/164] fix(ut3): install default configs from Game-Server-Configs (#5062) ut3server had no install_config block, so a fresh install only had the configs the game generates during fix_ut3. The web admin was disabled on port 80 and UTGame.ini had no AdminPassword. Download UTGame.ini, UTWeb.ini and UTEngine.ini into the ConfigSubDir before fix_ut3 runs, then set the server name and a random admin password. UT3 keeps pre-placed configs untouched when it generates the rest, so the web admin is enabled on 7779 with the admin password. --- lgsm/modules/install_config.sh | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/lgsm/modules/install_config.sh b/lgsm/modules/install_config.sh index e144c52c3d..db4fe908b8 100755 --- a/lgsm/modules/install_config.sh +++ b/lgsm/modules/install_config.sh @@ -797,6 +797,11 @@ elif [ "${shortname}" == "ut2k4" ]; then fn_default_config_remote fn_set_config_vars fn_list_config_locations +elif [ "${shortname}" == "ut3" ]; then + array_configs+=(UTGame.ini UTWeb.ini UTEngine.ini) + fn_default_config_remote + fn_set_config_vars + fn_list_config_locations elif [ "${shortname}" == "ut99" ]; then array_configs+=(Default.ini) fn_default_config_remote From e05c4a479b8a182f9effbcf5642bc5465596981e Mon Sep 17 00:00:00 2001 From: Daniel Gibbs Date: Fri, 16 Oct 2026 22:56:55 +0100 Subject: [PATCH 083/164] fix(ti): pass EOS credentials as launch arguments (#5061) The Isle deletes Saved/Config/LinuxServer/Engine.ini during its shutdown config flush on every graceful stop, so the next start failed with "Unable to initialize EOS platform". Pass the EOS dedicated server credentials with -ini:Engine:[EpicOnlineServices] start parameters so the server no longer depends on that file. For installs that override startparameters without these arguments, check_config now restores a missing Engine.ini from the defaults. Fixes #4936 --- lgsm/config-default/config-lgsm/tiserver/_default.cfg | 6 +++++- lgsm/modules/check_config.sh | 8 ++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/lgsm/config-default/config-lgsm/tiserver/_default.cfg b/lgsm/config-default/config-lgsm/tiserver/_default.cfg index 503c8de1bf..1be16d9616 100644 --- a/lgsm/config-default/config-lgsm/tiserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/tiserver/_default.cfg @@ -13,9 +13,13 @@ ip="0.0.0.0" port="7777" defaultmap="/Game/TheIsle/Maps/Game/Gateway/Gateway" +## Epic Online Services (EOS) Dedicated Server Credentials +eosclientid="xyza7891gk5PRo3J7G9puCJGFJjmEguW" +eosclientsecret="pKWl6t5i9NJK8gTpVlAxzENZ65P8hYzodV8Dqe5Rlc8" + ## Server Parameters | https://docs.linuxgsm.com/configuration/start-parameters#additional-parameters ## Game Server Docs | https://isle.fandom.com/wiki/The_Isle_Server_Settings_and_Configuration -startparameters="${defaultmap} -Port=${port} -log" +startparameters="${defaultmap} -Port=${port} -log -ini:Engine:[EpicOnlineServices]:DedicatedServerClientId=${eosclientid} -ini:Engine:[EpicOnlineServices]:DedicatedServerClientSecret=${eosclientsecret}" #### LinuxGSM Settings #### diff --git a/lgsm/modules/check_config.sh b/lgsm/modules/check_config.sh index 24bc1c37f5..71ee9d1bd6 100755 --- a/lgsm/modules/check_config.sh +++ b/lgsm/modules/check_config.sh @@ -15,6 +15,14 @@ if [ -n "${servercfgfullpath}" ] && [ ! -f "${servercfgfullpath}" ]; then install_config.sh fi +if [ "${shortname}" == "ti" ] && [[ "${startparameters}" != *"DedicatedServerClientId"* ]] && [ ! -f "${servercfgdir}/Engine.ini" ]; then + fn_print_warn_nl "Configuration file missing!" + echo -e "${servercfgdir}/Engine.ini" + fn_script_log_warn "Configuration file missing!" + fn_script_log_warn "${servercfgdir}/Engine.ini" + install_config.sh +fi + if [ "${shortname}" == "rust" ] && [ -v rconpassword ] && [ -z "${rconpassword}" ]; then fn_print_fail_nl "RCON password is not set" fn_script_log_warn "RCON password is not set" From 543bb3f31705d79f30cdfcbf797863c317b7a15a Mon Sep 17 00:00:00 2001 From: Daniel Gibbs Date: Fri, 16 Oct 2026 23:03:26 +0100 Subject: [PATCH 084/164] fix(update): report failed updates instead of treating them as success (#5060) * fix(update): report failed updates instead of treating them as success When the server is running, the update modules set exitbypass before downloading so the server is started again afterwards. A download failure calls core_exit.sh, which only clears exitbypass and returns, so the update carried on as if it had worked: it wrote last-updated.lock, sent the "update" alert and exited 0. updateonstart had the same problem from command_start.sh, where a failed remote build check left remotebuild empty, the compare saw "" != localbuild, and an update was reported with a blank "Remote build:" line (#4703). The download step now runs in a subshell via a shared fn_update_apply in command_update.sh, used by every update module and by force-update. A core_exit.sh inside the download ends only the subshell. The server is stopped and started again as before, but last-updated.lock is written only after a successful download. On failure the update-failed alert is sent, update.lock is removed and the command exits with the download's exit code. updateonstart now runs the update in a subshell without exitbypass, so a failed update is logged with its own exit code and the server still starts. This replaces the exitbypass save and restore in command_update.sh from #5056. force-update uses the same fn_update_apply, so a failed forced download is reported the same way. * fix(update): mark variables used by sourced modules for shellcheck --- lgsm/modules/command_start.sh | 10 ++++++--- lgsm/modules/command_update.sh | 38 +++++++++++++++++++++++++++++++-- lgsm/modules/core_steamcmd.sh | 19 +---------------- lgsm/modules/update_bb.sh | 26 +++++----------------- lgsm/modules/update_etl.sh | 26 +++++----------------- lgsm/modules/update_fctr.sh | 26 +++++----------------- lgsm/modules/update_hyt.sh | 17 +-------------- lgsm/modules/update_jk2.sh | 26 +++++----------------- lgsm/modules/update_jk3.sh | 18 +--------------- lgsm/modules/update_mc.sh | 26 +++++----------------- lgsm/modules/update_mcb.sh | 26 +++++----------------- lgsm/modules/update_mta.sh | 26 +++++----------------- lgsm/modules/update_pmc.sh | 26 +++++----------------- lgsm/modules/update_steamcmd.sh | 17 ++------------- lgsm/modules/update_ts3.sh | 26 +++++----------------- lgsm/modules/update_ut99.sh | 26 +++++----------------- lgsm/modules/update_vints.sh | 26 +++++----------------- lgsm/modules/update_xnt.sh | 26 +++++----------------- 18 files changed, 108 insertions(+), 323 deletions(-) diff --git a/lgsm/modules/command_start.sh b/lgsm/modules/command_start.sh index 4895bb5b2a..86ca683a38 100755 --- a/lgsm/modules/command_start.sh +++ b/lgsm/modules/command_start.sh @@ -271,10 +271,14 @@ core_logs.sh # Will check for updates if updateonstart is yes. if [ "${updateonstart}" == "yes" ] || [ "${updateonstart}" == "1" ] || [ "${updateonstart}" == "on" ]; then - exitbypass=1 unset updateonstart - command_update.sh - fn_firstcommand_reset + if ! ( + unset exitbypass + command_update.sh + ); then + fn_print_warn_nl "Update failed, starting ${servername} anyway" + fn_script_log_warn "Update failed, starting ${servername} anyway" + fi fi fn_print_dots "${servername}" diff --git a/lgsm/modules/command_update.sh b/lgsm/modules/command_update.sh index 8afa8f6aec..891f1eb2ae 100755 --- a/lgsm/modules/command_update.sh +++ b/lgsm/modules/command_update.sh @@ -9,7 +9,42 @@ commandname="UPDATE" commandaction="Updating" moduleselfname="$(basename "$(readlink -f "${BASH_SOURCE[0]}")")" fn_firstcommand_set -updateexitbypass="${exitbypass}" + +fn_update_apply() { + check_status.sh + updatestatus="${status}" + if [ "${updatestatus}" != "0" ]; then + fn_print_restart_warning + exitbypass=1 + command_stop.sh + fn_firstcommand_reset + fi + ( + unset exitbypass + "$@" + exit 0 + ) + updateexitcode=$? + if [ "${updateexitcode}" -eq 0 ]; then + date +%s > "${lockdir:?}/last-updated.lock" + fi + if [ "${updatestatus}" != "0" ]; then + # shellcheck disable=SC2034 # Used by command_start.sh. + exitbypass=1 + command_start.sh + fn_firstcommand_reset + fi + unset exitbypass + if [ "${updateexitcode}" -ne 0 ]; then + rm -f "${lockdir:?}/update.lock" + # shellcheck disable=SC2034 # Used by alert.sh. + alert="update-failed" + alert.sh + # shellcheck disable=SC2034 # Used by core_exit.sh. + exitcode="${updateexitcode}" + core_exit.sh + fi +} fn_print_dots "" check.sh @@ -60,5 +95,4 @@ fi # remove update lockfile. rm -f "${lockdir:?}/update.lock" -exitbypass="${updateexitbypass}" core_exit.sh diff --git a/lgsm/modules/core_steamcmd.sh b/lgsm/modules/core_steamcmd.sh index dc3f19abda..81b8d0cc23 100755 --- a/lgsm/modules/core_steamcmd.sh +++ b/lgsm/modules/core_steamcmd.sh @@ -239,25 +239,8 @@ fn_update_steamcmd_compare() { fn_script_log_info "${localbuild} > ${remotebuild}" if [ "${commandname}" == "UPDATE" ]; then - date +%s > "${lockdir:?}/last-updated.lock" unset updateonstart - check_status.sh - # If server stopped. - if [ "${status}" == "0" ]; then - fn_dl_steamcmd - # If server started. - else - fn_print_restart_warning - exitbypass=1 - command_stop.sh - fn_firstcommand_reset - exitbypass=1 - fn_dl_steamcmd - exitbypass=1 - command_start.sh - fn_firstcommand_reset - fi - unset exitbypass + fn_update_apply fn_dl_steamcmd alert="update" elif [ "${commandname}" == "CHECK-UPDATE" ]; then alert="check-update" diff --git a/lgsm/modules/update_bb.sh b/lgsm/modules/update_bb.sh index 1f2f12ce80..aeb47fe448 100755 --- a/lgsm/modules/update_bb.sh +++ b/lgsm/modules/update_bb.sh @@ -96,31 +96,15 @@ fn_update_compare() { fn_script_log_info "${localbuild} > ${remotebuild}" if [ "${commandname}" == "UPDATE" ]; then - date +%s > "${lockdir:?}/last-updated.lock" unset updateonstart - check_status.sh - # If server stopped. - if [ "${status}" == "0" ]; then - fn_update_dl - if [ "${localbuild}" == "0" ]; then - exitbypass=1 - command_start.sh - fn_firstcommand_reset - exitbypass=1 - fn_sleep_time_5 - command_stop.sh - fn_firstcommand_reset - fi - # If server started. - else - fn_print_restart_warning + fn_update_apply fn_update_dl + if [ "${updatestatus}" == "0" ] && [ "${localbuild}" == "0" ]; then exitbypass=1 - command_stop.sh + command_start.sh fn_firstcommand_reset exitbypass=1 - fn_update_dl - exitbypass=1 - command_start.sh + fn_sleep_time_5 + command_stop.sh fn_firstcommand_reset fi unset exitbypass diff --git a/lgsm/modules/update_etl.sh b/lgsm/modules/update_etl.sh index 8486343e24..fa3f9f591f 100755 --- a/lgsm/modules/update_etl.sh +++ b/lgsm/modules/update_etl.sh @@ -98,31 +98,15 @@ fn_update_compare() { fn_script_log_info "${localbuild} > ${remotebuild}" if [ "${commandname}" == "UPDATE" ]; then - date +%s > "${lockdir:?}/last-updated.lock" unset updateonstart - check_status.sh - # If server stopped. - if [ "${status}" == "0" ]; then - fn_update_dl - if [ "${localbuild}" == "0" ]; then - exitbypass=1 - command_start.sh - fn_firstcommand_reset - exitbypass=1 - fn_sleep_time_5 - command_stop.sh - fn_firstcommand_reset - fi - # If server started. - else - fn_print_restart_warning + fn_update_apply fn_update_dl + if [ "${updatestatus}" == "0" ] && [ "${localbuild}" == "0" ]; then exitbypass=1 - command_stop.sh + command_start.sh fn_firstcommand_reset exitbypass=1 - fn_update_dl - exitbypass=1 - command_start.sh + fn_sleep_time_5 + command_stop.sh fn_firstcommand_reset fi unset exitbypass diff --git a/lgsm/modules/update_fctr.sh b/lgsm/modules/update_fctr.sh index 5de789cdb1..d82f53881f 100755 --- a/lgsm/modules/update_fctr.sh +++ b/lgsm/modules/update_fctr.sh @@ -102,31 +102,15 @@ fn_update_compare() { if [ "${commandname}" == "UPDATE" ]; then # 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. - if [ "${status}" == "0" ]; then - fn_update_dl - if [ "${localbuild}" == "0" ]; then - exitbypass=1 - command_start.sh - fn_firstcommand_reset - exitbypass=1 - fn_sleep_time_5 - command_stop.sh - fn_firstcommand_reset - fi - # If server started. - else - fn_print_restart_warning + fn_update_apply fn_update_dl + if [ "${updatestatus}" == "0" ] && [ "${localbuild}" == "0" ]; then exitbypass=1 - command_stop.sh + command_start.sh fn_firstcommand_reset exitbypass=1 - fn_update_dl - exitbypass=1 - command_start.sh + fn_sleep_time_5 + command_stop.sh fn_firstcommand_reset fi # Refresh local build value after update (silent) so alerts show new version. diff --git a/lgsm/modules/update_hyt.sh b/lgsm/modules/update_hyt.sh index 86829bb686..56b3700007 100755 --- a/lgsm/modules/update_hyt.sh +++ b/lgsm/modules/update_hyt.sh @@ -252,23 +252,8 @@ fn_update_compare() { fn_script_log_info "Patchline: ${hytalepatchline}" if [ "${commandname}" == "UPDATE" ]; then - date +%s > "${lockdir:?}/last-updated.lock" unset updateonstart - check_status.sh - if [ "${status}" == "0" ]; then - fn_update_dl - else - fn_print_restart_warning - exitbypass=1 - command_stop.sh - fn_firstcommand_reset - exitbypass=1 - fn_update_dl - exitbypass=1 - command_start.sh - fn_firstcommand_reset - fi - unset exitbypass + fn_update_apply fn_update_dl alert="update" elif [ "${commandname}" == "CHECK-UPDATE" ]; then alert="check-update" diff --git a/lgsm/modules/update_jk2.sh b/lgsm/modules/update_jk2.sh index ee40988d92..1d2ba36458 100755 --- a/lgsm/modules/update_jk2.sh +++ b/lgsm/modules/update_jk2.sh @@ -90,31 +90,15 @@ fn_update_compare() { fn_script_log_info "${localbuild} > ${remotebuild}" if [ "${commandname}" == "UPDATE" ]; then - date +%s > "${lockdir:?}/last-updated.lock" unset updateonstart - check_status.sh - # If server stopped. - if [ "${status}" == "0" ]; then - fn_update_dl - if [ "${localbuild}" == "0" ]; then - exitbypass=1 - command_start.sh - fn_firstcommand_reset - exitbypass=1 - fn_sleep_time_5 - command_stop.sh - fn_firstcommand_reset - fi - # If server started. - else - fn_print_restart_warning + fn_update_apply fn_update_dl + if [ "${updatestatus}" == "0" ] && [ "${localbuild}" == "0" ]; then exitbypass=1 - command_stop.sh + command_start.sh fn_firstcommand_reset exitbypass=1 - fn_update_dl - exitbypass=1 - command_start.sh + fn_sleep_time_5 + command_stop.sh fn_firstcommand_reset fi unset exitbypass diff --git a/lgsm/modules/update_jk3.sh b/lgsm/modules/update_jk3.sh index e9cd792c1c..73da66b9d7 100755 --- a/lgsm/modules/update_jk3.sh +++ b/lgsm/modules/update_jk3.sh @@ -111,23 +111,7 @@ fn_update_compare() { if [ "${commandname}" == "UPDATE" ]; then unset updateonstart - check_status.sh - # If server stopped. - if [ "${status}" == "0" ]; then - fn_update_dl - # If server started. - else - fn_print_restart_warning - exitbypass=1 - command_stop.sh - fn_firstcommand_reset - fn_update_dl - exitbypass=1 - command_start.sh - fn_firstcommand_reset - fi - unset exitbypass - date +%s > "${lockdir:?}/last-updated.lock" + fn_update_apply fn_update_dl alert="update" elif [ "${commandname}" == "CHECK-UPDATE" ]; then alert="check-update" diff --git a/lgsm/modules/update_mc.sh b/lgsm/modules/update_mc.sh index 81540f0020..1daf40bb97 100755 --- a/lgsm/modules/update_mc.sh +++ b/lgsm/modules/update_mc.sh @@ -105,31 +105,15 @@ fn_update_compare() { fn_script_log_info "${localbuild} > ${remotebuild}" if [ "${commandname}" == "UPDATE" ]; then - date +%s > "${lockdir:?}/last-updated.lock" unset updateonstart - check_status.sh - # If server stopped. - if [ "${status}" == "0" ]; then - fn_update_dl - if [ "${localbuild}" == "0" ]; then - exitbypass=1 - command_start.sh - fn_firstcommand_reset - exitbypass=1 - fn_sleep_time_5 - command_stop.sh - fn_firstcommand_reset - fi - # If server started. - else - fn_print_restart_warning + fn_update_apply fn_update_dl + if [ "${updatestatus}" == "0" ] && [ "${localbuild}" == "0" ]; then exitbypass=1 - command_stop.sh + command_start.sh fn_firstcommand_reset exitbypass=1 - fn_update_dl - exitbypass=1 - command_start.sh + fn_sleep_time_5 + command_stop.sh fn_firstcommand_reset fi unset exitbypass diff --git a/lgsm/modules/update_mcb.sh b/lgsm/modules/update_mcb.sh index 9940415a1c..1dec5ed99e 100755 --- a/lgsm/modules/update_mcb.sh +++ b/lgsm/modules/update_mcb.sh @@ -116,31 +116,15 @@ fn_update_compare() { fn_script_log_info "${localbuild} > ${remotebuild}" if [ "${commandname}" == "UPDATE" ]; then - date +%s > "${lockdir:?}/last-updated.lock" unset updateonstart - check_status.sh - # If server stopped. - if [ "${status}" == "0" ]; then - fn_update_dl - if [ "${localbuild}" == "0" ]; then - exitbypass=1 - command_start.sh - fn_firstcommand_reset - exitbypass=1 - fn_sleep_time_5 - command_stop.sh - fn_firstcommand_reset - fi - # If server started. - else - fn_print_restart_warning + fn_update_apply fn_update_dl + if [ "${updatestatus}" == "0" ] && [ "${localbuild}" == "0" ]; then exitbypass=1 - command_stop.sh + command_start.sh fn_firstcommand_reset exitbypass=1 - fn_update_dl - exitbypass=1 - command_start.sh + fn_sleep_time_5 + command_stop.sh fn_firstcommand_reset fi unset exitbypass diff --git a/lgsm/modules/update_mta.sh b/lgsm/modules/update_mta.sh index 35f7228efd..5adbc57ed7 100755 --- a/lgsm/modules/update_mta.sh +++ b/lgsm/modules/update_mta.sh @@ -98,31 +98,15 @@ fn_update_compare() { fn_script_log_info "${localbuild} > ${remotebuild}" if [ "${commandname}" == "UPDATE" ]; then - date +%s > "${lockdir:?}/last-updated.lock" unset updateonstart - check_status.sh - # If server stopped. - if [ "${status}" == "0" ]; then - fn_update_dl - if [ "${localbuild}" == "0" ]; then - exitbypass=1 - command_start.sh - fn_firstcommand_reset - exitbypass=1 - fn_sleep_time_5 - command_stop.sh - fn_firstcommand_reset - fi - # If server started. - else - fn_print_restart_warning + fn_update_apply fn_update_dl + if [ "${updatestatus}" == "0" ] && [ "${localbuild}" == "0" ]; then exitbypass=1 - command_stop.sh + command_start.sh fn_firstcommand_reset exitbypass=1 - fn_update_dl - exitbypass=1 - command_start.sh + fn_sleep_time_5 + command_stop.sh fn_firstcommand_reset fi unset exitbypass diff --git a/lgsm/modules/update_pmc.sh b/lgsm/modules/update_pmc.sh index 9273a567ab..907e32dbe0 100755 --- a/lgsm/modules/update_pmc.sh +++ b/lgsm/modules/update_pmc.sh @@ -116,31 +116,15 @@ fn_update_compare() { fn_script_log_info "${localbuild} > ${remotebuild}" if [ "${commandname}" == "UPDATE" ]; then - date +%s > "${lockdir:?}/last-updated.lock" unset updateonstart - check_status.sh - # If server stopped. - if [ "${status}" == "0" ]; then - fn_update_dl - if [ "${localbuild}" == "0" ]; then - exitbypass=1 - command_start.sh - fn_firstcommand_reset - exitbypass=1 - fn_sleep_time_5 - command_stop.sh - fn_firstcommand_reset - fi - # If server started. - else - fn_print_restart_warning + fn_update_apply fn_update_dl + if [ "${updatestatus}" == "0" ] && [ "${localbuild}" == "0" ]; then exitbypass=1 - command_stop.sh + command_start.sh fn_firstcommand_reset exitbypass=1 - fn_update_dl - exitbypass=1 - command_start.sh + fn_sleep_time_5 + command_stop.sh fn_firstcommand_reset fi unset exitbypass diff --git a/lgsm/modules/update_steamcmd.sh b/lgsm/modules/update_steamcmd.sh index ccc8d6b368..cedbf82070 100755 --- a/lgsm/modules/update_steamcmd.sh +++ b/lgsm/modules/update_steamcmd.sh @@ -18,21 +18,8 @@ fn_print_dots "${remotelocation}" if [ "${forceupdate}" == "1" ]; then # forceupdate bypasses update checks. - if [ "${status}" != "0" ] && [ -v "${status}" ]; then - fn_print_restart_warning - exitbypass=1 - command_stop.sh - fn_firstcommand_reset - date '+%s' > "${lockdir:?}/update.lock" - fn_dl_steamcmd - date +%s > "${lockdir}/last-updated.lock" - exitbypass=1 - command_start.sh - fn_firstcommand_reset - else - fn_dl_steamcmd - date +%s > "${lockdir}/last-updated.lock" - fi + date '+%s' > "${lockdir:?}/update.lock" + fn_update_apply fn_dl_steamcmd else fn_update_steamcmd_localbuild fn_update_steamcmd_remotebuild diff --git a/lgsm/modules/update_ts3.sh b/lgsm/modules/update_ts3.sh index ec3bc0060e..58ad872b25 100755 --- a/lgsm/modules/update_ts3.sh +++ b/lgsm/modules/update_ts3.sh @@ -97,31 +97,15 @@ fn_update_compare() { fn_script_log_info "${localbuild} > ${remotebuild}" if [ "${commandname}" == "UPDATE" ]; then - date +%s > "${lockdir:?}/last-updated.lock" unset updateonstart - check_status.sh - # If server stopped. - if [ "${status}" == "0" ]; then - fn_update_dl - if [ "${localbuild}" == "0" ]; then - exitbypass=1 - command_start.sh - fn_firstcommand_reset - exitbypass=1 - fn_sleep_time_5 - command_stop.sh - fn_firstcommand_reset - fi - # If server started. - else - fn_print_restart_warning + fn_update_apply fn_update_dl + if [ "${updatestatus}" == "0" ] && [ "${localbuild}" == "0" ]; then exitbypass=1 - command_stop.sh + command_start.sh fn_firstcommand_reset exitbypass=1 - fn_update_dl - exitbypass=1 - command_start.sh + fn_sleep_time_5 + command_stop.sh fn_firstcommand_reset fi unset exitbypass diff --git a/lgsm/modules/update_ut99.sh b/lgsm/modules/update_ut99.sh index 4e3f93b310..776a0a3cfa 100755 --- a/lgsm/modules/update_ut99.sh +++ b/lgsm/modules/update_ut99.sh @@ -91,31 +91,15 @@ fn_update_compare() { fn_script_log_info "${localbuild} > ${remotebuild}" if [ "${commandname}" == "UPDATE" ]; then - date +%s > "${lockdir:?}/last-updated.lock" unset updateonstart - check_status.sh - # If server stopped. - if [ "${status}" == "0" ]; then - fn_update_dl - if [ "${localbuild}" == "0" ]; then - exitbypass=1 - command_start.sh - fn_firstcommand_reset - exitbypass=1 - fn_sleep_time_5 - command_stop.sh - fn_firstcommand_reset - fi - # If server started. - else - fn_print_restart_warning + fn_update_apply fn_update_dl + if [ "${updatestatus}" == "0" ] && [ "${localbuild}" == "0" ]; then exitbypass=1 - command_stop.sh + command_start.sh fn_firstcommand_reset exitbypass=1 - fn_update_dl - exitbypass=1 - command_start.sh + fn_sleep_time_5 + command_stop.sh fn_firstcommand_reset fi unset exitbypass diff --git a/lgsm/modules/update_vints.sh b/lgsm/modules/update_vints.sh index d9480501a7..0925e6f801 100755 --- a/lgsm/modules/update_vints.sh +++ b/lgsm/modules/update_vints.sh @@ -102,31 +102,15 @@ fn_update_compare() { fn_script_log_info "${localbuild} > ${remotebuild}" if [ "${commandname}" == "UPDATE" ]; then - date +%s > "${lockdir:?}/last-updated.lock" unset updateonstart - check_status.sh - # If server stopped. - if [ "${status}" == "0" ]; then - fn_update_dl - if [ "${localbuild}" == "0" ]; then - exitbypass=1 - command_start.sh - fn_firstcommand_reset - exitbypass=1 - fn_sleep_time_5 - command_stop.sh - fn_firstcommand_reset - fi - # If server started. - else - fn_print_restart_warning + fn_update_apply fn_update_dl + if [ "${updatestatus}" == "0" ] && [ "${localbuild}" == "0" ]; then exitbypass=1 - command_stop.sh + command_start.sh fn_firstcommand_reset exitbypass=1 - fn_update_dl - exitbypass=1 - command_start.sh + fn_sleep_time_5 + command_stop.sh fn_firstcommand_reset fi unset exitbypass diff --git a/lgsm/modules/update_xnt.sh b/lgsm/modules/update_xnt.sh index e6f88cc274..831f63325e 100755 --- a/lgsm/modules/update_xnt.sh +++ b/lgsm/modules/update_xnt.sh @@ -111,31 +111,15 @@ fn_update_compare() { fn_script_log_info "${localbuild} > ${remotebuild}" if [ "${commandname}" == "UPDATE" ]; then - date +%s > "${lockdir:?}/last-updated.lock" unset updateonstart - check_status.sh - # If server stopped. - if [ "${status}" == "0" ]; then - fn_update_dl - if [ "${localbuild}" == "0" ]; then - exitbypass=1 - command_start.sh - fn_firstcommand_reset - exitbypass=1 - fn_sleep_time_5 - command_stop.sh - fn_firstcommand_reset - fi - # If server started. - else - fn_print_restart_warning + fn_update_apply fn_update_dl + if [ "${updatestatus}" == "0" ] && [ "${localbuild}" == "0" ]; then exitbypass=1 - command_stop.sh + command_start.sh fn_firstcommand_reset exitbypass=1 - fn_update_dl - exitbypass=1 - command_start.sh + fn_sleep_time_5 + command_stop.sh fn_firstcommand_reset fi unset exitbypass From 629c3178585dc2a0b06d2ce26f70c0fa180ac16f Mon Sep 17 00:00:00 2001 From: Daniel Gibbs Date: Fri, 16 Oct 2026 23:07:10 +0100 Subject: [PATCH 085/164] fix(monitor): recheck backup and update before restarting the server (#5057) Monitor checks for a running backup or update once near the start, but the query loop can then take about 155 s of wall time because gamedig timeouts are not counted towards the 60 s limit. A backup that starts in that window stops the server, the query fails, and monitor's restart brings the server back up while the backup is still archiving the files. Run the backup and update checks again right before every monitor triggered restart, in the query fail path and in the session checks, so monitor exits instead of restarting when a backup or update now holds its lock. This narrows the race from minutes to milliseconds; a full lock between commands is tracked separately. --- lgsm/modules/command_monitor.sh | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/lgsm/modules/command_monitor.sh b/lgsm/modules/command_monitor.sh index 887e194190..78690f9c4d 100755 --- a/lgsm/modules/command_monitor.sh +++ b/lgsm/modules/command_monitor.sh @@ -245,6 +245,11 @@ fn_monitor_check_update() { fi } +fn_monitor_check_backup_update() { + fn_monitor_check_backup + fn_monitor_check_update +} + # Source engine games may display a messages to indicate the server needs restarting. fn_monitor_check_update_source() { if [ -f "${consolelogdir}/${selfname}-console.log" ] && [ "${engine}" == "source" ]; then @@ -278,6 +283,7 @@ fn_monitor_check_session() { fn_script_log_error "Checking session: There are PIDS with identical tmux sessions running" fn_script_log_error "Checking session: Killing all tmux sessions with the socketname name ${socketname} and session name ${sessionname}" pkill -f "tmux -L ${socketname} new-session -d -x ${sessionwidth} -y ${sessionheight} -s ${sessionname}" + fn_monitor_check_backup_update command_restart.sh core_exit.sh # Check for tmux pids with the same tmux session and socket names. This will reduce issues with migration to release v23.5.0. #4296 @@ -288,6 +294,7 @@ fn_monitor_check_session() { fn_script_log_error "Checking session: PIDS with the same tmux session and socket names are running" fn_script_log_error "Checking session: Killing session with the socketname name ${sessionname} and session name ${sessionname}" pkill -f "^tmux -L ${sessionname} new-session -d -x ${sessionwidth} -y ${sessionheight} -s ${sessionname}( |$)" + fn_monitor_check_backup_update command_restart.sh core_exit.sh # Check for tmux pids that are using the old type of tmux session. This will reduce issues with migration to release v23.5.0. #4296 @@ -298,6 +305,7 @@ fn_monitor_check_session() { fn_script_log_error "Checking session: PIDS with old type tmux session are running" fn_script_log_error "Checking session: Killing session with the session name ${sessionname}" pkill -f "^tmux new-session -d -x ${sessionwidth} -y ${sessionheight} -s ${sessionname}( |$)" + fn_monitor_check_backup_update command_restart.sh core_exit.sh elif [ "${status}" != "0" ]; then @@ -312,6 +320,7 @@ fn_monitor_check_session() { fn_print_error "Checking session" fn_print_fail_eol_nl fn_script_log_fail "Checking session: FAIL" + fn_monitor_check_backup_update alert="monitor-session" alert.sh fn_script_log_info "Checking session: Monitor is restarting ${selfname}" @@ -423,6 +432,7 @@ fn_monitor_query() { fn_print_fail "Querying port: ${querymethod}: ${queryip}:${queryport} : ${totalseconds}/${queryattempt}" fn_print_fail_eol_nl fn_script_log_warn "Querying port: ${querymethod}: ${queryip}:${queryport} : ${queryattempt} : FAIL" + fn_monitor_check_backup_update # Send alert if enabled. alert="monitor-query" alert.sh From 907d2711543ad316ebd2d27aba86a7b0587e74b6 Mon Sep 17 00:00:00 2001 From: Daniel Gibbs Date: Fri, 16 Oct 2026 23:28:46 +0100 Subject: [PATCH 086/164] fix(triage): parse SteamCMD app_info and respect manual Linux labels (#5063) The Linux support check regex-matched the whole SteamCMD app_info dump, so the Steamworks SDK redistributable depots (1004-1006) counted as Linux server support and Windows-only servers were labelled "linux support confirmed". Parse the app_info VDF and decide from common.oslist, launch entries and the server's own depots, ignoring redistributable and shared install depots. The check also overwrote manual corrections of the Linux status labels on every issue event. If the last change to either label was made by a person, keep it and note the override in the check comment. --- .../action-issue-triage-automation.yml | 122 +++++++++++++++--- 1 file changed, 104 insertions(+), 18 deletions(-) diff --git a/.github/workflows/action-issue-triage-automation.yml b/.github/workflows/action-issue-triage-automation.yml index f98cb91055..e2bc135af4 100644 --- a/.github/workflows/action-issue-triage-automation.yml +++ b/.github/workflows/action-issue-triage-automation.yml @@ -236,6 +236,38 @@ jobs: return false; } + function parseVdf(text) { + const root = {}; + const stack = [root]; + let pendingKey = null; + const tokenPattern = /"((?:[^"\\]|\\.)*)"|([{}])/g; + let match; + while ((match = tokenPattern.exec(text)) !== null) { + const current = stack[stack.length - 1]; + if (match[2] === '{') { + const child = {}; + if (pendingKey !== null) current[pendingKey] = child; + stack.push(child); + pendingKey = null; + } else if (match[2] === '}') { + if (stack.length > 1) stack.pop(); + pendingKey = null; + } else if (pendingKey === null) { + pendingKey = match[1]; + } else { + current[pendingKey] = match[1]; + pendingKey = null; + } + } + return root; + } + + function parseSteamAppInfo(output, appId) { + const start = output.search(new RegExp(`^"${appId}"\\s*$`, 'm')); + if (start === -1) return null; + return parseVdf(output.slice(start))[String(appId)] ?? null; + } + function runSteamCmdLinuxCheck(appId) { if (!appId) { return { status: 'skipped', reason: 'No Steam AppID provided.' }; @@ -271,23 +303,44 @@ jobs: maxBuffer: 10 * 1024 * 1024, }); - const normalized = output.toLowerCase(); - const linuxSignals = [ - /"oslist"\s+"linux"/i, - /"oslist"\s+"linux,windows"/i, - /"oslist"\s+"windows,linux"/i, - /"platforms"[\s\S]*?"linux"\s+"1"/i, - /linux32/i, - /linux64/i, - ]; - const windowsOnlySignals = [ - /"oslist"\s+"windows"/i, - /"platforms"[\s\S]*?"windows"\s+"1"/i, - ]; - - const hasLinuxSignal = linuxSignals.some((re) => re.test(normalized)); + const appInfo = parseSteamAppInfo(output, appId); + if (!appInfo) { + return { + status: 'unknown', + reason: `SteamCMD app_info returned no data for AppID ${appId}.`, + }; + } + + const osListOf = (node) => String(node?.config?.oslist ?? '').toLowerCase(); + const isObject = (value) => value && typeof value === 'object'; + const commonOsList = String(appInfo.common?.oslist ?? '').toLowerCase(); + const launches = Object.values(appInfo.config?.launch ?? {}).filter(isObject); + const serverDepots = Object.entries(appInfo.depots ?? {}).filter( + ([id, depot]) => + /^\d+$/.test(id) && + isObject(depot) && + !['1004', '1005', '1006'].includes(id) && + depot.depotfromapp === undefined && + depot.sharedinstall !== '1' + ); + + const hasLinuxSignal = + commonOsList.includes('linux') || + launches.some( + (launch) => + osListOf(launch).includes('linux') || + (!osListOf(launch) && /\.(sh|x86_64)$/i.test(launch.executable ?? '')) + ) || + serverDepots.some(([, depot]) => osListOf(depot).includes('linux')); const hasWindowsOnlySignal = - !hasLinuxSignal && windowsOnlySignals.some((re) => re.test(normalized)); + !hasLinuxSignal && + (commonOsList === 'windows' || + (launches.length > 0 && + launches.every( + (launch) => + osListOf(launch) === 'windows' || + /\.(exe|bat|cmd)$/i.test(launch.executable ?? '') + ))); if (hasLinuxSignal) { return { @@ -1010,8 +1063,36 @@ jobs: const CONFIRMED_LINUX_LABEL = 'status: linux support confirmed'; const LINUX_MARKER = ''; const steamDbLink = steamAppId ? `https://steamdb.info/app/${steamAppId}/` : null; - const shouldApplyNoLinuxLabel = confirmedNoLinux || suggestsNoLinux; - const shouldApplyConfirmedLinuxLabel = confirmedLinuxSupport && !confirmedNoLinux && !suggestsNoLinux; + + let linuxLabelOverrideBy = null; + try { + const issueEvents = await github.paginate(github.rest.issues.listEvents, { + owner, + repo, + issue_number: issueNumber, + per_page: 100, + }); + const lastLinuxLabelEvent = issueEvents + .filter( + (e) => + ['labeled', 'unlabeled'].includes(e.event) && + [NO_LINUX_LABEL, CONFIRMED_LINUX_LABEL].includes(e.label?.name) + ) + .at(-1); + if (lastLinuxLabelEvent && lastLinuxLabelEvent.actor?.type !== 'Bot') { + linuxLabelOverrideBy = lastLinuxLabelEvent.actor?.login ?? 'a maintainer'; + console.log(`Linux support label last set by ${linuxLabelOverrideBy}; keeping it.`); + } + } catch (err) { + console.log(`Could not read issue events: ${err.message}`); + } + + const shouldApplyNoLinuxLabel = linuxLabelOverrideBy + ? existingLabels.has(NO_LINUX_LABEL) + : confirmedNoLinux || suggestsNoLinux; + const shouldApplyConfirmedLinuxLabel = linuxLabelOverrideBy + ? existingLabels.has(CONFIRMED_LINUX_LABEL) && !existingLabels.has(NO_LINUX_LABEL) + : confirmedLinuxSupport && !confirmedNoLinux && !suggestsNoLinux; if (shouldApplyNoLinuxLabel) { // Auto-create the label if it does not exist yet. @@ -1162,9 +1243,14 @@ jobs: ? `**Label applied:** ${CONFIRMED_LINUX_LABEL}\n\n` : ''; + const overrideBlock = linuxLabelOverrideBy + ? `**Maintainer override:** the Linux support label was set manually by @${linuxLabelOverrideBy} and is no longer changed automatically.\n\n` + : ''; + const linuxCommentBody = `${LINUX_MARKER}\n` + `${linuxCommentHeader}\n\n` + + `${overrideBlock}` + `${verdictLine}\n\n` + `${confirmedLinuxLabelBlock}` + `${steamBlock}` + From 042193863ce971a279b3fb6a6425f358f88b0aa5 Mon Sep 17 00:00:00 2001 From: Daniel Gibbs Date: Fri, 16 Oct 2026 23:33:30 +0100 Subject: [PATCH 087/164] fix(triage): parse SteamCMD app_info and respect manual Linux labels (#5063) (#5064) The Linux support check regex-matched the whole SteamCMD app_info dump, so the Steamworks SDK redistributable depots (1004-1006) counted as Linux server support and Windows-only servers were labelled "linux support confirmed". Parse the app_info VDF and decide from common.oslist, launch entries and the server's own depots, ignoring redistributable and shared install depots. The check also overwrote manual corrections of the Linux status labels on every issue event. If the last change to either label was made by a person, keep it and note the override in the check comment. --- .../action-issue-triage-automation.yml | 122 +++++++++++++++--- 1 file changed, 104 insertions(+), 18 deletions(-) diff --git a/.github/workflows/action-issue-triage-automation.yml b/.github/workflows/action-issue-triage-automation.yml index 1e644ea468..16b7034ae6 100644 --- a/.github/workflows/action-issue-triage-automation.yml +++ b/.github/workflows/action-issue-triage-automation.yml @@ -236,6 +236,38 @@ jobs: return false; } + function parseVdf(text) { + const root = {}; + const stack = [root]; + let pendingKey = null; + const tokenPattern = /"((?:[^"\\]|\\.)*)"|([{}])/g; + let match; + while ((match = tokenPattern.exec(text)) !== null) { + const current = stack[stack.length - 1]; + if (match[2] === '{') { + const child = {}; + if (pendingKey !== null) current[pendingKey] = child; + stack.push(child); + pendingKey = null; + } else if (match[2] === '}') { + if (stack.length > 1) stack.pop(); + pendingKey = null; + } else if (pendingKey === null) { + pendingKey = match[1]; + } else { + current[pendingKey] = match[1]; + pendingKey = null; + } + } + return root; + } + + function parseSteamAppInfo(output, appId) { + const start = output.search(new RegExp(`^"${appId}"\\s*$`, 'm')); + if (start === -1) return null; + return parseVdf(output.slice(start))[String(appId)] ?? null; + } + function runSteamCmdLinuxCheck(appId) { if (!appId) { return { status: 'skipped', reason: 'No Steam AppID provided.' }; @@ -271,23 +303,44 @@ jobs: maxBuffer: 10 * 1024 * 1024, }); - const normalized = output.toLowerCase(); - const linuxSignals = [ - /"oslist"\s+"linux"/i, - /"oslist"\s+"linux,windows"/i, - /"oslist"\s+"windows,linux"/i, - /"platforms"[\s\S]*?"linux"\s+"1"/i, - /linux32/i, - /linux64/i, - ]; - const windowsOnlySignals = [ - /"oslist"\s+"windows"/i, - /"platforms"[\s\S]*?"windows"\s+"1"/i, - ]; - - const hasLinuxSignal = linuxSignals.some((re) => re.test(normalized)); + const appInfo = parseSteamAppInfo(output, appId); + if (!appInfo) { + return { + status: 'unknown', + reason: `SteamCMD app_info returned no data for AppID ${appId}.`, + }; + } + + const osListOf = (node) => String(node?.config?.oslist ?? '').toLowerCase(); + const isObject = (value) => value && typeof value === 'object'; + const commonOsList = String(appInfo.common?.oslist ?? '').toLowerCase(); + const launches = Object.values(appInfo.config?.launch ?? {}).filter(isObject); + const serverDepots = Object.entries(appInfo.depots ?? {}).filter( + ([id, depot]) => + /^\d+$/.test(id) && + isObject(depot) && + !['1004', '1005', '1006'].includes(id) && + depot.depotfromapp === undefined && + depot.sharedinstall !== '1' + ); + + const hasLinuxSignal = + commonOsList.includes('linux') || + launches.some( + (launch) => + osListOf(launch).includes('linux') || + (!osListOf(launch) && /\.(sh|x86_64)$/i.test(launch.executable ?? '')) + ) || + serverDepots.some(([, depot]) => osListOf(depot).includes('linux')); const hasWindowsOnlySignal = - !hasLinuxSignal && windowsOnlySignals.some((re) => re.test(normalized)); + !hasLinuxSignal && + (commonOsList === 'windows' || + (launches.length > 0 && + launches.every( + (launch) => + osListOf(launch) === 'windows' || + /\.(exe|bat|cmd)$/i.test(launch.executable ?? '') + ))); if (hasLinuxSignal) { return { @@ -1010,8 +1063,36 @@ jobs: const CONFIRMED_LINUX_LABEL = 'status: linux support confirmed'; const LINUX_MARKER = ''; const steamDbLink = steamAppId ? `https://steamdb.info/app/${steamAppId}/` : null; - const shouldApplyNoLinuxLabel = confirmedNoLinux || suggestsNoLinux; - const shouldApplyConfirmedLinuxLabel = confirmedLinuxSupport && !confirmedNoLinux && !suggestsNoLinux; + + let linuxLabelOverrideBy = null; + try { + const issueEvents = await github.paginate(github.rest.issues.listEvents, { + owner, + repo, + issue_number: issueNumber, + per_page: 100, + }); + const lastLinuxLabelEvent = issueEvents + .filter( + (e) => + ['labeled', 'unlabeled'].includes(e.event) && + [NO_LINUX_LABEL, CONFIRMED_LINUX_LABEL].includes(e.label?.name) + ) + .at(-1); + if (lastLinuxLabelEvent && lastLinuxLabelEvent.actor?.type !== 'Bot') { + linuxLabelOverrideBy = lastLinuxLabelEvent.actor?.login ?? 'a maintainer'; + console.log(`Linux support label last set by ${linuxLabelOverrideBy}; keeping it.`); + } + } catch (err) { + console.log(`Could not read issue events: ${err.message}`); + } + + const shouldApplyNoLinuxLabel = linuxLabelOverrideBy + ? existingLabels.has(NO_LINUX_LABEL) + : confirmedNoLinux || suggestsNoLinux; + const shouldApplyConfirmedLinuxLabel = linuxLabelOverrideBy + ? existingLabels.has(CONFIRMED_LINUX_LABEL) && !existingLabels.has(NO_LINUX_LABEL) + : confirmedLinuxSupport && !confirmedNoLinux && !suggestsNoLinux; if (shouldApplyNoLinuxLabel) { // Auto-create the label if it does not exist yet. @@ -1162,9 +1243,14 @@ jobs: ? `**Label applied:** ${CONFIRMED_LINUX_LABEL}\n\n` : ''; + const overrideBlock = linuxLabelOverrideBy + ? `**Maintainer override:** the Linux support label was set manually by @${linuxLabelOverrideBy} and is no longer changed automatically.\n\n` + : ''; + const linuxCommentBody = `${LINUX_MARKER}\n` + `${linuxCommentHeader}\n\n` + + `${overrideBlock}` + `${verdictLine}\n\n` + `${confirmedLinuxLabelBlock}` + `${steamBlock}` + From daad25241b07ddcc1fc24a39665f3db846f1643e Mon Sep 17 00:00:00 2001 From: Daniel Gibbs Date: Fri, 16 Oct 2026 23:40:37 +0100 Subject: [PATCH 088/164] fix(triage): match Linux check verdict to a maintainer-set label (#5065) When a maintainer has set the Linux support label manually, the check comment kept printing the automatic verdict, which could contradict the label (e.g. "does not appear to have native Linux support" alongside "linux support confirmed"). Derive the verdict from the kept label in that case; the automatic evidence list is unchanged. --- .github/workflows/action-issue-triage-automation.yml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/.github/workflows/action-issue-triage-automation.yml b/.github/workflows/action-issue-triage-automation.yml index e2bc135af4..55aa891099 100644 --- a/.github/workflows/action-issue-triage-automation.yml +++ b/.github/workflows/action-issue-triage-automation.yml @@ -1188,7 +1188,11 @@ jobs: if (likelySupportedByCheckbox) reasons.push('requester confirmed Linux support via the form checkbox; no contradicting evidence found'); let verdictLine = 'Linux support could not be confirmed automatically from the submitted details.'; - if (confirmedNoLinux) { + if (linuxLabelOverrideBy && shouldApplyNoLinuxLabel) { + verdictLine = 'A maintainer has confirmed this server has no native Linux support.'; + } else if (linuxLabelOverrideBy && shouldApplyConfirmedLinuxLabel) { + verdictLine = 'A maintainer has confirmed native Linux support.'; + } else if (confirmedNoLinux) { verdictLine = 'This server request does **not** appear to have native Linux support, which is required for LinuxGSM.'; } else if (suggestsNoLinux) { verdictLine = 'This server request **may not** have native Linux support based on submitted evidence.'; From f71b0dae66f95b33edbfad65b673f5bfdcc370f3 Mon Sep 17 00:00:00 2001 From: Daniel Gibbs Date: Fri, 16 Oct 2026 23:40:41 +0100 Subject: [PATCH 089/164] fix(triage): match Linux check verdict to a maintainer-set label (#5066) When a maintainer has set the Linux support label manually, the check comment kept printing the automatic verdict, which could contradict the label (e.g. "does not appear to have native Linux support" alongside "linux support confirmed"). Derive the verdict from the kept label in that case; the automatic evidence list is unchanged. (cherry picked from commit 63fce3dd4d0627a8c725e32b5c365d654186ca00) --- .github/workflows/action-issue-triage-automation.yml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/.github/workflows/action-issue-triage-automation.yml b/.github/workflows/action-issue-triage-automation.yml index 16b7034ae6..9c4f23fab2 100644 --- a/.github/workflows/action-issue-triage-automation.yml +++ b/.github/workflows/action-issue-triage-automation.yml @@ -1188,7 +1188,11 @@ jobs: if (likelySupportedByCheckbox) reasons.push('requester confirmed Linux support via the form checkbox; no contradicting evidence found'); let verdictLine = 'Linux support could not be confirmed automatically from the submitted details.'; - if (confirmedNoLinux) { + if (linuxLabelOverrideBy && shouldApplyNoLinuxLabel) { + verdictLine = 'A maintainer has confirmed this server has no native Linux support.'; + } else if (linuxLabelOverrideBy && shouldApplyConfirmedLinuxLabel) { + verdictLine = 'A maintainer has confirmed native Linux support.'; + } else if (confirmedNoLinux) { verdictLine = 'This server request does **not** appear to have native Linux support, which is required for LinuxGSM.'; } else if (suggestsNoLinux) { verdictLine = 'This server request **may not** have native Linux support based on submitted evidence.'; From 1a37fe9e6d1dee770c0afe1cfbeae18704a14e0d Mon Sep 17 00:00:00 2001 From: Daniel Gibbs Date: Sat, 17 Oct 2026 00:30:18 +0100 Subject: [PATCH 090/164] fix(permissions): accept files accessible through groups or ACLs (#5067) The ownership check rejected any file not owned by the current user, even when group permissions or ACLs granted full access. Only report files the user neither owns nor can read and write, and skip the rootdir and executable checks when access is already available. Fixes #3861 --- lgsm/modules/check_permissions.sh | 53 ++++++++++++------------------- 1 file changed, 20 insertions(+), 33 deletions(-) diff --git a/lgsm/modules/check_permissions.sh b/lgsm/modules/check_permissions.sh index 3dc521da7a..75eb45bb83 100755 --- a/lgsm/modules/check_permissions.sh +++ b/lgsm/modules/check_permissions.sh @@ -7,44 +7,31 @@ moduleselfname="$(basename "$(readlink -f "${BASH_SOURCE[0]}")")" +# Lists files the current user neither owns nor can access. +fn_find_ownership_issues() { + find "$@" -not -user "$(whoami)" \( -not -readable -o -not -writable -o \( -type d -not -executable \) \) -printf "%u\t%g\t%M\t%p\n" +} + fn_check_ownership() { - if [ -f "${rootdir}/${selfname}" ]; then - if [ "$(find "${rootdir}/${selfname}" -not -user "$(whoami)" | wc -l)" -ne "0" ]; then - selfownissue=1 - fi - fi - if [ -d "${lgsmdir}" ]; then - if [ "$(find "${lgsmdir}" -not -user "$(whoami)" | wc -l)" -ne "0" ]; then - lgsmownissue=1 + ownershipissues="$( + if [ -f "${rootdir}/${selfname}" ]; then + fn_find_ownership_issues "${rootdir}/${selfname}" fi - fi - if [ -d "${modulesdir}" ]; then - if [ "$(find "${modulesdir}" -not -name '*.swp' -not -user "$(whoami)" | wc -l)" -ne "0" ]; then - funcownissue=1 + if [ -d "${lgsmdir}" ]; then + fn_find_ownership_issues "${lgsmdir}" -not -name '*.swp' fi - fi - if [ -d "${serverfiles}" ]; then - if [ "$(find "${serverfiles}" -not -path "*/steamapps/compatdata/*" -not -name '*.swp' -not -user "$(whoami)" | wc -l)" -ne "0" ]; then - filesownissue=1 + if [ -d "${serverfiles}" ]; then + fn_find_ownership_issues "${serverfiles}" -not -path "*/steamapps/compatdata/*" -not -name '*.swp' fi - fi - if [ "${selfownissue}" == "1" ] || [ "${lgsmownissue}" == "1" ] || [ "${filesownissue}" == "1" ]; then + )" + if [ -n "${ownershipissues}" ]; then fn_print_fail_nl "Ownership issues found" fn_script_log_fail "Ownership issues found" - fn_print_information_nl "The current user ($(whoami)) does not have ownership of the following files:" - fn_script_log_info "The current user ($(whoami)) does not have ownership of the following files:" + fn_print_information_nl "The current user ($(whoami)) does not own and cannot access the following files:" + fn_script_log_info "The current user ($(whoami)) does not own and cannot access the following files:" { - echo -en "User\tGroup\tFile:" - if [ "${selfownissue}" == "1" ]; then - find "${rootdir}/${selfname}" -not -user "$(whoami)" -printf "%u\t%g\t%p\n" - fi - if [ "${lgsmownissue}" == "1" ]; then - find "${lgsmdir}" -not -user "$(whoami)" -printf "%u\t%g\t%p\n" - fi - if [ "${filesownissue}" == "1" ]; then - find "${serverfiles}" -not -path "*/steamapps/compatdata/*" -not -user "$(whoami)" -printf "%u\t%g\t%p\n" - fi - + echo -e "User\tGroup\tMode\tFile" + echo "${ownershipissues}" } | column -s $'\t' -t | tee -a "${lgsmlog}" echo -e "" fn_print_information_nl "please see https://docs.linuxgsm.com/support/faq#fail-starting-game-server-permission-issues-found" @@ -102,7 +89,7 @@ fn_check_permissions() { # Grab the first and second digit for user and group permission. userrootdirperm="${rootdirperm:0:1}" grouprootdirperm="${rootdirperm:1:1}" - if [ "${userrootdirperm}" != "7" ] && [ "${grouprootdirperm}" != "7" ]; then + if [ "${userrootdirperm}" != "7" ] && [ "${grouprootdirperm}" != "7" ] && { [ ! -r "${rootdir}" ] || [ ! -w "${rootdir}" ] || [ ! -x "${rootdir}" ]; }; then fn_print_fail_nl "Permissions issues found" fn_script_log_fail "Permissions issues found" fn_print_information_nl "The following directory does not have the correct permissions:" @@ -120,7 +107,7 @@ fn_check_permissions() { # Check if executable is executable and attempt to fix it. # First get executable name. execname=$(basename "${executable}") - if [ -f "${executabledir}/${execname}" ]; then + if [ -f "${executabledir}/${execname}" ] && [ ! -x "${executabledir}/${execname}" ]; then # Get permission numbers on file under the form 775. execperm=$(stat -c %a "${executabledir}/${execname}") # Grab the first and second digit for user and group permission. From 931509fe77d7a965f6b3fa7a460c241a6d25d9be Mon Sep 17 00:00:00 2001 From: Daniel Gibbs Date: Sat, 17 Oct 2026 12:50:52 +0100 Subject: [PATCH 091/164] fix(security): download linuxgsm.download files over HTTPS (#5070) Switch the md5-pinned linuxgsm.download tarballs from http:// to https://. fn_dl_hash already aborts on a checksum mismatch, so this is defence-in-depth and consistency with #5054, not a vulnerability fix. fn_fetch_file adds --proto-redir "=https" for https URLs, so a downloaded file cannot be redirected back to http. --- lgsm/modules/fix_bf1942.sh | 2 +- lgsm/modules/fix_bfv.sh | 2 +- lgsm/modules/install_server_files.sh | 50 ++++++++++++++-------------- 3 files changed, 27 insertions(+), 27 deletions(-) diff --git a/lgsm/modules/fix_bf1942.sh b/lgsm/modules/fix_bf1942.sh index 2993d55ed2..918d81a5e4 100755 --- a/lgsm/modules/fix_bf1942.sh +++ b/lgsm/modules/fix_bf1942.sh @@ -14,7 +14,7 @@ if ldd "${executabledir}/bf1942_lnxded.static" 2>&1 | grep -qE "lib(ncurses|tinf # shellcheck disable=SC2034 # Used by fn_fix_msg_start_nl and fn_fix_msg_end. fixname="libncurses5 i386" fn_fix_msg_start_nl - fn_fetch_file "http://linuxgsm.download/libraries/libncurses5-i386-6.3-2ubuntu0.3.tar.xz" "" "" "" "${tmpdir}" "libncurses5-i386-6.3-2ubuntu0.3.tar.xz" "nochmodx" "norun" "noforce" "ee141cb3a843e4201786b6f188347666" + fn_fetch_file "https://linuxgsm.download/libraries/libncurses5-i386-6.3-2ubuntu0.3.tar.xz" "" "" "" "${tmpdir}" "libncurses5-i386-6.3-2ubuntu0.3.tar.xz" "nochmodx" "norun" "noforce" "ee141cb3a843e4201786b6f188347666" fn_dl_extract "${tmpdir}" "libncurses5-i386-6.3-2ubuntu0.3.tar.xz" "${serverfiles}" fn_clear_tmp fn_fix_msg_end diff --git a/lgsm/modules/fix_bfv.sh b/lgsm/modules/fix_bfv.sh index 5397d6e69f..dbd10082e4 100755 --- a/lgsm/modules/fix_bfv.sh +++ b/lgsm/modules/fix_bfv.sh @@ -14,7 +14,7 @@ if ldd "${executabledir}/bfv_linded.static" 2>&1 | grep -qE "lib(ncurses|tinfo)\ # shellcheck disable=SC2034 # Used by fn_fix_msg_start_nl and fn_fix_msg_end. fixname="libncurses5 i386" fn_fix_msg_start_nl - fn_fetch_file "http://linuxgsm.download/libraries/libncurses5-i386-6.3-2ubuntu0.3.tar.xz" "" "" "" "${tmpdir}" "libncurses5-i386-6.3-2ubuntu0.3.tar.xz" "nochmodx" "norun" "noforce" "ee141cb3a843e4201786b6f188347666" + fn_fetch_file "https://linuxgsm.download/libraries/libncurses5-i386-6.3-2ubuntu0.3.tar.xz" "" "" "" "${tmpdir}" "libncurses5-i386-6.3-2ubuntu0.3.tar.xz" "nochmodx" "norun" "noforce" "ee141cb3a843e4201786b6f188347666" fn_dl_extract "${tmpdir}" "libncurses5-i386-6.3-2ubuntu0.3.tar.xz" "${serverfiles}" fn_clear_tmp fn_fix_msg_end diff --git a/lgsm/modules/install_server_files.sh b/lgsm/modules/install_server_files.sh index a7550cf784..11f5dca4cb 100755 --- a/lgsm/modules/install_server_files.sh +++ b/lgsm/modules/install_server_files.sh @@ -9,7 +9,7 @@ moduleselfname="$(basename "$(readlink -f "${BASH_SOURCE[0]}")")" fn_install_server_files() { if [ "${shortname}" == "ahl" ]; then - remote_fileurl="http://linuxgsm.download/ActionHalfLife/action_halflife-1.0.tar.xz" + remote_fileurl="https://linuxgsm.download/ActionHalfLife/action_halflife-1.0.tar.xz" local_filedir="${tmpdir}" local_filename="action_halflife-1.0.tar.xz" chmodx="nochmodx" @@ -17,7 +17,7 @@ fn_install_server_files() { force="noforce" md5="61d7b79fd714888b6d65944fdaafa94a" elif [ "${shortname}" == "bf1942" ]; then - remote_fileurl="http://linuxgsm.download/BattleField1942/bf1942_lnxded-1.61-hacked-to-1.612.full-linuxgsm.tar.xz" + remote_fileurl="https://linuxgsm.download/BattleField1942/bf1942_lnxded-1.61-hacked-to-1.612.full-linuxgsm.tar.xz" local_filedir="${tmpdir}" local_filename="bf1942_lnxded-1.61-hacked-to-1.612.full-linuxgsm.tar.xz" chmodx="nochmodx" @@ -25,7 +25,7 @@ fn_install_server_files() { force="noforce" md5="d58016b3c45f86a71bb56c39749ce941" elif [ "${shortname}" == "bfv" ]; then - remote_fileurl="http://linuxgsm.download/BattlefieldVietnam/bfv_linded-v1.21-20041207_patch-linuxgsm.tar.xz" + remote_fileurl="https://linuxgsm.download/BattlefieldVietnam/bfv_linded-v1.21-20041207_patch-linuxgsm.tar.xz" local_filedir="${tmpdir}" local_filename="bfv_linded-v1.21-20041207_patch-linuxgsm.tar.xz" chmodx="nochmodx" @@ -34,7 +34,7 @@ fn_install_server_files() { md5="9a8117732b8abd99cc59f1f0fa92adfa" elif [ "${shortname}" == "cod" ]; then - remote_fileurl="http://linuxgsm.download/CallOfDuty/cod-lnxded-1.5b-full.tar.xz" + remote_fileurl="https://linuxgsm.download/CallOfDuty/cod-lnxded-1.5b-full.tar.xz" local_filedir="${tmpdir}" local_filename="cod-lnxded-1.5-large.tar.xz" chmodx="nochmodx" @@ -42,7 +42,7 @@ fn_install_server_files() { force="noforce" md5="ee0ad1ccbfa1fd27fde01a4a431a5c2f" elif [ "${shortname}" == "coduo" ]; then - remote_fileurl="http://linuxgsm.download/CallOfDutyUnitedOffensive/coduo-lnxded-1.51b-full.tar.xz" + remote_fileurl="https://linuxgsm.download/CallOfDutyUnitedOffensive/coduo-lnxded-1.51b-full.tar.xz" local_filedir="${tmpdir}" local_filename="coduo-lnxded-1.51b-full.tar.xz" chmodx="nochmodx" @@ -50,7 +50,7 @@ fn_install_server_files() { force="noforce" md5="35cabccd67adcda44aaebc59405915b9" elif [ "${shortname}" == "cod2" ]; then - remote_fileurl="http://linuxgsm.download/CallOfDuty2/cod2-lnxded-1.3-full.tar.xz" + remote_fileurl="https://linuxgsm.download/CallOfDuty2/cod2-lnxded-1.3-full.tar.xz" local_filedir="${tmpdir}" local_filename="cod2-lnxded-1.3-full.tar.xz" chmodx="nochmodx" @@ -58,7 +58,7 @@ fn_install_server_files() { force="noforce" md5="b8c4c611f01627dd43348e78478a3d41" elif [ "${shortname}" == "cod4" ]; then - remote_fileurl="http://linuxgsm.download/CallOfDuty4/cod4x18_lnxded.tar.xz" + remote_fileurl="https://linuxgsm.download/CallOfDuty4/cod4x18_lnxded.tar.xz" local_filedir="${tmpdir}" local_filename="cod4x18_lnxded.tar.xz" chmodx="nochmodx" @@ -66,7 +66,7 @@ fn_install_server_files() { force="noforce" md5="d255b59b9756d7dbead67718208512ee" elif [ "${shortname}" == "codwaw" ]; then - remote_fileurl="http://linuxgsm.download/CallOfDutyWorldAtWar/codwaw-lnxded-1.7-full.tar.xz" + remote_fileurl="https://linuxgsm.download/CallOfDutyWorldAtWar/codwaw-lnxded-1.7-full.tar.xz" local_filedir="${tmpdir}" local_filename="codwaw-lnxded-1.7-full.tar.xz" chmodx="nochmodx" @@ -74,7 +74,7 @@ fn_install_server_files() { force="noforce" md5="2c6be1bb66ea631b9b2e7ae6216c6680" elif [ "${shortname}" == "mohaa" ]; then - remote_fileurl="http://linuxgsm.download/MedalofHonorAlliedAssault/moh_revival_v1.12_RC3.5.1.tar.xz" + remote_fileurl="https://linuxgsm.download/MedalofHonorAlliedAssault/moh_revival_v1.12_RC3.5.1.tar.xz" local_filedir="${tmpdir}" local_filename="moh_revival_v1.12_RC3.5.1.tar.xz" chmodx="nochmodx" @@ -82,7 +82,7 @@ fn_install_server_files() { force="noforce" md5="7c664538999252eeaf2b6d9949416480" elif [ "${shortname}" == "ns" ]; then - remote_fileurl="http://linuxgsm.download/NaturalSelection/ns_dedicated_server_v32.tar.xz" + remote_fileurl="https://linuxgsm.download/NaturalSelection/ns_dedicated_server_v32.tar.xz" local_filedir="${tmpdir}" local_filename="ns_dedicated_server_v32.tar.xz" chmodx="nochmodx" @@ -90,7 +90,7 @@ fn_install_server_files() { force="noforce" md5="23ec3cadd93d8bb1c475bad5b9cce370" elif [ "${shortname}" == "q2" ]; then - remote_fileurl="http://linuxgsm.download/Quake2/quake2-3.20-glibc-i386-full-linux2.0.tar.xz" + remote_fileurl="https://linuxgsm.download/Quake2/quake2-3.20-glibc-i386-full-linux2.0.tar.xz" local_filedir="${tmpdir}" local_filename="quake2-3.20-glibc-i386-full-linux2.0.tar.xz" chmodx="nochmodx" @@ -98,7 +98,7 @@ fn_install_server_files() { force="noforce" md5="2908164a32d4808bb720f2161f6b0c82" elif [ "${shortname}" == "q3" ]; then - remote_fileurl="http://linuxgsm.download/Quake3/quake3-1.32c-x86-full-linux.tar.xz" + remote_fileurl="https://linuxgsm.download/Quake3/quake3-1.32c-x86-full-linux.tar.xz" local_filedir="${tmpdir}" local_filename="quake3-1.32c-x86-full-linux.tar.xz" chmodx="nochmodx" @@ -106,7 +106,7 @@ fn_install_server_files() { force="noforce" md5="b0e26d8919fe9313fb9d8ded2360f3db" elif [ "${shortname}" == "q4" ]; then - remote_fileurl="http://linuxgsm.download/Quake4/quake4-1.4.2-x86-linuxded.tar.xz" + remote_fileurl="https://linuxgsm.download/Quake4/quake4-1.4.2-x86-linuxded.tar.xz" local_filedir="${tmpdir}" local_filename="quake4-1.4.2-x86-linuxded.tar.xz" chmodx="nochmodx" @@ -114,7 +114,7 @@ fn_install_server_files() { force="noforce" md5="afe30b44f23c8ae2ce6f0f464473d8ba" elif [ "${shortname}" == "qw" ]; then - remote_fileurl="http://linuxgsm.download/QuakeWorld/nquake.server.linux.190506.full.tar.xz" + remote_fileurl="https://linuxgsm.download/QuakeWorld/nquake.server.linux.190506.full.tar.xz" local_filedir="${tmpdir}" local_filename="nquake.server.linux.190506.full.tar.xz" chmodx="nochmodx" @@ -122,7 +122,7 @@ fn_install_server_files() { force="noforce" md5="82055b7d973206c13a606db8ba288d03" elif [ "${shortname}" == "rtcw" ]; then - remote_fileurl="http://linuxgsm.download/ReturnToCastleWolfenstein/iortcw-1.51c-x86_64-server-linux-20190507.tar.xz" + remote_fileurl="https://linuxgsm.download/ReturnToCastleWolfenstein/iortcw-1.51c-x86_64-server-linux-20190507.tar.xz" local_filedir="${tmpdir}" local_filename="iortcw-1.51c-x86_64-server-linux-20190507.tar.xz" chmodx="nochmodx" @@ -130,7 +130,7 @@ fn_install_server_files() { force="noforce" md5="df6ff664d37dd0d22787848bdb3cac5f" elif [ "${shortname}" == "sfc" ]; then - remote_fileurl="http://linuxgsm.download/SourceFortsClassic/SFClassic-1.0-RC7-fix.tar.xz" + remote_fileurl="https://linuxgsm.download/SourceFortsClassic/SFClassic-1.0-RC7-fix.tar.xz" local_filedir="${tmpdir}" local_filename="SFClassic-1.0-RC7-fix.tar.xz" chmodx="nochmodx" @@ -138,7 +138,7 @@ fn_install_server_files() { force="noforce" md5="70077137185700e28fe6bbb6021d12bc" elif [ "${shortname}" == "sof2" ]; then - remote_fileurl="http://linuxgsm.download/SoldierOfFortune2/sof2gold-1.03.tar.xz" + remote_fileurl="https://linuxgsm.download/SoldierOfFortune2/sof2gold-1.03.tar.xz" local_filedir="${tmpdir}" local_filename="sof2gold-1.03.tar.xz" chmodx="nochmodx" @@ -146,7 +146,7 @@ fn_install_server_files() { force="noforce" md5="201e23bab04207d00ce813d001c483d9" elif [ "${shortname}" == "ts" ]; then - remote_fileurl="http://linuxgsm.download/TheSpecialists/ts-3-linux-final.tar.xz" + remote_fileurl="https://linuxgsm.download/TheSpecialists/ts-3-linux-final.tar.xz" local_filedir="${tmpdir}" local_filename="ts-3-linux-final.tar.xz" chmodx="nochmodx" @@ -154,7 +154,7 @@ fn_install_server_files() { force="noforce" md5="3c66ecff6e3644f7ac88015732a0fb93" elif [ "${shortname}" == "ut2k4" ]; then - remote_fileurl="http://linuxgsm.download/UnrealTournament2004/ut2004-server-3369-3-ultimate-linux.tar.xz" + remote_fileurl="https://linuxgsm.download/UnrealTournament2004/ut2004-server-3369-3-ultimate-linux.tar.xz" local_filedir="${tmpdir}" local_filename="ut2004-server-3369-3-ultimate-linux.tar.xz" chmodx="nochmodx" @@ -162,7 +162,7 @@ fn_install_server_files() { force="noforce" md5="9fceaab68554749f4b45be66613b9a15" elif [ "${shortname}" == "ut99" ]; then - remote_fileurl="http://linuxgsm.download/UnrealTournament99/ut99-server-469b-ultimate-linux.tar.xz" + remote_fileurl="https://linuxgsm.download/UnrealTournament99/ut99-server-469b-ultimate-linux.tar.xz" local_filedir="${tmpdir}" local_filename="ut99-server-469b-ultimate-linux.tar.xz" chmodx="nochmodx" @@ -170,7 +170,7 @@ fn_install_server_files() { force="noforce" md5="dba3f1122a5e60ee45ece7422fcf78f5" elif [ "${shortname}" == "ut" ]; then - remote_fileurl="http://linuxgsm.download/UnrealTournament/UnrealTournament-Server-XAN-3525360-Linux.tar.xz" + remote_fileurl="https://linuxgsm.download/UnrealTournament/UnrealTournament-Server-XAN-3525360-Linux.tar.xz" local_filedir="${tmpdir}" local_filename="UnrealTournament-Server-XAN-3525360-Linux.tar.xz" chmodx="noexecute" @@ -178,7 +178,7 @@ fn_install_server_files() { force="noforce" md5="41dd92015713a78211eaccf503b72393" elif [ "${shortname}" == "ut3" ]; then - remote_fileurl="http://linuxgsm.download/UnrealTournament3/UT3-linux-server-2.1-openspy.tar.xz" + remote_fileurl="https://linuxgsm.download/UnrealTournament3/UT3-linux-server-2.1-openspy.tar.xz" local_filedir="${tmpdir}" local_filename="UT3-linux-server-2.1-openspy.tar.xz" chmodx="nochmodx" @@ -186,7 +186,7 @@ fn_install_server_files() { force="noforce" md5="f60b745613a8676666eb6a2450cbdc8e" elif [ "${shortname}" == "vs" ]; then - remote_fileurl="http://linuxgsm.download/VampireSlayer/vs_l-6.0_full.tar.xz" + remote_fileurl="https://linuxgsm.download/VampireSlayer/vs_l-6.0_full.tar.xz" local_filedir="${tmpdir}" local_filename="vs_l-6.0_full.tar.xz" chmodx="nochmodx" @@ -194,7 +194,7 @@ fn_install_server_files() { force="noforce" md5="b322f79e0abd31847493c52acf802667" elif [ "${shortname}" == "wet" ]; then - remote_fileurl="http://linuxgsm.download/WolfensteinEnemyTerritory/enemy-territory.260b.tar.xz" + remote_fileurl="https://linuxgsm.download/WolfensteinEnemyTerritory/enemy-territory.260b.tar.xz" local_filedir="${tmpdir}" local_filename="enemy-territory.260b.tar.xz" chmodx="nochmodx" @@ -210,7 +210,7 @@ fn_install_server_files() { force="noforce" md5="93705e165550c97484678236749198a4" elif [ "${shortname}" == "zmr" ]; then - remote_fileurl="http://linuxgsm.download/ZombieMasterReborn/zombie_master_reborn_b6_1.tar.xz" + remote_fileurl="https://linuxgsm.download/ZombieMasterReborn/zombie_master_reborn_b6_1.tar.xz" local_filedir="${tmpdir}" local_filename="zombie_master_reborn_b6_1.tar.xz" chmodx="nochmodx" From afae02c531716297d9e546a476dcec08448d23f7 Mon Sep 17 00:00:00 2001 From: Daniel Gibbs Date: Sat, 17 Oct 2026 13:04:19 +0100 Subject: [PATCH 092/164] fix(deps): fix bmdm on Debian 13 and hyt on older distros (#5071) * fix(deps): fix bmdm on Debian 13 and hyt on older distros Black Mesa: Deathmatch listed libncurses5:i386 on Debian 13, which trixie no longer packages (there is no libncurses5 or libtinfo5 compat package). The server does not link against ncurses; dedicated_srv.so only tries to dlopen the 32-bit libtinfo.so.5 or libncurses.so.5 to enable readline in the console and prints a warning if they are missing. The server starts and runs normally without them, so the dependency is removed, as already done for Ubuntu 24.04 and 26.04. Hytale listed openjdk-25-jre on Ubuntu 16.04 to 20.04, 23.04 and 23.10 and on Debian 9 to 12, none of which package Java 25 (not even bookworm-backports). The package is removed from those lists and check_deps now warns that Java 25 must be installed manually (for example Eclipse Temurin) or the distro upgraded, unless Java 25 is already the active java. * fix(deps): drop the Java vendor example from the hyt warning --- lgsm/data/debian-10.csv | 2 +- lgsm/data/debian-11.csv | 2 +- lgsm/data/debian-12.csv | 2 +- lgsm/data/debian-13.csv | 2 +- lgsm/data/debian-9.csv | 2 +- lgsm/data/ubuntu-16.04.csv | 2 +- lgsm/data/ubuntu-18.04.csv | 2 +- lgsm/data/ubuntu-20.04.csv | 2 +- lgsm/data/ubuntu-23.04.csv | 2 +- lgsm/data/ubuntu-23.10.csv | 2 +- lgsm/modules/check_deps.sh | 11 +++++++++++ 11 files changed, 21 insertions(+), 10 deletions(-) diff --git a/lgsm/data/debian-10.csv b/lgsm/data/debian-10.csv index 4bb6e3aeab..ccda5411d1 100644 --- a/lgsm/data/debian-10.csv +++ b/lgsm/data/debian-10.csv @@ -53,7 +53,7 @@ hl2dm hldm hldms hw,lib32z1 -hyt,openjdk-25-jre +hyt hz ins inss diff --git a/lgsm/data/debian-11.csv b/lgsm/data/debian-11.csv index 830af0721a..24e562cf6d 100644 --- a/lgsm/data/debian-11.csv +++ b/lgsm/data/debian-11.csv @@ -54,7 +54,7 @@ hl2dm hldm hldms hw,lib32z1 -hyt,openjdk-25-jre +hyt hz ins inss diff --git a/lgsm/data/debian-12.csv b/lgsm/data/debian-12.csv index b6347d6881..1ddb5ca6f5 100644 --- a/lgsm/data/debian-12.csv +++ b/lgsm/data/debian-12.csv @@ -54,7 +54,7 @@ hl2dm hldm hldms hw,lib32z1 -hyt,openjdk-25-jre +hyt hz ins inss diff --git a/lgsm/data/debian-13.csv b/lgsm/data/debian-13.csv index 8dee746bf6..cf3cc4bb69 100644 --- a/lgsm/data/debian-13.csv +++ b/lgsm/data/debian-13.csv @@ -13,7 +13,7 @@ bb2,libcurl4-gnutls-dev:i386 bd bf1942,libc6:i386 bfv,libc6:i386 -bmdm,libncurses5:i386 +bmdm bo bs bt,libicu-dev,dos2unix,libxml2 diff --git a/lgsm/data/debian-9.csv b/lgsm/data/debian-9.csv index e190c77d08..0fa7cf3516 100644 --- a/lgsm/data/debian-9.csv +++ b/lgsm/data/debian-9.csv @@ -54,7 +54,7 @@ hl2dm hldm hldms hw,lib32z1 -hyt,openjdk-25-jre +hyt hz ins inss diff --git a/lgsm/data/ubuntu-16.04.csv b/lgsm/data/ubuntu-16.04.csv index 165d81f296..d412f99b1f 100644 --- a/lgsm/data/ubuntu-16.04.csv +++ b/lgsm/data/ubuntu-16.04.csv @@ -55,7 +55,7 @@ hl2dm hldm hldms hw,lib32z1 -hyt,openjdk-25-jre +hyt hz ins inss diff --git a/lgsm/data/ubuntu-18.04.csv b/lgsm/data/ubuntu-18.04.csv index 29ca5089f4..08ab1b61b7 100644 --- a/lgsm/data/ubuntu-18.04.csv +++ b/lgsm/data/ubuntu-18.04.csv @@ -55,7 +55,7 @@ hl2dm hldm hldms hw,lib32z1 -hyt,openjdk-25-jre +hyt hz ins inss diff --git a/lgsm/data/ubuntu-20.04.csv b/lgsm/data/ubuntu-20.04.csv index a6e1ab5cb2..a88cad6df1 100644 --- a/lgsm/data/ubuntu-20.04.csv +++ b/lgsm/data/ubuntu-20.04.csv @@ -54,7 +54,7 @@ hl2dm hldm hldms hw,lib32z1 -hyt,openjdk-25-jre +hyt hz ins inss diff --git a/lgsm/data/ubuntu-23.04.csv b/lgsm/data/ubuntu-23.04.csv index 98bfd20a56..f0be27806f 100644 --- a/lgsm/data/ubuntu-23.04.csv +++ b/lgsm/data/ubuntu-23.04.csv @@ -54,7 +54,7 @@ hl2dm hldm hldms hw,lib32z1 -hyt,openjdk-25-jre +hyt hz ins inss diff --git a/lgsm/data/ubuntu-23.10.csv b/lgsm/data/ubuntu-23.10.csv index 98bfd20a56..f0be27806f 100644 --- a/lgsm/data/ubuntu-23.10.csv +++ b/lgsm/data/ubuntu-23.10.csv @@ -54,7 +54,7 @@ hl2dm hldm hldms hw,lib32z1 -hyt,openjdk-25-jre +hyt hz ins inss diff --git a/lgsm/modules/check_deps.sh b/lgsm/modules/check_deps.sh index ec003ba7e6..7b79a79cd1 100644 --- a/lgsm/modules/check_deps.sh +++ b/lgsm/modules/check_deps.sh @@ -423,6 +423,17 @@ if [ "${depcheckonly}" != "1" ]; then fn_script_log_warn "${gamename} may require newer .NET runtimes than ${distroname} provides." fi fi + + # Hytale needs Java 25, which Ubuntu before 22.04 and Debian before 13 do not package. + if [ "${shortname}" == "hyt" ]; then + if { [ "${distroid}" == "ubuntu" ] && [ "${distroversion}" != "22.04" ] && dpkg --compare-versions "${distroversion}" "lt" "24.04"; } || { [ "${distroid}" == "debian" ] && dpkg --compare-versions "${distroversion}" "lt" "13"; }; then + if ! echo "${javaversion}" | grep -Eq 'version "(2[5-9]|[3-9][0-9])'; then + fn_print_warning_nl "${gamename} requires Java 25, which ${distroname} does not provide." + echo -e "Install Java 25 manually or upgrade to Ubuntu 22.04+ or Debian 13+." + fn_script_log_warn "${gamename} requires Java 25, which ${distroname} does not provide." + fi + fi + fi fi if [ ! -f "${tmpdir}/dependency-no-check.tmp" ] && [ ! -f "${datadir}/${distroid}-${distroversioncsv}.csv" ]; then From 6c9e5d16923bcc5cf815ae3ad6ab788c13eebbad Mon Sep 17 00:00:00 2001 From: Daniel Gibbs Date: Sat, 17 Oct 2026 13:09:33 +0100 Subject: [PATCH 093/164] fix(cod,cod2,coduo,mohaa): provide 32-bit libstdc++5 on newer distros (#5069) * fix(cod,cod2,coduo,mohaa): provide 32-bit libstdc++5 on newer distros Debian 13, Ubuntu 26.04 and RHEL 9 no longer package the i386 libstdc++.so.5 that the Call of Duty, Call of Duty 2, Call of Duty: United Offensive and Medal of Honor: Allied Assault server binaries need, so check_deps failed and the servers could not start. New pre-start fix modules check the binary with ldd and, when libstdc++.so.5 is missing, download it into serverfiles and add serverfiles to LD_LIBRARY_PATH, the same approach used for the Battlefield ncurses 5 fix (#5043). The library is taken unmodified from Debian bookworm's libstdc++5_3.3.6-34_i386.deb and its download is pinned by md5. The libstdc++5:i386 dependency is replaced with libc6:i386 in the Debian 13 and Ubuntu 26.04 lists, and the unavailable compat-libstdc++-33.i686 is dropped from the RHEL 9 list (glibc.i686 and libstdc++.i686 are already in its base list). Older distros still install the system package, which the fix then detects and skips. Fixes #5026 * fix(cod,cod2,coduo,mohaa): download libstdc++5 over HTTPS Matches the other linuxgsm.download URLs, which moved to HTTPS in #5070. --- lgsm/data/debian-13.csv | 8 ++++---- lgsm/data/rhel-9.csv | 8 ++++---- lgsm/data/ubuntu-26.04.csv | 8 ++++---- lgsm/modules/core_modules.sh | 20 ++++++++++++++++++++ lgsm/modules/fix.sh | 2 +- lgsm/modules/fix_cod.sh | 21 +++++++++++++++++++++ lgsm/modules/fix_cod2.sh | 21 +++++++++++++++++++++ lgsm/modules/fix_coduo.sh | 21 +++++++++++++++++++++ lgsm/modules/fix_mohaa.sh | 21 +++++++++++++++++++++ 9 files changed, 117 insertions(+), 13 deletions(-) create mode 100755 lgsm/modules/fix_cod.sh create mode 100755 lgsm/modules/fix_cod2.sh create mode 100755 lgsm/modules/fix_coduo.sh create mode 100755 lgsm/modules/fix_mohaa.sh diff --git a/lgsm/data/debian-13.csv b/lgsm/data/debian-13.csv index cf3cc4bb69..242c5da77c 100644 --- a/lgsm/data/debian-13.csv +++ b/lgsm/data/debian-13.csv @@ -21,10 +21,10 @@ btl cc ck,xvfb,libxi6 cmw -cod,libstdc++5:i386 -cod2,libstdc++5:i386 +cod,libc6:i386 +cod2,libc6:i386 cod4 -coduo,libstdc++5:i386 +coduo,libc6:i386 codwaw col cs @@ -72,7 +72,7 @@ mc,openjdk-25-jre mcb mcv mh -mohaa,libstdc++5:i386 +mohaa,libc6:i386 mta,libncursesw6,libxml2 nd nec diff --git a/lgsm/data/rhel-9.csv b/lgsm/data/rhel-9.csv index 3e8350a78f..6cb9ec7140 100644 --- a/lgsm/data/rhel-9.csv +++ b/lgsm/data/rhel-9.csv @@ -21,10 +21,10 @@ btl cc ck,xorg-x11-server-Xvfb cmw -cod,compat-libstdc++-33.i686 -cod2,compat-libstdc++-33.i686 +cod +cod2 cod4 -coduo,compat-libstdc++-33.i686 +coduo codwaw col cs @@ -72,7 +72,7 @@ mc,java-21-openjdk mcb,libnsl mcv mh -mohaa,compat-libstdc++-33.i686 +mohaa mta,ncurses-compat-libs,libxml2 nd nec diff --git a/lgsm/data/ubuntu-26.04.csv b/lgsm/data/ubuntu-26.04.csv index f01738c06d..bc3115b344 100644 --- a/lgsm/data/ubuntu-26.04.csv +++ b/lgsm/data/ubuntu-26.04.csv @@ -21,10 +21,10 @@ btl cc ck,xvfb,libxi6 cmw -cod,libstdc++5:i386 -cod2,libstdc++5:i386 +cod,libc6:i386 +cod2,libc6:i386 cod4 -coduo,libstdc++5:i386 +coduo,libc6:i386 codwaw col cs @@ -72,7 +72,7 @@ mc,openjdk-25-jre mcb mcv mh -mohaa,libstdc++5:i386 +mohaa,libc6:i386 mta,libxml2-utils nd nec diff --git a/lgsm/modules/core_modules.sh b/lgsm/modules/core_modules.sh index 81ec05473e..f002f93a70 100755 --- a/lgsm/modules/core_modules.sh +++ b/lgsm/modules/core_modules.sh @@ -403,6 +403,21 @@ fix_cmw.sh() { fn_fetch_module } +fix_cod.sh() { + modulefile="${FUNCNAME[0]}" + fn_fetch_module +} + +fix_cod2.sh() { + modulefile="${FUNCNAME[0]}" + fn_fetch_module +} + +fix_coduo.sh() { + modulefile="${FUNCNAME[0]}" + fn_fetch_module +} + fix_csgo.sh() { modulefile="${FUNCNAME[0]}" fn_fetch_module @@ -443,6 +458,11 @@ fix_mcb.sh() { fn_fetch_module } +fix_mohaa.sh() { + modulefile="${FUNCNAME[0]}" + fn_fetch_module +} + fix_mta.sh() { modulefile="${FUNCNAME[0]}" fn_fetch_module diff --git a/lgsm/modules/fix.sh b/lgsm/modules/fix.sh index 69065a9fcd..9d6787314d 100755 --- a/lgsm/modules/fix.sh +++ b/lgsm/modules/fix.sh @@ -53,7 +53,7 @@ fn_apply_fix() { fi } -apply_pre_start_fix=(arma3 armar ark av bf1942 bfv bt bo csgo cmw dst hw ins ios kf nd nmrih onset pvr ro rust rw samp sdtd sfc sm sof2 squad st tf2 terraria ts3 mcb mta unt vh wurm xnt zmr) +apply_pre_start_fix=(arma3 armar ark av bf1942 bfv bt bo csgo cmw cod cod2 coduo dst hw ins ios kf nd nmrih onset pvr ro rust rw samp sdtd sfc sm sof2 squad st tf2 terraria ts3 mcb mohaa mta unt vh wurm xnt zmr) apply_post_install_fix=(av kf kf2 nd ro ut2k4 ut ut3) # validate registered fixes for safe development diff --git a/lgsm/modules/fix_cod.sh b/lgsm/modules/fix_cod.sh new file mode 100755 index 0000000000..d103ac857d --- /dev/null +++ b/lgsm/modules/fix_cod.sh @@ -0,0 +1,21 @@ +#!/bin/bash +# LinuxGSM fix_cod.sh module +# Author: Daniel Gibbs +# Contributors: https://linuxgsm.com/contrib +# Website: https://linuxgsm.com +# Description: Resolves issues with Call of Duty. + +# shellcheck disable=SC2034 # Used by the module loader. +moduleselfname="$(basename "$(readlink -f "${BASH_SOURCE[0]}")")" + +export LD_LIBRARY_PATH="$LD_LIBRARY_PATH:${serverfiles}" + +if ldd "${executabledir}/cod_lnxded" 2>&1 | grep -q "libstdc++\.so\.5 => not found"; then + # shellcheck disable=SC2034 # Used by fn_fix_msg_start_nl and fn_fix_msg_end. + fixname="libstdc++5 i386" + fn_fix_msg_start_nl + fn_fetch_file "https://linuxgsm.download/libraries/libstdc++5-i386-3.3.6-34.tar.xz" "" "" "" "${tmpdir}" "libstdc++5-i386-3.3.6-34.tar.xz" "nochmodx" "norun" "noforce" "288a4cc9d6b7647f28c702028437e0f3" + fn_dl_extract "${tmpdir}" "libstdc++5-i386-3.3.6-34.tar.xz" "${serverfiles}" + fn_clear_tmp + fn_fix_msg_end +fi diff --git a/lgsm/modules/fix_cod2.sh b/lgsm/modules/fix_cod2.sh new file mode 100755 index 0000000000..6468dd206b --- /dev/null +++ b/lgsm/modules/fix_cod2.sh @@ -0,0 +1,21 @@ +#!/bin/bash +# LinuxGSM fix_cod2.sh module +# Author: Daniel Gibbs +# Contributors: https://linuxgsm.com/contrib +# Website: https://linuxgsm.com +# Description: Resolves issues with Call of Duty 2. + +# shellcheck disable=SC2034 # Used by the module loader. +moduleselfname="$(basename "$(readlink -f "${BASH_SOURCE[0]}")")" + +export LD_LIBRARY_PATH="$LD_LIBRARY_PATH:${serverfiles}" + +if ldd "${executabledir}/cod2_lnxded" 2>&1 | grep -q "libstdc++\.so\.5 => not found"; then + # shellcheck disable=SC2034 # Used by fn_fix_msg_start_nl and fn_fix_msg_end. + fixname="libstdc++5 i386" + fn_fix_msg_start_nl + fn_fetch_file "https://linuxgsm.download/libraries/libstdc++5-i386-3.3.6-34.tar.xz" "" "" "" "${tmpdir}" "libstdc++5-i386-3.3.6-34.tar.xz" "nochmodx" "norun" "noforce" "288a4cc9d6b7647f28c702028437e0f3" + fn_dl_extract "${tmpdir}" "libstdc++5-i386-3.3.6-34.tar.xz" "${serverfiles}" + fn_clear_tmp + fn_fix_msg_end +fi diff --git a/lgsm/modules/fix_coduo.sh b/lgsm/modules/fix_coduo.sh new file mode 100755 index 0000000000..a2f87b75d8 --- /dev/null +++ b/lgsm/modules/fix_coduo.sh @@ -0,0 +1,21 @@ +#!/bin/bash +# LinuxGSM fix_coduo.sh module +# Author: Daniel Gibbs +# Contributors: https://linuxgsm.com/contrib +# Website: https://linuxgsm.com +# Description: Resolves issues with Call of Duty: United Offensive. + +# shellcheck disable=SC2034 # Used by the module loader. +moduleselfname="$(basename "$(readlink -f "${BASH_SOURCE[0]}")")" + +export LD_LIBRARY_PATH="$LD_LIBRARY_PATH:${serverfiles}" + +if ldd "${executabledir}/coduo_lnxded" 2>&1 | grep -q "libstdc++\.so\.5 => not found"; then + # shellcheck disable=SC2034 # Used by fn_fix_msg_start_nl and fn_fix_msg_end. + fixname="libstdc++5 i386" + fn_fix_msg_start_nl + fn_fetch_file "https://linuxgsm.download/libraries/libstdc++5-i386-3.3.6-34.tar.xz" "" "" "" "${tmpdir}" "libstdc++5-i386-3.3.6-34.tar.xz" "nochmodx" "norun" "noforce" "288a4cc9d6b7647f28c702028437e0f3" + fn_dl_extract "${tmpdir}" "libstdc++5-i386-3.3.6-34.tar.xz" "${serverfiles}" + fn_clear_tmp + fn_fix_msg_end +fi diff --git a/lgsm/modules/fix_mohaa.sh b/lgsm/modules/fix_mohaa.sh new file mode 100755 index 0000000000..a38e67e391 --- /dev/null +++ b/lgsm/modules/fix_mohaa.sh @@ -0,0 +1,21 @@ +#!/bin/bash +# LinuxGSM fix_mohaa.sh module +# Author: Daniel Gibbs +# Contributors: https://linuxgsm.com/contrib +# Website: https://linuxgsm.com +# Description: Resolves issues with Medal of Honor: Allied Assault. + +# shellcheck disable=SC2034 # Used by the module loader. +moduleselfname="$(basename "$(readlink -f "${BASH_SOURCE[0]}")")" + +export LD_LIBRARY_PATH="$LD_LIBRARY_PATH:${serverfiles}" + +if ldd "${executabledir}/mohaa_lnxded" 2>&1 | grep -q "libstdc++\.so\.5 => not found"; then + # shellcheck disable=SC2034 # Used by fn_fix_msg_start_nl and fn_fix_msg_end. + fixname="libstdc++5 i386" + fn_fix_msg_start_nl + fn_fetch_file "https://linuxgsm.download/libraries/libstdc++5-i386-3.3.6-34.tar.xz" "" "" "" "${tmpdir}" "libstdc++5-i386-3.3.6-34.tar.xz" "nochmodx" "norun" "noforce" "288a4cc9d6b7647f28c702028437e0f3" + fn_dl_extract "${tmpdir}" "libstdc++5-i386-3.3.6-34.tar.xz" "${serverfiles}" + fn_clear_tmp + fn_fix_msg_end +fi From 12c6f4dc92f9c3aeba0b693c2a8492428f8961ba Mon Sep 17 00:00:00 2001 From: Daniel Gibbs Date: Sat, 17 Oct 2026 13:37:49 +0100 Subject: [PATCH 094/164] fix(bt): read server name, max players and tick rate in both config forms (#5072) Barotrauma rewrites serversettings.xml on first start and renames some attributes (name to ServerName, maxplayers to MaxPlayers, tickrate to TickRate). XPath is case-sensitive, so the server name showed NOT SET after the first start, and max players and tick rate showed 0 before it. Read the game's form first and fall back to the LinuxGSM default form. Fixes #4782 --- lgsm/modules/info_game.sh | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/lgsm/modules/info_game.sh b/lgsm/modules/info_game.sh index 50b0793d97..7b0247af25 100755 --- a/lgsm/modules/info_game.sh +++ b/lgsm/modules/info_game.sh @@ -1005,11 +1005,20 @@ fn_info_game_bfv() { fn_info_game_bt() { if [ -f "${servercfgfullpath}" ]; then fn_info_game_xml "maxplayers" "/serversettings/@MaxPlayers" + if [ -z "${maxplayers}" ]; then + fn_info_game_xml "maxplayers" "/serversettings/@maxplayers" + fi fn_info_game_xml "port" "/serversettings/@port" fn_info_game_xml "queryport" "/serversettings/@queryport" - fn_info_game_xml "servername" "/serversettings/@name" + fn_info_game_xml "servername" "/serversettings/@ServerName" + if [ -z "${servername}" ]; then + fn_info_game_xml "servername" "/serversettings/@name" + fi fn_info_game_xml "serverpassword" "/serversettings/@password" fn_info_game_xml "tickrate" "/serversettings/@TickRate" + if [ -z "${tickrate}" ]; then + fn_info_game_xml "tickrate" "/serversettings/@tickrate" + fi fi maxplayers="${maxplayers:-"0"}" port="${port:-"0"}" From 4ae7a524c178f2e7c79c1f1058e0689bf15a706d Mon Sep 17 00:00:00 2001 From: Daniel Gibbs Date: Sat, 17 Oct 2026 14:53:54 +0100 Subject: [PATCH 095/164] fix(check-deps): validate Minecraft Java runtime (#5075) --- lgsm/modules/check_deps.sh | 57 +++++++++++++++++++++++++++++++++++++- 1 file changed, 56 insertions(+), 1 deletion(-) diff --git a/lgsm/modules/check_deps.sh b/lgsm/modules/check_deps.sh index 7b79a79cd1..59f58c9887 100644 --- a/lgsm/modules/check_deps.sh +++ b/lgsm/modules/check_deps.sh @@ -270,6 +270,10 @@ fn_check_loop() { } # Checks if dependency is installed or not. +fn_deps_version_ge() { + [ "$(printf '%s\n' "$1" "$2" | sort -V | head -1)" == "$2" ] +} + fn_deps_detector() { ## Check. # SteamCMD: Will be removed from required array if no appid is present or non-free repo is not available. @@ -292,6 +296,28 @@ fn_deps_detector() { # Is java already installed? if [ -n "${javaversion}" ]; then javamajorversion="$(echo "${javaversion}" | grep -Eo 'version "[0-9]+' | grep -Eo '[0-9]+' | head -1)" + javarequiredmajor="$(echo "${deptocheck}" | grep -Eo '[0-9]+' | head -1)" + if [ "${shortname}" == "mc" ] || [ "${shortname}" == "pmc" ]; then + if [ "${mcversion}" == "latest" ]; then + javarequiredmajor="25" + elif [[ "${mcversion}" =~ ^[0-9]+\.[0-9]+([.][0-9]+)?$ ]]; then + if fn_deps_version_ge "${mcversion}" "26.1"; then + javarequiredmajor="25" + elif [ "${shortname}" == "mc" ] && fn_deps_version_ge "${mcversion}" "1.20.5"; then + javarequiredmajor="21" + elif [ "${shortname}" == "pmc" ] && fn_deps_version_ge "${mcversion}" "1.20" && fn_deps_version_ge "1.21.11" "${mcversion}"; then + javarequiredmajor="21" + elif [ "${shortname}" == "pmc" ] && fn_deps_version_ge "${mcversion}" "1.17" && fn_deps_version_ge "1.19" "${mcversion}"; then + javarequiredmajor="17" + elif [ "${shortname}" == "pmc" ] && [ "${mcversion}" == "1.16.5" ]; then + javarequiredmajor="16" + elif [ "${shortname}" == "pmc" ] && fn_deps_version_ge "${mcversion}" "1.12" && ! fn_deps_version_ge "${mcversion}" "1.16.5"; then + javarequiredmajor="11" + elif [ "${shortname}" == "pmc" ] && ! fn_deps_version_ge "${mcversion}" "1.16.5"; then + javarequiredmajor="8" + fi + fi + fi if [ "${shortname}" == "hyt" ] && { [ -z "${javamajorversion}" ] || [ "${javamajorversion}" -lt "25" ]; }; then # Java 25 installed but not the active java: installing it again would not change that. if compgen -G "/usr/lib/jvm/*25*/bin/java" > /dev/null; then @@ -302,13 +328,42 @@ fn_deps_detector() { else depstatus=1 fi + elif [ -n "${javamajorversion}" ] && [ "${javamajorversion}" -lt "${javarequiredmajor}" ]; then + if [ "${depcheckonly}" == "1" ]; then + depstatus=1 + elif [ "${javarequiredmajor}" -gt "$(echo "${deptocheck}" | grep -Eo '[0-9]+' | head -1)" ]; then + fn_print_failure_nl "${gamename} ${mcversion} requires Java ${javarequiredmajor}; ${distroname} does not provide that version as a package." + echo -e "Install Java ${javarequiredmajor} manually or upgrade to Debian 13 or Ubuntu 24.04+." + fn_script_log_fail "${gamename} ${mcversion} requires Java ${javarequiredmajor}; ${distroname} does not provide it as a package." + core_exit.sh + else + fn_print_failure_nl "${gamename} ${mcversion} requires Java ${javarequiredmajor}; active Java is ${javamajorversion}." + echo -e "Select a compatible Java runtime with: sudo update-alternatives --config java" + fn_script_log_fail "${gamename} ${mcversion} requires Java ${javarequiredmajor}; active Java is ${javamajorversion}." + core_exit.sh + fi else # Added for users using Oracle JRE to bypass check. depstatus=0 deptocheck="${javaversion}" fi else - depstatus=1 + javarequiredmajor="$(echo "${deptocheck}" | grep -Eo '[0-9]+' | head -1)" + if [ "${shortname}" == "mc" ] || [ "${shortname}" == "pmc" ]; then + if [ "${mcversion}" == "latest" ] || fn_deps_version_ge "${mcversion}" "26.1"; then + javarequiredmajor="25" + elif { [ "${shortname}" == "mc" ] && fn_deps_version_ge "${mcversion}" "1.20.5"; } || { [ "${shortname}" == "pmc" ] && fn_deps_version_ge "${mcversion}" "1.20" && fn_deps_version_ge "1.21.11" "${mcversion}"; }; then + javarequiredmajor="21" + fi + fi + if [ "${javarequiredmajor}" -gt "$(echo "${deptocheck}" | grep -Eo '[0-9]+' | head -1)" ] && [ "${depcheckonly}" != "1" ]; then + fn_print_failure_nl "${gamename} ${mcversion} requires Java ${javarequiredmajor}; ${distroname} does not provide that version as a package." + echo -e "Install Java ${javarequiredmajor} manually or upgrade to Debian 13 or Ubuntu 24.04+." + fn_script_log_fail "${gamename} ${mcversion} requires Java ${javarequiredmajor}; ${distroname} does not provide it as a package." + core_exit.sh + else + depstatus=1 + fi fi # Mono: A Mono repo needs to be installed. elif [ "${deptocheck}" == "mono-complete" ]; then From be39f6e2a3636f7c4f9a585851ad21da40ee935d Mon Sep 17 00:00:00 2001 From: Daniel Gibbs Date: Sat, 17 Oct 2026 17:50:19 +0100 Subject: [PATCH 096/164] fix: report CPU topology and frequency accurately (#5076) * fix: report CPU topology and frequency accurately * fix: expose CPU display values to modules * fix: preserve CPU stats payload compatibility * fix: preserve CPU display exports for checks * fix: export CPU average display value * fix: guard CPU core count and collapse single-value frequency range * style: drop redundant comment and format redirects * style: remove duplicated comment on memory total lines --- .../command_dev_parse_distro_details.sh | 5 +- lgsm/modules/info_distro.sh | 62 +++++++++++++++++-- lgsm/modules/info_messages.sh | 5 +- lgsm/modules/info_stats.sh | 7 ++- 4 files changed, 70 insertions(+), 9 deletions(-) diff --git a/lgsm/modules/command_dev_parse_distro_details.sh b/lgsm/modules/command_dev_parse_distro_details.sh index dfb68ba2bf..2f3ec74ffb 100755 --- a/lgsm/modules/command_dev_parse_distro_details.sh +++ b/lgsm/modules/command_dev_parse_distro_details.sh @@ -27,7 +27,10 @@ declare -A server_details=( ['Backup Last']="${lastbackup}" ['CPU Average Load']="${load}" ['CPU Cores']="${cpucores}" - ['CPU Frequency']="${cpufreqency}" + ['CPU Cores Display']="${cpuphysicalcoresdisplay}" + ['CPU Logical CPUs']="${cpulogicalcores}" + ['CPU Average Frequency']="${cpufrequencyaveragedisplay}" + ['CPU Frequency Range']="${cpufrequencydisplay}" ['CPU Model']="${cpumodel}" ['Distro Codename']="${distrocodename}" ['Distro ID Like']="${distroidlike}" diff --git a/lgsm/modules/info_distro.sh b/lgsm/modules/info_distro.sh index 4ece95e4de..da11cb52e7 100755 --- a/lgsm/modules/info_distro.sh +++ b/lgsm/modules/info_distro.sh @@ -139,8 +139,62 @@ load="$(uptime | awk -F 'load average: ' '{ print $2 }')" # e.g 0.01, 0.05, 0.11 ## CPU information cpumodel="$(awk -F: '/model name/ {name=$2} END {print name}' /proc/cpuinfo | sed 's/^[ \t]*//;s/[ \t]*$//')" # e.g Intel(R) Xeon(R) CPU E5-2676 v3 @ 2.40GHz -cpucores="$(awk -F: '/model name/ {core++} END {print core}' /proc/cpuinfo)" -cpufreqency="$(awk -F: '/cpu MHz/ {freq=$2} END {print freq}' /proc/cpuinfo | sed 's/^[ \t]*//;s/[ \t]*$//')" # e.g 2394.503 +cpulogicalcores="$(find /sys/devices/system/cpu -maxdepth 1 -type d -name 'cpu[0-9]*' 2> /dev/null | while IFS= read -r cpu; do + if [ ! -f "${cpu}/online" ] || [ "$(< "${cpu}/online")" = "1" ]; then + echo "${cpu##*cpu}" + fi +done | wc -l | tr -d ' ')" +if [ -z "${cpumodel}" ] && [ "$(command -v lscpu 2> /dev/null)" ]; then + cpumodel="$(lscpu 2> /dev/null | sed -n 's/^Model name:[[:space:]]*//p')" +fi +if [ "${cpulogicalcores:-0}" -eq 0 ] && [ "$(command -v lscpu 2> /dev/null)" ]; then + cpulogicalcores="$(lscpu --parse=CPU 2> /dev/null | awk -F, '!/^#/ && $1 ~ /^[0-9]+$/ { count++ } END { print count+0 }')" +fi +if [ "${cpulogicalcores:-0}" -eq 0 ]; then + cpulogicalcores="$(awk -F: '/^[[:space:]]*processor[[:space:]]*:/ { count++ } END { print count+0 }' /proc/cpuinfo)" +fi +cpuphysicalcores="$(for cpu in /sys/devices/system/cpu/cpu[0-9]*; do + [ -d "${cpu}" ] || continue + [ ! -f "${cpu}/online" ] || [ "$(< "${cpu}/online")" = "1" ] || continue + if [ -r "${cpu}/topology/physical_package_id" ] && [ -r "${cpu}/topology/core_id" ]; then + printf '%s:%s\n' "$(< "${cpu}/topology/physical_package_id")" "$(< "${cpu}/topology/core_id")" + fi +done | sort -u | wc -l | tr -d ' ')" +if [ "${cpuphysicalcores:-0}" -eq 0 ] && [ "$(command -v lscpu 2> /dev/null)" ]; then + cpuphysicalcores="$(lscpu --parse=CORE,SOCKET 2> /dev/null | awk -F, '!/^#/ && NF >= 2 && $1 != "" && $2 != "" { cores[$1 ":" $2]=1 } END { for (core in cores) count++; print count+0 }')" +fi +if [ "${cpuphysicalcores:-0}" -eq 0 ]; then + cpuphysicalcores="$(awk -F: ' + BEGIN { package="0" } + /^[[:space:]]*physical id[[:space:]]*:/ { package=$2; gsub(/[[:space:]]/, "", package) } + /^[[:space:]]*core id[[:space:]]*:/ { core=$2; gsub(/[[:space:]]/, "", core); cores[package ":" core]=1; has_core=1 } + /^[[:space:]]*cpu cores[[:space:]]*:/ { package_cores=$2; gsub(/[[:space:]]/, "", package_cores); cores_per_package[package]=package_cores } + /^[[:space:]]*$/ { package="0" } + END { + if (has_core) { for (core in cores) total++; print total+0 } + else { for (package in cores_per_package) total+=cores_per_package[package]; print total+0 } + } + ' /proc/cpuinfo)" +fi +cpucores="${cpuphysicalcores}" +cpuphysicalcoresdisplay="${cpucores}" +if [ "${cpucores:-0}" -eq 0 ]; then + cpuphysicalcoresdisplay="unavailable" +fi +cpufrequencydata="$(awk -F: '/^[[:space:]]*cpu MHz[[:space:]]*:/ { value=$2; gsub(/[[:space:]]/, "", value); if (value ~ /^[0-9]+([.][0-9]+)?$/) print value }' /proc/cpuinfo)" +if [ -z "${cpufrequencydata}" ] && [ "$(command -v lscpu 2> /dev/null)" ]; then + cpufrequencydata="$(lscpu --parse=MHZ 2> /dev/null | awk -F, '!/^#/ && $1 ~ /^[0-9]+([.][0-9]+)?$/ { print $1 }')" +fi +read -r cpufreqency cpufrequencydisplay < <(printf '%s\n' "${cpufrequencydata}" | awk ' + NF && $1 ~ /^[0-9]+([.][0-9]+)?$/ { value=$1; if (!count || value < min) min=value; if (!count || value > max) max=value; sum+=value; count++ } + END { if (!count) printf "0.00 unavailable"; else if (min == max) printf "%.2f %.2fMHz", sum/count, min; else printf "%.2f %.2f-%.2fMHz", sum/count, min, max } + ') +cpufreqency="${cpufreqency:-0}" +export cpuphysicalcoresdisplay cpufrequencydisplay +export cpufrequencyaveragedisplay="${cpufreqency}" +if [ "${cpufrequencydisplay}" = "unavailable" ]; then + cpufrequencyaveragedisplay="unavailable" +fi # CPU usage of the game server pid if [ -n "${gameserverpid}" ]; then cpuused="$(ps --forest -o pcpu -g "${gameserverpid}" | awk '{s+=$1} END {print s}')" # integer @@ -169,8 +223,8 @@ if [ "$(command -v numfmt 2> /dev/null)" ]; then fi # Available RAM and swap. - physmemtotalmb="$(((physmemtotalkb + 512) / 1024))" # integer # integer - physmemtotalgb="$(((physmemtotalmb + 512) / 1024))" # integer # integer + physmemtotalmb="$(((physmemtotalkb + 512) / 1024))" # integer + physmemtotalgb="$(((physmemtotalmb + 512) / 1024))" # integer physmemtotal="$(numfmt --to=iec --from=iec --suffix=B "${physmemtotalkb}K")" # string physmemfree="$(numfmt --to=iec --from=iec --suffix=B "${physmemactualfreekb}K")" # string physmemused="$(numfmt --to=iec --from=iec --suffix=B "$((physmemtotalkb - physmemfreekb - physmembufferskb - physmemcachedkb - physmemreclaimablekb))K")" # string diff --git a/lgsm/modules/info_messages.sh b/lgsm/modules/info_messages.sh index 512e5d3464..95e794bf34 100644 --- a/lgsm/modules/info_messages.sh +++ b/lgsm/modules/info_messages.sh @@ -168,8 +168,9 @@ fn_info_messages_server_resource() { { echo -e "${bold}${lightyellow}CPU\t${default}" echo -e "${lightblue}Model:\t${default}${cpumodel}" - echo -e "${lightblue}Cores:\t${default}${cpucores}" - echo -e "${lightblue}Frequency:\t${default}${cpufreqency}MHz" + echo -e "${lightblue}Cores:\t${default}${cpuphysicalcoresdisplay}" + echo -e "${lightblue}Threads:\t${default}${cpulogicalcores}" + echo -e "${lightblue}Frequency:\t${default}${cpufrequencydisplay} per logical CPU" echo -e "${lightblue}Avg Load:\t${default}${load}" } | column -s $'\t' -t echo -e "" diff --git a/lgsm/modules/info_stats.sh b/lgsm/modules/info_stats.sh index c8a96552a0..168388d64b 100755 --- a/lgsm/modules/info_stats.sh +++ b/lgsm/modules/info_stats.sh @@ -76,7 +76,10 @@ payload="{ \"memusedmbroundup\": \"${memusedmbroundup}\", \"ramused\": \"${memusedmbroundup}\", \"servercpu\": \"${cpumodel} ${cpucores} cores\", - \"servercpufreq\": \"${cpufreqency} x${cpucores}\", + \"servercpufreq\": \"${cpufreqency} x${cpulogicalcores}\", + \"servercpuphysicalcores\": \"${cpuphysicalcoresdisplay}\", + \"servercpulogicalcpus\": \"${cpulogicalcores}\", + \"servercpufreqrange\": \"${cpufrequencydisplay}\", \"serverdisk\": \"${totalspace}\", \"serverfilesdu\": \"${serverfilesdu}\", \"serverram\": \"${physmemtotal}\", @@ -165,7 +168,7 @@ fn_script_log_info "* Game Server CPU Used: ${cpuusedmhzroundup}MHz" fn_script_log_info "* Game Server RAM Used: ${memusedmbroundup}MB" fn_script_log_info "* Game Server Disk Used: ${serverfilesdu}" fn_script_log_info "* Server CPU Model: ${cpumodel}" -fn_script_log_info "* Server CPU Frequency: ${cpufreqency}" +fn_script_log_info "* Server CPU Average Frequency: ${cpufreqency}" fn_script_log_info "* Server RAM: ${physmemtotal}" fn_script_log_info "* Server Disk: ${totalspace}" fn_script_log_info "* Virtual Environment: ${virtualenvironment}" From 26522ca2ede39ce193cfe762ccf4396049b1165b Mon Sep 17 00:00:00 2001 From: Daniel Gibbs Date: Sat, 17 Oct 2026 18:48:18 +0100 Subject: [PATCH 097/164] fix: restore executable bit on check_deps.sh and info_messages.sh (#5081) * ci: lint pull requests and restore module executable bits * chore: leave super-linter workflow to repo-sync --- lgsm/modules/check_deps.sh | 0 lgsm/modules/info_messages.sh | 0 2 files changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 lgsm/modules/check_deps.sh mode change 100644 => 100755 lgsm/modules/info_messages.sh diff --git a/lgsm/modules/check_deps.sh b/lgsm/modules/check_deps.sh old mode 100644 new mode 100755 diff --git a/lgsm/modules/info_messages.sh b/lgsm/modules/info_messages.sh old mode 100644 new mode 100755 From e0f5741351c7b1a2507bda00cb52d0b60ad3abcd Mon Sep 17 00:00:00 2001 From: Daniel Gibbs Date: Sat, 17 Oct 2026 19:05:32 +0100 Subject: [PATCH 098/164] chore: automate milestones and release closing for linked issues (#5080) * chore: sync PR milestones to linked issues Assign the next open milestone to new PRs into develop and copy the PR milestone to issues referenced with Fixes, Closes, Resolves or Related to. On merge, move referenced issues to the PR milestone. * chore: label fixed issues and close them when the release merges --- .github/workflows/action-milestone-sync.yml | 94 +++++++++++++++++++++ .github/workflows/action-release-issues.yml | 65 ++++++++++++++ 2 files changed, 159 insertions(+) create mode 100755 .github/workflows/action-milestone-sync.yml create mode 100755 .github/workflows/action-release-issues.yml diff --git a/.github/workflows/action-milestone-sync.yml b/.github/workflows/action-milestone-sync.yml new file mode 100755 index 0000000000..a252c5244d --- /dev/null +++ b/.github/workflows/action-milestone-sync.yml @@ -0,0 +1,94 @@ +name: Milestone Sync +on: + pull_request_target: + types: + - opened + - reopened + - ready_for_review + - edited + - milestoned + - closed + branches: + - develop + +permissions: + issues: write + pull-requests: write + +concurrency: + group: milestone-sync-${{ github.event.pull_request.number }} + +jobs: + milestone-sync: + if: github.repository_owner == 'GameServerManagers' + runs-on: ubuntu-latest + steps: + - name: Set PR milestone and update linked issues + uses: actions/github-script@v9 + with: + script: | + const { owner, repo } = context.repo; + const pr = context.payload.pull_request; + const action = context.payload.action; + const fixedLabel = 'status: fixed in develop'; + + if (action === 'closed' && !pr.merged) { + return; + } + + let milestone = pr.milestone; + if (!milestone && ['opened', 'reopened', 'ready_for_review'].includes(action)) { + const open = await github.paginate(github.rest.issues.listMilestones, { owner, repo, state: 'open', per_page: 100 }); + open.sort((a, b) => { + if (a.due_on && b.due_on) return a.due_on.localeCompare(b.due_on); + if (a.due_on) return -1; + if (b.due_on) return 1; + return a.number - b.number; + }); + if (open.length === 0) { + core.warning('No open milestone to assign.'); + } else { + milestone = open[0]; + await github.rest.issues.update({ owner, repo, issue_number: pr.number, milestone: milestone.number }); + core.info(`Set PR #${pr.number} milestone to ${milestone.title}.`); + } + } + + const body = (pr.body || '').replace(//g, ''); + const issueRef = /\b(close[sd]?|fix(?:e[sd])?|resolve[sd]?|related to):?\s+(?:([\w.-]+)\/([\w.-]+))?#(\d+)/gi; + const issues = new Map(); + for (const m of body.matchAll(issueRef)) { + if (m[2] && (m[2].toLowerCase() !== owner.toLowerCase() || m[3].toLowerCase() !== repo.toLowerCase())) { + continue; + } + const number = Number(m[4]); + const closing = !/^related to$/i.test(m[1]); + issues.set(number, issues.get(number) || closing); + } + + for (const [number, closing] of issues) { + let issue; + try { + ({ data: issue } = await github.rest.issues.get({ owner, repo, issue_number: number })); + } catch (error) { + core.warning(`Could not read #${number}: ${error.message}`); + continue; + } + if (issue.pull_request) { + continue; + } + + if (milestone && issue.milestone?.number !== milestone.number) { + if (issue.milestone && !pr.merged) { + core.info(`#${number} is in ${issue.milestone.title}; it will move to ${milestone.title} when this PR merges.`); + } else { + await github.rest.issues.update({ owner, repo, issue_number: number, milestone: milestone.number }); + core.info(`Set #${number} milestone to ${milestone.title}.`); + } + } + + if (pr.merged && closing && issue.state === 'open' && !issue.labels.some((l) => (l.name || l) === fixedLabel)) { + await github.rest.issues.addLabels({ owner, repo, issue_number: number, labels: [fixedLabel] }); + core.info(`Labelled #${number} "${fixedLabel}".`); + } + } diff --git a/.github/workflows/action-release-issues.yml b/.github/workflows/action-release-issues.yml new file mode 100755 index 0000000000..b491f998d8 --- /dev/null +++ b/.github/workflows/action-release-issues.yml @@ -0,0 +1,65 @@ +name: Release Issues +on: + pull_request_target: + types: + - opened + - reopened + - synchronize + - ready_for_review + - closed + branches: + - master + +permissions: + issues: write + pull-requests: write + +concurrency: + group: release-issues-${{ github.event.pull_request.number }} + +jobs: + release-issues: + if: github.repository_owner == 'GameServerManagers' && startsWith(github.event.pull_request.head.ref, 'release/') && github.event.pull_request.head.repo.full_name == github.repository + runs-on: ubuntu-latest + steps: + - name: List fixed issues in the release PR and close them on merge + uses: actions/github-script@v9 + with: + script: | + const { owner, repo } = context.repo; + const pr = context.payload.pull_request; + const fixedLabel = 'status: fixed in develop'; + const start = ''; + const end = ''; + + const labelled = (await github.paginate(github.rest.issues.listForRepo, { owner, repo, state: 'all', labels: fixedLabel, per_page: 100 })) + .filter((issue) => !issue.pull_request) + .sort((a, b) => a.number - b.number); + + if (context.payload.action === 'closed') { + if (!pr.merged) { + return; + } + const version = pr.head.ref.replace(/^release\//, ''); + for (const issue of labelled) { + if (issue.state === 'open') { + await github.rest.issues.createComment({ owner, repo, issue_number: issue.number, body: `Released in ${version} (#${pr.number}).` }); + await github.rest.issues.update({ owner, repo, issue_number: issue.number, state: 'closed', state_reason: 'completed' }); + core.info(`Closed #${issue.number}.`); + } + await github.rest.issues.removeLabel({ owner, repo, issue_number: issue.number, name: fixedLabel }).catch(() => {}); + } + return; + } + + const open = labelled.filter((issue) => issue.state === 'open'); + const lines = open.length > 0 ? open.map((issue) => `Fixes #${issue.number}`) : [`No open issues are labelled "${fixedLabel}".`]; + const block = [start, '## Issues fixed in this release', '', ...lines, end].join('\n'); + + const current = pr.body || ''; + const pattern = new RegExp(`${start}[\\s\\S]*?${end}`); + const updated = pattern.test(current) ? current.replace(pattern, block) : `${current.trim() ? `${current.trimEnd()}\n\n` : ''}${block}\n`; + if (updated !== current) { + await github.rest.pulls.update({ owner, repo, pull_number: pr.number, body: updated }); + core.info(`Listed ${open.length} issue(s) in #${pr.number}.`); + } From 1c6eb98f479bdd49191b8eab4a2a7a4bb352749b Mon Sep 17 00:00:00 2001 From: Daniel Gibbs Date: Sat, 17 Oct 2026 19:06:07 +0100 Subject: [PATCH 099/164] chore: enforce PR template and tidy its sections (#5078) * chore: enforce PR template and closing keywords for agents Add AGENTS.md with pull request rules, a PR Body Check workflow that fails when the template is dropped or the issue placeholder is left in, and closing keyword guidance in the PR template. * fix: only flag an unedited Fixes #[issue] placeholder line * chore: drop AGENTS.md and tidy PR template sections * chore: avoid a real issue reference in the checklist wording --- .github/pull_request_template.md | 24 ++++++------ .github/workflows/action-pr-body-check.yml | 44 ++++++++++++++++++++++ 2 files changed, 55 insertions(+), 13 deletions(-) create mode 100755 .github/workflows/action-pr-body-check.yml diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index d95b4278eb..a666c2f241 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -1,20 +1,23 @@ # Description -Please include a summary of the change and which issues are fixed. + Fixes #[issue] +Affected servers: + ## 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). +- [ ] Chore (CI, workflows, tooling or other maintenance). - [ ] Comment update (typo, spelling, explanation, examples, etc). ## Testing -Please list the exact validation you performed and the outcome. + - Commands/tests run: - Result: @@ -30,28 +33,23 @@ Please list the exact validation you performed and the outcome. - [ ] No breaking changes. - [ ] Breaking changes included (describe below). -## Documentation impact +## Documentation + + - [ ] No documentation update required. -- [ ] User documentation update required. -- [ ] Developer documentation update required. +- [ ] User documentation update required ([LinuxGSM-Docs](https://github.com/GameServerManagers/LinuxGSM-Docs)). +- [ ] Developer documentation update required ([LinuxGSM-Dev-Docs](https://github.com/GameServerManagers/LinuxGSM-Dev-Docs)). ## Checklist PR will not be merged until all steps are complete. -- [ ] This pull request links to an issue. +- [ ] This pull request links to an issue ("Fixes", or "Related to" for a partial fix). - [ ] 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 provided a detailed enough description of this PR. -## Documentation - -If documentation does need updating either update it by creating a PR (preferred) or request a documentation update. - -- User docs: -- Dev docs: - **Thank you for your Pull Request!** diff --git a/.github/workflows/action-pr-body-check.yml b/.github/workflows/action-pr-body-check.yml new file mode 100755 index 0000000000..1642133222 --- /dev/null +++ b/.github/workflows/action-pr-body-check.yml @@ -0,0 +1,44 @@ +name: PR Body Check +on: + pull_request: + types: + - opened + - edited + - reopened + - synchronize + branches: + - develop + +permissions: + contents: read + +jobs: + pr-body-check: + if: github.repository_owner == 'GameServerManagers' && github.event.pull_request.user.type != 'Bot' + runs-on: ubuntu-latest + steps: + - name: Check pull request body follows the template + uses: actions/github-script@v9 + with: + script: | + const body = (context.payload.pull_request.body || '').replace(//g, ''); + const requiredHeadings = ['# Description', '## Type of change', '## Testing', '## Checklist']; + const missing = requiredHeadings.filter((h) => !body.split(/\r?\n/).some((line) => line.trim() === h)); + const errors = []; + + if (missing.length > 0) { + errors.push(`Missing template sections: ${missing.join(', ')}. Use .github/pull_request_template.md as the pull request body.`); + } + if (/^\s*fixes #\[issue\]\s*$/im.test(body)) { + errors.push('Replace the "Fixes #[issue]" placeholder with the issue number, for example "Fixes #123".'); + } + + const closingKeyword = /\b(close[sd]?|fix(e[sd])?|resolve[sd]?):?\s+([\w.-]+\/[\w.-]+)?#\d+/i; + const relatedIssue = /\brelated to:?\s+([\w.-]+\/[\w.-]+)?#\d+/i; + if (!closingKeyword.test(body) && !relatedIssue.test(body)) { + core.warning('No closing keyword found. Add "Fixes #123" to link the issue, or "Related to #123" if this pull request does not fully resolve it.'); + } + + if (errors.length > 0) { + core.setFailed(errors.join('\n')); + } From 9036f58f59cd1e9e7baeb9945ec0e76934314155 Mon Sep 17 00:00:00 2001 From: Daniel Gibbs Date: Sat, 17 Oct 2026 19:10:00 +0100 Subject: [PATCH 100/164] chore(sync): synced local '.github/' with remote 'general/.github/' (#5082) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Synced from dgibbs64/repo-sync@5b508220d2782bd61f87f1a838fecfd322df4be5 — feat(sync): sync each group in a parallel matrix job (#25) Co-authored-by: dgibbs64 --- .github/workflows/action-super-linter.yml | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/.github/workflows/action-super-linter.yml b/.github/workflows/action-super-linter.yml index 3eff60805f..472fbd27b3 100644 --- a/.github/workflows/action-super-linter.yml +++ b/.github/workflows/action-super-linter.yml @@ -4,10 +4,13 @@ on: workflow_dispatch: push: branches: - - "*" + - main + - master + - develop + pull_request: concurrency: - group: super-linter-${{ github.ref }} + group: super-linter-${{ github.event.pull_request.number || github.ref }} cancel-in-progress: true permissions: {} @@ -41,6 +44,7 @@ jobs: env: # To report GitHub Actions status checks GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + MULTI_STATUS: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository }} VALIDATE_BIOME_FORMAT: false VALIDATE_BIOME_LINT: false VALIDATE_GITHUB_ACTIONS_ZIZMOR: false From 7107e1dfc79b2aa767928b7fcb5b9d7b6e9fa032 Mon Sep 17 00:00:00 2001 From: Daniel Gibbs Date: Sat, 17 Oct 2026 19:10:28 +0100 Subject: [PATCH 101/164] fix(ci): skip PR body check for repo-sync PRs (#5083) --- .github/workflows/action-pr-body-check.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/action-pr-body-check.yml b/.github/workflows/action-pr-body-check.yml index 1642133222..af5b8ddf3d 100755 --- a/.github/workflows/action-pr-body-check.yml +++ b/.github/workflows/action-pr-body-check.yml @@ -14,7 +14,7 @@ permissions: jobs: pr-body-check: - if: github.repository_owner == 'GameServerManagers' && github.event.pull_request.user.type != 'Bot' + if: github.repository_owner == 'GameServerManagers' && github.event.pull_request.user.type != 'Bot' && !startsWith(github.event.pull_request.head.ref, 'repo-sync/') runs-on: ubuntu-latest steps: - name: Check pull request body follows the template From c4a5c502e2f735710f2c089bcf61923a148c4c5c Mon Sep 17 00:00:00 2001 From: Daniel Gibbs Date: Sat, 17 Oct 2026 19:52:19 +0100 Subject: [PATCH 102/164] ci: add milestone sync and release issue workflows to master --- .github/workflows/action-milestone-sync.yml | 94 +++++++++++++++++++++ .github/workflows/action-release-issues.yml | 65 ++++++++++++++ 2 files changed, 159 insertions(+) create mode 100755 .github/workflows/action-milestone-sync.yml create mode 100755 .github/workflows/action-release-issues.yml diff --git a/.github/workflows/action-milestone-sync.yml b/.github/workflows/action-milestone-sync.yml new file mode 100755 index 0000000000..a252c5244d --- /dev/null +++ b/.github/workflows/action-milestone-sync.yml @@ -0,0 +1,94 @@ +name: Milestone Sync +on: + pull_request_target: + types: + - opened + - reopened + - ready_for_review + - edited + - milestoned + - closed + branches: + - develop + +permissions: + issues: write + pull-requests: write + +concurrency: + group: milestone-sync-${{ github.event.pull_request.number }} + +jobs: + milestone-sync: + if: github.repository_owner == 'GameServerManagers' + runs-on: ubuntu-latest + steps: + - name: Set PR milestone and update linked issues + uses: actions/github-script@v9 + with: + script: | + const { owner, repo } = context.repo; + const pr = context.payload.pull_request; + const action = context.payload.action; + const fixedLabel = 'status: fixed in develop'; + + if (action === 'closed' && !pr.merged) { + return; + } + + let milestone = pr.milestone; + if (!milestone && ['opened', 'reopened', 'ready_for_review'].includes(action)) { + const open = await github.paginate(github.rest.issues.listMilestones, { owner, repo, state: 'open', per_page: 100 }); + open.sort((a, b) => { + if (a.due_on && b.due_on) return a.due_on.localeCompare(b.due_on); + if (a.due_on) return -1; + if (b.due_on) return 1; + return a.number - b.number; + }); + if (open.length === 0) { + core.warning('No open milestone to assign.'); + } else { + milestone = open[0]; + await github.rest.issues.update({ owner, repo, issue_number: pr.number, milestone: milestone.number }); + core.info(`Set PR #${pr.number} milestone to ${milestone.title}.`); + } + } + + const body = (pr.body || '').replace(//g, ''); + const issueRef = /\b(close[sd]?|fix(?:e[sd])?|resolve[sd]?|related to):?\s+(?:([\w.-]+)\/([\w.-]+))?#(\d+)/gi; + const issues = new Map(); + for (const m of body.matchAll(issueRef)) { + if (m[2] && (m[2].toLowerCase() !== owner.toLowerCase() || m[3].toLowerCase() !== repo.toLowerCase())) { + continue; + } + const number = Number(m[4]); + const closing = !/^related to$/i.test(m[1]); + issues.set(number, issues.get(number) || closing); + } + + for (const [number, closing] of issues) { + let issue; + try { + ({ data: issue } = await github.rest.issues.get({ owner, repo, issue_number: number })); + } catch (error) { + core.warning(`Could not read #${number}: ${error.message}`); + continue; + } + if (issue.pull_request) { + continue; + } + + if (milestone && issue.milestone?.number !== milestone.number) { + if (issue.milestone && !pr.merged) { + core.info(`#${number} is in ${issue.milestone.title}; it will move to ${milestone.title} when this PR merges.`); + } else { + await github.rest.issues.update({ owner, repo, issue_number: number, milestone: milestone.number }); + core.info(`Set #${number} milestone to ${milestone.title}.`); + } + } + + if (pr.merged && closing && issue.state === 'open' && !issue.labels.some((l) => (l.name || l) === fixedLabel)) { + await github.rest.issues.addLabels({ owner, repo, issue_number: number, labels: [fixedLabel] }); + core.info(`Labelled #${number} "${fixedLabel}".`); + } + } diff --git a/.github/workflows/action-release-issues.yml b/.github/workflows/action-release-issues.yml new file mode 100755 index 0000000000..b491f998d8 --- /dev/null +++ b/.github/workflows/action-release-issues.yml @@ -0,0 +1,65 @@ +name: Release Issues +on: + pull_request_target: + types: + - opened + - reopened + - synchronize + - ready_for_review + - closed + branches: + - master + +permissions: + issues: write + pull-requests: write + +concurrency: + group: release-issues-${{ github.event.pull_request.number }} + +jobs: + release-issues: + if: github.repository_owner == 'GameServerManagers' && startsWith(github.event.pull_request.head.ref, 'release/') && github.event.pull_request.head.repo.full_name == github.repository + runs-on: ubuntu-latest + steps: + - name: List fixed issues in the release PR and close them on merge + uses: actions/github-script@v9 + with: + script: | + const { owner, repo } = context.repo; + const pr = context.payload.pull_request; + const fixedLabel = 'status: fixed in develop'; + const start = ''; + const end = ''; + + const labelled = (await github.paginate(github.rest.issues.listForRepo, { owner, repo, state: 'all', labels: fixedLabel, per_page: 100 })) + .filter((issue) => !issue.pull_request) + .sort((a, b) => a.number - b.number); + + if (context.payload.action === 'closed') { + if (!pr.merged) { + return; + } + const version = pr.head.ref.replace(/^release\//, ''); + for (const issue of labelled) { + if (issue.state === 'open') { + await github.rest.issues.createComment({ owner, repo, issue_number: issue.number, body: `Released in ${version} (#${pr.number}).` }); + await github.rest.issues.update({ owner, repo, issue_number: issue.number, state: 'closed', state_reason: 'completed' }); + core.info(`Closed #${issue.number}.`); + } + await github.rest.issues.removeLabel({ owner, repo, issue_number: issue.number, name: fixedLabel }).catch(() => {}); + } + return; + } + + const open = labelled.filter((issue) => issue.state === 'open'); + const lines = open.length > 0 ? open.map((issue) => `Fixes #${issue.number}`) : [`No open issues are labelled "${fixedLabel}".`]; + const block = [start, '## Issues fixed in this release', '', ...lines, end].join('\n'); + + const current = pr.body || ''; + const pattern = new RegExp(`${start}[\\s\\S]*?${end}`); + const updated = pattern.test(current) ? current.replace(pattern, block) : `${current.trim() ? `${current.trimEnd()}\n\n` : ''}${block}\n`; + if (updated !== current) { + await github.rest.pulls.update({ owner, repo, pull_number: pr.number, body: updated }); + core.info(`Listed ${open.length} issue(s) in #${pr.number}.`); + } From db1a751e95cca6f5265fc41d6d8d1893d306745a Mon Sep 17 00:00:00 2001 From: Daniel Gibbs Date: Sat, 17 Oct 2026 19:54:24 +0100 Subject: [PATCH 103/164] chore: add updated PR template to master --- .github/pull_request_template.md | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index d95b4278eb..a666c2f241 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -1,20 +1,23 @@ # Description -Please include a summary of the change and which issues are fixed. + Fixes #[issue] +Affected servers: + ## 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). +- [ ] Chore (CI, workflows, tooling or other maintenance). - [ ] Comment update (typo, spelling, explanation, examples, etc). ## Testing -Please list the exact validation you performed and the outcome. + - Commands/tests run: - Result: @@ -30,28 +33,23 @@ Please list the exact validation you performed and the outcome. - [ ] No breaking changes. - [ ] Breaking changes included (describe below). -## Documentation impact +## Documentation + + - [ ] No documentation update required. -- [ ] User documentation update required. -- [ ] Developer documentation update required. +- [ ] User documentation update required ([LinuxGSM-Docs](https://github.com/GameServerManagers/LinuxGSM-Docs)). +- [ ] Developer documentation update required ([LinuxGSM-Dev-Docs](https://github.com/GameServerManagers/LinuxGSM-Dev-Docs)). ## Checklist PR will not be merged until all steps are complete. -- [ ] This pull request links to an issue. +- [ ] This pull request links to an issue ("Fixes", or "Related to" for a partial fix). - [ ] 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 provided a detailed enough description of this PR. -## Documentation - -If documentation does need updating either update it by creating a PR (preferred) or request a documentation update. - -- User docs: -- Dev docs: - **Thank you for your Pull Request!** From 0e0a2477a5ff596168edf27006ac21d9d22a2c5f Mon Sep 17 00:00:00 2001 From: Daniel Gibbs Date: Sat, 17 Oct 2026 20:26:08 +0100 Subject: [PATCH 104/164] chore(sync): synced local '.github/' with remote 'general/.github/' (#5084) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Synced from dgibbs64/repo-sync@50af2c573b68d742251f90f30e878678e3da6f69 — perf(workflows): use slim super-linter and lint changed files on PRs (#26) Co-authored-by: dgibbs64 --- .github/workflows/action-super-linter.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/action-super-linter.yml b/.github/workflows/action-super-linter.yml index 472fbd27b3..567db5f327 100644 --- a/.github/workflows/action-super-linter.yml +++ b/.github/workflows/action-super-linter.yml @@ -40,11 +40,12 @@ jobs: npm install --no-save prettier prettier-plugin-sh prettier-plugin-jinja-template || true - name: Super-linter - uses: super-linter/super-linter@v9 + uses: super-linter/super-linter/slim@v9 env: # To report GitHub Actions status checks GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} MULTI_STATUS: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository }} + VALIDATE_ALL_CODEBASE: ${{ github.event_name != 'pull_request' }} VALIDATE_BIOME_FORMAT: false VALIDATE_BIOME_LINT: false VALIDATE_GITHUB_ACTIONS_ZIZMOR: false From be2d940ba93f0327e7da29575fbcc41c710fa2c2 Mon Sep 17 00:00:00 2001 From: Daniel Gibbs Date: Sat, 17 Oct 2026 20:29:26 +0100 Subject: [PATCH 105/164] fix(ck): allocate unique Xvfb displays (#5074) --- lgsm/config-default/config-lgsm/ckserver/_default.cfg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lgsm/config-default/config-lgsm/ckserver/_default.cfg b/lgsm/config-default/config-lgsm/ckserver/_default.cfg index de6b248f91..6be4b1c2c1 100644 --- a/lgsm/config-default/config-lgsm/ckserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/ckserver/_default.cfg @@ -181,7 +181,7 @@ glibc="2.15" ## Game Server Directories systemdir="${serverfiles}" executabledir="${serverfiles}" -preexecutable="xvfb-run" +preexecutable="xvfb-run -a" executable="./CoreKeeperServer" servercfgdir="${systemdir}/gamedata/${selfname}" servercfg="ServerConfig.json" From 4197b3a4fbd4b5fbcade400197d6856561884869 Mon Sep 17 00:00:00 2001 From: Daniel Gibbs Date: Sat, 17 Oct 2026 22:07:02 +0100 Subject: [PATCH 106/164] fix(deps): use Java 25 for mc and pmc on Ubuntu 22.04 (#5079) Minecraft 26.1 and later need Java 25 and refuse to start on Java 21. jammy-updates packages openjdk-25-jre, which hyt already uses on 22.04, so mc and pmc now install it too. --- lgsm/data/ubuntu-22.04.csv | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lgsm/data/ubuntu-22.04.csv b/lgsm/data/ubuntu-22.04.csv index def0e20b8f..f255fdd1bd 100644 --- a/lgsm/data/ubuntu-22.04.csv +++ b/lgsm/data/ubuntu-22.04.csv @@ -68,7 +68,7 @@ kf kf2 l4d l4d2 -mc,openjdk-21-jre +mc,openjdk-25-jre mcb mcv mh @@ -85,7 +85,7 @@ onset,libmariadb-dev opfor pc pc2 -pmc,openjdk-21-jre +pmc,openjdk-25-jre squad44 pvkii pvr,libc++1 From e76e35b6e658e1be8589788740aa08641c7434a6 Mon Sep 17 00:00:00 2001 From: Daniel Gibbs Date: Sat, 17 Oct 2026 22:28:27 +0100 Subject: [PATCH 107/164] fix(deps): fix RHEL family dependency lists for Rocky Linux 9 (#5077) * fix(deps): update Java and libstdc++ 5 deps for the RHEL family Minecraft 26.1+ needs Java 25. EL9 AppStream packages java-25-openjdk, so mc and pmc use it on AlmaLinux, CentOS Stream, RHEL and Rocky 9. EL7 and EL8 keep their older Java packages for pinned older releases, and the Minecraft Java runtime check stops with guidance when the configured version needs a newer Java. Hytale's java-25-openjdk is not packaged on EL7 or EL8, so the hyt rows there have no packages and check_deps warns that Java 25 must be installed manually, as it already does on older Debian and Ubuntu. compat-libstdc++-33.i686 is not packaged on EL8 or EL9. The cod, cod2, coduo and mohaa fix modules already provide libstdc++.so.5 when it is missing, so those rows have no packages there, matching rhel-9. EL7 still packages it and is unchanged. * fix(pvr): provide libc++ on distros that do not package it The Pavlov VR server links against libc++.so.1 and libc++abi.so.1. The RHEL family lists asked for libcxx, which no EL8 or EL9 repo provides, including EPEL and CRB. When ldd reports either library missing, fix_pvr now downloads libcxx-amd64-11.0.1-2.tar.xz (md5 pinned) and extracts it into serverfiles/linux64, which is already on LD_LIBRARY_PATH. The tarball holds the unmodified libraries and copyright files from Debian bullseye's libc++1-11 and libc++abi1-11 11.0.1-2 packages. LLVM 11 is used because it needs only glibc 2.18 and libatomic, so it also runs on EL8. The existing libc++.so copy now falls back to the bundled library. libcxx is replaced with libatomic in the RHEL family lists. Distros that package libc++1 are unaffected, as ldd finds the system library. --- lgsm/data/almalinux-8.csv | 12 ++++++------ lgsm/data/almalinux-9.csv | 14 +++++++------- lgsm/data/centos-7.csv | 4 ++-- lgsm/data/centos-8.csv | 12 ++++++------ lgsm/data/centos-9.csv | 14 +++++++------- lgsm/data/rhel-7.csv | 4 ++-- lgsm/data/rhel-8.csv | 12 ++++++------ lgsm/data/rhel-9.csv | 6 +++--- lgsm/data/rocky-8.csv | 12 ++++++------ lgsm/data/rocky-9.csv | 14 +++++++------- lgsm/modules/check_deps.sh | 6 +++--- lgsm/modules/fix_pvr.sh | 20 +++++++++++++++++--- 12 files changed, 72 insertions(+), 58 deletions(-) diff --git a/lgsm/data/almalinux-8.csv b/lgsm/data/almalinux-8.csv index 1ebeed9124..b6f53d271f 100644 --- a/lgsm/data/almalinux-8.csv +++ b/lgsm/data/almalinux-8.csv @@ -21,10 +21,10 @@ btl cc ck,xorg-x11-server-Xvfb cmw -cod,compat-libstdc++-33.i686 -cod2,compat-libstdc++-33.i686 +cod +cod2 cod4 -coduo,compat-libstdc++-33.i686 +coduo codwaw col cs @@ -54,7 +54,7 @@ hl2dm hldm hldms hw,zlib-devel -hyt,java-25-openjdk +hyt hz ins inss @@ -72,7 +72,7 @@ mc,java-21-openjdk mcb,libnsl mcv mh -mohaa,compat-libstdc++-33.i686 +mohaa mta,ncurses-compat-libs,libxml2 nd nec @@ -87,7 +87,7 @@ pc pc2 pmc,java-21-openjdk pvkii -pvr,libcxx +pvr,libatomic pw pz,java-11-openjdk rng-tools q2 diff --git a/lgsm/data/almalinux-9.csv b/lgsm/data/almalinux-9.csv index 3e8350a78f..bf90748489 100644 --- a/lgsm/data/almalinux-9.csv +++ b/lgsm/data/almalinux-9.csv @@ -21,10 +21,10 @@ btl cc ck,xorg-x11-server-Xvfb cmw -cod,compat-libstdc++-33.i686 -cod2,compat-libstdc++-33.i686 +cod +cod2 cod4 -coduo,compat-libstdc++-33.i686 +coduo codwaw col cs @@ -68,11 +68,11 @@ kf kf2 l4d l4d2 -mc,java-21-openjdk +mc,java-25-openjdk mcb,libnsl mcv mh -mohaa,compat-libstdc++-33.i686 +mohaa mta,ncurses-compat-libs,libxml2 nd nec @@ -85,9 +85,9 @@ onset,mariadb-connector-c opfor pc pc2 -pmc,java-21-openjdk +pmc,java-25-openjdk pvkii -pvr,libcxx +pvr,libatomic pw pz,java-21-openjdk rng-tools q2 diff --git a/lgsm/data/centos-7.csv b/lgsm/data/centos-7.csv index 060e2cf27a..578040039f 100644 --- a/lgsm/data/centos-7.csv +++ b/lgsm/data/centos-7.csv @@ -54,7 +54,7 @@ hl2dm hldm hldms hw,zlib-devel -hyt,java-25-openjdk +hyt hz ins inss @@ -87,7 +87,7 @@ pc pc2 pmc,java-11-openjdk pvkii -pvr,libcxx +pvr,libatomic pw pz,java-11-openjdk rng-tools q2 diff --git a/lgsm/data/centos-8.csv b/lgsm/data/centos-8.csv index 7dd7165cc2..e901a793e3 100644 --- a/lgsm/data/centos-8.csv +++ b/lgsm/data/centos-8.csv @@ -21,10 +21,10 @@ btl cc ck,xorg-x11-server-Xvfb cmw -cod,compat-libstdc++-33.i686 -cod2,compat-libstdc++-33.i686 +cod +cod2 cod4 -coduo,compat-libstdc++-33.i686 +coduo codwaw col cs @@ -54,7 +54,7 @@ hl2dm hldm hldms hw,zlib-devel -hyt,java-25-openjdk +hyt hz ins inss @@ -72,7 +72,7 @@ mc,java-21-openjdk mcb,libnsl mcv mh -mohaa,compat-libstdc++-33.i686 +mohaa mta,ncurses-compat-libs,libxml2 nd nec @@ -87,7 +87,7 @@ pc pc2 pmc,java-17-openjdk pvkii -pvr,libcxx +pvr,libatomic pw pz,java-11-openjdk rng-tools q2 diff --git a/lgsm/data/centos-9.csv b/lgsm/data/centos-9.csv index 935eff7e83..a029dadf41 100644 --- a/lgsm/data/centos-9.csv +++ b/lgsm/data/centos-9.csv @@ -21,10 +21,10 @@ btl cc ck,xorg-x11-server-Xvfb cmw -cod,compat-libstdc++-33.i686 -cod2,compat-libstdc++-33.i686 +cod +cod2 cod4 -coduo,compat-libstdc++-33.i686 +coduo codwaw col cs @@ -68,11 +68,11 @@ kf kf2 l4d l4d2 -mc,java-17-openjdk +mc,java-25-openjdk mcb,libnsl mcv mh -mohaa,compat-libstdc++-33.i686 +mohaa mta,ncurses-compat-libs,libxml2 nd nec @@ -85,9 +85,9 @@ onset,mariadb-connector-c opfor pc pc2 -pmc,java-17-openjdk +pmc,java-25-openjdk pvkii -pvr,libcxx +pvr,libatomic pw pz,java-21-openjdk rng-tools q2 diff --git a/lgsm/data/rhel-7.csv b/lgsm/data/rhel-7.csv index ff3f41901f..7b1fdd5f3f 100644 --- a/lgsm/data/rhel-7.csv +++ b/lgsm/data/rhel-7.csv @@ -55,7 +55,7 @@ hl2dm hldm hldms hw,zlib-devel -hyt,java-25-openjdk +hyt hz ins inss @@ -88,7 +88,7 @@ pc pc2 pmc,java-11-openjdk pvkii -pvr,libcxx +pvr,libatomic pz,java-11-openjdk rng-tools q2 q3 diff --git a/lgsm/data/rhel-8.csv b/lgsm/data/rhel-8.csv index 7097fe244c..b626fd6213 100644 --- a/lgsm/data/rhel-8.csv +++ b/lgsm/data/rhel-8.csv @@ -21,10 +21,10 @@ btl cc ck,xorg-x11-server-Xvfb cmw -cod,compat-libstdc++-33.i686 -cod2,compat-libstdc++-33.i686 +cod +cod2 cod4 -coduo,compat-libstdc++-33.i686 +coduo codwaw col cs @@ -54,7 +54,7 @@ hl2dm hldm hldms hw,zlib-devel -hyt,java-25-openjdk +hyt hz ins inss @@ -72,7 +72,7 @@ mc,java-21-openjdk mcb,libnsl mcv mh -mohaa,compat-libstdc++-33.i686 +mohaa mta,ncurses-compat-libs,libxml2 nd nec @@ -87,7 +87,7 @@ pc pc2 pmc,java-21-openjdk pvkii -pvr,libcxx +pvr,libatomic pw pz,java-21-openjdk rng-tools q2 diff --git a/lgsm/data/rhel-9.csv b/lgsm/data/rhel-9.csv index 6cb9ec7140..bf90748489 100644 --- a/lgsm/data/rhel-9.csv +++ b/lgsm/data/rhel-9.csv @@ -68,7 +68,7 @@ kf kf2 l4d l4d2 -mc,java-21-openjdk +mc,java-25-openjdk mcb,libnsl mcv mh @@ -85,9 +85,9 @@ onset,mariadb-connector-c opfor pc pc2 -pmc,java-21-openjdk +pmc,java-25-openjdk pvkii -pvr,libcxx +pvr,libatomic pw pz,java-21-openjdk rng-tools q2 diff --git a/lgsm/data/rocky-8.csv b/lgsm/data/rocky-8.csv index 7097fe244c..b626fd6213 100644 --- a/lgsm/data/rocky-8.csv +++ b/lgsm/data/rocky-8.csv @@ -21,10 +21,10 @@ btl cc ck,xorg-x11-server-Xvfb cmw -cod,compat-libstdc++-33.i686 -cod2,compat-libstdc++-33.i686 +cod +cod2 cod4 -coduo,compat-libstdc++-33.i686 +coduo codwaw col cs @@ -54,7 +54,7 @@ hl2dm hldm hldms hw,zlib-devel -hyt,java-25-openjdk +hyt hz ins inss @@ -72,7 +72,7 @@ mc,java-21-openjdk mcb,libnsl mcv mh -mohaa,compat-libstdc++-33.i686 +mohaa mta,ncurses-compat-libs,libxml2 nd nec @@ -87,7 +87,7 @@ pc pc2 pmc,java-21-openjdk pvkii -pvr,libcxx +pvr,libatomic pw pz,java-21-openjdk rng-tools q2 diff --git a/lgsm/data/rocky-9.csv b/lgsm/data/rocky-9.csv index 3e8350a78f..bf90748489 100644 --- a/lgsm/data/rocky-9.csv +++ b/lgsm/data/rocky-9.csv @@ -21,10 +21,10 @@ btl cc ck,xorg-x11-server-Xvfb cmw -cod,compat-libstdc++-33.i686 -cod2,compat-libstdc++-33.i686 +cod +cod2 cod4 -coduo,compat-libstdc++-33.i686 +coduo codwaw col cs @@ -68,11 +68,11 @@ kf kf2 l4d l4d2 -mc,java-21-openjdk +mc,java-25-openjdk mcb,libnsl mcv mh -mohaa,compat-libstdc++-33.i686 +mohaa mta,ncurses-compat-libs,libxml2 nd nec @@ -85,9 +85,9 @@ onset,mariadb-connector-c opfor pc pc2 -pmc,java-21-openjdk +pmc,java-25-openjdk pvkii -pvr,libcxx +pvr,libatomic pw pz,java-21-openjdk rng-tools q2 diff --git a/lgsm/modules/check_deps.sh b/lgsm/modules/check_deps.sh index 59f58c9887..3d52cd0ed3 100755 --- a/lgsm/modules/check_deps.sh +++ b/lgsm/modules/check_deps.sh @@ -479,12 +479,12 @@ if [ "${depcheckonly}" != "1" ]; then fi fi - # Hytale needs Java 25, which Ubuntu before 22.04 and Debian before 13 do not package. + # Hytale needs Java 25, which Ubuntu before 22.04, Debian before 13 and RHEL before 9 do not package. if [ "${shortname}" == "hyt" ]; then - if { [ "${distroid}" == "ubuntu" ] && [ "${distroversion}" != "22.04" ] && dpkg --compare-versions "${distroversion}" "lt" "24.04"; } || { [ "${distroid}" == "debian" ] && dpkg --compare-versions "${distroversion}" "lt" "13"; }; then + if { [ "${distroid}" == "ubuntu" ] && [ "${distroversion}" != "22.04" ] && dpkg --compare-versions "${distroversion}" "lt" "24.04"; } || { [ "${distroid}" == "debian" ] && dpkg --compare-versions "${distroversion}" "lt" "13"; } || { [ -n "${distroversionrh}" ] && [ "${distroversionrh}" -lt "9" ]; }; then if ! echo "${javaversion}" | grep -Eq 'version "(2[5-9]|[3-9][0-9])'; then fn_print_warning_nl "${gamename} requires Java 25, which ${distroname} does not provide." - echo -e "Install Java 25 manually or upgrade to Ubuntu 22.04+ or Debian 13+." + echo -e "Install Java 25 manually or upgrade to Ubuntu 22.04+, Debian 13+ or a RHEL 9 based distro." fn_script_log_warn "${gamename} requires Java 25, which ${distroname} does not provide." fi fi diff --git a/lgsm/modules/fix_pvr.sh b/lgsm/modules/fix_pvr.sh index e4409bc37b..39d4fd3ee4 100755 --- a/lgsm/modules/fix_pvr.sh +++ b/lgsm/modules/fix_pvr.sh @@ -7,8 +7,22 @@ moduleselfname="$(basename "$(readlink -f "${BASH_SOURCE[0]}")")" -if [ ! -f "${serverfiles}/linux64/libc++.so" ] && [ -f "/usr/lib/x86_64-linux-gnu/libc++.so.1" ]; then - cp "/usr/lib/x86_64-linux-gnu/libc++.so.1" "${serverfiles}/linux64/libc++.so" +export LD_LIBRARY_PATH="$LD_LIBRARY_PATH:${serverfiles}:${serverfiles}/linux64" + +if ldd "${executabledir}/PavlovServer-Linux-Shipping" 2>&1 | grep -qE "libc\+\+(abi)?\.so\.1 => not found"; then + # shellcheck disable=SC2034 # Used by fn_fix_msg_start_nl and fn_fix_msg_end. + fixname="libc++ amd64" + fn_fix_msg_start_nl + fn_fetch_file "https://linuxgsm.download/libraries/libcxx-amd64-11.0.1-2.tar.xz" "" "" "" "${tmpdir}" "libcxx-amd64-11.0.1-2.tar.xz" "nochmodx" "norun" "noforce" "2a75a54c6637d217e3821220b0d5571f" + fn_dl_extract "${tmpdir}" "libcxx-amd64-11.0.1-2.tar.xz" "${serverfiles}/linux64" + fn_clear_tmp + fn_fix_msg_end fi -export LD_LIBRARY_PATH="$LD_LIBRARY_PATH:${serverfiles}:${serverfiles}/linux64" +if [ ! -f "${serverfiles}/linux64/libc++.so" ]; then + if [ -f "/usr/lib/x86_64-linux-gnu/libc++.so.1" ]; then + cp "/usr/lib/x86_64-linux-gnu/libc++.so.1" "${serverfiles}/linux64/libc++.so" + elif [ -f "${serverfiles}/linux64/libc++.so.1" ]; then + cp -L "${serverfiles}/linux64/libc++.so.1" "${serverfiles}/linux64/libc++.so" + fi +fi From 6872f095b9c870cef27fb1b3c93b0042bb77c595 Mon Sep 17 00:00:00 2001 From: Daniel Gibbs Date: Sat, 17 Oct 2026 22:39:12 +0100 Subject: [PATCH 108/164] fix: repair console timestamp logging (#5073) --- lgsm/modules/check_deps.sh | 3 +++ lgsm/modules/command_start.sh | 5 +++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/lgsm/modules/check_deps.sh b/lgsm/modules/check_deps.sh index 3d52cd0ed3..bbd3e5747d 100755 --- a/lgsm/modules/check_deps.sh +++ b/lgsm/modules/check_deps.sh @@ -511,6 +511,9 @@ if [ -f "${datadir}/${distroid}-${distroversioncsv}.csv" ]; then array_deps_required=("${depall} ${depsteamcmd} ${depshortname}") array_deps_required_steamcmd=("${depsteamcmd}") fn_deps_email + if [ "${logtimestamp}" == "on" ]; then + array_deps_required+=(gawk) + fi # Unique sort dependency array. IFS=" " read -r -a array_deps_required <<< "$(echo "${array_deps_required[@]}" | tr ' ' '\n' | sort -u | tr '\n' ' ')" diff --git a/lgsm/modules/command_start.sh b/lgsm/modules/command_start.sh index 86ca683a38..255bc29fbf 100755 --- a/lgsm/modules/command_start.sh +++ b/lgsm/modules/command_start.sh @@ -8,7 +8,8 @@ commandname="START" commandaction="Starting" moduleselfname="$(basename "$(readlink -f "${BASH_SOURCE[0]}")")" -addtimestamp="gawk '{ print strftime(\\\"[$logtimestampformat]\\\"), \\\$0 }'" +logtimestampformat_tmux="${logtimestampformat//%/%%}" +addtimestamp="gawk '{ print strftime(\"[$logtimestampformat_tmux]\"), \$0; fflush() }'" fn_firstcommand_set # This will allow the Jedi Knight 2 version to be printed in console on start. @@ -157,7 +158,7 @@ fn_start_tmux() { if [ "${consolelogging}" == "on" ] || [ -z "${consolelogging}" ]; then # timestamp will break mcb update check. if [ "${logtimestamp}" == "on" ] && [ "${shortname}" != "mcb" ]; then - TERM=screen tmux -L "${socketname}" pipe-pane -o -t "${sessionname}" "exec bash -c \"cat | $addtimestamp\" >> '${consolelog}'" + TERM=screen tmux -L "${socketname}" pipe-pane -o -t "${sessionname}" "exec ${addtimestamp} >> '${consolelog}'" else TERM=screen tmux -L "${socketname}" pipe-pane -o -t "${sessionname}" "exec cat >> '${consolelog}'" fi From 57c73bc9562385cc27490c2e5d9f52a0568e75df Mon Sep 17 00:00:00 2001 From: Daniel Gibbs Date: Sat, 17 Oct 2026 22:53:18 +0100 Subject: [PATCH 109/164] fix(steamcmd): stream progress output and propagate SteamCMD exit code (#5055) * fix(steamcmd): stream progress output and propagate SteamCMD exit code SteamCMD output was piped through uniq before tee. uniq writes to a pipe, so it block-buffers its output and progress only reached the terminal and logs when SteamCMD exited, defeating unbuffer. stdbuf -oL is not a portable fix: it has no effect on uutils coreutils (the Ubuntu 26.04 default), and mawk also buffers pipe input. Replace uniq with fn_dl_steamcmd_output, a bash read loop that drops consecutive duplicate lines (keeping the #3010 behaviour) and writes each line immediately. exitcode=$? after the pipelines was tee's status, so a SteamCMD crash without an "Error!" line was reported as success. Capture ${PIPESTATUS[0]} after each SteamCMD pipeline instead, so non-zero exits are reported and retried. unbuffer passes the child exit code through. Fixes #3655 * fix(steamcmd): restore executable bit on core_dl.sh --- lgsm/modules/core_dl.sh | 48 ++++++++++++++++++++++++++++++----------- 1 file changed, 35 insertions(+), 13 deletions(-) diff --git a/lgsm/modules/core_dl.sh b/lgsm/modules/core_dl.sh index 752d4871a1..7da65094eb 100755 --- a/lgsm/modules/core_dl.sh +++ b/lgsm/modules/core_dl.sh @@ -19,6 +19,20 @@ moduleselfname="$(basename "$(readlink -f "${BASH_SOURCE[0]}")")" +# Removes consecutive duplicate lines from SteamCMD output without buffering. +fn_dl_steamcmd_output() { + local line="" + local previousline="" + local firstline="1" + while IFS= read -r line || [ -n "${line}" ]; do + if [ -n "${firstline}" ] || [ "${line}" != "${previousline}" ]; then + printf '%s\n' "${line}" + fi + previousline="${line}" + firstline="" + done +} + fn_dl_steamcmd() { remotelocation="SteamCMD" fn_print_start_nl "${remotelocation}" @@ -74,11 +88,14 @@ fn_dl_steamcmd() { if [ "${appid}" == "90" ]; then # If using a specific branch. if [ -n "${branch}" ] && [ -n "${betapassword}" ]; then - "${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}" + "${unbuffercommand[@]}" "${steamcmdcommandarray[@]}" +force_install_dir "${serverfiles}" +login "${steamuser}" "${steampass}" +app_set_config 90 mod "${appidmod}" +app_update "${appid}" -beta "${branch}" -betapassword "${betapassword}" "${validateparam[@]}" +quit | fn_dl_steamcmd_output | tee -a "${lgsmlog}" "${steamcmdlog}" + exitcode="${PIPESTATUS[0]}" elif [ -n "${branch}" ]; then - "${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}" + "${unbuffercommand[@]}" "${steamcmdcommandarray[@]}" +force_install_dir "${serverfiles}" +login "${steamuser}" "${steampass}" +app_set_config 90 mod "${appidmod}" +app_update "${appid}" -beta "${branch}" "${validateparam[@]}" +quit | fn_dl_steamcmd_output | tee -a "${lgsmlog}" "${steamcmdlog}" + exitcode="${PIPESTATUS[0]}" else - "${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}" + "${unbuffercommand[@]}" "${steamcmdcommandarray[@]}" +force_install_dir "${serverfiles}" +login "${steamuser}" "${steampass}" +app_set_config 90 mod "${appidmod}" +app_update "${appid}" "${validateparam[@]}" +quit | fn_dl_steamcmd_output | tee -a "${lgsmlog}" "${steamcmdlog}" + exitcode="${PIPESTATUS[0]}" fi # Force Windows Platform type. elif [ "${steamcmdforcewindows}" == "yes" ]; then @@ -89,18 +106,21 @@ fn_dl_steamcmd() { fn_script_log_fail "${commandaction} ${selfname}: baseappid is set but supportdir is not defined" core_exit.sh fi - "${unbuffercommand[@]}" "${steamcmdcommandarray[@]}" +@sSteamCmdForcePlatformType windows +force_install_dir "${supportdir}" +login "${steamuser}" "${steampass}" +app_update "${baseappid}" "${validateparam[@]}" +quit | uniq | tee -a "${lgsmlog}" "${steamcmdlog}" + "${unbuffercommand[@]}" "${steamcmdcommandarray[@]}" +@sSteamCmdForcePlatformType windows +force_install_dir "${supportdir}" +login "${steamuser}" "${steampass}" +app_update "${baseappid}" "${validateparam[@]}" +quit | fn_dl_steamcmd_output | tee -a "${lgsmlog}" "${steamcmdlog}" exitcode="${PIPESTATUS[0]}" if [ "${exitcode}" -ne 0 ]; then continue fi fi if [ -n "${branch}" ] && [ -n "${betapassword}" ]; then - "${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}" + "${unbuffercommand[@]}" "${steamcmdcommandarray[@]}" +@sSteamCmdForcePlatformType windows +force_install_dir "${serverfiles}" +login "${steamuser}" "${steampass}" +app_update "${appid}" -beta "${branch}" -betapassword "${betapassword}" "${validateparam[@]}" +quit | fn_dl_steamcmd_output | tee -a "${lgsmlog}" "${steamcmdlog}" + exitcode="${PIPESTATUS[0]}" elif [ -n "${branch}" ]; then - "${unbuffercommand[@]}" "${steamcmdcommandarray[@]}" +@sSteamCmdForcePlatformType windows +force_install_dir "${serverfiles}" +login "${steamuser}" "${steampass}" +app_update "${appid}" -beta "${branch}" "${validateparam[@]}" +quit | uniq | tee -a "${lgsmlog}" "${steamcmdlog}" + "${unbuffercommand[@]}" "${steamcmdcommandarray[@]}" +@sSteamCmdForcePlatformType windows +force_install_dir "${serverfiles}" +login "${steamuser}" "${steampass}" +app_update "${appid}" -beta "${branch}" "${validateparam[@]}" +quit | fn_dl_steamcmd_output | tee -a "${lgsmlog}" "${steamcmdlog}" + exitcode="${PIPESTATUS[0]}" else - "${unbuffercommand[@]}" "${steamcmdcommandarray[@]}" +@sSteamCmdForcePlatformType windows +force_install_dir "${serverfiles}" +login "${steamuser}" "${steampass}" +app_update "${appid}" "${validateparam[@]}" +quit | uniq | tee -a "${lgsmlog}" "${steamcmdlog}" + "${unbuffercommand[@]}" "${steamcmdcommandarray[@]}" +@sSteamCmdForcePlatformType windows +force_install_dir "${serverfiles}" +login "${steamuser}" "${steampass}" +app_update "${appid}" "${validateparam[@]}" +quit | fn_dl_steamcmd_output | tee -a "${lgsmlog}" "${steamcmdlog}" + exitcode="${PIPESTATUS[0]}" fi # All other servers. else @@ -111,24 +131,26 @@ fn_dl_steamcmd() { fn_script_log_fail "${commandaction} ${selfname}: baseappid is set but supportdir is not defined" core_exit.sh fi - "${unbuffercommand[@]}" "${steamcmdcommandarray[@]}" +force_install_dir "${supportdir}" +login "${steamuser}" "${steampass}" +app_update "${baseappid}" "${validateparam[@]}" +quit | uniq | tee -a "${lgsmlog}" "${steamcmdlog}" + "${unbuffercommand[@]}" "${steamcmdcommandarray[@]}" +force_install_dir "${supportdir}" +login "${steamuser}" "${steampass}" +app_update "${baseappid}" "${validateparam[@]}" +quit | fn_dl_steamcmd_output | tee -a "${lgsmlog}" "${steamcmdlog}" exitcode="${PIPESTATUS[0]}" if [ "${exitcode}" -ne 0 ]; then continue fi fi if [ -n "${branch}" ] && [ -n "${betapassword}" ]; then - "${unbuffercommand[@]}" "${steamcmdcommandarray[@]}" +force_install_dir "${serverfiles}" +login "${steamuser}" "${steampass}" +app_update "${appid}" -beta "${branch}" -betapassword "${betapassword}" "${validateparam[@]}" +quit | uniq | tee -a "${lgsmlog}" "${steamcmdlog}" + "${unbuffercommand[@]}" "${steamcmdcommandarray[@]}" +force_install_dir "${serverfiles}" +login "${steamuser}" "${steampass}" +app_update "${appid}" -beta "${branch}" -betapassword "${betapassword}" "${validateparam[@]}" +quit | fn_dl_steamcmd_output | tee -a "${lgsmlog}" "${steamcmdlog}" + exitcode="${PIPESTATUS[0]}" elif [ -n "${branch}" ]; then - "${unbuffercommand[@]}" "${steamcmdcommandarray[@]}" +force_install_dir "${serverfiles}" +login "${steamuser}" "${steampass}" +app_update "${appid}" -beta "${branch}" "${validateparam[@]}" +quit | uniq | tee -a "${lgsmlog}" "${steamcmdlog}" + "${unbuffercommand[@]}" "${steamcmdcommandarray[@]}" +force_install_dir "${serverfiles}" +login "${steamuser}" "${steampass}" +app_update "${appid}" -beta "${branch}" "${validateparam[@]}" +quit | fn_dl_steamcmd_output | tee -a "${lgsmlog}" "${steamcmdlog}" + exitcode="${PIPESTATUS[0]}" else - "${unbuffercommand[@]}" "${steamcmdcommandarray[@]}" +force_install_dir "${serverfiles}" +login "${steamuser}" "${steampass}" +app_update "${appid}" "${validateparam[@]}" +quit | uniq | tee -a "${lgsmlog}" "${steamcmdlog}" + "${unbuffercommand[@]}" "${steamcmdcommandarray[@]}" +force_install_dir "${serverfiles}" +login "${steamuser}" "${steampass}" +app_update "${appid}" "${validateparam[@]}" +quit | fn_dl_steamcmd_output | tee -a "${lgsmlog}" "${steamcmdlog}" + exitcode="${PIPESTATUS[0]}" fi fi # Error checking for SteamCMD. Some errors will loop to try again and some will just exit. # Check also if we have more errors than retries to be sure that we do not loop to many times and error out. - exitcode=$? if [ -n "$(grep -i "Error!" "${steamcmdlog}" | tail -1)" ] && [ "$(grep -ic "Error!" "${steamcmdlog}")" -ge "${counter}" ]; then # Not enough space. if [ -n "$(grep "0x202" "${steamcmdlog}" | tail -1)" ]; then @@ -145,7 +167,7 @@ fn_dl_steamcmd() { invalidplatformworkaround="1" fn_print_error2_nl "${commandaction} ${selfname}: ${remotelocation}: Invalid platform - applying SteamCMD Windows platform workaround" fn_script_log_error "${commandaction} ${selfname}: ${remotelocation}: Invalid platform - applying SteamCMD Windows platform workaround" - "${unbuffercommand[@]}" "${steamcmdcommandarray[@]}" +@sSteamCmdForcePlatformType windows +force_install_dir "${serverfiles}" +login "${steamuser}" "${steampass}" +app_update "${appid}" +quit | uniq | tee -a "${lgsmlog}" "${steamcmdlog}" + "${unbuffercommand[@]}" "${steamcmdcommandarray[@]}" +@sSteamCmdForcePlatformType windows +force_install_dir "${serverfiles}" +login "${steamuser}" "${steampass}" +app_update "${appid}" +quit | fn_dl_steamcmd_output | tee -a "${lgsmlog}" "${steamcmdlog}" validateparam=("validate") rm -f "${steamcmdlog:?}" counter=0 From d8ba5da7bbf534ab5c144b73ddb3b1a910dde765 Mon Sep 17 00:00:00 2001 From: Daniel Gibbs Date: Sat, 17 Oct 2026 23:16:53 +0100 Subject: [PATCH 110/164] feat(ceserver): add Conan Exiles server (#5068) * feat(ceserver): add Conan Exiles server Adds the native Linux dedicated server for Conan Exiles (Enhanced), Steam appid 443030. Resolves #4923 * feat(ceserver): add stop mode for Conan Exiles The first CTRL+c runs the engine shutdown but the process then hangs. A second CTRL+c exits it. * fix(ceserver): require glibc 2.28 --- .../config-lgsm/ceserver/_default.cfg | 216 ++++++++++++++++++ lgsm/data/almalinux-8.csv | 1 + lgsm/data/almalinux-9.csv | 1 + lgsm/data/centos-7.csv | 1 + lgsm/data/centos-8.csv | 1 + lgsm/data/centos-9.csv | 1 + lgsm/data/debian-10.csv | 1 + lgsm/data/debian-11.csv | 1 + lgsm/data/debian-12.csv | 1 + lgsm/data/debian-13.csv | 1 + lgsm/data/debian-9.csv | 1 + lgsm/data/gameicons/ce-icon.png | Bin 0 -> 2479 bytes lgsm/data/rhel-7.csv | 1 + lgsm/data/rhel-8.csv | 1 + lgsm/data/rhel-9.csv | 1 + lgsm/data/rocky-8.csv | 1 + lgsm/data/rocky-9.csv | 1 + lgsm/data/serverlist.csv | 1 + lgsm/data/ubuntu-16.04.csv | 1 + lgsm/data/ubuntu-18.04.csv | 1 + lgsm/data/ubuntu-20.04.csv | 1 + lgsm/data/ubuntu-22.04.csv | 1 + lgsm/data/ubuntu-23.04.csv | 1 + lgsm/data/ubuntu-23.10.csv | 1 + lgsm/data/ubuntu-24.04.csv | 1 + lgsm/data/ubuntu-26.04.csv | 1 + lgsm/modules/check_system_requirements.sh | 2 + lgsm/modules/command_stop.sh | 10 + lgsm/modules/info_game.sh | 21 ++ lgsm/modules/info_messages.sh | 15 +- 30 files changed, 287 insertions(+), 1 deletion(-) create mode 100644 lgsm/config-default/config-lgsm/ceserver/_default.cfg create mode 100644 lgsm/data/gameicons/ce-icon.png diff --git a/lgsm/config-default/config-lgsm/ceserver/_default.cfg b/lgsm/config-default/config-lgsm/ceserver/_default.cfg new file mode 100644 index 0000000000..5dbde6730b --- /dev/null +++ b/lgsm/config-default/config-lgsm/ceserver/_default.cfg @@ -0,0 +1,216 @@ +################################## +######## Default Settings ######## +################################## +# DO NOT EDIT, ANY CHANGES WILL BE OVERWRITTEN! +# Copy settings from here and use them in either: +# common.cfg - applies settings to every instance. +# [instance].cfg - applies settings to a specific instance. + +#### Game Server Settings #### + +## Predefined Parameters | https://docs.linuxgsm.com/configuration/start-parameters +ip="0.0.0.0" +port="7777" +queryport="27015" +servername="LinuxGSM" +maxplayers="40" + +## Server Parameters | https://docs.linuxgsm.com/configuration/start-parameters#additional-parameters +startparameters="ConanSandbox -log -MULTIHOME=${ip} -Port=${port} -QueryPort=${queryport} -ServerName='${servername}' -MaxPlayers=${maxplayers}" + +#### LinuxGSM Settings #### + +## LinuxGSM Stats +# Send useful stats to LinuxGSM developers. +# https://docs.linuxgsm.com/configuration/linuxgsm-stats +# (on|off) +stats="off" + +## Notification Alerts +# (on|off) + +# Display IP | https://docs.linuxgsm.com/alerts#display-ip +displayip="" + +# More info | https://docs.linuxgsm.com/alerts#more-info +postalert="off" + +# Alert on Start/Stop/Restart +statusalert="off" + +# Discord Alerts | https://docs.linuxgsm.com/alerts/discord +discordalert="off" +discordwebhook="webhook" + +# Email Alerts | https://docs.linuxgsm.com/alerts/email +emailalert="off" +email="email@example.com" +emailfrom="" + +# Gotify Alerts | https://docs.linuxgsm.com/alerts/gotify +gotifyalert="off" +gotifytoken="token" +gotifywebhook="webhook" + +# IFTTT Alerts | https://docs.linuxgsm.com/alerts/ifttt +iftttalert="off" +ifttttoken="accesstoken" +iftttevent="linuxgsm_alert" + +# ntfy Alerts | https://docs.linuxgsm.com/alerts/ntfy +ntfyalert="off" +ntfytopic="LinuxGSM" +ntfyserver="https://ntfy.sh" +ntfytoken="" +ntfyusername="" +ntfypassword="" +ntfypriority="" +ntfytags="" + +# Matrix Alerts | https://docs.linuxgsm.com/alerts/matrix +matrixalert="off" +matrixhomeserver="matrix.org" +matrixtoken="accesstoken" +matrixroom="" + +# Pushbullet Alerts | https://docs.linuxgsm.com/alerts/pushbullet +pushbulletalert="off" +pushbullettoken="accesstoken" +channeltag="" + +# Pushover Alerts | https://docs.linuxgsm.com/alerts/pushover +pushoveralert="off" +pushovertoken="accesstoken" +pushoveruserkey="userkey" + +# Rocket.Chat Alerts | https://docs.linuxgsm.com/alerts/rocket.chat +rocketchatalert="off" +rocketchatwebhook="webhook" + +# Slack Alerts | https://docs.linuxgsm.com/alerts/slack +slackalert="off" +slackwebhook="webhook" + +# Telegram Alerts | https://docs.linuxgsm.com/alerts/telegram +# You can add a custom cURL string eg proxy (useful in Russia) in "curlcustomstring". +# For example "--socks5 ipaddr:port" for socks5 proxy see more in "curl --help all". +telegramapi="api.telegram.org" +telegramalert="off" +telegramtoken="accesstoken" +telegramchatid="" +telegramthreadid="" +telegramsilentnotification="false" +curlcustomstring="" + +## Stop | https://docs.linuxgsm.com/commands/start-stop-restart +stoponlyifnoplayers="off" +stoponlyifnoplayersallcommands="on" + +## Player Warnings | https://docs.linuxgsm.com/features/player-warnings +# Minutes to warn players in-game before a stop, restart or update. 0 to disable. +# e.g. 15 warns at 15, 10, 5, 3 and 1 minutes. +warnplayerstimer="0" + +## Updating | https://docs.linuxgsm.com/commands/update +updateonstart="off" + +## Backup | https://docs.linuxgsm.com/commands/backup +maxbackups="4" +maxbackupdays="30" +stoponbackup="on" + +## Logging | https://docs.linuxgsm.com/features/logging +consolelogging="on" +logdays="7" + +## Monitor | https://docs.linuxgsm.com/commands/monitor +# Query delay time +querydelay="5" + +## ANSI Colors | https://docs.linuxgsm.com/features/ansi-colors +ansi="on" + +#### Advanced Settings #### + +## Message Display Time | https://docs.linuxgsm.com/features/message-display-time +sleeptime="0.5" + +## SteamCMD Settings | https://docs.linuxgsm.com/steamcmd +# Server appid +appid="443030" +steamcmdforcewindows="no" +# SteamCMD Branch | https://docs.linuxgsm.com/steamcmd/branch +branch="" +betapassword="" +# Master Server | https://docs.linuxgsm.com/steamcmd/steam-master-server +steammaster="true" + +## Stop Mode | https://docs.linuxgsm.com/features/stop-mode +# 1: tmux kill +# 2: CTRL+c +# 3: quit +# 4: quit 120s +# 5: stop +# 6: q +# 7: exit +# 8: 7 Days to Die +# 9: GoldSrc +# 10: Avorion +# 11: end +# 12: shutdown +# 13: soulmask +# 14: Running With Rifles +# 15: Rising World +# 16: Conan Exiles +stopmode="16" + +## Query mode +# 1: session only +# 2: gamedig (gsquery fallback) +# 3: gamedig +# 4: gsquery +# 5: tcp +querymode="2" +querytype="protocol-valve" + +## Console type +consoleverbose="yes" +consoleinteract="no" + +## Game Server Details +# Do not edit +gamename="Conan Exiles" +engine="unreal5" +glibc="2.28" + +#### Directories #### +# Edit with care + +## Game Server Directories +systemdir="${serverfiles}/ConanSandbox" +executabledir="${systemdir}/Binaries/Linux" +executable="./ConanSandboxServer-Linux-Shipping" +servercfgdir="${systemdir}/Saved/Config/LinuxServer" +servercfg="ServerSettings.ini" +servercfgfullpath="${servercfgdir}/${servercfg}" + +## Backup Directory +backupdir="${lgsmdir}/backup" + +## Logging Directories +[ -n "${LGSM_LOGDIR}" ] && logdir="${LGSM_LOGDIR}" || logdir="${rootdir}/log" +gamelogdir="${systemdir}/Saved/Logs" +lgsmlogdir="${logdir}/script" +consolelogdir="${logdir}/console" +lgsmlog="${lgsmlogdir}/${selfname}-script.log" +consolelog="${consolelogdir}/${selfname}-console.log" +alertlog="${lgsmlogdir}/${selfname}-alert.log" +postdetailslog="${lgsmlogdir}/${selfname}-postdetails.log" + +## Logs Naming +lgsmlogdate="${lgsmlogdir}/${selfname}-script-$(date '+%Y-%m-%d-%H:%M:%S').log" +consolelogdate="${consolelogdir}/${selfname}-console-$(date '+%Y-%m-%d-%H:%M:%S').log" + +## Log Parameters +logtimestamp="off" +logtimestampformat="%Y-%m-%d %H:%M:%S" diff --git a/lgsm/data/almalinux-8.csv b/lgsm/data/almalinux-8.csv index b6f53d271f..009e15bcb7 100644 --- a/lgsm/data/almalinux-8.csv +++ b/lgsm/data/almalinux-8.csv @@ -19,6 +19,7 @@ bs bt,libicu,dos2unix,libxml2 btl cc +ce ck,xorg-x11-server-Xvfb cmw cod diff --git a/lgsm/data/almalinux-9.csv b/lgsm/data/almalinux-9.csv index bf90748489..0e0242c76c 100644 --- a/lgsm/data/almalinux-9.csv +++ b/lgsm/data/almalinux-9.csv @@ -19,6 +19,7 @@ bs bt,libicu,dos2unix,libxml2 btl cc +ce ck,xorg-x11-server-Xvfb cmw cod diff --git a/lgsm/data/centos-7.csv b/lgsm/data/centos-7.csv index 578040039f..03a5f0066d 100644 --- a/lgsm/data/centos-7.csv +++ b/lgsm/data/centos-7.csv @@ -19,6 +19,7 @@ bs bt,libicu,dos2unix,libxml2 btl cc +ce ck,xorg-x11-server-Xvfb cmw cod,compat-libstdc++-33.i686 diff --git a/lgsm/data/centos-8.csv b/lgsm/data/centos-8.csv index e901a793e3..3254439dd5 100644 --- a/lgsm/data/centos-8.csv +++ b/lgsm/data/centos-8.csv @@ -19,6 +19,7 @@ bs bt,libicu,dos2unix,libxml2 btl cc +ce ck,xorg-x11-server-Xvfb cmw cod diff --git a/lgsm/data/centos-9.csv b/lgsm/data/centos-9.csv index a029dadf41..7639b0e3d0 100644 --- a/lgsm/data/centos-9.csv +++ b/lgsm/data/centos-9.csv @@ -19,6 +19,7 @@ bs bt,libicu,dos2unix,libxml2 btl cc +ce ck,xorg-x11-server-Xvfb cmw cod diff --git a/lgsm/data/debian-10.csv b/lgsm/data/debian-10.csv index ccda5411d1..29008bc5f8 100644 --- a/lgsm/data/debian-10.csv +++ b/lgsm/data/debian-10.csv @@ -18,6 +18,7 @@ bs bt,libicu-dev,dos2unix,libxml2-utils btl cc +ce ck,xvfb,libxi6 cmw cod,libstdc++5:i386 diff --git a/lgsm/data/debian-11.csv b/lgsm/data/debian-11.csv index 24e562cf6d..dacf209c43 100644 --- a/lgsm/data/debian-11.csv +++ b/lgsm/data/debian-11.csv @@ -19,6 +19,7 @@ bs bt,libicu-dev,dos2unix,libxml2-utils btl cc +ce ck,xvfb,libxi6 cmw cod,libstdc++5:i386 diff --git a/lgsm/data/debian-12.csv b/lgsm/data/debian-12.csv index 1ddb5ca6f5..fbfd1ce0fd 100644 --- a/lgsm/data/debian-12.csv +++ b/lgsm/data/debian-12.csv @@ -19,6 +19,7 @@ bs bt,libicu-dev,dos2unix,libxml2-utils btl cc +ce ck,xvfb,libxi6 cmw cod,libstdc++5:i386 diff --git a/lgsm/data/debian-13.csv b/lgsm/data/debian-13.csv index 242c5da77c..795122139c 100644 --- a/lgsm/data/debian-13.csv +++ b/lgsm/data/debian-13.csv @@ -19,6 +19,7 @@ bs bt,libicu-dev,dos2unix,libxml2 btl cc +ce ck,xvfb,libxi6 cmw cod,libc6:i386 diff --git a/lgsm/data/debian-9.csv b/lgsm/data/debian-9.csv index 0fa7cf3516..ecde61d9cc 100644 --- a/lgsm/data/debian-9.csv +++ b/lgsm/data/debian-9.csv @@ -19,6 +19,7 @@ bs bt,libicu-dev,dos2unix,libxml2-utils btl cc +ce ck,xvfb,libxi6 cmw cod,libstdc++5:i386 diff --git a/lgsm/data/gameicons/ce-icon.png b/lgsm/data/gameicons/ce-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..64b866e67ce9213f4c06aa2cec0ac3bad1818667 GIT binary patch literal 2479 zcmV;g2~hTlP)0owTX~A(?Raw8+7&ph%BYR+$WUMXn+#3s#H4p#@WJE*;fCvBp;MrEi zMq14W(i}zZHDPmYb@8^dVnht%>57z7TeTR6-Ib;>Mqto@6pg90CV|13I!2pn5x_Be z77QW;@}6Bl&mykN%pKhtN-2SJwj-I&r=<&}*yK2}mh@Pa@2%msuyE zY(49u=Y(=XWt2vgjFM3W7A_EDB2->BJnG6e$XfP@uxz8v2GjCT+}X`nlC1GIrU~k_ zX)P7SwW9-rG0Rf#Y%o?3S!Wy5Hm2>62+sN75h#Y}d{*ZmRaXu=`NY&J*Pngj*MIK*pJnGUa#0jj+hpC2_0HKggaC+2DInp!51xrg zXyKYx6MLD>OM7tbg>QZH>wo_*S7c3SI3|)*qyVvO8c*?0{`ij`c=yk|eD$R?Nr-56 za2T0+Q8EG%dGBM4004pnDJi9tvOYZ2*^0r?)U)yKjm+<_^)z8$lF%v3z&t}{seD;~ z^jAOfp@%>GXMg&|-}v<75nwP}alvb?o2o8~f=xg~<`6=_$V#asNu-oAm(8s7d1wFD z{x80D?cra#_>FHrJ8SxqA{ML~;9J-PfHRw0fAG7%_tJA$p7`|R0FdVDXfXo@mB@al zJD*QIi=rsq?!9jJ7gEMU+p?9GW7GWKy@F6FMFKd)Q3i)4ZKV3d_SSPhJUE+>iO(D@>h)vC2K|my+0mk&Tp$0`F?i>NcU(VO4AaDW&&&uw zghV8S(2}H-g`7sZJ>;5fKpq06Dy=39+LTgMz33^QGNM1T9hcr9nwjwDs~W zC-1!fC-42kC!cBz@9dl$kH>2|JutIoTEFYU&gvbfzVc7syLObt`Ua;%W@cs*fQbD6 zKpZ5=k79d3F3pO~t_;qL8hcV8HEnax-S3#}-~8^kzY_sM2$@#KwTBhv2>0K;wL7k^ zzEO#8M|6&NBp_l$h%vso+nXsf2O<&1r(5eA?OCEs@2vHjOyJ9MOE(lzydY--nlot)S{dFs?@YHxMA!Y zte(94@z4CuW>@yKuN`+ZQM9J1tu=_G(~Qy%=-j6nSGA6Q4$kFWY$#{tG>W`85JIiV zJ#6-$d4A6)i80PLY+4f{PRnY#m_7EfM<0FcF=Ct>vz&|}h8SGrfFy-d%n$;{W|4JP zB49P&(3N3=SN&~a>?$SHYeBeXBeDSUeXU?42xMLdtplu-frmSX1 z2a~F{`#<(ARNR@>`;#}G|KjJqQkzXYvvz#0=KGWS!uHmK?>RT#-~0FPU%z_u$jLOb ztt40?fhY(F?Hmvk!N$h=*|Vq5z5Vp5lP5OU*M_}rk)?W|a+mx0a?y-mAHV*kFMsXE zYqL}ocxv^yiH8P+#NJjnzWd%C2Xy7??tfqVakB&uz^Sl~A*ejnwOI;=2p|M9GekfD z37{mT3cP_2yyyJ;fBxK;|MnkVd?N{7Z1=qAt)wG0A|YmOX^q%@`9}$rr%!F3+Fb2) zhYt08xuC!)a^oYA5X=k^nV6ADMj#KuvUKs-C|y4C;q(9e&F?+;;v!S2R&g0g^mQT$ zGa?;=1Ggag+QjXSO`gGR>-o8@93)2|D~UsV>(&MUMBosDQVIa7Whnsb+KhVnXeBv*d~niMsBH*;NzUCD4)?nkaAG!4O^&4Nmd}ZlezcU_fe}j;hm{;Js@rO97=4(Ls-8PYTP{E6@^}IxI_XA_XBLdkjWE8056EI@lQWhnZgO zXQM&x$t;@1-#qiOI-s5PJJ{AU+ulkO3x1=jOR|)B5Lp@)&NdzhN%$B72NKXt3+pSAqPAMVOuM=?oj_P92`fEZ z%u|Yl!FubN6sTOJEi4$kCm8^17b1|-QbkcQ3f&!~m_`mQEZR+AIJ7002ovPDHLkV1l&k;YI)e literal 0 HcmV?d00001 diff --git a/lgsm/data/rhel-7.csv b/lgsm/data/rhel-7.csv index 7b1fdd5f3f..bcb47463bc 100644 --- a/lgsm/data/rhel-7.csv +++ b/lgsm/data/rhel-7.csv @@ -20,6 +20,7 @@ bs bt,libicu,dos2unix,libxml2 btl cc +ce ck,xorg-x11-server-Xvfb cmw cod,compat-libstdc++-33.i686 diff --git a/lgsm/data/rhel-8.csv b/lgsm/data/rhel-8.csv index b626fd6213..f302361215 100644 --- a/lgsm/data/rhel-8.csv +++ b/lgsm/data/rhel-8.csv @@ -19,6 +19,7 @@ bs bt,libicu,dos2unix,libxml2 btl cc +ce ck,xorg-x11-server-Xvfb cmw cod diff --git a/lgsm/data/rhel-9.csv b/lgsm/data/rhel-9.csv index bf90748489..0e0242c76c 100644 --- a/lgsm/data/rhel-9.csv +++ b/lgsm/data/rhel-9.csv @@ -19,6 +19,7 @@ bs bt,libicu,dos2unix,libxml2 btl cc +ce ck,xorg-x11-server-Xvfb cmw cod diff --git a/lgsm/data/rocky-8.csv b/lgsm/data/rocky-8.csv index b626fd6213..f302361215 100644 --- a/lgsm/data/rocky-8.csv +++ b/lgsm/data/rocky-8.csv @@ -19,6 +19,7 @@ bs bt,libicu,dos2unix,libxml2 btl cc +ce ck,xorg-x11-server-Xvfb cmw cod diff --git a/lgsm/data/rocky-9.csv b/lgsm/data/rocky-9.csv index bf90748489..0e0242c76c 100644 --- a/lgsm/data/rocky-9.csv +++ b/lgsm/data/rocky-9.csv @@ -19,6 +19,7 @@ bs bt,libicu,dos2unix,libxml2 btl cc +ce ck,xorg-x11-server-Xvfb cmw cod diff --git a/lgsm/data/serverlist.csv b/lgsm/data/serverlist.csv index 752029b185..458d1eb2cd 100644 --- a/lgsm/data/serverlist.csv +++ b/lgsm/data/serverlist.csv @@ -18,6 +18,7 @@ bs,bsserver,Blade Symphony,ubuntu-26.04 bt,btserver,Barotrauma,ubuntu-26.04 btl,btlserver,BATTALION: Legacy,ubuntu-20.04 cc,ccserver,Codename CURE,ubuntu-26.04 +ce,ceserver,Conan Exiles,ubuntu-26.04 ck,ckserver,Core Keeper,ubuntu-26.04 cmw,cmwserver,Chivalry: Medieval Warfare,ubuntu-26.04 cod,codserver,Call of Duty,ubuntu-24.04 diff --git a/lgsm/data/ubuntu-16.04.csv b/lgsm/data/ubuntu-16.04.csv index d412f99b1f..2631343da2 100644 --- a/lgsm/data/ubuntu-16.04.csv +++ b/lgsm/data/ubuntu-16.04.csv @@ -20,6 +20,7 @@ bs bt,libicu-dev,dos2unix,libxml2-utils btl cc +ce ck,xvfb,libxi6 cmw cod,libstdc++5:i386 diff --git a/lgsm/data/ubuntu-18.04.csv b/lgsm/data/ubuntu-18.04.csv index 08ab1b61b7..0e81a9b2b9 100644 --- a/lgsm/data/ubuntu-18.04.csv +++ b/lgsm/data/ubuntu-18.04.csv @@ -20,6 +20,7 @@ bs bt,libicu-dev,dos2unix,libxml2-utils btl cc +ce ck,xvfb,libxi6 cmw cod,libstdc++5:i386 diff --git a/lgsm/data/ubuntu-20.04.csv b/lgsm/data/ubuntu-20.04.csv index a88cad6df1..ae6f6ca5b7 100644 --- a/lgsm/data/ubuntu-20.04.csv +++ b/lgsm/data/ubuntu-20.04.csv @@ -19,6 +19,7 @@ bs bt,libicu-dev,dos2unix,libxml2-utils btl cc +ce ck,xvfb,libxi6 cmw cod,libstdc++5:i386 diff --git a/lgsm/data/ubuntu-22.04.csv b/lgsm/data/ubuntu-22.04.csv index f255fdd1bd..51e303e30c 100644 --- a/lgsm/data/ubuntu-22.04.csv +++ b/lgsm/data/ubuntu-22.04.csv @@ -19,6 +19,7 @@ bs bt,libicu-dev,dos2unix,libxml2-utils btl cc +ce ck,xvfb,libxi6 cmw cod,libstdc++5:i386 diff --git a/lgsm/data/ubuntu-23.04.csv b/lgsm/data/ubuntu-23.04.csv index f0be27806f..dfdef2422b 100644 --- a/lgsm/data/ubuntu-23.04.csv +++ b/lgsm/data/ubuntu-23.04.csv @@ -19,6 +19,7 @@ bs bt,libicu-dev,dos2unix,libxml2-utils btl cc +ce ck,xvfb,libxi6 cmw cod,libstdc++5:i386 diff --git a/lgsm/data/ubuntu-23.10.csv b/lgsm/data/ubuntu-23.10.csv index f0be27806f..dfdef2422b 100644 --- a/lgsm/data/ubuntu-23.10.csv +++ b/lgsm/data/ubuntu-23.10.csv @@ -19,6 +19,7 @@ bs bt,libicu-dev,dos2unix,libxml2-utils btl cc +ce ck,xvfb,libxi6 cmw cod,libstdc++5:i386 diff --git a/lgsm/data/ubuntu-24.04.csv b/lgsm/data/ubuntu-24.04.csv index f01738c06d..357abc0ca2 100644 --- a/lgsm/data/ubuntu-24.04.csv +++ b/lgsm/data/ubuntu-24.04.csv @@ -19,6 +19,7 @@ bs bt,libicu-dev,dos2unix,libxml2-utils btl cc +ce ck,xvfb,libxi6 cmw cod,libstdc++5:i386 diff --git a/lgsm/data/ubuntu-26.04.csv b/lgsm/data/ubuntu-26.04.csv index bc3115b344..4e542a1022 100644 --- a/lgsm/data/ubuntu-26.04.csv +++ b/lgsm/data/ubuntu-26.04.csv @@ -19,6 +19,7 @@ bs bt,libicu-dev,dos2unix,libxml2-utils btl cc +ce ck,xvfb,libxi6 cmw cod,libc6:i386 diff --git a/lgsm/modules/check_system_requirements.sh b/lgsm/modules/check_system_requirements.sh index 791f4f135b..d80d7f0ba9 100755 --- a/lgsm/modules/check_system_requirements.sh +++ b/lgsm/modules/check_system_requirements.sh @@ -25,6 +25,8 @@ elif [ "${shortname}" == "bt" ]; then ramrequirementgb="1" elif [ "${shortname}" == "cc" ]; then ramrequirementgb="1" +elif [ "${shortname}" == "ce" ]; then + ramrequirementgb="8" elif [ "${shortname}" == "dayz" ]; then ramrequirementgb="5" elif [ "${shortname}" == "dodr" ]; then diff --git a/lgsm/modules/command_stop.sh b/lgsm/modules/command_stop.sh index 0bd9843bb0..3a7d1302fc 100755 --- a/lgsm/modules/command_stop.sh +++ b/lgsm/modules/command_stop.sh @@ -470,6 +470,14 @@ fn_stop_graceful_rwr() { fn_stop_graceful_ctrlc } +fn_stop_graceful_ce() { + fn_print_dots "Graceful: CTRL+c" + fn_script_log_info "Graceful: CTRL+c" + TERM=screen tmux -L "${socketname}" send-keys -t "${sessionname}" C-c > /dev/null 2>&1 + fn_sleep_time_5 + fn_stop_graceful_ctrlc +} + # Attempts graceful shutdown of Rising World using 'shutdown'. # Its console can miss input, so the command is sent again every 10 seconds until the server stops. fn_stop_graceful_rw() { @@ -535,6 +543,8 @@ fn_stop_graceful_select() { fn_stop_graceful_rwr elif [ "${stopmode}" == "15" ]; then fn_stop_graceful_rw + elif [ "${stopmode}" == "16" ]; then + fn_stop_graceful_ce fi } diff --git a/lgsm/modules/info_game.sh b/lgsm/modules/info_game.sh index 7b0247af25..e83f8238cf 100755 --- a/lgsm/modules/info_game.sh +++ b/lgsm/modules/info_game.sh @@ -1052,6 +1052,25 @@ fn_info_game_cd() { steamport="${steamport:-"0"}" } +# Config Type: ini +# Parameters: true +# Comment: ; or # +# Example: ServerPassword=PASSWORD +# Filetype: ini +fn_info_game_ce() { + if [ -f "${servercfgfullpath}" ]; then + fn_info_game_ini "adminpassword" "AdminPassword" + fn_info_game_ini "serverpassword" "ServerPassword" + fi + adminpassword="${adminpassword:-"NOT SET"}" + maxplayers="${maxplayers:-"0"}" + port="${port:-"0"}" + queryport="${queryport:-"0"}" + rawport="$((port + 1))" + servername="${servername:-"NOT SET"}" + serverpassword="${serverpassword:-"NOT SET"}" +} + # Config Type: json # Parameters: true # Comment: // or /* */ @@ -2436,6 +2455,8 @@ elif [ "${shortname}" == "bt" ]; then fn_info_game_bt elif [ "${shortname}" == "btl" ]; then fn_info_game_btl +elif [ "${shortname}" == "ce" ]; then + fn_info_game_ce elif [ "${shortname}" == "ck" ]; then fn_info_game_ck elif [ "${shortname}" == "cmw" ]; then diff --git a/lgsm/modules/info_messages.sh b/lgsm/modules/info_messages.sh index 95e794bf34..2d6422942a 100755 --- a/lgsm/modules/info_messages.sh +++ b/lgsm/modules/info_messages.sh @@ -737,7 +737,7 @@ fn_info_messages_ports_edit() { fi done # engines/games that require editing the start parameters. - local ports_edit_array=("av" "ck" "col" "cs2" "fctr" "goldsrc" "hcu" "hw" "hyt" "iw3.0" "ioquake3" "pw" "qfusion" "rsdw" "rust" "scpsl" "sf" "sol" "spark" "source" "unreal4" "arma3" "dayz" "unt" "vh") + local ports_edit_array=("av" "ce" "ck" "col" "cs2" "fctr" "goldsrc" "hcu" "hw" "hyt" "iw3.0" "ioquake3" "pw" "qfusion" "rsdw" "rust" "scpsl" "sf" "sol" "spark" "source" "unreal4" "arma3" "dayz" "unt" "vh") for port_edit in "${ports_edit_array[@]}"; do if [ "${engine}" == "${port_edit}" ] || [ "${gamename}" == "${port_edit}" ] || [ "${shortname}" == "${port_edit}" ]; then startparameterslocation="${configdirserver}" @@ -757,6 +757,8 @@ fn_info_messages_ports() { portcommand="ss -tuplwn | grep bf1942_lnxded" elif [ "${shortname}" == "bfv" ]; then portcommand="ss -tuplwn | grep bfv_linded" + elif [ "${shortname}" == "ce" ]; then + portcommand="ss -tuplwn | grep ConanSandbox" elif [ "${shortname}" == "dayz" ]; then portcommand="ss -tuplwn | grep enfMain" elif [ "${shortname}" == "q4" ]; then @@ -958,6 +960,15 @@ fn_info_messages_cd() { } | column -s $'\t' -t } +fn_info_messages_ce() { + { + fn_port "header" + fn_port "Game" port udp + fn_port "Raw UDP" rawport udp + fn_port "Query" queryport udp + } | column -s $'\t' -t +} + fn_info_messages_ck() { { fn_port "header" @@ -1871,6 +1882,8 @@ fn_info_messages_select_engine() { fn_info_messages_bt elif [ "${shortname}" == "btl" ]; then fn_info_messages_btl + elif [ "${shortname}" == "ce" ]; then + fn_info_messages_ce elif [ "${shortname}" == "ck" ]; then fn_info_messages_ck elif [ "${shortname}" == "cs2" ]; then From c2a1bbaffa85dd49ec813f6f5af4fb7e91aa9185 Mon Sep 17 00:00:00 2001 From: Daniel Gibbs Date: Sat, 17 Oct 2026 23:59:00 +0100 Subject: [PATCH 111/164] fix: handle virtualization detection failures (#5086) --- lgsm/modules/info_distro.sh | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/lgsm/modules/info_distro.sh b/lgsm/modules/info_distro.sh index da11cb52e7..96c9efe298 100755 --- a/lgsm/modules/info_distro.sh +++ b/lgsm/modules/info_distro.sh @@ -72,8 +72,14 @@ for distro_info in "${distro_info_array[@]}"; do done # Get virtual environment type. +virtualenvironment="unavailable" if [ "$(command -v systemd-detect-virt 2> /dev/null)" ]; then - virtualenvironment="$(systemd-detect-virt)" # e.g. kvm + virtualenvironment="$(systemd-detect-virt 2> /dev/null)" + virtualenvironmentstatus=$? + # systemd-detect-virt returns "none" with a nonzero status on bare metal. + if [ "${virtualenvironment}" != "none" ] && { [ "${virtualenvironmentstatus}" != "0" ] || [[ ! "${virtualenvironment}" =~ ^[a-zA-Z0-9_-]+$ ]]; }; then + virtualenvironment="unavailable" + fi fi # distroversioncsv is used for selecting the correct distro csv in data directory From 24969baa70865cfecbf3e7c4e211ee7ee2b2ddf5 Mon Sep 17 00:00:00 2001 From: Daniel Gibbs Date: Sun, 18 Oct 2026 12:13:34 +0100 Subject: [PATCH 112/164] fix(ut99): validate and retry release API responses (#5089) --- lgsm/modules/update_ut99.sh | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/lgsm/modules/update_ut99.sh b/lgsm/modules/update_ut99.sh index 776a0a3cfa..f21117125b 100755 --- a/lgsm/modules/update_ut99.sh +++ b/lgsm/modules/update_ut99.sh @@ -34,15 +34,25 @@ fn_update_localbuild() { fn_update_remotebuild() { # Gets remote build info. apiurl="https://api.github.com/repos/OldUnreal/UnrealTournamentPatches/releases/latest" - 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') - remotebuild=$(echo "${remotebuildresponse}" | jq -r '.tag_name') + local attempt + for attempt in 1 2 3; do + remotebuildresponse=$(curl --connect-timeout 10 --max-time 30 --fail --silent --show-error --location "${apiurl}") || remotebuildresponse="" + remotebuild=$(echo "${remotebuildresponse}" | jq -er 'select((.tag_name | type) == "string" and (.tag_name | length) > 0) | .tag_name' 2> /dev/null) || remotebuild="" + remotebuildasset=$(echo "${remotebuildresponse}" | jq -cer '[.assets[]? | select((.browser_download_url | type) == "string" and (.browser_download_url | contains("Linux-amd64")))] | select(length == 1) | .[0]' 2> /dev/null) || remotebuildasset="" + remotebuildfilename=$(echo "${remotebuildasset}" | jq -er 'select((.name | type) == "string" and (.name | length) > 0) | .name' 2> /dev/null) || remotebuildfilename="" + remotebuildurl=$(echo "${remotebuildasset}" | jq -er 'select((.browser_download_url | type) == "string" and (.browser_download_url | length) > 0) | .browser_download_url' 2> /dev/null) || remotebuildurl="" + if [ -n "${remotebuild}" ] && [ -n "${remotebuildfilename}" ] && [ -n "${remotebuildurl}" ]; then + break + fi + if [ "${attempt}" -lt 3 ]; then + sleep 2 + fi + done if [ "${firstcommandname}" != "INSTALL" ]; then fn_print_dots "Checking remote build: ${remotelocation}" # Checks if remotebuild variable has been set. - if [ -z "${remotebuild}" ] || [ "${remotebuild}" == "null" ]; then + if [ -z "${remotebuild}" ] || [ -z "${remotebuildfilename}" ] || [ -z "${remotebuildurl}" ]; then fn_print_fail "Checking remote build: ${remotelocation}" fn_script_log_fail "Checking remote build" core_exit.sh @@ -52,7 +62,7 @@ fn_update_remotebuild() { fi else # Checks if remotebuild variable has been set. - if [ -z "${remotebuild}" ] || [ "${remotebuild}" == "null" ]; then + if [ -z "${remotebuild}" ] || [ -z "${remotebuildfilename}" ] || [ -z "${remotebuildurl}" ]; then fn_print_failure "Unable to get remote build" fn_script_log_fail "Unable to get remote build" core_exit.sh From 811ddaf98b77b6ae76c6423079d66766a73e3c86 Mon Sep 17 00:00:00 2001 From: Daniel Gibbs Date: Sun, 18 Oct 2026 12:21:26 +0100 Subject: [PATCH 113/164] fix(ci): activate Java 25 for Minecraft update checks (#5090) --- .github/workflows/action-update-check.yml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/.github/workflows/action-update-check.yml b/.github/workflows/action-update-check.yml index ad1150f7bd..bf62a720f6 100644 --- a/.github/workflows/action-update-check.yml +++ b/.github/workflows/action-update-check.yml @@ -31,6 +31,13 @@ jobs: - name: Install dependencies run: sudo dpkg --add-architecture i386; sudo apt-get update; + - name: Install Java 25 + if: matrix.shortname == 'mc' || matrix.shortname == 'pmc' + run: | + sudo apt-get install -y openjdk-25-jre + sudo update-alternatives --set java /usr/lib/jvm/java-25-openjdk-amd64/bin/java + java -version + - name: Grab server run: LGSM_GITHUBBRANCH="${LGSM_REF}" ./linuxgsm.sh ${{ matrix.shortname }}server From 3443716249ac504d07a9bb60d6b86d690d20a75d Mon Sep 17 00:00:00 2001 From: Daniel Gibbs Date: Sun, 18 Oct 2026 12:40:48 +0100 Subject: [PATCH 114/164] fix(ci): leave milestone assignment to maintainers (#5091) --- .github/workflows/action-milestone-sync.yml | 20 ++------------------ 1 file changed, 2 insertions(+), 18 deletions(-) diff --git a/.github/workflows/action-milestone-sync.yml b/.github/workflows/action-milestone-sync.yml index a252c5244d..e0891094ad 100755 --- a/.github/workflows/action-milestone-sync.yml +++ b/.github/workflows/action-milestone-sync.yml @@ -23,7 +23,7 @@ jobs: if: github.repository_owner == 'GameServerManagers' runs-on: ubuntu-latest steps: - - name: Set PR milestone and update linked issues + - name: Sync selected milestone to linked issues uses: actions/github-script@v9 with: script: | @@ -36,23 +36,7 @@ jobs: return; } - let milestone = pr.milestone; - if (!milestone && ['opened', 'reopened', 'ready_for_review'].includes(action)) { - const open = await github.paginate(github.rest.issues.listMilestones, { owner, repo, state: 'open', per_page: 100 }); - open.sort((a, b) => { - if (a.due_on && b.due_on) return a.due_on.localeCompare(b.due_on); - if (a.due_on) return -1; - if (b.due_on) return 1; - return a.number - b.number; - }); - if (open.length === 0) { - core.warning('No open milestone to assign.'); - } else { - milestone = open[0]; - await github.rest.issues.update({ owner, repo, issue_number: pr.number, milestone: milestone.number }); - core.info(`Set PR #${pr.number} milestone to ${milestone.title}.`); - } - } + const milestone = pr.milestone; const body = (pr.body || '').replace(//g, ''); const issueRef = /\b(close[sd]?|fix(?:e[sd])?|resolve[sd]?|related to):?\s+(?:([\w.-]+)\/([\w.-]+))?#(\d+)/gi; From a43b4eb94d69c01ab0872fa8f00faed65ac88dd4 Mon Sep 17 00:00:00 2001 From: Daniel Gibbs Date: Sun, 18 Oct 2026 16:56:54 +0100 Subject: [PATCH 115/164] Release v26.4.0 --- lgsm/modules/core_modules.sh | 2 +- linuxgsm.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lgsm/modules/core_modules.sh b/lgsm/modules/core_modules.sh index 09f2d9b67c..9f0982f2c7 100755 --- a/lgsm/modules/core_modules.sh +++ b/lgsm/modules/core_modules.sh @@ -8,7 +8,7 @@ moduleselfname="$(basename "$(readlink -f "${BASH_SOURCE[0]}")")" -modulesversion="v26.3.0" +modulesversion="v26.4.0" # Core diff --git a/linuxgsm.sh b/linuxgsm.sh index 643673b319..cfc4258c45 100755 --- a/linuxgsm.sh +++ b/linuxgsm.sh @@ -24,7 +24,7 @@ if [ -f ".dev-debug" ]; then set -x fi -version="v26.3.0" +version="v26.4.0" shortname="core" gameservername="core" commandname="CORE" From 2909ed03f0945e4dca266384ced44a3afb3bed33 Mon Sep 17 00:00:00 2001 From: Daniel Gibbs Date: Sun, 18 Oct 2026 17:42:20 +0100 Subject: [PATCH 116/164] fix(install): download SteamCMD games without fn_update_apply (#5093) install_server_files.sh runs update_steamcmd.sh with forceupdate=1. Since #5060 that branch calls fn_update_apply, which is defined in command_update.sh and is not loaded during install, so every SteamCMD install printed "fn_update_apply: command not found" and only downloaded the game through the missing appmanifest fallback. It also left an update.lock behind. During install, download directly and write last-updated.lock, as before #5060. force-update still uses fn_update_apply. --- lgsm/modules/update_steamcmd.sh | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/lgsm/modules/update_steamcmd.sh b/lgsm/modules/update_steamcmd.sh index cedbf82070..dd2b9282ee 100755 --- a/lgsm/modules/update_steamcmd.sh +++ b/lgsm/modules/update_steamcmd.sh @@ -18,8 +18,13 @@ fn_print_dots "${remotelocation}" if [ "${forceupdate}" == "1" ]; then # forceupdate bypasses update checks. - date '+%s' > "${lockdir:?}/update.lock" - fn_update_apply fn_dl_steamcmd + if [ "${firstcommandname}" == "INSTALL" ]; then + fn_dl_steamcmd + date +%s > "${lockdir:?}/last-updated.lock" + else + date '+%s' > "${lockdir:?}/update.lock" + fn_update_apply fn_dl_steamcmd + fi else fn_update_steamcmd_localbuild fn_update_steamcmd_remotebuild From da67b9c799d3fc00909297c662442df3fde7fe61 Mon Sep 17 00:00:00 2001 From: Daniel Gibbs Date: Thu, 22 Oct 2026 21:34:24 +0100 Subject: [PATCH 117/164] fix(deps): bump http-cache-semantics to 4.3.0 (#5096) Resolves Dependabot alert GHSA-ch52-4w7c-c8xp (CVE-2026-93748), transitive via gamedig > got > cacheable-request. --- package-lock.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 581f6ea8a8..cac32dc8c0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -358,9 +358,9 @@ } }, "node_modules/http-cache-semantics": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz", - "integrity": "sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==" + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.3.0.tgz", + "integrity": "sha512-M5t5LlJpS1UHMjvwRQVdFHvPISGeLAxNcrWuJkeGh0KxsqCHZ1O3NXZU/8x7cD0BDcGW8kapxMKTvwlqrNkHkA==" }, "node_modules/http2-wrapper": { "version": "2.2.1", From abff9471ce7ee635b406abae1e954ce2ee9a70f1 Mon Sep 17 00:00:00 2001 From: Daniel Gibbs Date: Thu, 22 Oct 2026 21:39:21 +0100 Subject: [PATCH 118/164] fix(triage): respect manual game/engine labels and skip closed issues (#5097) The triage bot re-added game and engine labels a maintainer removed by hand, because removing a label triggers the job again and it re-derives them from the issue text. It also ran on closed issues. Only run the label jobs on open issues, and keep a game/engine label as a person last left it (removed or added), like the Linux support label override. The backfill job follows the same rule. --- .../action-issue-triage-automation.yml | 71 +++++++++++++++++-- 1 file changed, 65 insertions(+), 6 deletions(-) diff --git a/.github/workflows/action-issue-triage-automation.yml b/.github/workflows/action-issue-triage-automation.yml index 9c4f23fab2..70282cbd74 100644 --- a/.github/workflows/action-issue-triage-automation.yml +++ b/.github/workflows/action-issue-triage-automation.yml @@ -69,7 +69,7 @@ env: jobs: issue-regex-labeler: - if: github.repository_owner == 'GameServerManagers' && github.event_name == 'issues' && (github.event.action == 'opened' || github.event.action == 'edited') + if: github.repository_owner == 'GameServerManagers' && github.event_name == 'issues' && github.event.issue.state == 'open' && (github.event.action == 'opened' || github.event.action == 'edited') runs-on: ubuntu-latest steps: - name: Issue Labeler @@ -82,7 +82,7 @@ jobs: sync-labels: 0 issue-ai-maintenance: - if: github.repository_owner == 'GameServerManagers' && (github.event_name == 'issues' || github.event_name == 'issue_comment') + if: github.repository_owner == 'GameServerManagers' && (github.event_name == 'issues' || github.event_name == 'issue_comment') && github.event.issue.state == 'open' runs-on: ubuntu-latest steps: - name: Reconcile issue labels and AI triage @@ -819,8 +819,37 @@ jobs: } // Avoid pointless API calls. - const finalAdds = [...labelsToAdd].filter((label) => !existingLabels.has(label)); - const finalRemoves = [...labelsToRemove].filter((label) => existingLabels.has(label)); + let finalAdds = [...labelsToAdd].filter((label) => !existingLabels.has(label)); + let finalRemoves = [...labelsToRemove].filter((label) => existingLabels.has(label)); + + const isGameOrEngineLabel = (label) => label.startsWith('game: ') || label.startsWith('engine: '); + if ([...finalAdds, ...finalRemoves].some(isGameOrEngineLabel)) { + try { + const issueEvents = await github.paginate(github.rest.issues.listEvents, { + owner, + repo, + issue_number: issueNumber, + per_page: 100, + }); + const lastManualLabelEvent = new Map(); + for (const e of issueEvents) { + if (!['labeled', 'unlabeled'].includes(e.event) || !e.label?.name) continue; + lastManualLabelEvent.set(e.label.name, e.actor?.type === 'Bot' ? null : e.event); + } + finalAdds = finalAdds.filter((label) => { + if (!isGameOrEngineLabel(label) || lastManualLabelEvent.get(label) !== 'unlabeled') return true; + console.log(`Label "${label}" was removed manually; not adding it back.`); + return false; + }); + finalRemoves = finalRemoves.filter((label) => { + if (!isGameOrEngineLabel(label) || lastManualLabelEvent.get(label) !== 'labeled') return true; + console.log(`Label "${label}" was added manually; keeping it.`); + return false; + }); + } catch (err) { + console.log(`Could not read issue events: ${err.message}`); + } + } for (const label of finalRemoves) { try { @@ -2199,8 +2228,38 @@ jobs: } // Apply changes - const finalAdds = [...labelsToAdd].filter((label) => !existingLabels.has(label)); - const finalRemoves = [...labelsToRemove].filter((label) => existingLabels.has(label)); + let finalAdds = [...labelsToAdd].filter((label) => !existingLabels.has(label)); + let finalRemoves = [...labelsToRemove].filter((label) => existingLabels.has(label)); + + const isGameOrEngineLabel = (label) => label.startsWith('game: ') || label.startsWith('engine: '); + if ([...finalAdds, ...finalRemoves].some(isGameOrEngineLabel)) { + try { + const issueEvents = await github.paginate(github.rest.issues.listEvents, { + owner, + repo, + issue_number: rawIssue.number, + per_page: 100, + }); + const lastManualLabelEvent = new Map(); + for (const e of issueEvents) { + if (!['labeled', 'unlabeled'].includes(e.event) || !e.label?.name) continue; + lastManualLabelEvent.set(e.label.name, e.actor?.type === 'Bot' ? null : e.event); + } + finalAdds = finalAdds.filter((label) => { + if (!isGameOrEngineLabel(label) || lastManualLabelEvent.get(label) !== 'unlabeled') return true; + console.log(`#${rawIssue.number}: "${label}" was removed manually; not adding it back`); + return false; + }); + finalRemoves = finalRemoves.filter((label) => { + if (!isGameOrEngineLabel(label) || lastManualLabelEvent.get(label) !== 'labeled') return true; + console.log(`#${rawIssue.number}: "${label}" was added manually; keeping it`); + return false; + }); + } catch (err) { + if (isApiRateLimitError(err)) throw err; + console.log(`#${rawIssue.number}: could not read issue events: ${err.message}`); + } + } let labelAdded = 0; let labelRemoved = 0; From 06174740b912becffdb1c5513fb2a3ae4da0b07d Mon Sep 17 00:00:00 2001 From: Daniel Gibbs Date: Thu, 22 Oct 2026 21:39:21 +0100 Subject: [PATCH 119/164] fix(triage): respect manual game/engine labels and skip closed issues (#5097) The triage bot re-added game and engine labels a maintainer removed by hand, because removing a label triggers the job again and it re-derives them from the issue text. It also ran on closed issues. Only run the label jobs on open issues, and keep a game/engine label as a person last left it (removed or added), like the Linux support label override. The backfill job follows the same rule. (cherry picked from commit abff9471ce7ee635b406abae1e954ce2ee9a70f1) --- .../action-issue-triage-automation.yml | 71 +++++++++++++++++-- 1 file changed, 65 insertions(+), 6 deletions(-) diff --git a/.github/workflows/action-issue-triage-automation.yml b/.github/workflows/action-issue-triage-automation.yml index 9c4f23fab2..70282cbd74 100644 --- a/.github/workflows/action-issue-triage-automation.yml +++ b/.github/workflows/action-issue-triage-automation.yml @@ -69,7 +69,7 @@ env: jobs: issue-regex-labeler: - if: github.repository_owner == 'GameServerManagers' && github.event_name == 'issues' && (github.event.action == 'opened' || github.event.action == 'edited') + if: github.repository_owner == 'GameServerManagers' && github.event_name == 'issues' && github.event.issue.state == 'open' && (github.event.action == 'opened' || github.event.action == 'edited') runs-on: ubuntu-latest steps: - name: Issue Labeler @@ -82,7 +82,7 @@ jobs: sync-labels: 0 issue-ai-maintenance: - if: github.repository_owner == 'GameServerManagers' && (github.event_name == 'issues' || github.event_name == 'issue_comment') + if: github.repository_owner == 'GameServerManagers' && (github.event_name == 'issues' || github.event_name == 'issue_comment') && github.event.issue.state == 'open' runs-on: ubuntu-latest steps: - name: Reconcile issue labels and AI triage @@ -819,8 +819,37 @@ jobs: } // Avoid pointless API calls. - const finalAdds = [...labelsToAdd].filter((label) => !existingLabels.has(label)); - const finalRemoves = [...labelsToRemove].filter((label) => existingLabels.has(label)); + let finalAdds = [...labelsToAdd].filter((label) => !existingLabels.has(label)); + let finalRemoves = [...labelsToRemove].filter((label) => existingLabels.has(label)); + + const isGameOrEngineLabel = (label) => label.startsWith('game: ') || label.startsWith('engine: '); + if ([...finalAdds, ...finalRemoves].some(isGameOrEngineLabel)) { + try { + const issueEvents = await github.paginate(github.rest.issues.listEvents, { + owner, + repo, + issue_number: issueNumber, + per_page: 100, + }); + const lastManualLabelEvent = new Map(); + for (const e of issueEvents) { + if (!['labeled', 'unlabeled'].includes(e.event) || !e.label?.name) continue; + lastManualLabelEvent.set(e.label.name, e.actor?.type === 'Bot' ? null : e.event); + } + finalAdds = finalAdds.filter((label) => { + if (!isGameOrEngineLabel(label) || lastManualLabelEvent.get(label) !== 'unlabeled') return true; + console.log(`Label "${label}" was removed manually; not adding it back.`); + return false; + }); + finalRemoves = finalRemoves.filter((label) => { + if (!isGameOrEngineLabel(label) || lastManualLabelEvent.get(label) !== 'labeled') return true; + console.log(`Label "${label}" was added manually; keeping it.`); + return false; + }); + } catch (err) { + console.log(`Could not read issue events: ${err.message}`); + } + } for (const label of finalRemoves) { try { @@ -2199,8 +2228,38 @@ jobs: } // Apply changes - const finalAdds = [...labelsToAdd].filter((label) => !existingLabels.has(label)); - const finalRemoves = [...labelsToRemove].filter((label) => existingLabels.has(label)); + let finalAdds = [...labelsToAdd].filter((label) => !existingLabels.has(label)); + let finalRemoves = [...labelsToRemove].filter((label) => existingLabels.has(label)); + + const isGameOrEngineLabel = (label) => label.startsWith('game: ') || label.startsWith('engine: '); + if ([...finalAdds, ...finalRemoves].some(isGameOrEngineLabel)) { + try { + const issueEvents = await github.paginate(github.rest.issues.listEvents, { + owner, + repo, + issue_number: rawIssue.number, + per_page: 100, + }); + const lastManualLabelEvent = new Map(); + for (const e of issueEvents) { + if (!['labeled', 'unlabeled'].includes(e.event) || !e.label?.name) continue; + lastManualLabelEvent.set(e.label.name, e.actor?.type === 'Bot' ? null : e.event); + } + finalAdds = finalAdds.filter((label) => { + if (!isGameOrEngineLabel(label) || lastManualLabelEvent.get(label) !== 'unlabeled') return true; + console.log(`#${rawIssue.number}: "${label}" was removed manually; not adding it back`); + return false; + }); + finalRemoves = finalRemoves.filter((label) => { + if (!isGameOrEngineLabel(label) || lastManualLabelEvent.get(label) !== 'labeled') return true; + console.log(`#${rawIssue.number}: "${label}" was added manually; keeping it`); + return false; + }); + } catch (err) { + if (isApiRateLimitError(err)) throw err; + console.log(`#${rawIssue.number}: could not read issue events: ${err.message}`); + } + } let labelAdded = 0; let labelRemoved = 0; From 034471f15090252f2e6577898cd97357a7047fec Mon Sep 17 00:00:00 2001 From: Daniel Gibbs Date: Fri, 23 Oct 2026 12:53:51 +0100 Subject: [PATCH 120/164] feat(fastdl): incremental, parallel FastDL with custom folders and exclusions (#5100) * feat(fastdl): incremental, parallel FastDL with custom folders and exclusions The fastdl command wiped the FastDL directory on every run and then copied and bzip2-compressed every file again, one at a time. On a stock TF2 install that is several GB of work each run. It also ignored content in Source's custom// folders and had no way to leave out paths such as maps/workshop/. The command now builds one file list, works out what changed and only touches those files: - Source content is also collected from custom/// using the same per-type extension lists, and lands at the path clients request (custom/foo/maps/x.bsp goes to maps/x.bsp). When the same path exists more than once, custom folders win over the stock folder and the first custom folder in name order wins, following the server's own search path. Skipped duplicates are logged. - The FastDL directory is kept between runs. A file is copied and compressed only when its FastDL copy is missing or its modification time differs from the source. Compressed files get their source's mtime with touch -r, because bzip2 only keeps whole seconds. Files in FastDL with no source any more are removed, along with empty folders. - Files over 150 MB are copied without compression, as Source clients will not download a larger compressed file. - Compression runs in parallel with xargs -P "$(nproc)". Each file is still logged as a pass or fail. - New fastdlexclude setting: space-separated paths relative to the FastDL directory. Defaults to maps/workshop/ for Source servers and is empty for GoldSrc. Excluded files already in FastDL are removed. - The "Overwrite existing directory?" prompt becomes "Rebuild Fastdl directory from scratch?" (default no). Yes clears the directory and rebuilds everything as before. Garry's Mod uses the same file list, mapping addons// and lua/ content to the same paths as the previous copy-then-move steps, and the download enforcer is generated from the client paths in that list. GoldSrc keeps its directory layout and file types from #5045, copies without compression, and is now incremental too. Fixes #1521 Fixes #4138 Fixes #2873 Fixes #3153 * feat(fastdl): only remove files fastdl wrote, tracked in a record Removing every file in the FastDL directory without a source deleted files users put there on purpose, such as index.html or .htaccess, and when two servers shared one FastDL directory each run deleted the other server's files. Each run now saves a record of the files it wrote to lgsm/data/-fastdl.txt: the FastDL path, the source path, its size and its modification time. Only files listed in the previous record and no longer expected are removed. Anything else in the directory is counted and reported as left alone. The record starts with the FastDL directory it belongs to and is ignored if webdir changes. Change detection also uses the record: a file is updated when its FastDL copy is missing or its source path, size or modification time differs. Comparing the modification time alone missed a change of winning source for a duplicate path, because files written within the same few milliseconds share a timestamp. Compressed files no longer need their mtime copied from the source. The record is saved only after a run completes. The rebuild prompt now says that it deletes everything in the directory. * refactor(fastdl): drop explanatory comments and fix log typo Keep comment density in line with other modules, ignore blank lines in the file record, and fix "filesr" in the download enforcer log line. --- .../config-lgsm/ahl2server/_default.cfg | 5 + .../config-lgsm/ahlserver/_default.cfg | 5 + .../config-lgsm/bb2server/_default.cfg | 5 + .../config-lgsm/bbserver/_default.cfg | 5 + .../config-lgsm/bdserver/_default.cfg | 5 + .../config-lgsm/bmdmserver/_default.cfg | 5 + .../config-lgsm/bsserver/_default.cfg | 5 + .../config-lgsm/ccserver/_default.cfg | 5 + .../config-lgsm/csczserver/_default.cfg | 5 + .../config-lgsm/csgoserver/_default.cfg | 5 + .../config-lgsm/csserver/_default.cfg | 5 + .../config-lgsm/cssserver/_default.cfg | 5 + .../config-lgsm/dabserver/_default.cfg | 5 + .../config-lgsm/dmcserver/_default.cfg | 5 + .../config-lgsm/dodserver/_default.cfg | 5 + .../config-lgsm/dodsserver/_default.cfg | 5 + .../config-lgsm/doiserver/_default.cfg | 5 + .../config-lgsm/dysserver/_default.cfg | 5 + .../config-lgsm/emserver/_default.cfg | 5 + .../config-lgsm/fofserver/_default.cfg | 5 + .../config-lgsm/gmodserver/_default.cfg | 5 + .../config-lgsm/hl2dmserver/_default.cfg | 5 + .../config-lgsm/hldmserver/_default.cfg | 5 + .../config-lgsm/hldmsserver/_default.cfg | 5 + .../config-lgsm/insserver/_default.cfg | 5 + .../config-lgsm/iosserver/_default.cfg | 5 + .../config-lgsm/jbep3server/_default.cfg | 5 + .../config-lgsm/l4d2server/_default.cfg | 5 + .../config-lgsm/l4dserver/_default.cfg | 5 + .../config-lgsm/mcvserver/_default.cfg | 5 + .../config-lgsm/ndserver/_default.cfg | 5 + .../config-lgsm/nmrihserver/_default.cfg | 5 + .../config-lgsm/nsserver/_default.cfg | 5 + .../config-lgsm/opforserver/_default.cfg | 5 + .../config-lgsm/pvkiiserver/_default.cfg | 5 + .../config-lgsm/ricochetserver/_default.cfg | 5 + .../config-lgsm/sfcserver/_default.cfg | 5 + .../config-lgsm/svenserver/_default.cfg | 5 + .../config-lgsm/tf2cserver/_default.cfg | 5 + .../config-lgsm/tf2server/_default.cfg | 5 + .../config-lgsm/tfcserver/_default.cfg | 5 + .../config-lgsm/tsserver/_default.cfg | 5 + .../config-lgsm/vsserver/_default.cfg | 5 + .../config-lgsm/zmrserver/_default.cfg | 5 + .../config-lgsm/zpsserver/_default.cfg | 5 + lgsm/modules/command_fastdl.sh | 519 +++++++++++------- 46 files changed, 533 insertions(+), 211 deletions(-) diff --git a/lgsm/config-default/config-lgsm/ahl2server/_default.cfg b/lgsm/config-default/config-lgsm/ahl2server/_default.cfg index 81d68fa19a..d70b96b90c 100644 --- a/lgsm/config-default/config-lgsm/ahl2server/_default.cfg +++ b/lgsm/config-default/config-lgsm/ahl2server/_default.cfg @@ -124,6 +124,11 @@ maxbackups="4" maxbackupdays="30" stoponbackup="on" +## Fastdl | https://docs.linuxgsm.com/commands/fastdl +# Paths to leave out of Fastdl, relative to the Fastdl directory and separated by spaces. +# e.g. "maps/workshop/ sound/music/" +fastdlexclude="maps/workshop/" + ## Logging | https://docs.linuxgsm.com/features/logging consolelogging="on" logdays="7" diff --git a/lgsm/config-default/config-lgsm/ahlserver/_default.cfg b/lgsm/config-default/config-lgsm/ahlserver/_default.cfg index 4558e9f257..182f20ee2d 100644 --- a/lgsm/config-default/config-lgsm/ahlserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/ahlserver/_default.cfg @@ -119,6 +119,11 @@ maxbackups="4" maxbackupdays="30" stoponbackup="on" +## Fastdl | https://docs.linuxgsm.com/commands/fastdl +# Paths to leave out of Fastdl, relative to the Fastdl directory and separated by spaces. +# e.g. "maps/workshop/ sound/music/" +fastdlexclude="" + ## Logging | https://docs.linuxgsm.com/features/logging consolelogging="on" logdays="7" diff --git a/lgsm/config-default/config-lgsm/bb2server/_default.cfg b/lgsm/config-default/config-lgsm/bb2server/_default.cfg index 1348d86905..9b936f0da7 100644 --- a/lgsm/config-default/config-lgsm/bb2server/_default.cfg +++ b/lgsm/config-default/config-lgsm/bb2server/_default.cfg @@ -125,6 +125,11 @@ maxbackups="4" maxbackupdays="30" stoponbackup="on" +## Fastdl | https://docs.linuxgsm.com/commands/fastdl +# Paths to leave out of Fastdl, relative to the Fastdl directory and separated by spaces. +# e.g. "maps/workshop/ sound/music/" +fastdlexclude="maps/workshop/" + ## Logging | https://docs.linuxgsm.com/features/logging consolelogging="on" logdays="7" diff --git a/lgsm/config-default/config-lgsm/bbserver/_default.cfg b/lgsm/config-default/config-lgsm/bbserver/_default.cfg index 789853f747..9fb311e91d 100644 --- a/lgsm/config-default/config-lgsm/bbserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/bbserver/_default.cfg @@ -119,6 +119,11 @@ maxbackups="4" maxbackupdays="30" stoponbackup="on" +## Fastdl | https://docs.linuxgsm.com/commands/fastdl +# Paths to leave out of Fastdl, relative to the Fastdl directory and separated by spaces. +# e.g. "maps/workshop/ sound/music/" +fastdlexclude="" + ## Logging | https://docs.linuxgsm.com/features/logging consolelogging="on" logdays="7" diff --git a/lgsm/config-default/config-lgsm/bdserver/_default.cfg b/lgsm/config-default/config-lgsm/bdserver/_default.cfg index 83fc499e0c..fdd4c47a5a 100644 --- a/lgsm/config-default/config-lgsm/bdserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/bdserver/_default.cfg @@ -119,6 +119,11 @@ maxbackups="4" maxbackupdays="30" stoponbackup="on" +## Fastdl | https://docs.linuxgsm.com/commands/fastdl +# Paths to leave out of Fastdl, relative to the Fastdl directory and separated by spaces. +# e.g. "maps/workshop/ sound/music/" +fastdlexclude="" + ## Logging | https://docs.linuxgsm.com/features/logging consolelogging="on" logdays="7" diff --git a/lgsm/config-default/config-lgsm/bmdmserver/_default.cfg b/lgsm/config-default/config-lgsm/bmdmserver/_default.cfg index b3c738528e..436be070c1 100644 --- a/lgsm/config-default/config-lgsm/bmdmserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/bmdmserver/_default.cfg @@ -125,6 +125,11 @@ maxbackups="4" maxbackupdays="30" stoponbackup="on" +## Fastdl | https://docs.linuxgsm.com/commands/fastdl +# Paths to leave out of Fastdl, relative to the Fastdl directory and separated by spaces. +# e.g. "maps/workshop/ sound/music/" +fastdlexclude="maps/workshop/" + ## Logging | https://docs.linuxgsm.com/features/logging consolelogging="on" logdays="7" diff --git a/lgsm/config-default/config-lgsm/bsserver/_default.cfg b/lgsm/config-default/config-lgsm/bsserver/_default.cfg index 599965e5af..17b34602c7 100644 --- a/lgsm/config-default/config-lgsm/bsserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/bsserver/_default.cfg @@ -129,6 +129,11 @@ maxbackups="4" maxbackupdays="30" stoponbackup="on" +## Fastdl | https://docs.linuxgsm.com/commands/fastdl +# Paths to leave out of Fastdl, relative to the Fastdl directory and separated by spaces. +# e.g. "maps/workshop/ sound/music/" +fastdlexclude="maps/workshop/" + ## Logging | https://docs.linuxgsm.com/features/logging consolelogging="on" logdays="7" diff --git a/lgsm/config-default/config-lgsm/ccserver/_default.cfg b/lgsm/config-default/config-lgsm/ccserver/_default.cfg index f55339bffa..78c567bcff 100644 --- a/lgsm/config-default/config-lgsm/ccserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/ccserver/_default.cfg @@ -120,6 +120,11 @@ maxbackups="4" maxbackupdays="30" stoponbackup="on" +## Fastdl | https://docs.linuxgsm.com/commands/fastdl +# Paths to leave out of Fastdl, relative to the Fastdl directory and separated by spaces. +# e.g. "maps/workshop/ sound/music/" +fastdlexclude="maps/workshop/" + ## Logging | https://docs.linuxgsm.com/features/logging consolelogging="on" logdays="7" diff --git a/lgsm/config-default/config-lgsm/csczserver/_default.cfg b/lgsm/config-default/config-lgsm/csczserver/_default.cfg index 184b72104d..f8c90c52c2 100644 --- a/lgsm/config-default/config-lgsm/csczserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/csczserver/_default.cfg @@ -119,6 +119,11 @@ maxbackups="4" maxbackupdays="30" stoponbackup="on" +## Fastdl | https://docs.linuxgsm.com/commands/fastdl +# Paths to leave out of Fastdl, relative to the Fastdl directory and separated by spaces. +# e.g. "maps/workshop/ sound/music/" +fastdlexclude="" + ## Logging | https://docs.linuxgsm.com/features/logging consolelogging="on" logdays="7" diff --git a/lgsm/config-default/config-lgsm/csgoserver/_default.cfg b/lgsm/config-default/config-lgsm/csgoserver/_default.cfg index 0b459fba5f..15df32d2ae 100644 --- a/lgsm/config-default/config-lgsm/csgoserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/csgoserver/_default.cfg @@ -157,6 +157,11 @@ maxbackups="4" maxbackupdays="30" stoponbackup="on" +## Fastdl | https://docs.linuxgsm.com/commands/fastdl +# Paths to leave out of Fastdl, relative to the Fastdl directory and separated by spaces. +# e.g. "maps/workshop/ sound/music/" +fastdlexclude="maps/workshop/" + ## Logging | https://docs.linuxgsm.com/features/logging consolelogging="on" logdays="7" diff --git a/lgsm/config-default/config-lgsm/csserver/_default.cfg b/lgsm/config-default/config-lgsm/csserver/_default.cfg index 61bf0c040c..9f20d59150 100644 --- a/lgsm/config-default/config-lgsm/csserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/csserver/_default.cfg @@ -119,6 +119,11 @@ maxbackups="4" maxbackupdays="30" stoponbackup="on" +## Fastdl | https://docs.linuxgsm.com/commands/fastdl +# Paths to leave out of Fastdl, relative to the Fastdl directory and separated by spaces. +# e.g. "maps/workshop/ sound/music/" +fastdlexclude="" + ## Logging | https://docs.linuxgsm.com/features/logging consolelogging="on" logdays="7" diff --git a/lgsm/config-default/config-lgsm/cssserver/_default.cfg b/lgsm/config-default/config-lgsm/cssserver/_default.cfg index 1a2aefc10d..aadc378380 100644 --- a/lgsm/config-default/config-lgsm/cssserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/cssserver/_default.cfg @@ -125,6 +125,11 @@ maxbackups="4" maxbackupdays="30" stoponbackup="on" +## Fastdl | https://docs.linuxgsm.com/commands/fastdl +# Paths to leave out of Fastdl, relative to the Fastdl directory and separated by spaces. +# e.g. "maps/workshop/ sound/music/" +fastdlexclude="maps/workshop/" + ## Logging | https://docs.linuxgsm.com/features/logging consolelogging="on" logdays="7" diff --git a/lgsm/config-default/config-lgsm/dabserver/_default.cfg b/lgsm/config-default/config-lgsm/dabserver/_default.cfg index a14c5cafb5..385152099f 100644 --- a/lgsm/config-default/config-lgsm/dabserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/dabserver/_default.cfg @@ -120,6 +120,11 @@ maxbackups="4" maxbackupdays="30" stoponbackup="on" +## Fastdl | https://docs.linuxgsm.com/commands/fastdl +# Paths to leave out of Fastdl, relative to the Fastdl directory and separated by spaces. +# e.g. "maps/workshop/ sound/music/" +fastdlexclude="maps/workshop/" + ## Logging | https://docs.linuxgsm.com/features/logging consolelogging="on" logdays="7" diff --git a/lgsm/config-default/config-lgsm/dmcserver/_default.cfg b/lgsm/config-default/config-lgsm/dmcserver/_default.cfg index 910c83b9bc..8cfcd505f8 100644 --- a/lgsm/config-default/config-lgsm/dmcserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/dmcserver/_default.cfg @@ -119,6 +119,11 @@ maxbackups="4" maxbackupdays="30" stoponbackup="on" +## Fastdl | https://docs.linuxgsm.com/commands/fastdl +# Paths to leave out of Fastdl, relative to the Fastdl directory and separated by spaces. +# e.g. "maps/workshop/ sound/music/" +fastdlexclude="" + ## Logging | https://docs.linuxgsm.com/features/logging consolelogging="on" logdays="7" diff --git a/lgsm/config-default/config-lgsm/dodserver/_default.cfg b/lgsm/config-default/config-lgsm/dodserver/_default.cfg index cf0d03a7c2..d2f8daba58 100644 --- a/lgsm/config-default/config-lgsm/dodserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/dodserver/_default.cfg @@ -119,6 +119,11 @@ maxbackups="4" maxbackupdays="30" stoponbackup="on" +## Fastdl | https://docs.linuxgsm.com/commands/fastdl +# Paths to leave out of Fastdl, relative to the Fastdl directory and separated by spaces. +# e.g. "maps/workshop/ sound/music/" +fastdlexclude="" + ## Logging | https://docs.linuxgsm.com/features/logging consolelogging="on" logdays="7" diff --git a/lgsm/config-default/config-lgsm/dodsserver/_default.cfg b/lgsm/config-default/config-lgsm/dodsserver/_default.cfg index aa9f24e872..1fa0f3c1e1 100644 --- a/lgsm/config-default/config-lgsm/dodsserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/dodsserver/_default.cfg @@ -120,6 +120,11 @@ maxbackups="4" maxbackupdays="30" stoponbackup="on" +## Fastdl | https://docs.linuxgsm.com/commands/fastdl +# Paths to leave out of Fastdl, relative to the Fastdl directory and separated by spaces. +# e.g. "maps/workshop/ sound/music/" +fastdlexclude="maps/workshop/" + ## Logging | https://docs.linuxgsm.com/features/logging consolelogging="on" logdays="7" diff --git a/lgsm/config-default/config-lgsm/doiserver/_default.cfg b/lgsm/config-default/config-lgsm/doiserver/_default.cfg index b38c33cf28..9ee92a76f9 100644 --- a/lgsm/config-default/config-lgsm/doiserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/doiserver/_default.cfg @@ -121,6 +121,11 @@ maxbackups="4" maxbackupdays="30" stoponbackup="on" +## Fastdl | https://docs.linuxgsm.com/commands/fastdl +# Paths to leave out of Fastdl, relative to the Fastdl directory and separated by spaces. +# e.g. "maps/workshop/ sound/music/" +fastdlexclude="maps/workshop/" + ## Logging | https://docs.linuxgsm.com/features/logging consolelogging="on" logdays="7" diff --git a/lgsm/config-default/config-lgsm/dysserver/_default.cfg b/lgsm/config-default/config-lgsm/dysserver/_default.cfg index 03bec8e5c8..567c338fcb 100644 --- a/lgsm/config-default/config-lgsm/dysserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/dysserver/_default.cfg @@ -125,6 +125,11 @@ maxbackups="4" maxbackupdays="30" stoponbackup="on" +## Fastdl | https://docs.linuxgsm.com/commands/fastdl +# Paths to leave out of Fastdl, relative to the Fastdl directory and separated by spaces. +# e.g. "maps/workshop/ sound/music/" +fastdlexclude="maps/workshop/" + ## Logging | https://docs.linuxgsm.com/features/logging consolelogging="on" logdays="7" diff --git a/lgsm/config-default/config-lgsm/emserver/_default.cfg b/lgsm/config-default/config-lgsm/emserver/_default.cfg index 144e58a494..7fd98d437f 100644 --- a/lgsm/config-default/config-lgsm/emserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/emserver/_default.cfg @@ -125,6 +125,11 @@ maxbackups="4" maxbackupdays="30" stoponbackup="on" +## Fastdl | https://docs.linuxgsm.com/commands/fastdl +# Paths to leave out of Fastdl, relative to the Fastdl directory and separated by spaces. +# e.g. "maps/workshop/ sound/music/" +fastdlexclude="maps/workshop/" + ## Logging | https://docs.linuxgsm.com/features/logging consolelogging="on" logdays="7" diff --git a/lgsm/config-default/config-lgsm/fofserver/_default.cfg b/lgsm/config-default/config-lgsm/fofserver/_default.cfg index 86087fbf3e..a4a2f2e670 100644 --- a/lgsm/config-default/config-lgsm/fofserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/fofserver/_default.cfg @@ -120,6 +120,11 @@ maxbackups="4" maxbackupdays="30" stoponbackup="on" +## Fastdl | https://docs.linuxgsm.com/commands/fastdl +# Paths to leave out of Fastdl, relative to the Fastdl directory and separated by spaces. +# e.g. "maps/workshop/ sound/music/" +fastdlexclude="maps/workshop/" + ## Logging | https://docs.linuxgsm.com/features/logging consolelogging="on" logdays="7" diff --git a/lgsm/config-default/config-lgsm/gmodserver/_default.cfg b/lgsm/config-default/config-lgsm/gmodserver/_default.cfg index eebbe366a5..ccae6e6422 100644 --- a/lgsm/config-default/config-lgsm/gmodserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/gmodserver/_default.cfg @@ -130,6 +130,11 @@ maxbackups="4" maxbackupdays="30" stoponbackup="on" +## Fastdl | https://docs.linuxgsm.com/commands/fastdl +# Paths to leave out of Fastdl, relative to the Fastdl directory and separated by spaces. +# e.g. "maps/workshop/ sound/music/" +fastdlexclude="maps/workshop/" + ## Logging | https://docs.linuxgsm.com/features/logging consolelogging="on" logdays="7" diff --git a/lgsm/config-default/config-lgsm/hl2dmserver/_default.cfg b/lgsm/config-default/config-lgsm/hl2dmserver/_default.cfg index 45ed3b7eb0..a1d6e4390c 100644 --- a/lgsm/config-default/config-lgsm/hl2dmserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/hl2dmserver/_default.cfg @@ -122,6 +122,11 @@ maxbackups="4" maxbackupdays="30" stoponbackup="on" +## Fastdl | https://docs.linuxgsm.com/commands/fastdl +# Paths to leave out of Fastdl, relative to the Fastdl directory and separated by spaces. +# e.g. "maps/workshop/ sound/music/" +fastdlexclude="maps/workshop/" + ## Logging | https://docs.linuxgsm.com/features/logging consolelogging="on" logdays="7" diff --git a/lgsm/config-default/config-lgsm/hldmserver/_default.cfg b/lgsm/config-default/config-lgsm/hldmserver/_default.cfg index f917bcdb17..69ee4dddbd 100644 --- a/lgsm/config-default/config-lgsm/hldmserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/hldmserver/_default.cfg @@ -119,6 +119,11 @@ maxbackups="4" maxbackupdays="30" stoponbackup="on" +## Fastdl | https://docs.linuxgsm.com/commands/fastdl +# Paths to leave out of Fastdl, relative to the Fastdl directory and separated by spaces. +# e.g. "maps/workshop/ sound/music/" +fastdlexclude="" + ## Logging | https://docs.linuxgsm.com/features/logging consolelogging="on" logdays="7" diff --git a/lgsm/config-default/config-lgsm/hldmsserver/_default.cfg b/lgsm/config-default/config-lgsm/hldmsserver/_default.cfg index 52436737b9..8fb2e338d0 100644 --- a/lgsm/config-default/config-lgsm/hldmsserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/hldmsserver/_default.cfg @@ -120,6 +120,11 @@ maxbackups="4" maxbackupdays="30" stoponbackup="on" +## Fastdl | https://docs.linuxgsm.com/commands/fastdl +# Paths to leave out of Fastdl, relative to the Fastdl directory and separated by spaces. +# e.g. "maps/workshop/ sound/music/" +fastdlexclude="maps/workshop/" + ## Logging | https://docs.linuxgsm.com/features/logging consolelogging="on" logdays="7" diff --git a/lgsm/config-default/config-lgsm/insserver/_default.cfg b/lgsm/config-default/config-lgsm/insserver/_default.cfg index 335e7a99b2..8bde6ab8e4 100644 --- a/lgsm/config-default/config-lgsm/insserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/insserver/_default.cfg @@ -126,6 +126,11 @@ maxbackups="4" maxbackupdays="30" stoponbackup="on" +## Fastdl | https://docs.linuxgsm.com/commands/fastdl +# Paths to leave out of Fastdl, relative to the Fastdl directory and separated by spaces. +# e.g. "maps/workshop/ sound/music/" +fastdlexclude="maps/workshop/" + ## Logging | https://docs.linuxgsm.com/features/logging consolelogging="on" logdays="7" diff --git a/lgsm/config-default/config-lgsm/iosserver/_default.cfg b/lgsm/config-default/config-lgsm/iosserver/_default.cfg index 7c844ddf53..1e42b23be4 100644 --- a/lgsm/config-default/config-lgsm/iosserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/iosserver/_default.cfg @@ -120,6 +120,11 @@ maxbackups="4" maxbackupdays="30" stoponbackup="on" +## Fastdl | https://docs.linuxgsm.com/commands/fastdl +# Paths to leave out of Fastdl, relative to the Fastdl directory and separated by spaces. +# e.g. "maps/workshop/ sound/music/" +fastdlexclude="maps/workshop/" + ## Logging | https://docs.linuxgsm.com/features/logging consolelogging="on" logdays="7" diff --git a/lgsm/config-default/config-lgsm/jbep3server/_default.cfg b/lgsm/config-default/config-lgsm/jbep3server/_default.cfg index 9894833644..1025826a29 100644 --- a/lgsm/config-default/config-lgsm/jbep3server/_default.cfg +++ b/lgsm/config-default/config-lgsm/jbep3server/_default.cfg @@ -114,6 +114,11 @@ maxbackups="4" maxbackupdays="30" stoponbackup="on" +## Fastdl | https://docs.linuxgsm.com/commands/fastdl +# Paths to leave out of Fastdl, relative to the Fastdl directory and separated by spaces. +# e.g. "maps/workshop/ sound/music/" +fastdlexclude="maps/workshop/" + ## Logging | https://docs.linuxgsm.com/features/logging consolelogging="on" logdays="7" diff --git a/lgsm/config-default/config-lgsm/l4d2server/_default.cfg b/lgsm/config-default/config-lgsm/l4d2server/_default.cfg index e0fbf03682..d525c4b387 100644 --- a/lgsm/config-default/config-lgsm/l4d2server/_default.cfg +++ b/lgsm/config-default/config-lgsm/l4d2server/_default.cfg @@ -125,6 +125,11 @@ maxbackups="4" maxbackupdays="30" stoponbackup="on" +## Fastdl | https://docs.linuxgsm.com/commands/fastdl +# Paths to leave out of Fastdl, relative to the Fastdl directory and separated by spaces. +# e.g. "maps/workshop/ sound/music/" +fastdlexclude="maps/workshop/" + ## Logging | https://docs.linuxgsm.com/features/logging consolelogging="on" logdays="7" diff --git a/lgsm/config-default/config-lgsm/l4dserver/_default.cfg b/lgsm/config-default/config-lgsm/l4dserver/_default.cfg index 73962c0fb7..ba0322710a 100644 --- a/lgsm/config-default/config-lgsm/l4dserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/l4dserver/_default.cfg @@ -119,6 +119,11 @@ maxbackups="4" maxbackupdays="30" stoponbackup="on" +## Fastdl | https://docs.linuxgsm.com/commands/fastdl +# Paths to leave out of Fastdl, relative to the Fastdl directory and separated by spaces. +# e.g. "maps/workshop/ sound/music/" +fastdlexclude="maps/workshop/" + ## Logging | https://docs.linuxgsm.com/features/logging consolelogging="on" logdays="7" diff --git a/lgsm/config-default/config-lgsm/mcvserver/_default.cfg b/lgsm/config-default/config-lgsm/mcvserver/_default.cfg index 9048f68342..907ce818fa 100644 --- a/lgsm/config-default/config-lgsm/mcvserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/mcvserver/_default.cfg @@ -105,6 +105,11 @@ maxbackups="4" maxbackupdays="30" stoponbackup="on" +## Fastdl | https://docs.linuxgsm.com/commands/fastdl +# Paths to leave out of Fastdl, relative to the Fastdl directory and separated by spaces. +# e.g. "maps/workshop/ sound/music/" +fastdlexclude="maps/workshop/" + ## Logging | https://docs.linuxgsm.com/features/logging consolelogging="on" logdays="7" diff --git a/lgsm/config-default/config-lgsm/ndserver/_default.cfg b/lgsm/config-default/config-lgsm/ndserver/_default.cfg index 8009fe1a3c..322a5a3fc5 100644 --- a/lgsm/config-default/config-lgsm/ndserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/ndserver/_default.cfg @@ -125,6 +125,11 @@ maxbackups="4" maxbackupdays="30" stoponbackup="on" +## Fastdl | https://docs.linuxgsm.com/commands/fastdl +# Paths to leave out of Fastdl, relative to the Fastdl directory and separated by spaces. +# e.g. "maps/workshop/ sound/music/" +fastdlexclude="maps/workshop/" + ## Logging | https://docs.linuxgsm.com/features/logging consolelogging="on" logdays="7" diff --git a/lgsm/config-default/config-lgsm/nmrihserver/_default.cfg b/lgsm/config-default/config-lgsm/nmrihserver/_default.cfg index 3600221ab7..8ab45a0106 100644 --- a/lgsm/config-default/config-lgsm/nmrihserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/nmrihserver/_default.cfg @@ -125,6 +125,11 @@ maxbackups="4" maxbackupdays="30" stoponbackup="on" +## Fastdl | https://docs.linuxgsm.com/commands/fastdl +# Paths to leave out of Fastdl, relative to the Fastdl directory and separated by spaces. +# e.g. "maps/workshop/ sound/music/" +fastdlexclude="maps/workshop/" + ## Logging | https://docs.linuxgsm.com/features/logging consolelogging="on" logdays="7" diff --git a/lgsm/config-default/config-lgsm/nsserver/_default.cfg b/lgsm/config-default/config-lgsm/nsserver/_default.cfg index 8ad8c16a2b..2c3c24cc40 100644 --- a/lgsm/config-default/config-lgsm/nsserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/nsserver/_default.cfg @@ -119,6 +119,11 @@ maxbackups="4" maxbackupdays="30" stoponbackup="on" +## Fastdl | https://docs.linuxgsm.com/commands/fastdl +# Paths to leave out of Fastdl, relative to the Fastdl directory and separated by spaces. +# e.g. "maps/workshop/ sound/music/" +fastdlexclude="" + ## Logging | https://docs.linuxgsm.com/features/logging consolelogging="on" logdays="7" diff --git a/lgsm/config-default/config-lgsm/opforserver/_default.cfg b/lgsm/config-default/config-lgsm/opforserver/_default.cfg index c8fd40c857..c55598b917 100644 --- a/lgsm/config-default/config-lgsm/opforserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/opforserver/_default.cfg @@ -119,6 +119,11 @@ maxbackups="4" maxbackupdays="30" stoponbackup="on" +## Fastdl | https://docs.linuxgsm.com/commands/fastdl +# Paths to leave out of Fastdl, relative to the Fastdl directory and separated by spaces. +# e.g. "maps/workshop/ sound/music/" +fastdlexclude="" + ## Logging | https://docs.linuxgsm.com/features/logging consolelogging="on" logdays="7" diff --git a/lgsm/config-default/config-lgsm/pvkiiserver/_default.cfg b/lgsm/config-default/config-lgsm/pvkiiserver/_default.cfg index c8e39c7375..81ff3fd340 100644 --- a/lgsm/config-default/config-lgsm/pvkiiserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/pvkiiserver/_default.cfg @@ -120,6 +120,11 @@ maxbackups="4" maxbackupdays="30" stoponbackup="on" +## Fastdl | https://docs.linuxgsm.com/commands/fastdl +# Paths to leave out of Fastdl, relative to the Fastdl directory and separated by spaces. +# e.g. "maps/workshop/ sound/music/" +fastdlexclude="maps/workshop/" + ## Logging | https://docs.linuxgsm.com/features/logging consolelogging="on" logdays="7" diff --git a/lgsm/config-default/config-lgsm/ricochetserver/_default.cfg b/lgsm/config-default/config-lgsm/ricochetserver/_default.cfg index 7ee7763b0b..f8002b0a19 100644 --- a/lgsm/config-default/config-lgsm/ricochetserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/ricochetserver/_default.cfg @@ -119,6 +119,11 @@ maxbackups="4" maxbackupdays="30" stoponbackup="on" +## Fastdl | https://docs.linuxgsm.com/commands/fastdl +# Paths to leave out of Fastdl, relative to the Fastdl directory and separated by spaces. +# e.g. "maps/workshop/ sound/music/" +fastdlexclude="" + ## Logging | https://docs.linuxgsm.com/features/logging consolelogging="on" logdays="7" diff --git a/lgsm/config-default/config-lgsm/sfcserver/_default.cfg b/lgsm/config-default/config-lgsm/sfcserver/_default.cfg index 2be02488b4..99562af6ab 100644 --- a/lgsm/config-default/config-lgsm/sfcserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/sfcserver/_default.cfg @@ -120,6 +120,11 @@ maxbackups="4" maxbackupdays="30" stoponbackup="on" +## Fastdl | https://docs.linuxgsm.com/commands/fastdl +# Paths to leave out of Fastdl, relative to the Fastdl directory and separated by spaces. +# e.g. "maps/workshop/ sound/music/" +fastdlexclude="maps/workshop/" + ## Logging | https://docs.linuxgsm.com/features/logging consolelogging="on" logdays="7" diff --git a/lgsm/config-default/config-lgsm/svenserver/_default.cfg b/lgsm/config-default/config-lgsm/svenserver/_default.cfg index e591fbc057..362cfe6032 100644 --- a/lgsm/config-default/config-lgsm/svenserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/svenserver/_default.cfg @@ -119,6 +119,11 @@ maxbackups="4" maxbackupdays="30" stoponbackup="on" +## Fastdl | https://docs.linuxgsm.com/commands/fastdl +# Paths to leave out of Fastdl, relative to the Fastdl directory and separated by spaces. +# e.g. "maps/workshop/ sound/music/" +fastdlexclude="" + ## Logging | https://docs.linuxgsm.com/features/logging consolelogging="on" logdays="7" diff --git a/lgsm/config-default/config-lgsm/tf2cserver/_default.cfg b/lgsm/config-default/config-lgsm/tf2cserver/_default.cfg index 592d1aba28..adb83a2574 100644 --- a/lgsm/config-default/config-lgsm/tf2cserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/tf2cserver/_default.cfg @@ -127,6 +127,11 @@ maxbackups="4" maxbackupdays="30" stoponbackup="on" +## Fastdl | https://docs.linuxgsm.com/commands/fastdl +# Paths to leave out of Fastdl, relative to the Fastdl directory and separated by spaces. +# e.g. "maps/workshop/ sound/music/" +fastdlexclude="maps/workshop/" + ## Logging | https://docs.linuxgsm.com/features/logging consolelogging="on" logdays="7" diff --git a/lgsm/config-default/config-lgsm/tf2server/_default.cfg b/lgsm/config-default/config-lgsm/tf2server/_default.cfg index 0c1404a937..021574d7fd 100644 --- a/lgsm/config-default/config-lgsm/tf2server/_default.cfg +++ b/lgsm/config-default/config-lgsm/tf2server/_default.cfg @@ -127,6 +127,11 @@ maxbackups="4" maxbackupdays="30" stoponbackup="on" +## Fastdl | https://docs.linuxgsm.com/commands/fastdl +# Paths to leave out of Fastdl, relative to the Fastdl directory and separated by spaces. +# e.g. "maps/workshop/ sound/music/" +fastdlexclude="maps/workshop/" + ## Logging | https://docs.linuxgsm.com/features/logging consolelogging="on" logdays="7" diff --git a/lgsm/config-default/config-lgsm/tfcserver/_default.cfg b/lgsm/config-default/config-lgsm/tfcserver/_default.cfg index 35e3d98c8c..acae133c13 100644 --- a/lgsm/config-default/config-lgsm/tfcserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/tfcserver/_default.cfg @@ -119,6 +119,11 @@ maxbackups="4" maxbackupdays="30" stoponbackup="on" +## Fastdl | https://docs.linuxgsm.com/commands/fastdl +# Paths to leave out of Fastdl, relative to the Fastdl directory and separated by spaces. +# e.g. "maps/workshop/ sound/music/" +fastdlexclude="" + ## Logging | https://docs.linuxgsm.com/features/logging consolelogging="on" logdays="7" diff --git a/lgsm/config-default/config-lgsm/tsserver/_default.cfg b/lgsm/config-default/config-lgsm/tsserver/_default.cfg index 25987d7d63..ba59e0071c 100644 --- a/lgsm/config-default/config-lgsm/tsserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/tsserver/_default.cfg @@ -119,6 +119,11 @@ maxbackups="4" maxbackupdays="30" stoponbackup="on" +## Fastdl | https://docs.linuxgsm.com/commands/fastdl +# Paths to leave out of Fastdl, relative to the Fastdl directory and separated by spaces. +# e.g. "maps/workshop/ sound/music/" +fastdlexclude="" + ## Logging | https://docs.linuxgsm.com/features/logging consolelogging="on" logdays="7" diff --git a/lgsm/config-default/config-lgsm/vsserver/_default.cfg b/lgsm/config-default/config-lgsm/vsserver/_default.cfg index bb212d398f..529054a535 100644 --- a/lgsm/config-default/config-lgsm/vsserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/vsserver/_default.cfg @@ -119,6 +119,11 @@ maxbackups="4" maxbackupdays="30" stoponbackup="on" +## Fastdl | https://docs.linuxgsm.com/commands/fastdl +# Paths to leave out of Fastdl, relative to the Fastdl directory and separated by spaces. +# e.g. "maps/workshop/ sound/music/" +fastdlexclude="" + ## Logging | https://docs.linuxgsm.com/features/logging consolelogging="on" logdays="7" diff --git a/lgsm/config-default/config-lgsm/zmrserver/_default.cfg b/lgsm/config-default/config-lgsm/zmrserver/_default.cfg index 8bdeb2fbf5..04a987deae 100644 --- a/lgsm/config-default/config-lgsm/zmrserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/zmrserver/_default.cfg @@ -120,6 +120,11 @@ maxbackups="4" maxbackupdays="30" stoponbackup="on" +## Fastdl | https://docs.linuxgsm.com/commands/fastdl +# Paths to leave out of Fastdl, relative to the Fastdl directory and separated by spaces. +# e.g. "maps/workshop/ sound/music/" +fastdlexclude="maps/workshop/" + ## Logging | https://docs.linuxgsm.com/features/logging consolelogging="on" logdays="7" diff --git a/lgsm/config-default/config-lgsm/zpsserver/_default.cfg b/lgsm/config-default/config-lgsm/zpsserver/_default.cfg index fc4b50fb92..eb2d2fe0cf 100644 --- a/lgsm/config-default/config-lgsm/zpsserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/zpsserver/_default.cfg @@ -125,6 +125,11 @@ maxbackups="4" maxbackupdays="30" stoponbackup="on" +## Fastdl | https://docs.linuxgsm.com/commands/fastdl +# Paths to leave out of Fastdl, relative to the Fastdl directory and separated by spaces. +# e.g. "maps/workshop/ sound/music/" +fastdlexclude="maps/workshop/" + ## Logging | https://docs.linuxgsm.com/features/logging consolelogging="on" logdays="7" diff --git a/lgsm/modules/command_fastdl.sh b/lgsm/modules/command_fastdl.sh index 93dc87d262..67b0df0071 100755 --- a/lgsm/modules/command_fastdl.sh +++ b/lgsm/modules/command_fastdl.sh @@ -21,6 +21,17 @@ luasvautorundir="${systemdir}/lua/autorun/server" luafastdlfile="lgsm_cl_force_fastdl.lua" luafastdlfullpath="${luasvautorundir}/${luafastdlfile}" +# File lists. +fastdlfilelist="${tmpdir}/fastdl_files.txt" +fastdlduplicatelist="${tmpdir}/fastdl_files_duplicate.txt" +fastdlnewrecord="${tmpdir}/fastdl_record.txt" +fastdlrecord="${datadir}/${selfname}-fastdl.txt" +fastdlclientlist="${tmpdir}/fastdl_files_client.txt" +fastdlupdatelist="${tmpdir}/fastdl_files_to_update.txt" +fastdlremovelist="${tmpdir}/fastdl_files_to_remove.txt" +fastdlcompresslist="${tmpdir}/fastdl_files_to_compress.txt" +fastdlmaxcompresssize="157286400" + # Header fn_print_header fn_print_nl "More info: ${italic}https://docs.linuxgsm.com/commands/fastdl" @@ -30,15 +41,17 @@ fn_print_nl "" fn_print_nl "${bold}${lightyellow}${commandaction} Setup" fn_messages_separator -# Prompt for clearing old files if directory was already here. +# Prompt for a full rebuild if directory was already here. +fastdlrebuild="off" if [ -d "${fastdldir}" ]; then - fn_print_warning_nl "Fastdl directory already exists." + fn_print_info_nl "Fastdl directory already exists, only changed files will be updated." fn_print_nl "${fastdldir}" fn_print_nl "" - if fn_prompt_yn "Overwrite existing directory?" Y; then - fn_script_log_info "Overwrite existing directory: YES" + if fn_prompt_yn "Rebuild Fastdl directory from scratch? This deletes everything in it." N; then + fastdlrebuild="on" + fn_script_log_info "Rebuild Fastdl directory from scratch: YES" else - core_exit.sh + fn_script_log_info "Rebuild Fastdl directory from scratch: NO" fi fi @@ -50,7 +63,7 @@ if [ "${shortname}" == "gmod" ]; then fn_script_log_info "Force clients to download files: YES" else luaresource="off" - fn_script_log_info "Force clients to download filesr: NO" + fn_script_log_info "Force clients to download files: NO" fi fi @@ -153,34 +166,182 @@ fn_fastdl_goldsrc_extensions() { fi } +# Sets the Source file types to include for the current directory. +fn_fastdl_source_extensions() { + fastdl_find_maxdepth=() + if [ "${directory}" == "maps" ]; then + allowed_extentions_array=("*.bsp" "*.ain" "*.nav" "*.jpg" "*.txt") + elif [ "${directory}" == "materials" ]; then + allowed_extentions_array=("*.vtf" "*.vmt" "*.vbf" "*.png" "*.svg") + elif [ "${directory}" == "models" ]; then + allowed_extentions_array=("*.vtx" "*.vvd" "*.mdl" "*.phy" "*.jpg" "*.png" "*.vmt" "*.vtf") + elif [ "${directory}" == "particles" ]; then + allowed_extentions_array=("*.pcf") + elif [ "${directory}" == "sound" ]; then + allowed_extentions_array=("*.wav" "*.mp3" "*.ogg") + elif [ "${directory}" == "resource" ]; then + allowed_extentions_array=("*") + fi +} + +# Adds the allowed files in a content directory to the file list. +fn_fastdl_gather() { + local basedir="${1}" + local priority="${2}" + local label="${directory}" + if [ "${basedir}" != "${systemdir}" ]; then + label="${basedir#"${systemdir}/"}/${directory}" + fi + for allowed_extention in "${allowed_extentions_array[@]}"; do + fileswc=0 + tput sc + while IFS=$'\t' read -r filesize filemtime fastdlfile; do + ((fileswc++)) + tput rc + tput el + fn_print "gathering ${label} ${allowed_extention} : ${fileswc}" + fastdlrelpath="${fastdlfile#"${basedir}/"}" + printf '%s\t%s\t%s\t%s\t%s\n' "${priority}" "${fastdlrelpath#./}" "${filesize}" "${filemtime}" "${fastdlfile}" >> "${fastdlfilelist}" + done < <(find "${basedir}/${directory}" "${fastdl_find_maxdepth[@]}" -type f -iname "${allowed_extention}" -printf '%s\t%T@\t%p\n') + tput rc + tput el + fn_print "gathering ${label} ${allowed_extention} : ${fileswc}" + if [ ${fileswc} != 0 ]; then + fn_print_ok_eol_nl + else + fn_print_info_eol_nl + fi + done +} + +# Adds Garry's Mod files to the file list. +fn_fastdl_gather_gmod() { + cd "${systemdir}" || exit + allowed_extentions_array=("*.ain" "*.bsp" "*.mdl" "*.mp3" "*.ogg" "*.otf" "*.pcf" "*.phy" "*.png" "*.svg" "*.vtf" "*.vmt" "*.vtx" "*.vvd" "*.ttf" "*.wav") + for allowed_extention in "${allowed_extentions_array[@]}"; do + fileswc=0 + tput sc + while IFS=$'\t' read -r filesize filemtime fastdlfile; do + ((fileswc++)) + tput rc + tput el + fn_print "gathering ${allowed_extention} : ${fileswc}" + fastdlrelpath="${fastdlfile#./}" + priority="2" + if [[ "${fastdlrelpath}" == addons/* ]]; then + addonname="${fastdlrelpath#addons/}" + addonname="${addonname%%/*}" + if [ "addons/${addonname}" == "${fastdlrelpath}" ]; then + continue + fi + priority="1:${addonname}" + fastdlrelpath="${fastdlrelpath#addons/"${addonname}"/}" + fi + printf '%s\t%s\t%s\t%s\t%s\n' "${priority}" "${fastdlrelpath}" "${filesize}" "${filemtime}" "${systemdir}/${fastdlfile#./}" >> "${fastdlfilelist}" + if [[ "${fastdlrelpath}" == lua/* ]]; then + printf '%s\t%s\t%s\t%s\t%s\n' "0" "${fastdlrelpath#lua/}" "${filesize}" "${filemtime}" "${systemdir}/${fastdlfile#./}" >> "${fastdlfilelist}" + fi + done < <(find . -type f -iname "${allowed_extention}" -printf '%s\t%T@\t%p\n') + if [ ${fileswc} != 0 ]; then + fn_print_ok_eol_nl + else + fn_print_skip_eol_nl + fi + done +} + +# Works out which files need to be copied, compressed or removed. +fn_fastdl_plan() { + LC_ALL=C sort -t $'\t' -k2,2 -k1,1 "${fastdlfilelist}" | awk -F '\t' -v dupes="${fastdlduplicatelist}" 'seen[$2]++ { print $5 " > " $2 > dupes; next } { print }' > "${fastdlfilelist}.sorted" + mv -f "${fastdlfilelist}.sorted" "${fastdlfilelist}" + if [ -f "${fastdlduplicatelist}" ]; then + duplicatefiles=$(wc -l < "${fastdlduplicatelist}") + while read -r duplicatefile; do + fn_script_log_info "Skipping ${duplicatefile}, already provided by a higher priority path" + done < "${fastdlduplicatelist}" + fi + + declare -A fastdlrecordsource=() + declare -A fastdlexpected=() + if [ "${fastdlrebuild}" != "on" ] && [ -f "${fastdlrecord}" ] && [ "$(head -n 1 "${fastdlrecord}")" == "${fastdldir}" ]; then + while IFS=$'\t' read -r fastdltarget recordsource; do + [ -n "${fastdltarget}" ] && fastdlrecordsource["${fastdltarget}"]="${recordsource}" + done < <(tail -n +2 "${fastdlrecord}") + fi + echo "${fastdldir}" > "${fastdlnewrecord}" + + read -ra fastdlexcludearray <<< "${fastdlexclude}" + while IFS=$'\t' read -r priority fastdlrelpath filesize filemtime fastdlfile; do + for excludepath in "${fastdlexcludearray[@]}"; do + # shellcheck disable=SC2254 + case "${fastdlrelpath}" in + ${excludepath#/}*) + ((excludedfiles++)) + continue 2 + ;; + esac + done + if [ "${engine}" == "goldsrc" ] || [ "${filesize}" -gt "${fastdlmaxcompresssize}" ]; then + fastdlmode="copy" + fastdltarget="${fastdlrelpath}" + if [ "${engine}" != "goldsrc" ]; then + ((largefiles++)) + fi + else + fastdlmode="compress" + fastdltarget="${fastdlrelpath}.bz2" + fi + fastdlsource="${fastdlfile}"$'\t'"${filesize}"$'\t'"${filemtime}" + fastdlexpected["${fastdltarget}"]="on" + printf '%s\t%s\n' "${fastdltarget}" "${fastdlsource}" >> "${fastdlnewrecord}" + echo "${fastdlrelpath}" >> "${fastdlclientlist}" + if [ ! -f "${fastdldir}/${fastdltarget}" ] || [ "${fastdlrecordsource["${fastdltarget}"]}" != "${fastdlsource}" ]; then + printf '%s\t%s\t%s\n' "${fastdlmode}" "${fastdlrelpath}" "${fastdlfile}" >> "${fastdlupdatelist}" + ((updatefiles++)) + filesizetotal=$((filesizetotal + filesize)) + if [ "${fastdlmode}" == "compress" ]; then + ((compressfiles++)) + fi + else + ((unchangedfiles++)) + fi + done < "${fastdlfilelist}" + + for fastdltarget in "${!fastdlrecordsource[@]}"; do + if [ -z "${fastdlexpected["${fastdltarget}"]}" ] && [ -f "${fastdldir}/${fastdltarget}" ]; then + echo "${fastdltarget}" >> "${fastdlremovelist}" + ((removefiles++)) + fi + done + if [ -d "${fastdldir}" ] && [ "${fastdlrebuild}" != "on" ]; then + while read -r fastdltarget; do + if [ -z "${fastdlexpected["${fastdltarget}"]}" ] && [ -z "${fastdlrecordsource["${fastdltarget}"]}" ]; then + ((untrackedfiles++)) + fi + done < <(find "${fastdldir}" -type f -printf '%P\n') + fi +} + # Provides info about the fastdl directory content and prompts for confirmation. fn_fastdl_preview() { # Remove any file list. - if [ -f "${tmpdir}/fastdl_files_to_compress.txt" ]; then - rm -f "${tmpdir:?}/fastdl_files_to_compress.txt" - fi + rm -f "${fastdlfilelist:?}" "${fastdlduplicatelist:?}" "${fastdlnewrecord:?}" "${fastdlclientlist:?}" "${fastdlupdatelist:?}" "${fastdlremovelist:?}" "${fastdlcompresslist:?}" + touch "${fastdlclientlist}" + totalfiles=0 + untrackedfiles=0 + duplicatefiles=0 + excludedfiles=0 + largefiles=0 + updatefiles=0 + compressfiles=0 + unchangedfiles=0 + removefiles=0 + filesizetotal=0 fn_print_nl "analysing required files" fn_script_log_info "Analysing required files" # Garry's Mod if [ "${shortname}" == "gmod" ]; then - cd "${systemdir}" || exit - allowed_extentions_array=("*.ain" "*.bsp" "*.mdl" "*.mp3" "*.ogg" "*.otf" "*.pcf" "*.phy" "*.png" "*.svg" "*.vtf" "*.vmt" "*.vtx" "*.vvd" "*.ttf" "*.wav") - for allowed_extention in "${allowed_extentions_array[@]}"; do - fileswc=0 - tput sc - while read -r ext; do - ((fileswc++)) - tput rc - tput el - fn_print "gathering ${allowed_extention} : ${fileswc}" - echo -e "${ext}" >> "${tmpdir}/fastdl_files_to_compress.txt" - done < <(find . -type f -iname "${allowed_extention}") - if [ ${fileswc} != 0 ]; then - fn_print_ok_eol_nl - else - fn_print_skip_eol_nl - fi - done + fn_fastdl_gather_gmod # Source and GoldSrc engines else if [ "${engine}" == "goldsrc" ]; then @@ -188,219 +349,124 @@ fn_fastdl_preview() { else fastdl_directories_array=("maps" "materials" "models" "particles" "sound" "resource") fi + fastdl_custom_array=() + if [ "${engine}" == "source" ] && [ -d "${systemdir}/custom" ]; then + while IFS= read -r -d '' customdir; do + fastdl_custom_array+=("${customdir}") + done < <(find "${systemdir}/custom" -mindepth 1 -maxdepth 1 -type d -print0 | LC_ALL=C sort -z) + fi for directory in "${fastdl_directories_array[@]}"; do - if [ -d "${systemdir}/${directory}" ]; then - if [ "${engine}" == "goldsrc" ]; then - fn_fastdl_goldsrc_extensions - elif [ "${directory}" == "maps" ]; then - local allowed_extentions_array=("*.bsp" "*.ain" "*.nav" "*.jpg" "*.txt") - elif [ "${directory}" == "materials" ]; then - local allowed_extentions_array=("*.vtf" "*.vmt" "*.vbf" "*.png" "*.svg") - elif [ "${directory}" == "models" ]; then - local allowed_extentions_array=("*.vtx" "*.vvd" "*.mdl" "*.phy" "*.jpg" "*.png" "*.vmt" "*.vtf") - elif [ "${directory}" == "particles" ]; then - local allowed_extentions_array=("*.pcf") - elif [ "${directory}" == "sound" ]; then - local allowed_extentions_array=("*.wav" "*.mp3" "*.ogg") - elif [ "${directory}" == "resource" ]; then - local allowed_extentions_array=("*") + if [ "${engine}" == "goldsrc" ]; then + fn_fastdl_goldsrc_extensions + else + fn_fastdl_source_extensions + fi + for customdir in "${fastdl_custom_array[@]}"; do + if [ -d "${customdir}/${directory}" ]; then + fn_fastdl_gather "${customdir}" "0:${customdir##*/}" fi - for allowed_extention in "${allowed_extentions_array[@]}"; do - fileswc=0 - tput sc - while read -r ext; do - ((fileswc++)) - tput rc - tput el - fn_print "gathering ${directory} ${allowed_extention} : ${fileswc}" - echo -e "${ext}" >> "${tmpdir}/fastdl_files_to_compress.txt" - done < <(find "${systemdir}/${directory}" "${fastdl_find_maxdepth[@]}" -type f -iname "${allowed_extention}") - tput rc - tput el - fn_print "gathering ${directory} ${allowed_extention} : ${fileswc}" - if [ ${fileswc} != 0 ]; then - fn_print_ok_eol_nl - else - fn_print_info_eol_nl - fi - done + done + if [ -d "${systemdir}/${directory}" ]; then + fn_fastdl_gather "${systemdir}" "1" fi done fi - if [ -f "${tmpdir}/fastdl_files_to_compress.txt" ]; then - fn_print_nl "calculating total file size" + if [ -f "${fastdlfilelist}" ]; then + fn_print_nl "calculating changes" fn_sleep_time_1 - totalfiles=$(wc -l < "${tmpdir}/fastdl_files_to_compress.txt") - # Calculates total file size. - while read -r dufile; do - filesize=$(stat -c %s "${dufile}") - filesizetotal=$((filesizetotal + filesize)) - exitcode=$? - if [ "${exitcode}" -ne 0 ]; then - fn_print_fail_eol_nl - fn_script_log_fail "Calculating total file size" - core_exit.sh - fi - done < "${tmpdir}/fastdl_files_to_compress.txt" + totalfiles=$(wc -l < "${fastdlfilelist}") + fn_fastdl_plan else fn_print_fail_eol_nl "generating file list" fn_script_log_fail "Generating file list." core_exit.sh fi - 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)" + echo -e "found ${totalfiles} files: ${unchangedfiles} unchanged, ${excludedfiles} excluded, ${duplicatefiles} duplicate" + if [ "${updatefiles}" -gt 0 ]; then + if [ "${engine}" == "source" ]; then + echo -e "about to update ${updatefiles} files, ${compressfiles} to compress, total size $(fn_human_readable_file_size "${filesizetotal}" 0)" + elif [ "${engine}" == "goldsrc" ]; then + echo -e "about to copy ${updatefiles} files, total size $(fn_human_readable_file_size "${filesizetotal}" 0)" + fi + fi + if [ "${largefiles}" -gt 0 ]; then + echo -e "${largefiles} files over 150 MB will be copied without compression" + fi + if [ "${removefiles}" -gt 0 ]; then + echo -e "about to remove ${removefiles} files no longer on the server" + fi + if [ "${untrackedfiles}" -gt 0 ]; then + echo -e "${untrackedfiles} files in the Fastdl directory were not added by ${selfname} and will be left alone" + fi + if [ "${updatefiles}" -eq 0 ] && [ "${removefiles}" -eq 0 ]; then + echo -e "Fastdl directory is up to date" fi - fn_script_log_info "${totalfiles} files, total size $(fn_human_readable_file_size "${filesizetotal}" 0)" - rm -f "${tmpdir:?}/fastdl_files_to_compress.txt" + fn_script_log_info "${totalfiles} files, ${updatefiles} to update, ${unchangedfiles} unchanged, ${excludedfiles} excluded, ${removefiles} to remove, total size $(fn_human_readable_file_size "${filesizetotal}" 0)" if ! fn_prompt_yn "Continue?" Y; then exitcode=0 core_exit.sh fi } -# Builds Garry's Mod fastdl directory content. -fn_fastdl_gmod() { - cd "${systemdir}" || exit - for allowed_extention in "${allowed_extentions_array[@]}"; do +# Removes files from the fastdl directory that are no longer on the server. +fn_fastdl_remove() { + if [ -s "${fastdlremovelist}" ]; then + fn_print "removing ${removefiles} files no longer on the server" + while read -r fastdlstalefile; do + rm -f "${fastdldir:?}/${fastdlstalefile}" + exitcode=$? + if [ "${exitcode}" -ne 0 ]; then + fn_print_fail_eol_nl + fn_script_log_fail "Removing ${fastdldir}/${fastdlstalefile}" + core_exit.sh + else + fn_script_log_pass "Removing ${fastdldir}/${fastdlstalefile}" + fi + done < "${fastdlremovelist}" + find "${fastdldir:?}" -mindepth 1 -type d -empty -delete + fn_print_ok_eol_nl + fi +} + +# Copies new and changed files to the fastdl directory. +fn_fastdl_copy() { + if [ -s "${fastdlupdatelist}" ]; then fileswc=0 tput sc - while read -r fastdlfile; do + while IFS=$'\t' read -r fastdlmode fastdlrelpath fastdlfile; do ((fileswc++)) tput rc tput el - fn_print "copying ${allowed_extention} : ${fileswc}" - cp --parents "${fastdlfile}" "${fastdldir}" + fn_print "copying files : ${fileswc}/${updatefiles}" + fastdltarget="${fastdldir}/${fastdlrelpath}" + mkdir -p "${fastdltarget%/*}" && cp -p "${fastdlfile}" "${fastdltarget}" exitcode=$? if [ "${exitcode}" -ne 0 ]; then fn_print_fail_eol_nl - fn_script_log_fail "Copying ${fastdlfile} > ${fastdldir}" + fn_script_log_fail "Copying ${fastdlfile} > ${fastdltarget}" core_exit.sh else - fn_script_log_pass "Copying ${fastdlfile} > ${fastdldir}" + fn_script_log_pass "Copying ${fastdlfile} > ${fastdltarget}" fi - done < <(find . -type f -iname "${allowed_extention}") - if [ ${fileswc} != 0 ]; then - fn_print_ok_eol_nl - fi - done - # Correct addons directory structure for Fastdl. - if [ -d "${fastdldir}/addons" ]; then - fn_print "updating addons file structure..." - cp -Rf "${fastdldir}"/addons/*/* "${fastdldir}" - exitcode=$? - if [ "${exitcode}" -ne 0 ]; then - fn_print_fail_eol_nl - fn_script_log_fail "Updating addons file structure" - core_exit.sh - else - fn_print_ok_eol_nl - fn_script_log_pass "Updating addons file structure" - fi - # Clear addons directory in fastdl. - fn_print "clearing addons dir from fastdl dir..." - fn_sleep_time_1 - rm -rf "${fastdldir:?}/addons" - exitcode=$? - if [ "${exitcode}" -ne 0 ]; then - fn_print_fail_eol_nl - fn_script_log_fail "Clearing addons dir from fastdl dir" - core_exit.sh - else - fn_print_ok_eol_nl - fn_script_log_pass "Clearing addons dir from fastdl dir" - fi - fi - # Correct content that may be into a lua directory by mistake like some darkrpmodification addons. - if [ -d "${fastdldir}/lua" ]; then - fn_print "correcting DarkRP files..." - fn_sleep_time_1 - cp -Rf "${fastdldir}/lua/"* "${fastdldir}" - exitcode=$? - if [ "${exitcode}" -ne 0 ]; then - fn_print_fail_eol_nl - fn_script_log_fail "Correcting DarkRP files" - core_exit.sh - else - fn_print_ok_eol_nl - fn_script_log_pass "Correcting DarkRP files" - fi - fi - if [ -f "${tmpdir}/fastdl_files_to_compress.txt" ]; then - totalfiles=$(wc -l < "${tmpdir}/fastdl_files_to_compress.txt") - # Calculates total file size. - while read -r dufile; do - filesize=$(du -b "${dufile}" | awk '{ print $1 }') - filesizetotal=$((filesizetotal + filesize)) - done < "${tmpdir}/fastdl_files_to_compress.txt" - fi -} - -fn_fastdl_source() { - for directory in "${fastdl_directories_array[@]}"; do - if [ -d "${systemdir}/${directory}" ]; then - if [ "${engine}" == "goldsrc" ]; then - fn_fastdl_goldsrc_extensions - elif [ "${directory}" == "maps" ]; then - local allowed_extentions_array=("*.bsp" "*.ain" "*.nav" "*.jpg" "*.txt") - elif [ "${directory}" == "materials" ]; then - local allowed_extentions_array=("*.vtf" "*.vmt" "*.vbf" "*.png" "*.svg") - elif [ "${directory}" == "models" ]; then - local allowed_extentions_array=("*.vtx" "*.vvd" "*.mdl" "*.phy" "*.jpg" "*.png") - elif [ "${directory}" == "particles" ]; then - local allowed_extentions_array=("*.pcf") - elif [ "${directory}" == "sound" ]; then - local allowed_extentions_array=("*.wav" "*.mp3" "*.ogg") - elif [ "${directory}" == "resource" ]; then - local allowed_extentions_array=("*") + if [ "${fastdlmode}" == "compress" ]; then + printf '%s\0' "${fastdltarget}" >> "${fastdlcompresslist}" fi - for allowed_extention in "${allowed_extentions_array[@]}"; do - fileswc=0 - tput sc - while read -r fastdlfile; do - ((fileswc++)) - tput rc - tput el - fn_print "copying ${directory} ${allowed_extention} : ${fileswc}" - fn_sleep_time - # get relative path of file in the dir - tmprelfilepath="${fastdlfile#"${systemdir}/"}" - copytodir="${tmprelfilepath%/*}" - # create relative path for fastdl - if [ ! -d "${fastdldir}/${copytodir}" ]; then - mkdir -p "${fastdldir}/${copytodir}" - fi - cp "${fastdlfile}" "${fastdldir}/${copytodir}" - exitcode=$? - if [ "${exitcode}" -ne 0 ]; then - fn_print_fail_eol_nl - fn_script_log_fail "Copying ${fastdlfile} > ${fastdldir}/${copytodir}" - core_exit.sh - else - fn_script_log_pass "Copying ${fastdlfile} > ${fastdldir}/${copytodir}" - fi - done < <(find "${systemdir}/${directory}" "${fastdl_find_maxdepth[@]}" -type f -iname "${allowed_extention}") - if [ ${fileswc} != 0 ]; then - fn_print_ok_eol_nl - fi - done - fi - done + done < "${fastdlupdatelist}" + fn_print_ok_eol_nl + fi } # Builds the fastdl directory content. fn_fastdl_build() { # Copy all needed files for Fastdl. - fn_print_nl "copying files to ${fastdldir}" - fn_script_log_info "Copying files to ${fastdldir}" + fn_print_nl "updating files in ${fastdldir}" + fn_script_log_info "Updating files in ${fastdldir}" + fn_fastdl_remove + fn_fastdl_copy if [ "${shortname}" == "gmod" ]; then - fn_fastdl_gmod fn_fastdl_gmod_dl_enforcer - else - fn_fastdl_source fi } @@ -427,7 +493,7 @@ fn_fastdl_gmod_dl_enforcer() { # Read all filenames and put them into a lua file at the right path. while read -r line; do echo -e "resource.AddFile( \"${line}\" )" >> "${luafastdlfullpath}" - done < <(find "${fastdldir:?}" \( -type f ! -name "*.bz2" \) -printf '%P\n') + done < "${fastdlclientlist}" exitcode=$? if [ "${exitcode}" -ne 0 ]; then fn_print_fail_eol_nl @@ -442,30 +508,61 @@ fn_fastdl_gmod_dl_enforcer() { # Compresses Fastdl files using bzip2. fn_fastdl_bzip2() { - while read -r filetocompress; do - fn_print "compressing ${filetocompress}" - bzip2 -f "${filetocompress}" - exitcode=$? - if [ "${exitcode}" -ne 0 ]; then + if [ -s "${fastdlcompresslist}" ]; then + fastdlthreads="$(nproc)" + fn_print "compressing ${compressfiles} files using ${fastdlthreads} threads" + xargs -0 -r -n 1 -P "${fastdlthreads}" bzip2 -f < "${fastdlcompresslist}" + compressexitcode=$? + while IFS=$'\t' read -r fastdlmode fastdlrelpath fastdlfile; do + if [ "${fastdlmode}" == "compress" ]; then + filetocompress="${fastdldir}/${fastdlrelpath}" + if [ -f "${filetocompress}.bz2" ] && [ ! -f "${filetocompress}" ]; then + fn_script_log_pass "Compressing ${filetocompress}" + else + fn_script_log_fail "Compressing ${filetocompress}" + fi + fi + done < "${fastdlupdatelist}" + if [ "${compressexitcode}" -ne 0 ]; then fn_print_fail_eol_nl - fn_script_log_fail "Compressing ${filetocompress}" + fn_script_log_fail "Compressing files" + exitcode=1 core_exit.sh else fn_print_ok_eol_nl - fn_script_log_pass "Compressing ${filetocompress}" + fn_script_log_pass "Compressing files" fi - done < <(find "${fastdldir:?}" \( -type f ! -name "*.bz2" \)) + fi +} + +# Saves the list of files written to the fastdl directory. +fn_fastdl_record() { + fn_print "saving Fastdl file record ${fastdlrecord}" + mkdir -p "${datadir}" && mv -f "${fastdlnewrecord}" "${fastdlrecord}" + exitcode=$? + if [ "${exitcode}" -ne 0 ]; then + fn_print_fail_eol_nl + fn_script_log_fail "Saving Fastdl file record ${fastdlrecord}" + core_exit.sh + else + fn_print_ok_eol_nl + fn_script_log_pass "Saving Fastdl file record ${fastdlrecord}" + fi } check.sh # Run functions. fn_fastdl_preview -fn_clear_old_fastdl +if [ "${fastdlrebuild}" == "on" ]; then + fn_clear_old_fastdl +fi fn_fastdl_dirs fn_fastdl_build if [ "${engine}" == "source" ]; then fn_fastdl_bzip2 fi +fn_fastdl_record +rm -f "${fastdlfilelist:?}" "${fastdlduplicatelist:?}" "${fastdlnewrecord:?}" "${fastdlclientlist:?}" "${fastdlupdatelist:?}" "${fastdlremovelist:?}" "${fastdlcompresslist:?}" # Finished message. fn_print_nl "Fastdl files are located in:" fn_print_nl "${fastdldir}" From 1ed97ac26e82c74a90d62207a2a73da8ef4d8aa1 Mon Sep 17 00:00:00 2001 From: Daniel Gibbs Date: Fri, 23 Oct 2026 19:12:35 +0100 Subject: [PATCH 121/164] feat(newserver): add Half-Life WON2 server (#5104) * feat(hlwon): add native Half-Life WON2 server * fix(hlwon): satisfy Python lint conventions * fix(hlwon): match hlds_i686 process and hide fastdl The WON server runs as hlds_i686 rather than hlds_linux, so the details port command and the HLDS PID lookup now match that binary for hlwon. FastDL is no longer offered for hlwon: protocol 46 clients predate sv_downloadurl, so the generated HTTP download setup would never be used. * refactor(hlwon): install from a single linuxgsm.download archive The WON2 server is a fixed legacy release, so it now installs like the other archived servers through fn_install_server_files. The archive bundles HLDS 3.1.1.1 with the 3.1.1.1e update, the patched hlds_run, the WON2 protection libraries and valvecomm.lst. This removes install_hlwon.sh, which carved a tarball out of a Wayback Machine copy of the 4Players installer and pulled six files from a third-party repository, and the unused WON query test script. * fix(hlwon): drop unneeded ncurses dependency on RHEL family hlds_i686, the engine and the WON2 libraries only link libc, libm, libdl and libpthread, which glibc.i686 in the base dependency list already provides. On Rocky 9 the server installed, started and answered queries with ncurses-libs.i686 removed. --- .../config-lgsm/hlwonserver/_default.cfg | 202 ++++++++++++++++++ lgsm/data/almalinux-8.csv | 1 + lgsm/data/almalinux-9.csv | 1 + lgsm/data/centos-7.csv | 1 + lgsm/data/centos-8.csv | 1 + lgsm/data/centos-9.csv | 1 + lgsm/data/debian-10.csv | 1 + lgsm/data/debian-11.csv | 1 + lgsm/data/debian-12.csv | 1 + lgsm/data/debian-13.csv | 1 + lgsm/data/debian-9.csv | 1 + lgsm/data/gameicons/hlwon-icon.png | Bin 0 -> 2722 bytes lgsm/data/rhel-7.csv | 1 + lgsm/data/rhel-8.csv | 1 + lgsm/data/rhel-9.csv | 1 + lgsm/data/rocky-8.csv | 1 + lgsm/data/rocky-9.csv | 1 + lgsm/data/serverlist.csv | 1 + lgsm/data/ubuntu-16.04.csv | 1 + lgsm/data/ubuntu-18.04.csv | 1 + lgsm/data/ubuntu-20.04.csv | 1 + lgsm/data/ubuntu-22.04.csv | 1 + lgsm/data/ubuntu-23.04.csv | 1 + lgsm/data/ubuntu-23.10.csv | 1 + lgsm/data/ubuntu-24.04.csv | 1 + lgsm/data/ubuntu-26.04.csv | 1 + lgsm/modules/core_getopt.sh | 4 +- lgsm/modules/info_distro.sh | 2 + lgsm/modules/info_messages.sh | 8 +- lgsm/modules/install_config.sh | 2 +- lgsm/modules/install_server_files.sh | 8 + lgsm/modules/query_gsquery.py | 13 +- 32 files changed, 258 insertions(+), 5 deletions(-) create mode 100644 lgsm/config-default/config-lgsm/hlwonserver/_default.cfg create mode 100644 lgsm/data/gameicons/hlwon-icon.png diff --git a/lgsm/config-default/config-lgsm/hlwonserver/_default.cfg b/lgsm/config-default/config-lgsm/hlwonserver/_default.cfg new file mode 100644 index 0000000000..db21837476 --- /dev/null +++ b/lgsm/config-default/config-lgsm/hlwonserver/_default.cfg @@ -0,0 +1,202 @@ +################################## +######## Default Settings ######## +################################## +# DO NOT EDIT, ANY CHANGES WILL BE OVERWRITTEN! +# Copy settings from here and use them in either: +# common.cfg - applies settings to every instance. +# [instance].cfg - applies settings to a specific instance. + +#### Game Server Settings #### + +## Predefined Parameters | https://docs.linuxgsm.com/configuration/start-parameters +ip="0.0.0.0" +port="27015" +clientport="27005" +defaultmap="crossfire" +maxplayers="16" + +## Server Parameters | https://docs.linuxgsm.com/configuration/start-parameters#additional-parameters +startparameters="-game valve -binary ./hlds_i686 -noipx -insecure +ip ${ip} -port ${port} +clientport ${clientport} +map ${defaultmap} +servercfgfile ${servercfg} -maxplayers ${maxplayers}" + +#### LinuxGSM Settings #### + +## LinuxGSM Stats +# Send useful stats to LinuxGSM developers. +# https://docs.linuxgsm.com/configuration/linuxgsm-stats +# (on|off) +stats="off" + +## Notification Alerts +# (on|off) + +# Display IP | https://docs.linuxgsm.com/alerts#display-ip +displayip="" + +# More info | https://docs.linuxgsm.com/alerts#more-info +postalert="off" + +# Alert on Start/Stop/Restart +statusalert="off" + +# Discord Alerts | https://docs.linuxgsm.com/alerts/discord +discordalert="off" +discordwebhook="webhook" + +# Email Alerts | https://docs.linuxgsm.com/alerts/email +emailalert="off" +email="email@example.com" +emailfrom="" + +# Gotify Alerts | https://docs.linuxgsm.com/alerts/gotify +gotifyalert="off" +gotifytoken="token" +gotifywebhook="webhook" + +# IFTTT Alerts | https://docs.linuxgsm.com/alerts/ifttt +iftttalert="off" +ifttttoken="accesstoken" +iftttevent="linuxgsm_alert" + +# ntfy Alerts | https://docs.linuxgsm.com/alerts/ntfy +ntfyalert="off" +ntfytopic="LinuxGSM" +ntfyserver="https://ntfy.sh" +ntfytoken="" +ntfyusername="" +ntfypassword="" +ntfypriority="" +ntfytags="" + +# Matrix Alerts | https://docs.linuxgsm.com/alerts/matrix +matrixalert="off" +matrixhomeserver="matrix.org" +matrixtoken="accesstoken" +matrixroom="" + +# Pushbullet Alerts | https://docs.linuxgsm.com/alerts/pushbullet +pushbulletalert="off" +pushbullettoken="accesstoken" +channeltag="" + +# Pushover Alerts | https://docs.linuxgsm.com/alerts/pushover +pushoveralert="off" +pushovertoken="accesstoken" +pushoveruserkey="userkey" + +# Rocket.Chat Alerts | https://docs.linuxgsm.com/alerts/rocket.chat +rocketchatalert="off" +rocketchatwebhook="webhook" + +# Slack Alerts | https://docs.linuxgsm.com/alerts/slack +slackalert="off" +slackwebhook="webhook" + +# Telegram Alerts | https://docs.linuxgsm.com/alerts/telegram +# You can add a custom cURL string eg proxy (useful in Russia) in "curlcustomstring". +# For example "--socks5 ipaddr:port" for socks5 proxy see more in "curl --help all". +telegramapi="api.telegram.org" +telegramalert="off" +telegramtoken="accesstoken" +telegramchatid="" +telegramthreadid="" +telegramsilentnotification="false" +curlcustomstring="" + +## Stop | https://docs.linuxgsm.com/commands/start-stop-restart +stoponlyifnoplayers="off" +stoponlyifnoplayersallcommands="on" + +## Player Warnings | https://docs.linuxgsm.com/features/player-warnings +# Minutes to warn players in-game before a stop, restart or update. 0 to disable. +# e.g. 15 warns at 15, 10, 5, 3 and 1 minutes. +warnplayerstimer="0" + +## Updating | https://docs.linuxgsm.com/commands/update +updateonstart="off" + +## Backup | https://docs.linuxgsm.com/commands/backup +maxbackups="4" +maxbackupdays="30" +stoponbackup="on" + +## Logging | https://docs.linuxgsm.com/features/logging +consolelogging="on" +logdays="7" + +## Monitor | https://docs.linuxgsm.com/commands/monitor +# Query delay time +querydelay="1" + +## ANSI Colors | https://docs.linuxgsm.com/features/ansi-colors +ansi="on" + +#### Advanced Settings #### + +## Message Display Time | https://docs.linuxgsm.com/features/message-display-time +sleeptime="0.5" + +## Stop Mode | https://docs.linuxgsm.com/features/stop-mode +# 1: tmux kill +# 2: CTRL+c +# 3: quit +# 4: quit 120s +# 5: stop +# 6: q +# 7: exit +# 8: 7 Days to Die +# 9: GoldSrc +# 10: Avorion +# 11: end +stopmode="9" + +## Query mode +# 1: session only +# 2: gamedig (gsquery fallback) +# 3: gamedig +# 4: gsquery +# 5: tcp +querymode="4" +querytype="protocol-valve-won" + +## Console type +consoleverbose="yes" +consoleinteract="yes" + +## Game Server Details +# Do not edit +gamename="Half-Life: WON2" +engine="goldsrc" +glibc="2.0" + +#### Directories #### +# Edit with care + +## Game Server Directories +systemdir="${serverfiles}/valve" +executabledir="${serverfiles}" +executable="./hlds_run" +servercfgdir="${systemdir}" +servercfg="${selfname}.cfg" +servercfgdefault="server.cfg" +servercfgfullpath="${servercfgdir}/${servercfg}" + +## Backup Directory +backupdir="${lgsmdir}/backup" + +## Logging Directories +[ -n "${LGSM_LOGDIR}" ] && logdir="${LGSM_LOGDIR}" || logdir="${rootdir}/log" +gamelogdir="${systemdir}/logs" +lgsmlogdir="${logdir}/script" +consolelogdir="${logdir}/console" +lgsmlog="${lgsmlogdir}/${selfname}-script.log" +consolelog="${consolelogdir}/${selfname}-console.log" +alertlog="${lgsmlogdir}/${selfname}-alert.log" +postdetailslog="${lgsmlogdir}/${selfname}-postdetails.log" + +## Logs Naming +lgsmlogdate="${lgsmlogdir}/${selfname}-script-$(date '+%Y-%m-%d-%H:%M:%S').log" +consolelogdate="${consolelogdir}/${selfname}-console-$(date '+%Y-%m-%d-%H:%M:%S').log" + +## Log Parameters +logtimestamp="off" +logtimestampformat="%Y-%m-%d %H:%M:%S" diff --git a/lgsm/data/almalinux-8.csv b/lgsm/data/almalinux-8.csv index 009e15bcb7..25eafae836 100644 --- a/lgsm/data/almalinux-8.csv +++ b/lgsm/data/almalinux-8.csv @@ -54,6 +54,7 @@ hcu hl2dm hldm hldms +hlwon hw,zlib-devel hyt hz diff --git a/lgsm/data/almalinux-9.csv b/lgsm/data/almalinux-9.csv index 0e0242c76c..3476f9949d 100644 --- a/lgsm/data/almalinux-9.csv +++ b/lgsm/data/almalinux-9.csv @@ -54,6 +54,7 @@ hcu hl2dm hldm hldms +hlwon hw,zlib-devel hyt,java-25-openjdk hz diff --git a/lgsm/data/centos-7.csv b/lgsm/data/centos-7.csv index 03a5f0066d..b1a4eaec7b 100644 --- a/lgsm/data/centos-7.csv +++ b/lgsm/data/centos-7.csv @@ -54,6 +54,7 @@ hcu hl2dm hldm hldms +hlwon hw,zlib-devel hyt hz diff --git a/lgsm/data/centos-8.csv b/lgsm/data/centos-8.csv index 3254439dd5..a577b35d4a 100644 --- a/lgsm/data/centos-8.csv +++ b/lgsm/data/centos-8.csv @@ -54,6 +54,7 @@ hcu hl2dm hldm hldms +hlwon hw,zlib-devel hyt hz diff --git a/lgsm/data/centos-9.csv b/lgsm/data/centos-9.csv index 7639b0e3d0..56c8b5dd1d 100644 --- a/lgsm/data/centos-9.csv +++ b/lgsm/data/centos-9.csv @@ -54,6 +54,7 @@ hcu hl2dm hldm hldms +hlwon hw,zlib-devel hyt,java-25-openjdk hz diff --git a/lgsm/data/debian-10.csv b/lgsm/data/debian-10.csv index 29008bc5f8..70c89716d4 100644 --- a/lgsm/data/debian-10.csv +++ b/lgsm/data/debian-10.csv @@ -53,6 +53,7 @@ hcu hl2dm hldm hldms +hlwon,libc6:i386 hw,lib32z1 hyt hz diff --git a/lgsm/data/debian-11.csv b/lgsm/data/debian-11.csv index dacf209c43..00d537fa37 100644 --- a/lgsm/data/debian-11.csv +++ b/lgsm/data/debian-11.csv @@ -54,6 +54,7 @@ hcu hl2dm hldm hldms +hlwon,libc6:i386 hw,lib32z1 hyt hz diff --git a/lgsm/data/debian-12.csv b/lgsm/data/debian-12.csv index fbfd1ce0fd..7e6fe9d019 100644 --- a/lgsm/data/debian-12.csv +++ b/lgsm/data/debian-12.csv @@ -54,6 +54,7 @@ hcu hl2dm hldm hldms +hlwon,libc6:i386 hw,lib32z1 hyt hz diff --git a/lgsm/data/debian-13.csv b/lgsm/data/debian-13.csv index 795122139c..6ccd09c53d 100644 --- a/lgsm/data/debian-13.csv +++ b/lgsm/data/debian-13.csv @@ -54,6 +54,7 @@ hcu hl2dm hldm hldms +hlwon,libc6:i386 hw,lib32z1 hyt,openjdk-25-jre hz diff --git a/lgsm/data/debian-9.csv b/lgsm/data/debian-9.csv index ecde61d9cc..a0a878a4a0 100644 --- a/lgsm/data/debian-9.csv +++ b/lgsm/data/debian-9.csv @@ -54,6 +54,7 @@ hcu hl2dm hldm hldms +hlwon,libc6:i386 hw,lib32z1 hyt hz diff --git a/lgsm/data/gameicons/hlwon-icon.png b/lgsm/data/gameicons/hlwon-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..2a97796401490cb48e8be7955801bfe9b58c9325 GIT binary patch literal 2722 zcmZ{mdpy(c`^Vo~!bw6H@>)-2vsfmFA>^IrTsr0cvjEZz3}-M5%7GIFt{KL`A+9Y;;yCdgTLZqZbw0RdU-fH zxjLYH{5>5|cAlQfDgf*sV5onktOiq6RaZN6`V3iJ6OBeI?@D!7yLILtVUGjJyA$^k zjc~do!%u3L2oJ5MEGpNiLxC0r)bg^N+?@fAd-->_cmFZPh>j|PLdJ%Y_}DgV7!>kA z*3zC1m58vdI}s+3cO_JkUI^%i@fgy1@6kPRC{%~B*0GNMIp6P`!<6#x9EZK!wqRhK5yL-C;Tkn_$@2hXnobEA)NgZPj;Zj}$HcAC*e=7T3DXzk7R5ci z{rz5G08b}GqscwU&7M5ZR4mRy%9KY0Kfjn4#h-FiTeHwVnK5d9h)w$erO{gS&l!!q zIqYhDSrlPrrF_`VS@LG4SUrHahtvD&;QK7-lK8{Lq?`5kP32@4pA;TINegxj7m>*{ zfmM30yws zSeLl;>50~Z^nG{U+FM(?U-#&G+AtO{{%d4xYG@f_@W}gh&dKHvUxZM(=Rk|?pJxy= zlj`62q8Em1!`D)hIT-oVzqj6JTrHW)ZzA$-${Yt;g`sympABLBhB5RReWg4_x4e8S zXQdTwKe6t88h$d^Ta{~}C8_3dO-KszdT!bGcqUTk7`G)^t>3OORKD75I+!X!vXAK5 zNVt#hpx4Er2&BiY%av6@Y^Ca}#@5%Ee|-ICL~|)S%Y{Mro`u^H2$>wO4-HEhE0H!f zx#1fL6yKd0ZqkjM(qR@Ly49Q2M~gl|&)LFFQj%9swEj98C}09Ui|k(R3U?N>c4r`F zzvOprtxq++E{t+g`)JM*6QMkqdiNfXuH1}7F3xYdKeDZ0h!ehxO zIS_9q)9!CEAKr67|4Pzyg)=2Tu`_=hOsG?W(1imAcCgFYRkhb4^P(vgl(&%S#ruLtv7j;`B z2H`cO#cvAV0#%+&`Dn?O3U9op`-e#REqjjw;F(l5MnuKcQ8GxRjdRo#Dq%RXCt|oi zhQBHn1+oUXi9z?*3~QBYYRBnuG10<0oi_lf{D@Me3y4@I3@n}7stGtc#%Y7GmJ1OQV!2@he7 z3L<=s*tk4<)ht|IPS%3Bb4rTMxm4cOqP<)y&89AC=UF@A_IR7#&>n6_9l5x4yLW0^ z8fyVU;n~eu030p}goj1rj4@50cuTJ90{l6^V&Y*_(8;#39wjy4*5t@&ATmiVR%mx zwkn;(Y91gxYlC-~V7>9=D7EsQfI!pIkimKQ@tOeU1ZSkn@`>dI$cvZRp#Q4V!(iA5 z78F!6_#9k&*~4`|(S-N-z&B0kEnQ)H#F)pzh9Fedle;k9cI|fhw#bd-VsP?9I&17_tgByr)a{LT1A6712Hj+$@3i?QUDea(5&m z<;9Ul0hRGxs~1fn5Ih8D0Rb(2N!Y`?#9u(NtZUe)2jHXvo8Z^oAAjYECGQWdd6Glx zlBy)Ls(iN1wO)KB29L3{E+J;8*sBxQu8rz^|4~tRsLgdF>qu%T z4=Mta5t{~rSnyy05LQoKNNibWu*?ZS9^C^DAO40_B+t!z<nRDY{UKs DwgK*+ literal 0 HcmV?d00001 diff --git a/lgsm/data/rhel-7.csv b/lgsm/data/rhel-7.csv index bcb47463bc..9212b7060b 100644 --- a/lgsm/data/rhel-7.csv +++ b/lgsm/data/rhel-7.csv @@ -55,6 +55,7 @@ hcu hl2dm hldm hldms +hlwon hw,zlib-devel hyt hz diff --git a/lgsm/data/rhel-8.csv b/lgsm/data/rhel-8.csv index f302361215..8ef014e094 100644 --- a/lgsm/data/rhel-8.csv +++ b/lgsm/data/rhel-8.csv @@ -54,6 +54,7 @@ hcu hl2dm hldm hldms +hlwon hw,zlib-devel hyt hz diff --git a/lgsm/data/rhel-9.csv b/lgsm/data/rhel-9.csv index 0e0242c76c..3476f9949d 100644 --- a/lgsm/data/rhel-9.csv +++ b/lgsm/data/rhel-9.csv @@ -54,6 +54,7 @@ hcu hl2dm hldm hldms +hlwon hw,zlib-devel hyt,java-25-openjdk hz diff --git a/lgsm/data/rocky-8.csv b/lgsm/data/rocky-8.csv index f302361215..8ef014e094 100644 --- a/lgsm/data/rocky-8.csv +++ b/lgsm/data/rocky-8.csv @@ -54,6 +54,7 @@ hcu hl2dm hldm hldms +hlwon hw,zlib-devel hyt hz diff --git a/lgsm/data/rocky-9.csv b/lgsm/data/rocky-9.csv index 0e0242c76c..3476f9949d 100644 --- a/lgsm/data/rocky-9.csv +++ b/lgsm/data/rocky-9.csv @@ -54,6 +54,7 @@ hcu hl2dm hldm hldms +hlwon hw,zlib-devel hyt,java-25-openjdk hz diff --git a/lgsm/data/serverlist.csv b/lgsm/data/serverlist.csv index 458d1eb2cd..4ba7f41db1 100644 --- a/lgsm/data/serverlist.csv +++ b/lgsm/data/serverlist.csv @@ -53,6 +53,7 @@ hcu,hcuserver,HYPERCHARGE: Unboxed,ubuntu-26.04 hl2dm,hl2dmserver,Half-Life 2: Deathmatch,ubuntu-26.04 hldm,hldmserver,Half-Life: Deathmatch,ubuntu-26.04 hldms,hldmsserver,Half-Life Deathmatch: Source,ubuntu-26.04 +hlwon,hlwonserver,Half-Life: WON2,ubuntu-26.04 hw,hwserver,Hurtworld,ubuntu-26.04 hyt,hytserver,Hytale,ubuntu-26.04 hz,hzserver,Humanitz,ubuntu-26.04 diff --git a/lgsm/data/ubuntu-16.04.csv b/lgsm/data/ubuntu-16.04.csv index 2631343da2..a957dbe1ba 100644 --- a/lgsm/data/ubuntu-16.04.csv +++ b/lgsm/data/ubuntu-16.04.csv @@ -55,6 +55,7 @@ hcu hl2dm hldm hldms +hlwon,libc6:i386 hw,lib32z1 hyt hz diff --git a/lgsm/data/ubuntu-18.04.csv b/lgsm/data/ubuntu-18.04.csv index 0e81a9b2b9..52a9ac2997 100644 --- a/lgsm/data/ubuntu-18.04.csv +++ b/lgsm/data/ubuntu-18.04.csv @@ -55,6 +55,7 @@ hcu hl2dm hldm hldms +hlwon,libc6:i386 hw,lib32z1 hyt hz diff --git a/lgsm/data/ubuntu-20.04.csv b/lgsm/data/ubuntu-20.04.csv index ae6f6ca5b7..6257ec10aa 100644 --- a/lgsm/data/ubuntu-20.04.csv +++ b/lgsm/data/ubuntu-20.04.csv @@ -54,6 +54,7 @@ hcu hl2dm hldm hldms +hlwon,libc6:i386 hw,lib32z1 hyt hz diff --git a/lgsm/data/ubuntu-22.04.csv b/lgsm/data/ubuntu-22.04.csv index 51e303e30c..a06263ccb3 100644 --- a/lgsm/data/ubuntu-22.04.csv +++ b/lgsm/data/ubuntu-22.04.csv @@ -54,6 +54,7 @@ hcu hl2dm hldm hldms +hlwon,libc6:i386 hw,lib32z1 hyt,openjdk-25-jre hz diff --git a/lgsm/data/ubuntu-23.04.csv b/lgsm/data/ubuntu-23.04.csv index dfdef2422b..a691ce6cfa 100644 --- a/lgsm/data/ubuntu-23.04.csv +++ b/lgsm/data/ubuntu-23.04.csv @@ -54,6 +54,7 @@ hcu hl2dm hldm hldms +hlwon,libc6:i386 hw,lib32z1 hyt hz diff --git a/lgsm/data/ubuntu-23.10.csv b/lgsm/data/ubuntu-23.10.csv index dfdef2422b..a691ce6cfa 100644 --- a/lgsm/data/ubuntu-23.10.csv +++ b/lgsm/data/ubuntu-23.10.csv @@ -54,6 +54,7 @@ hcu hl2dm hldm hldms +hlwon,libc6:i386 hw,lib32z1 hyt hz diff --git a/lgsm/data/ubuntu-24.04.csv b/lgsm/data/ubuntu-24.04.csv index 357abc0ca2..8cfd9bb104 100644 --- a/lgsm/data/ubuntu-24.04.csv +++ b/lgsm/data/ubuntu-24.04.csv @@ -54,6 +54,7 @@ hcu hl2dm hldm hldms +hlwon,libc6:i386 hw,lib32z1 hyt,openjdk-25-jre hz diff --git a/lgsm/data/ubuntu-26.04.csv b/lgsm/data/ubuntu-26.04.csv index 4e542a1022..aab323d1f1 100644 --- a/lgsm/data/ubuntu-26.04.csv +++ b/lgsm/data/ubuntu-26.04.csv @@ -54,6 +54,7 @@ hcu hl2dm hldm hldms +hlwon,libc6:i386 hw,lib32z1 hyt,openjdk-25-jre hz diff --git a/lgsm/modules/core_getopt.sh b/lgsm/modules/core_getopt.sh index c42324ae0d..087283f36b 100755 --- a/lgsm/modules/core_getopt.sh +++ b/lgsm/modules/core_getopt.sh @@ -69,7 +69,7 @@ currentopt+=("${cmd_update_linuxgsm[@]}") # Exclude noupdate games here. if [ "${shortname}" == "jk2" ] || [ "${shortname}" == "jk3" ] || [ "${shortname}" == "etl" ] || [ "${engine}" != "idtech3" ]; then - if [ "${shortname}" != "bf1942" ] && [ "${shortname}" != "bfv" ] && [ "${engine}" != "idtech2" ] && [ "${engine}" != "iw2.0" ] && [ "${engine}" != "iw3.0" ] && [ "${engine}" != "quake" ] && [ "${shortname}" != "samp" ] && [ "${shortname}" != "ut2k4" ]; then + if [ "${shortname}" != "hlwon" ] && [ "${shortname}" != "bf1942" ] && [ "${shortname}" != "bfv" ] && [ "${engine}" != "idtech2" ] && [ "${engine}" != "iw2.0" ] && [ "${engine}" != "iw3.0" ] && [ "${engine}" != "quake" ] && [ "${shortname}" != "samp" ] && [ "${shortname}" != "ut2k4" ]; then currentopt+=("${cmd_update[@]}" "${cmd_check_update[@]}") # force update for SteamCMD, Multi Theft Auto or Hytale only. if [ "${appid}" ] || [ "${shortname}" == "mta" ] || [ "${shortname}" == "hyt" ]; then @@ -97,7 +97,7 @@ fi ## Game server exclusive commands. # FastDL command. -if [ "${engine}" == "source" ] || [ "${engine}" == "goldsrc" ]; then +if { [ "${engine}" == "source" ] || [ "${engine}" == "goldsrc" ]; } && [ "${shortname}" != "hlwon" ]; then currentopt+=("${cmd_fastdl[@]}") fi diff --git a/lgsm/modules/info_distro.sh b/lgsm/modules/info_distro.sh index 96c9efe298..dbfbb8cbfa 100755 --- a/lgsm/modules/info_distro.sh +++ b/lgsm/modules/info_distro.sh @@ -14,6 +14,8 @@ if [ "${status}" == "1" ]; then gameserverpid="$(TERM=screen tmux -L "${socketname}" list-sessions -F "#{session_name} #{pane_pid}" | grep "^${sessionname} " | awk '{print $NF}')" if [ "${engine}" == "source" ]; then srcdslinuxpid="$(pgrep -P "${gameserverpid}" -x srcds_linux 2> /dev/null | head -n 1)" + elif [ "${shortname}" == "hlwon" ]; then + hldslinuxpid="$(pgrep -P "${gameserverpid}" -x hlds_i686 2> /dev/null | head -n 1)" elif [ "${engine}" == "goldsrc" ]; then hldslinuxpid="$(pgrep -P "${gameserverpid}" -x hlds_linux 2> /dev/null | head -n 1)" fi diff --git a/lgsm/modules/info_messages.sh b/lgsm/modules/info_messages.sh index 2d6422942a..2ba9502d41 100755 --- a/lgsm/modules/info_messages.sh +++ b/lgsm/modules/info_messages.sh @@ -771,6 +771,8 @@ fn_info_messages_ports() { portcommand="ss -tuplwn | grep Main" elif [ "${shortname}" == "sm" ]; then portcommand="ss -tuplwn | grep WSServer-Linux" + elif [ "${shortname}" == "hlwon" ]; then + portcommand="ss -tuplwn | grep hlds_i686" elif [ "${engine}" == "source" ]; then portcommand="ss -tuplwn | grep srcds_linux" elif [ "${engine}" == "goldsrc" ]; then @@ -1121,7 +1123,11 @@ fn_info_messages_goldsrc() { { fn_port "header" fn_port "Game" port udp - fn_port "Query" queryport tcp + if [ "${shortname}" == "hlwon" ]; then + fn_port "Query" queryport udp + else + fn_port "Query" queryport tcp + fi fn_port "Client" clientport udp } | column -s $'\t' -t } diff --git a/lgsm/modules/install_config.sh b/lgsm/modules/install_config.sh index db4fe908b8..c685d766f1 100755 --- a/lgsm/modules/install_config.sh +++ b/lgsm/modules/install_config.sh @@ -492,7 +492,7 @@ elif [ "${shortname}" == "gmod" ]; then fn_default_config_remote fn_set_config_vars fn_list_config_locations -elif [ "${shortname}" == "hldm" ]; then +elif [ "${shortname}" == "hldm" ] || [ "${shortname}" == "hlwon" ]; then array_configs+=(server.cfg) fn_default_config_remote fn_set_config_vars diff --git a/lgsm/modules/install_server_files.sh b/lgsm/modules/install_server_files.sh index 11f5dca4cb..e54db1b584 100755 --- a/lgsm/modules/install_server_files.sh +++ b/lgsm/modules/install_server_files.sh @@ -73,6 +73,14 @@ fn_install_server_files() { run="norun" force="noforce" md5="2c6be1bb66ea631b9b2e7ae6216c6680" + elif [ "${shortname}" == "hlwon" ]; then + remote_fileurl="https://linuxgsm.download/HalfLifeWON2/hlds_l-3111e-won2-linuxgsm.tar.xz" + local_filedir="${tmpdir}" + local_filename="hlds_l-3111e-won2-linuxgsm.tar.xz" + chmodx="nochmodx" + run="norun" + force="noforce" + md5="83164405c744a5e424814e67eacf27fb" elif [ "${shortname}" == "mohaa" ]; then remote_fileurl="https://linuxgsm.download/MedalofHonorAlliedAssault/moh_revival_v1.12_RC3.5.1.tar.xz" local_filedir="${tmpdir}" diff --git a/lgsm/modules/query_gsquery.py b/lgsm/modules/query_gsquery.py index 180f49a086..35c46b10d5 100755 --- a/lgsm/modules/query_gsquery.py +++ b/lgsm/modules/query_gsquery.py @@ -13,6 +13,7 @@ engine_types = ( "protocol-valve", + "protocol-valve-won", "protocol-quake2", "protocol-quake3", "protocol-gamespy1", @@ -34,6 +35,7 @@ class GSQuery: default_buffer_length = 1024 sourcequery = ( "protocol-valve", + "protocol-valve-won", "avalanche3.0", "barotrauma", "madness", @@ -65,7 +67,11 @@ def __init__(self, arguments): 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\xffdetails\0" + if self.argument.engine == "protocol-valve-won" + else 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" elif self.argument.engine in self.idtech3query: @@ -139,6 +145,11 @@ def responding(self): # Response. if self.response is None: self.fatal_error("No response", 3) + if self.argument.engine == "protocol-valve-won" and ( + not self.response.startswith(b"\xff\xff\xff\xffm") + or len(self.response.split(b"\0")) < 7 + ): + self.fatal_error("Invalid WON server response", 3) if len(self.response) < 5: sys.exit("Short response.", 3) else: From 3d43749102ef206df93f1b6dae650e431dc8c3b0 Mon Sep 17 00:00:00 2001 From: Daniel Gibbs Date: Fri, 23 Oct 2026 19:26:11 +0100 Subject: [PATCH 122/164] feat(newserver): add Counter-Strike WON2 server (#5105) * feat(hlwon): add native Half-Life WON2 server * fix(hlwon): satisfy Python lint conventions * fix(hlwon): match hlds_i686 process and hide fastdl The WON server runs as hlds_i686 rather than hlds_linux, so the details port command and the HLDS PID lookup now match that binary for hlwon. FastDL is no longer offered for hlwon: protocol 46 clients predate sv_downloadurl, so the generated HTTP download setup would never be used. * refactor(hlwon): install from a single linuxgsm.download archive The WON2 server is a fixed legacy release, so it now installs like the other archived servers through fn_install_server_files. The archive bundles HLDS 3.1.1.1 with the 3.1.1.1e update, the patched hlds_run, the WON2 protection libraries and valvecomm.lst. This removes install_hlwon.sh, which carved a tarball out of a Wayback Machine copy of the 4Players installer and pulled six files from a third-party repository, and the unused WON query test script. * feat(cswon): add native Counter-Strike WON2 server Adds Counter-Strike 1.5 on the WON2 protocol 46 stack used by hlwonserver. It installs from a single linuxgsm.download archive containing the HLDS 3.1.1.1e WON2 base plus the cstrike folder from Valve's cs_15_full.tar.gz, keeping the newer cs_i386.so from the 3111e update. The hlwon shortname checks for the update, check-update and fastdl commands, the hlds_i686 PID and port command and the UDP query port now match querytype protocol-valve-won so both WON servers share them. --- .../config-lgsm/cswonserver/_default.cfg | 202 ++++++++++++++++++ lgsm/data/almalinux-8.csv | 1 + lgsm/data/almalinux-9.csv | 1 + lgsm/data/centos-7.csv | 1 + lgsm/data/centos-8.csv | 1 + lgsm/data/centos-9.csv | 1 + lgsm/data/debian-10.csv | 1 + lgsm/data/debian-11.csv | 1 + lgsm/data/debian-12.csv | 1 + lgsm/data/debian-13.csv | 1 + lgsm/data/debian-9.csv | 1 + lgsm/data/gameicons/cswon-icon.png | Bin 0 -> 2150 bytes lgsm/data/rhel-7.csv | 1 + lgsm/data/rhel-8.csv | 1 + lgsm/data/rhel-9.csv | 1 + lgsm/data/rocky-8.csv | 1 + lgsm/data/rocky-9.csv | 1 + lgsm/data/serverlist.csv | 1 + lgsm/data/ubuntu-16.04.csv | 1 + lgsm/data/ubuntu-18.04.csv | 1 + lgsm/data/ubuntu-20.04.csv | 1 + lgsm/data/ubuntu-22.04.csv | 1 + lgsm/data/ubuntu-23.04.csv | 1 + lgsm/data/ubuntu-23.10.csv | 1 + lgsm/data/ubuntu-24.04.csv | 1 + lgsm/data/ubuntu-26.04.csv | 1 + lgsm/modules/core_getopt.sh | 4 +- lgsm/modules/info_distro.sh | 2 +- lgsm/modules/info_messages.sh | 4 +- lgsm/modules/install_config.sh | 2 +- lgsm/modules/install_server_files.sh | 8 + 31 files changed, 240 insertions(+), 6 deletions(-) create mode 100644 lgsm/config-default/config-lgsm/cswonserver/_default.cfg create mode 100644 lgsm/data/gameicons/cswon-icon.png diff --git a/lgsm/config-default/config-lgsm/cswonserver/_default.cfg b/lgsm/config-default/config-lgsm/cswonserver/_default.cfg new file mode 100644 index 0000000000..b4124087ca --- /dev/null +++ b/lgsm/config-default/config-lgsm/cswonserver/_default.cfg @@ -0,0 +1,202 @@ +################################## +######## Default Settings ######## +################################## +# DO NOT EDIT, ANY CHANGES WILL BE OVERWRITTEN! +# Copy settings from here and use them in either: +# common.cfg - applies settings to every instance. +# [instance].cfg - applies settings to a specific instance. + +#### Game Server Settings #### + +## Predefined Parameters | https://docs.linuxgsm.com/configuration/start-parameters +ip="0.0.0.0" +port="27015" +clientport="27005" +defaultmap="de_dust2" +maxplayers="16" + +## Server Parameters | https://docs.linuxgsm.com/configuration/start-parameters#additional-parameters +startparameters="-game cstrike -binary ./hlds_i686 -noipx -insecure +ip ${ip} -port ${port} +clientport ${clientport} +map ${defaultmap} +servercfgfile ${servercfg} -maxplayers ${maxplayers}" + +#### LinuxGSM Settings #### + +## LinuxGSM Stats +# Send useful stats to LinuxGSM developers. +# https://docs.linuxgsm.com/configuration/linuxgsm-stats +# (on|off) +stats="off" + +## Notification Alerts +# (on|off) + +# Display IP | https://docs.linuxgsm.com/alerts#display-ip +displayip="" + +# More info | https://docs.linuxgsm.com/alerts#more-info +postalert="off" + +# Alert on Start/Stop/Restart +statusalert="off" + +# Discord Alerts | https://docs.linuxgsm.com/alerts/discord +discordalert="off" +discordwebhook="webhook" + +# Email Alerts | https://docs.linuxgsm.com/alerts/email +emailalert="off" +email="email@example.com" +emailfrom="" + +# Gotify Alerts | https://docs.linuxgsm.com/alerts/gotify +gotifyalert="off" +gotifytoken="token" +gotifywebhook="webhook" + +# IFTTT Alerts | https://docs.linuxgsm.com/alerts/ifttt +iftttalert="off" +ifttttoken="accesstoken" +iftttevent="linuxgsm_alert" + +# ntfy Alerts | https://docs.linuxgsm.com/alerts/ntfy +ntfyalert="off" +ntfytopic="LinuxGSM" +ntfyserver="https://ntfy.sh" +ntfytoken="" +ntfyusername="" +ntfypassword="" +ntfypriority="" +ntfytags="" + +# Matrix Alerts | https://docs.linuxgsm.com/alerts/matrix +matrixalert="off" +matrixhomeserver="matrix.org" +matrixtoken="accesstoken" +matrixroom="" + +# Pushbullet Alerts | https://docs.linuxgsm.com/alerts/pushbullet +pushbulletalert="off" +pushbullettoken="accesstoken" +channeltag="" + +# Pushover Alerts | https://docs.linuxgsm.com/alerts/pushover +pushoveralert="off" +pushovertoken="accesstoken" +pushoveruserkey="userkey" + +# Rocket.Chat Alerts | https://docs.linuxgsm.com/alerts/rocket.chat +rocketchatalert="off" +rocketchatwebhook="webhook" + +# Slack Alerts | https://docs.linuxgsm.com/alerts/slack +slackalert="off" +slackwebhook="webhook" + +# Telegram Alerts | https://docs.linuxgsm.com/alerts/telegram +# You can add a custom cURL string eg proxy (useful in Russia) in "curlcustomstring". +# For example "--socks5 ipaddr:port" for socks5 proxy see more in "curl --help all". +telegramapi="api.telegram.org" +telegramalert="off" +telegramtoken="accesstoken" +telegramchatid="" +telegramthreadid="" +telegramsilentnotification="false" +curlcustomstring="" + +## Stop | https://docs.linuxgsm.com/commands/start-stop-restart +stoponlyifnoplayers="off" +stoponlyifnoplayersallcommands="on" + +## Player Warnings | https://docs.linuxgsm.com/features/player-warnings +# Minutes to warn players in-game before a stop, restart or update. 0 to disable. +# e.g. 15 warns at 15, 10, 5, 3 and 1 minutes. +warnplayerstimer="0" + +## Updating | https://docs.linuxgsm.com/commands/update +updateonstart="off" + +## Backup | https://docs.linuxgsm.com/commands/backup +maxbackups="4" +maxbackupdays="30" +stoponbackup="on" + +## Logging | https://docs.linuxgsm.com/features/logging +consolelogging="on" +logdays="7" + +## Monitor | https://docs.linuxgsm.com/commands/monitor +# Query delay time +querydelay="1" + +## ANSI Colors | https://docs.linuxgsm.com/features/ansi-colors +ansi="on" + +#### Advanced Settings #### + +## Message Display Time | https://docs.linuxgsm.com/features/message-display-time +sleeptime="0.5" + +## Stop Mode | https://docs.linuxgsm.com/features/stop-mode +# 1: tmux kill +# 2: CTRL+c +# 3: quit +# 4: quit 120s +# 5: stop +# 6: q +# 7: exit +# 8: 7 Days to Die +# 9: GoldSrc +# 10: Avorion +# 11: end +stopmode="9" + +## Query mode +# 1: session only +# 2: gamedig (gsquery fallback) +# 3: gamedig +# 4: gsquery +# 5: tcp +querymode="4" +querytype="protocol-valve-won" + +## Console type +consoleverbose="yes" +consoleinteract="yes" + +## Game Server Details +# Do not edit +gamename="Counter-Strike: WON2" +engine="goldsrc" +glibc="2.0" + +#### Directories #### +# Edit with care + +## Game Server Directories +systemdir="${serverfiles}/cstrike" +executabledir="${serverfiles}" +executable="./hlds_run" +servercfgdir="${systemdir}" +servercfg="${selfname}.cfg" +servercfgdefault="server.cfg" +servercfgfullpath="${servercfgdir}/${servercfg}" + +## Backup Directory +backupdir="${lgsmdir}/backup" + +## Logging Directories +[ -n "${LGSM_LOGDIR}" ] && logdir="${LGSM_LOGDIR}" || logdir="${rootdir}/log" +gamelogdir="${systemdir}/logs" +lgsmlogdir="${logdir}/script" +consolelogdir="${logdir}/console" +lgsmlog="${lgsmlogdir}/${selfname}-script.log" +consolelog="${consolelogdir}/${selfname}-console.log" +alertlog="${lgsmlogdir}/${selfname}-alert.log" +postdetailslog="${lgsmlogdir}/${selfname}-postdetails.log" + +## Logs Naming +lgsmlogdate="${lgsmlogdir}/${selfname}-script-$(date '+%Y-%m-%d-%H:%M:%S').log" +consolelogdate="${consolelogdir}/${selfname}-console-$(date '+%Y-%m-%d-%H:%M:%S').log" + +## Log Parameters +logtimestamp="off" +logtimestampformat="%Y-%m-%d %H:%M:%S" diff --git a/lgsm/data/almalinux-8.csv b/lgsm/data/almalinux-8.csv index 25eafae836..23b23936da 100644 --- a/lgsm/data/almalinux-8.csv +++ b/lgsm/data/almalinux-8.csv @@ -33,6 +33,7 @@ cs2 cscz csgo css,ncurses-libs.i686 +cswon ct dab dayz diff --git a/lgsm/data/almalinux-9.csv b/lgsm/data/almalinux-9.csv index 3476f9949d..3b541a77a7 100644 --- a/lgsm/data/almalinux-9.csv +++ b/lgsm/data/almalinux-9.csv @@ -33,6 +33,7 @@ cs2 cscz csgo css,ncurses-libs.i686 +cswon ct dab dayz diff --git a/lgsm/data/centos-7.csv b/lgsm/data/centos-7.csv index b1a4eaec7b..5af075d201 100644 --- a/lgsm/data/centos-7.csv +++ b/lgsm/data/centos-7.csv @@ -33,6 +33,7 @@ cs2 cscz csgo css,ncurses-libs.i686 +cswon ct dab dayz diff --git a/lgsm/data/centos-8.csv b/lgsm/data/centos-8.csv index a577b35d4a..1d50e811fd 100644 --- a/lgsm/data/centos-8.csv +++ b/lgsm/data/centos-8.csv @@ -33,6 +33,7 @@ cs2 cscz csgo css,ncurses-libs.i686 +cswon ct dab dayz diff --git a/lgsm/data/centos-9.csv b/lgsm/data/centos-9.csv index 56c8b5dd1d..90683ee310 100644 --- a/lgsm/data/centos-9.csv +++ b/lgsm/data/centos-9.csv @@ -33,6 +33,7 @@ cs2 cscz csgo css,ncurses-libs.i686 +cswon ct dab dayz diff --git a/lgsm/data/debian-10.csv b/lgsm/data/debian-10.csv index 70c89716d4..f2b484645a 100644 --- a/lgsm/data/debian-10.csv +++ b/lgsm/data/debian-10.csv @@ -32,6 +32,7 @@ cs2 cscz csgo css,libtinfo5:i386 +cswon,libc6:i386 ct dab dayz diff --git a/lgsm/data/debian-11.csv b/lgsm/data/debian-11.csv index 00d537fa37..13c3e81e2c 100644 --- a/lgsm/data/debian-11.csv +++ b/lgsm/data/debian-11.csv @@ -33,6 +33,7 @@ cs2 cscz csgo css,libtinfo5:i386 +cswon,libc6:i386 ct dab dayz diff --git a/lgsm/data/debian-12.csv b/lgsm/data/debian-12.csv index 7e6fe9d019..2b67c76eab 100644 --- a/lgsm/data/debian-12.csv +++ b/lgsm/data/debian-12.csv @@ -33,6 +33,7 @@ cs2 cscz csgo css,libtinfo5:i386 +cswon,libc6:i386 ct dab dayz diff --git a/lgsm/data/debian-13.csv b/lgsm/data/debian-13.csv index 6ccd09c53d..48c733479d 100644 --- a/lgsm/data/debian-13.csv +++ b/lgsm/data/debian-13.csv @@ -33,6 +33,7 @@ cs2 cscz csgo css +cswon,libc6:i386 ct dab dayz diff --git a/lgsm/data/debian-9.csv b/lgsm/data/debian-9.csv index a0a878a4a0..3a305dcd41 100644 --- a/lgsm/data/debian-9.csv +++ b/lgsm/data/debian-9.csv @@ -33,6 +33,7 @@ cs2 cscz csgo css,libtinfo5:i386 +cswon,libc6:i386 ct dab dayz diff --git a/lgsm/data/gameicons/cswon-icon.png b/lgsm/data/gameicons/cswon-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..5e61337e05a6124abf8e4e744e33169ac03cfb20 GIT binary patch literal 2150 zcmZ`)X*|?x8~zVtX)4DW=a@3QBV_46)@&mh%#dxei+Aj@&SAtP%ZtbolVz;as1(Lt zorW~VREm(T%{t_bHk?e7WpYN}-Vg6}Ki6|T&vpN<-~I8SyD0Kh>U7K0Zk zVvpiNf_q0{`R3jy5Q}#JfD108GjOK%Q9rz{O0^5Dl=m z#Q?i|Rl}+)7C8HeSg$yN2L0l1)ZQ7vLyUxTuohc_NlL+#m=^D<1(prT+LMI$Pe2f3 zV?xeF1|vvhVlcv=NJQxZuwMd0`~u1Vrmt^gV5nypU}Ow}AWA@e0R=GprLe-J0Kr5t z863va75nUxdsM!!o1AY1J&wCE2#%lAHfUF}lFNa-RC$sHv6Pn4q8^fk3CZ!VL%wB; zO5O~Uad=ry0bE?bG{Uh%)`7@A4}1o63JWc{tSxlo9?fw(adkFfbz(q?sYjD#EWLTb zGL4|!eKY$R-r~b-VKA)o4y|8cxi`KF(??cRAVp8X?zq(J7K)hX0w;Bi(<@vb?c1Lw zyyyqEv^f5m8MXz1_n_iL38JfKWLmKI@iz|0c-;D2WkXYGP0 z7#P?CsOfr$B)Z6oNx;i#w8KiP%hR2Djt+a!_I*J5`mUGeSU0sSM1h_mkosic^XcnV zP@#@5xrOwkl?kaL=!tyG5=Hxv}BE)Rvo zMgBtU9`1~PY}1kSFL2Rda_o<A=s%2@>?xUU2b3;%gnc`5y^^RC(b0zCVj%G zwRC9)JAJkt zZe=fyo6^aDZ-%C_Qyx!hZ&(lzI0gS|?$2Fg&f~(UM$4hW8Hh!Az!x9x^v-oX$9}Qk zL!Q)R?}Y~utrondyRYd9=e7Myty{+gzko~=w*b-<_l#N zqVL6Dr|{all&+o}OJ-jLK2S0dkLLcpJL#c$d`?`s7+w#T2sscESF^tYd&ET;hN0kT zVrk+7RPDF~yqjGM5MqVgXHjzgt%(W*7{N(%u2y5mDh(oljtt_Pz8Td{Q$l=OTWZ?Y zbkA9?Qj<>*>uCu4`>BhuGXU@q(T<3-iw|<9zzuJG1mW)SY`Q zx63b43V12bm{U2WB5KW!6^0+_Bi7e(PYVM!y0^x(UZV&r0C9mC(_-aORK=WR3P2h{l@fxb+8l%NgZYCnr*{K-$+!E;E7bKZiphnl3Y_s7L803c%{BX6NPpJvdZo{v8V3r~+K&V;+ti zK1p(_^>m^ZRU?yF1xX@h{nIR+cxo^Yz7lQa&X6_NV1J}`{St3$hjY_F-I_F{;Dwyso12SlyTW1yfAc>R{N?k!HG6dIl2f$s&bAR3=$&BQU6axv+h{ITk5apXz5V)@ z+imHIOP>;;jY3jZ#mKpvqhX-J7cQI4U6r?%+U9d+SxJh`r@ze;J3baGDv=|n8jrJt zicJSk+nto9>5giQ1Q;B3~uxp<`)|F%e547YoxD`9wW@Y{BBi*M4( zTB+vky0X)ba07ITYglbh0YyEn)U0tsRY>FI66MDR?Re^{DYuz_k+-OLMdcLrQVHI! zK|QyU@TSFgnm8-cDLQ^8@2N>%<>3&oDxm<8;XY(~F3=;zQdYFI$wL07uYrRcjk}E1 zxT-avJIqUAvqOikDJ-Ny(7)#~Gjpce1PfPnZ{Y^{lY&hGV}k_(=z_X>+9*&PW$21B tG69WE^b9mX&;$fA;rDs}6NrilIu}Cz{{aId2`51Sz*#$DTC51^{{Sl$&?o=^ literal 0 HcmV?d00001 diff --git a/lgsm/data/rhel-7.csv b/lgsm/data/rhel-7.csv index 9212b7060b..8931345341 100644 --- a/lgsm/data/rhel-7.csv +++ b/lgsm/data/rhel-7.csv @@ -34,6 +34,7 @@ cs2 cscz csgo css,ncurses-libs.i686 +cswon ct dab dayz diff --git a/lgsm/data/rhel-8.csv b/lgsm/data/rhel-8.csv index 8ef014e094..5dc7584bed 100644 --- a/lgsm/data/rhel-8.csv +++ b/lgsm/data/rhel-8.csv @@ -33,6 +33,7 @@ cs2 cscz csgo css,ncurses-libs.i686 +cswon ct dab dayz diff --git a/lgsm/data/rhel-9.csv b/lgsm/data/rhel-9.csv index 3476f9949d..3b541a77a7 100644 --- a/lgsm/data/rhel-9.csv +++ b/lgsm/data/rhel-9.csv @@ -33,6 +33,7 @@ cs2 cscz csgo css,ncurses-libs.i686 +cswon ct dab dayz diff --git a/lgsm/data/rocky-8.csv b/lgsm/data/rocky-8.csv index 8ef014e094..5dc7584bed 100644 --- a/lgsm/data/rocky-8.csv +++ b/lgsm/data/rocky-8.csv @@ -33,6 +33,7 @@ cs2 cscz csgo css,ncurses-libs.i686 +cswon ct dab dayz diff --git a/lgsm/data/rocky-9.csv b/lgsm/data/rocky-9.csv index 3476f9949d..3b541a77a7 100644 --- a/lgsm/data/rocky-9.csv +++ b/lgsm/data/rocky-9.csv @@ -33,6 +33,7 @@ cs2 cscz csgo css,ncurses-libs.i686 +cswon ct dab dayz diff --git a/lgsm/data/serverlist.csv b/lgsm/data/serverlist.csv index 4ba7f41db1..99fc8cbe44 100644 --- a/lgsm/data/serverlist.csv +++ b/lgsm/data/serverlist.csv @@ -32,6 +32,7 @@ cs2,cs2server,Counter-Strike 2,ubuntu-26.04 cscz,csczserver,Counter-Strike: Condition Zero,ubuntu-26.04 csgo,csgoserver,Counter-Strike: Global Offensive,ubuntu-26.04 css,cssserver,Counter-Strike: Source,ubuntu-26.04 +cswon,cswonserver,Counter-Strike: WON2,ubuntu-26.04 ct,ctserver,Craftopia,ubuntu-26.04 dab,dabserver,Double Action: Boogaloo,ubuntu-26.04 dayz,dayzserver,DayZ,ubuntu-26.04 diff --git a/lgsm/data/ubuntu-16.04.csv b/lgsm/data/ubuntu-16.04.csv index a957dbe1ba..bb21193591 100644 --- a/lgsm/data/ubuntu-16.04.csv +++ b/lgsm/data/ubuntu-16.04.csv @@ -34,6 +34,7 @@ cs2 cscz csgo css,libtinfo5:i386 +cswon,libc6:i386 ct dab dayz diff --git a/lgsm/data/ubuntu-18.04.csv b/lgsm/data/ubuntu-18.04.csv index 52a9ac2997..834fefdf5e 100644 --- a/lgsm/data/ubuntu-18.04.csv +++ b/lgsm/data/ubuntu-18.04.csv @@ -34,6 +34,7 @@ cs2 cscz csgo css,libtinfo5:i386 +cswon,libc6:i386 ct dab dayz diff --git a/lgsm/data/ubuntu-20.04.csv b/lgsm/data/ubuntu-20.04.csv index 6257ec10aa..92e0482c6a 100644 --- a/lgsm/data/ubuntu-20.04.csv +++ b/lgsm/data/ubuntu-20.04.csv @@ -33,6 +33,7 @@ cs2 cscz csgo css,libtinfo5:i386 +cswon,libc6:i386 ct dab dayz diff --git a/lgsm/data/ubuntu-22.04.csv b/lgsm/data/ubuntu-22.04.csv index a06263ccb3..164d204a73 100644 --- a/lgsm/data/ubuntu-22.04.csv +++ b/lgsm/data/ubuntu-22.04.csv @@ -33,6 +33,7 @@ cs2 cscz csgo css,libtinfo5:i386 +cswon,libc6:i386 ct dab dayz diff --git a/lgsm/data/ubuntu-23.04.csv b/lgsm/data/ubuntu-23.04.csv index a691ce6cfa..9259c2f390 100644 --- a/lgsm/data/ubuntu-23.04.csv +++ b/lgsm/data/ubuntu-23.04.csv @@ -33,6 +33,7 @@ cs2 cscz csgo css,libtinfo5:i386 +cswon,libc6:i386 ct dab dayz diff --git a/lgsm/data/ubuntu-23.10.csv b/lgsm/data/ubuntu-23.10.csv index a691ce6cfa..9259c2f390 100644 --- a/lgsm/data/ubuntu-23.10.csv +++ b/lgsm/data/ubuntu-23.10.csv @@ -33,6 +33,7 @@ cs2 cscz csgo css,libtinfo5:i386 +cswon,libc6:i386 ct dab dayz diff --git a/lgsm/data/ubuntu-24.04.csv b/lgsm/data/ubuntu-24.04.csv index 8cfd9bb104..001114017f 100644 --- a/lgsm/data/ubuntu-24.04.csv +++ b/lgsm/data/ubuntu-24.04.csv @@ -33,6 +33,7 @@ cs2 cscz csgo css +cswon,libc6:i386 ct dab dayz diff --git a/lgsm/data/ubuntu-26.04.csv b/lgsm/data/ubuntu-26.04.csv index aab323d1f1..6f69d6c172 100644 --- a/lgsm/data/ubuntu-26.04.csv +++ b/lgsm/data/ubuntu-26.04.csv @@ -33,6 +33,7 @@ cs2 cscz csgo css +cswon,libc6:i386 ct dab dayz diff --git a/lgsm/modules/core_getopt.sh b/lgsm/modules/core_getopt.sh index 087283f36b..df93c08326 100755 --- a/lgsm/modules/core_getopt.sh +++ b/lgsm/modules/core_getopt.sh @@ -69,7 +69,7 @@ currentopt+=("${cmd_update_linuxgsm[@]}") # Exclude noupdate games here. if [ "${shortname}" == "jk2" ] || [ "${shortname}" == "jk3" ] || [ "${shortname}" == "etl" ] || [ "${engine}" != "idtech3" ]; then - if [ "${shortname}" != "hlwon" ] && [ "${shortname}" != "bf1942" ] && [ "${shortname}" != "bfv" ] && [ "${engine}" != "idtech2" ] && [ "${engine}" != "iw2.0" ] && [ "${engine}" != "iw3.0" ] && [ "${engine}" != "quake" ] && [ "${shortname}" != "samp" ] && [ "${shortname}" != "ut2k4" ]; then + if [ "${querytype}" != "protocol-valve-won" ] && [ "${shortname}" != "bf1942" ] && [ "${shortname}" != "bfv" ] && [ "${engine}" != "idtech2" ] && [ "${engine}" != "iw2.0" ] && [ "${engine}" != "iw3.0" ] && [ "${engine}" != "quake" ] && [ "${shortname}" != "samp" ] && [ "${shortname}" != "ut2k4" ]; then currentopt+=("${cmd_update[@]}" "${cmd_check_update[@]}") # force update for SteamCMD, Multi Theft Auto or Hytale only. if [ "${appid}" ] || [ "${shortname}" == "mta" ] || [ "${shortname}" == "hyt" ]; then @@ -97,7 +97,7 @@ fi ## Game server exclusive commands. # FastDL command. -if { [ "${engine}" == "source" ] || [ "${engine}" == "goldsrc" ]; } && [ "${shortname}" != "hlwon" ]; then +if { [ "${engine}" == "source" ] || [ "${engine}" == "goldsrc" ]; } && [ "${querytype}" != "protocol-valve-won" ]; then currentopt+=("${cmd_fastdl[@]}") fi diff --git a/lgsm/modules/info_distro.sh b/lgsm/modules/info_distro.sh index dbfbb8cbfa..d90a62e3c9 100755 --- a/lgsm/modules/info_distro.sh +++ b/lgsm/modules/info_distro.sh @@ -14,7 +14,7 @@ if [ "${status}" == "1" ]; then gameserverpid="$(TERM=screen tmux -L "${socketname}" list-sessions -F "#{session_name} #{pane_pid}" | grep "^${sessionname} " | awk '{print $NF}')" if [ "${engine}" == "source" ]; then srcdslinuxpid="$(pgrep -P "${gameserverpid}" -x srcds_linux 2> /dev/null | head -n 1)" - elif [ "${shortname}" == "hlwon" ]; then + elif [ "${querytype}" == "protocol-valve-won" ]; then hldslinuxpid="$(pgrep -P "${gameserverpid}" -x hlds_i686 2> /dev/null | head -n 1)" elif [ "${engine}" == "goldsrc" ]; then hldslinuxpid="$(pgrep -P "${gameserverpid}" -x hlds_linux 2> /dev/null | head -n 1)" diff --git a/lgsm/modules/info_messages.sh b/lgsm/modules/info_messages.sh index 2ba9502d41..7bd94c50ce 100755 --- a/lgsm/modules/info_messages.sh +++ b/lgsm/modules/info_messages.sh @@ -771,7 +771,7 @@ fn_info_messages_ports() { portcommand="ss -tuplwn | grep Main" elif [ "${shortname}" == "sm" ]; then portcommand="ss -tuplwn | grep WSServer-Linux" - elif [ "${shortname}" == "hlwon" ]; then + elif [ "${querytype}" == "protocol-valve-won" ]; then portcommand="ss -tuplwn | grep hlds_i686" elif [ "${engine}" == "source" ]; then portcommand="ss -tuplwn | grep srcds_linux" @@ -1123,7 +1123,7 @@ fn_info_messages_goldsrc() { { fn_port "header" fn_port "Game" port udp - if [ "${shortname}" == "hlwon" ]; then + if [ "${querytype}" == "protocol-valve-won" ]; then fn_port "Query" queryport udp else fn_port "Query" queryport tcp diff --git a/lgsm/modules/install_config.sh b/lgsm/modules/install_config.sh index c685d766f1..344220a3a3 100755 --- a/lgsm/modules/install_config.sh +++ b/lgsm/modules/install_config.sh @@ -492,7 +492,7 @@ elif [ "${shortname}" == "gmod" ]; then fn_default_config_remote fn_set_config_vars fn_list_config_locations -elif [ "${shortname}" == "hldm" ] || [ "${shortname}" == "hlwon" ]; then +elif [ "${shortname}" == "hldm" ] || [ "${shortname}" == "hlwon" ] || [ "${shortname}" == "cswon" ]; then array_configs+=(server.cfg) fn_default_config_remote fn_set_config_vars diff --git a/lgsm/modules/install_server_files.sh b/lgsm/modules/install_server_files.sh index e54db1b584..56acae909f 100755 --- a/lgsm/modules/install_server_files.sh +++ b/lgsm/modules/install_server_files.sh @@ -73,6 +73,14 @@ fn_install_server_files() { run="norun" force="noforce" md5="2c6be1bb66ea631b9b2e7ae6216c6680" + elif [ "${shortname}" == "cswon" ]; then + remote_fileurl="https://linuxgsm.download/CounterStrikeWON2/hlds_l-3111e-cs15-won2-linuxgsm.tar.xz" + local_filedir="${tmpdir}" + local_filename="hlds_l-3111e-cs15-won2-linuxgsm.tar.xz" + chmodx="nochmodx" + run="norun" + force="noforce" + md5="8109a66e2e906ff2c309e3a6b412132a" elif [ "${shortname}" == "hlwon" ]; then remote_fileurl="https://linuxgsm.download/HalfLifeWON2/hlds_l-3111e-won2-linuxgsm.tar.xz" local_filedir="${tmpdir}" From aa5344ba144c524186f7d5e48cad3be66f95c538 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guilherme=20Pra=C3=A7a?= Date: Fri, 30 Oct 2026 07:13:00 -0300 Subject: [PATCH 123/164] fix(core): propagate archive extraction and copy failures (#5109) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit fn_dl_extract could report success when nothing was extracted: - an unsupported MIME type matched no branch and the if returned 0 - in selective ZIP extraction the status came from rm, hiding unzip and cp failures Fail explicitly on unsupported archive types, chain unzip and cp so either failure is reported, clean up the temp directory only after capturing the exit code, and capture stderr so the failure reason is written to the log. Co-authored-by: Guilherme Praça <247475208+guilherme-praca@users.noreply.github.com> --- lgsm/modules/core_dl.sh | 28 +++++++++++++++++----------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/lgsm/modules/core_dl.sh b/lgsm/modules/core_dl.sh index 7da65094eb..1087d44b92 100755 --- a/lgsm/modules/core_dl.sh +++ b/lgsm/modules/core_dl.sh @@ -293,7 +293,7 @@ fn_dl_hash() { fi } -# Extracts bzip2, gzip or zip files. +# Extracts gzip, bzip2, xz or zip files. Any other file type fails. # Extracts can be defined in code like so: # fn_dl_extract "${local_filedir}" "${local_filename}" "${extractdest}" "${extractsrc}" # fn_dl_extract "/home/gameserver/lgsm/tmp" "file.tar.bz2" "/home/gamserver/serverfiles" @@ -318,33 +318,39 @@ fn_dl_extract() { mime=$(file -b --mime-type "${local_filedir}/${local_filename}") if [ "${mime}" == "application/gzip" ] || [ "${mime}" == "application/x-gzip" ]; then if [ -n "${extractsrc}" ]; then - extractcmd=$(tar -zxf "${local_filedir}/${local_filename}" -C "${extractdest}" --strip-components=1 "${extractsrc}") + extractcmd=$(tar -zxf "${local_filedir}/${local_filename}" -C "${extractdest}" --strip-components=1 "${extractsrc}" 2>&1) else - extractcmd=$(tar -zxf "${local_filedir}/${local_filename}" -C "${extractdest}") + extractcmd=$(tar -zxf "${local_filedir}/${local_filename}" -C "${extractdest}" 2>&1) fi elif [ "${mime}" == "application/x-bzip2" ]; then if [ -n "${extractsrc}" ]; then - extractcmd=$(tar -jxf "${local_filedir}/${local_filename}" -C "${extractdest}" --strip-components=1 "${extractsrc}") + extractcmd=$(tar -jxf "${local_filedir}/${local_filename}" -C "${extractdest}" --strip-components=1 "${extractsrc}" 2>&1) else - extractcmd=$(tar -jxf "${local_filedir}/${local_filename}" -C "${extractdest}") + extractcmd=$(tar -jxf "${local_filedir}/${local_filename}" -C "${extractdest}" 2>&1) fi elif [ "${mime}" == "application/x-xz" ]; then if [ -n "${extractsrc}" ]; then - extractcmd=$(tar -Jxf "${local_filedir}/${local_filename}" -C "${extractdest}" --strip-components=1 "${extractsrc}") + extractcmd=$(tar -Jxf "${local_filedir}/${local_filename}" -C "${extractdest}" --strip-components=1 "${extractsrc}" 2>&1) else - extractcmd=$(tar -Jxf "${local_filedir}/${local_filename}" -C "${extractdest}") + extractcmd=$(tar -Jxf "${local_filedir}/${local_filename}" -C "${extractdest}" 2>&1) fi elif [ "${mime}" == "application/zip" ]; then if [ -n "${extractsrc}" ]; then temp_extractdir="${tmpdir}/${extractsrc}" - extractcmd=$(unzip -qo "${local_filedir}/${local_filename}" "${extractsrc}/*" -d "${temp_extractdir}") - cp -a "${temp_extractdir}/${extractsrc}/." "${extractdest}/" - rm -rf "${temp_extractdir}" + extractcmd=$(unzip -qo "${local_filedir}/${local_filename}" "${extractsrc}/*" -d "${temp_extractdir}" 2>&1 && cp -a "${temp_extractdir}/${extractsrc}/." "${extractdest}/" 2>&1) else - extractcmd=$(unzip -qo -d "${extractdest}" "${local_filedir}/${local_filename}") + extractcmd=$(unzip -qo -d "${extractdest}" "${local_filedir}/${local_filename}" 2>&1) fi + else + extractcmd="Unsupported archive type: ${mime}" + false fi exitcode=$? + # Clean up after capturing the exit code so cleanup cannot mask a failed extraction or copy. + if [ -n "${temp_extractdir}" ]; then + rm -rf "${temp_extractdir}" + unset temp_extractdir + fi if [ "${exitcode}" -ne 0 ]; then fn_print_fail_eol_nl fn_script_log_fail "Extracting ${local_filename}" From ff15be6235bbed01c87bddbf52e9196b10ca1763 Mon Sep 17 00:00:00 2001 From: Daniel Gibbs Date: Fri, 30 Oct 2026 10:17:17 +0000 Subject: [PATCH 124/164] fix(core): follow-up failure handling for extraction, updates and logs (#5113) * fix(update): force download of update archives Ten update modules passed "force" to fn_fetch_file, which only recognises "forcedl", so an archive already in tmpdir was reused. A failed extraction leaves the archive in tmpdir, and for fixed file names such as multitheftauto_linux_x64.tar.gz the next update would extract the stale file again. * fix(install): exit non-zero when log directories cannot be created install_logs.sh called core_exit.sh without setting exitcode, so a failure to create a log directory, log file or symlink printed FAIL but exited with code 0. Log each failure with fn_script_log_fail, which sets exitcode to 1. * fix(mta): exit cleanly after install-default-resources The module never called core_exit.sh, so running ./mtaserver install-default-resources always ended with "Command did not exit correctly" and exit code 2, even on success. Exit only when it is the first command, so the install flow that calls it carries on. * fix(core): stop SteamCMD install when extraction fails under exitbypass When exitbypass is set, core_exit.sh returns instead of exiting, so a failed extraction fell through to the caller. fn_install_steamcmd then ran chmod on a steamcmd.sh that was never extracted. This is reachable when an update restarts the server and check_steamcmd.sh installs SteamCMD. fn_dl_extract now returns 1 after a bypassed failure, and fn_install_steamcmd stops on it. --- lgsm/modules/command_install_resources_mta.sh | 5 +++++ lgsm/modules/core_dl.sh | 2 ++ lgsm/modules/core_steamcmd.sh | 2 +- lgsm/modules/install_logs.sh | 8 ++++++++ lgsm/modules/update_bb.sh | 2 +- lgsm/modules/update_etl.sh | 2 +- lgsm/modules/update_fctr.sh | 2 +- lgsm/modules/update_jk2.sh | 2 +- lgsm/modules/update_mta.sh | 2 +- lgsm/modules/update_pmc.sh | 2 +- lgsm/modules/update_ts3.sh | 2 +- lgsm/modules/update_ut99.sh | 2 +- lgsm/modules/update_vints.sh | 2 +- lgsm/modules/update_xnt.sh | 2 +- 14 files changed, 26 insertions(+), 11 deletions(-) diff --git a/lgsm/modules/command_install_resources_mta.sh b/lgsm/modules/command_install_resources_mta.sh index 7b1c45d12d..72084f77ae 100755 --- a/lgsm/modules/command_install_resources_mta.sh +++ b/lgsm/modules/command_install_resources_mta.sh @@ -30,3 +30,8 @@ else fn_print_warning_nl "Default resources are not installed when using ./${selfname} auto-install." fn_print_information_nl "To install default resources use ./${selfname} install" fi + +if [ "${firstcommandname}" == "DEFAULT-RESOURCES" ]; then + exitcode=0 + core_exit.sh +fi diff --git a/lgsm/modules/core_dl.sh b/lgsm/modules/core_dl.sh index 1087d44b92..e22766f7cd 100755 --- a/lgsm/modules/core_dl.sh +++ b/lgsm/modules/core_dl.sh @@ -314,6 +314,7 @@ fn_dl_extract() { fn_script_log_fail "Extracting ${local_filename}" fn_script_log_fail "File ${local_filedir}/${local_filename} not found" core_exit.sh + return 1 fi mime=$(file -b --mime-type "${local_filedir}/${local_filename}") if [ "${mime}" == "application/gzip" ] || [ "${mime}" == "application/x-gzip" ]; then @@ -359,6 +360,7 @@ fn_dl_extract() { fi echo -e "${extractcmd}" core_exit.sh + return 1 else fn_print_ok_eol_nl fn_script_log_pass "Extracting ${local_filename}" diff --git a/lgsm/modules/core_steamcmd.sh b/lgsm/modules/core_steamcmd.sh index 81b8d0cc23..d8043ed269 100755 --- a/lgsm/modules/core_steamcmd.sh +++ b/lgsm/modules/core_steamcmd.sh @@ -15,7 +15,7 @@ fn_install_steamcmd() { mkdir -p "${steamcmddir}" fi fn_fetch_file "https://media.steampowered.com/client/steamcmd_linux.tar.gz" "" "" "" "${tmpdir}" "steamcmd_linux.tar.gz" "nochmodx" "norun" "noforce" "nohash" - fn_dl_extract "${tmpdir}" "steamcmd_linux.tar.gz" "${steamcmddir}" + fn_dl_extract "${tmpdir}" "steamcmd_linux.tar.gz" "${steamcmddir}" || return 1 chmod +x "${steamcmddir}/steamcmd.sh" } diff --git a/lgsm/modules/install_logs.sh b/lgsm/modules/install_logs.sh index 9e1b89dbdf..987e7e8937 100755 --- a/lgsm/modules/install_logs.sh +++ b/lgsm/modules/install_logs.sh @@ -17,6 +17,7 @@ echo -en "creating log directory [ ${italic}${logdir}${default} ]" if [ ! -d "${logdir}" ]; then if ! mkdir -p "${logdir}"; then fn_print_fail_eol_nl + fn_script_log_fail "Creating log directory ${logdir}" core_exit.sh else fn_print_ok_eol_nl @@ -29,6 +30,7 @@ echo -en "creating script log directory [ ${italic}${lgsmlogdir}${default} ]" if [ ! -d "${lgsmlogdir}" ]; then if ! mkdir -p "${lgsmlogdir}"; then fn_print_fail_eol_nl + fn_script_log_fail "Creating script log directory ${lgsmlogdir}" core_exit.sh else fn_print_ok_eol_nl @@ -41,6 +43,7 @@ echo -en "creating script log [ ${italic}${lgsmlog}${default} ]" if [ ! -f "${lgsmlog}" ]; then if ! touch "${lgsmlog}"; then fn_print_fail_eol_nl + fn_script_log_fail "Creating script log ${lgsmlog}" core_exit.sh else fn_print_ok_eol_nl @@ -53,6 +56,7 @@ echo -en "creating console log directory [ ${italic}${consolelogdir}${default} ] if [ ! -d "${consolelogdir}" ]; then if ! mkdir -p "${consolelogdir}"; then fn_print_fail_eol_nl + fn_script_log_fail "Creating console log directory ${consolelogdir}" core_exit.sh else fn_print_ok_eol_nl @@ -65,6 +69,7 @@ echo -en "creating console log [ ${italic}${consolelog}${default} ]" if [ ! -f "${consolelog}" ]; then if ! touch "${consolelog}"; then fn_print_fail_eol_nl + fn_script_log_fail "Creating console log ${consolelog}" core_exit.sh else fn_print_ok_eol_nl @@ -78,6 +83,7 @@ if [ -n "${gamelogdir}" ]; then if [ ! -d "${gamelogdir}" ]; then if ! mkdir -p "${gamelogdir}"; then fn_print_fail_eol_nl + fn_script_log_fail "Creating game log directory ${gamelogdir}" core_exit.sh else fn_print_ok_eol_nl @@ -97,6 +103,7 @@ if [ -n "${gamelogdir}" ] && [ "${gamelogdir:0:${#logdir}}" != "${logdir}" ]; th if [ ! -h "${logdir}/server" ] || [ "$(readlink -f "${logdir}/server")" != "${gamelogdir}" ]; then if ! ln -nfs "${gamelogdir}" "${logdir}/server"; then fn_print_fail_eol_nl + fn_script_log_fail "Creating symlink to game log directory ${logdir}/server" core_exit.sh else fn_print_ok_eol_nl @@ -112,6 +119,7 @@ if [ -d "${HOME}/.steam/steam/logs" ]; then if [ ! -L "${logdir}/steam" ]; then if ! ln -nfs "${HOME}/.steam/steam/logs" "${logdir}/steam"; then fn_print_fail_eol_nl + fn_script_log_fail "Creating symlink to steam log directory ${logdir}/steam" core_exit.sh else fn_print_ok_eol_nl diff --git a/lgsm/modules/update_bb.sh b/lgsm/modules/update_bb.sh index aeb47fe448..51b3f76d33 100755 --- a/lgsm/modules/update_bb.sh +++ b/lgsm/modules/update_bb.sh @@ -9,7 +9,7 @@ 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" "${remotebuildhash}" + fn_fetch_file "${remotebuildurl}" "" "" "" "${tmpdir}" "${remotebuildfilename}" "nochmodx" "norun" "forcedl" "${remotebuildhash}" fn_dl_extract "${tmpdir}" "${remotebuildfilename}" "${serverfiles}" echo "${remotebuild}" > "${serverfiles}/build.txt" fn_clear_tmp diff --git a/lgsm/modules/update_etl.sh b/lgsm/modules/update_etl.sh index fa3f9f591f..e44c058f8d 100755 --- a/lgsm/modules/update_etl.sh +++ b/lgsm/modules/update_etl.sh @@ -9,7 +9,7 @@ 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" "${remotebuildhash}" + fn_fetch_file "${remotebuildurl}" "" "" "" "${tmpdir}" "${remotebuildfilename}" "nochmodx" "norun" "forcedl" "${remotebuildhash}" fn_dl_extract "${tmpdir}" "${remotebuildfilename}" "${serverfiles}" echo "${remotebuild}" > "${serverfiles}/build.txt" fn_clear_tmp diff --git a/lgsm/modules/update_fctr.sh b/lgsm/modules/update_fctr.sh index d82f53881f..8b065738ea 100755 --- a/lgsm/modules/update_fctr.sh +++ b/lgsm/modules/update_fctr.sh @@ -9,7 +9,7 @@ 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_fetch_file "${remotebuildurl}" "" "" "" "${tmpdir}" "${remotebuildfilename}" "nochmodx" "norun" "forcedl" "nohash" fn_dl_extract "${tmpdir}" "factorio_headless_${factorioarch}-${remotebuild}.tar.xz" "${serverfiles}" "factorio" fn_clear_tmp } diff --git a/lgsm/modules/update_jk2.sh b/lgsm/modules/update_jk2.sh index 1d2ba36458..930f5ea98d 100755 --- a/lgsm/modules/update_jk2.sh +++ b/lgsm/modules/update_jk2.sh @@ -9,7 +9,7 @@ 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_fetch_file "${remotebuildurl}" "" "" "" "${tmpdir}" "${remotebuildfilename}" "nochmodx" "norun" "forcedl" "nohash" fn_dl_extract "${tmpdir}" "${remotebuildfilename}" "${serverfiles}/GameData" "linux-amd64" fn_clear_tmp } diff --git a/lgsm/modules/update_mta.sh b/lgsm/modules/update_mta.sh index 5adbc57ed7..353dca9d07 100755 --- a/lgsm/modules/update_mta.sh +++ b/lgsm/modules/update_mta.sh @@ -9,7 +9,7 @@ moduleselfname="$(basename "$(readlink -f "${BASH_SOURCE[0]}")")" fn_update_dl() { # Download and extract files to tmpdir. - fn_fetch_file "https://linux.multitheftauto.com/dl/multitheftauto_linux_x64.tar.gz" "" "" "" "${tmpdir}" "multitheftauto_linux_x64.tar.gz" "nochmodx" "norun" "force" "nohash" + fn_fetch_file "https://linux.multitheftauto.com/dl/multitheftauto_linux_x64.tar.gz" "" "" "" "${tmpdir}" "multitheftauto_linux_x64.tar.gz" "nochmodx" "norun" "forcedl" "nohash" fn_dl_extract "${tmpdir}" "multitheftauto_linux_x64.tar.gz" "${serverfiles}" "multitheftauto_linux_x64" fn_clear_tmp } diff --git a/lgsm/modules/update_pmc.sh b/lgsm/modules/update_pmc.sh index 907e32dbe0..a5185e6929 100755 --- a/lgsm/modules/update_pmc.sh +++ b/lgsm/modules/update_pmc.sh @@ -9,7 +9,7 @@ moduleselfname="$(basename "$(readlink -f "${BASH_SOURCE[0]}")")" fn_update_dl() { # Download and extract files to serverfiles. - fn_fetch_file "${remotebuildurl}" "" "" "" "${tmpdir}" "${remotebuildfilename}" "chmodx" "norun" "force" "${remotebuildhash}" + fn_fetch_file "${remotebuildurl}" "" "" "" "${tmpdir}" "${remotebuildfilename}" "chmodx" "norun" "forcedl" "${remotebuildhash}" cp -f "${tmpdir}/${remotebuildfilename}" "${serverfiles}/${executable#./}" echo "${remotebuild}" > "${serverfiles}/build.txt" fn_clear_tmp diff --git a/lgsm/modules/update_ts3.sh b/lgsm/modules/update_ts3.sh index 58ad872b25..92136ed5d4 100755 --- a/lgsm/modules/update_ts3.sh +++ b/lgsm/modules/update_ts3.sh @@ -9,7 +9,7 @@ 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" "${remotebuildhash}" + fn_fetch_file "${remotebuildurl}" "" "" "" "${tmpdir}" "${remotebuildfilename}" "nochmodx" "norun" "forcedl" "${remotebuildhash}" fn_dl_extract "${tmpdir}" "${remotebuildfilename}" "${serverfiles}" "teamspeak3-server_linux_${ts3arch}" fn_clear_tmp } diff --git a/lgsm/modules/update_ut99.sh b/lgsm/modules/update_ut99.sh index f21117125b..ce8158d05f 100755 --- a/lgsm/modules/update_ut99.sh +++ b/lgsm/modules/update_ut99.sh @@ -9,7 +9,7 @@ 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_fetch_file "${remotebuildurl}" "" "" "" "${tmpdir}" "${remotebuildfilename}" "nochmodx" "norun" "forcedl" "nohash" fn_dl_extract "${tmpdir}" "${remotebuildfilename}" "${serverfiles}" echo "${remotebuild}" > "${serverfiles}/build.txt" fn_clear_tmp diff --git a/lgsm/modules/update_vints.sh b/lgsm/modules/update_vints.sh index 0925e6f801..6f2da81ebd 100755 --- a/lgsm/modules/update_vints.sh +++ b/lgsm/modules/update_vints.sh @@ -9,7 +9,7 @@ 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" "${remotebuildhash}" + fn_fetch_file "${remotebuildurl}" "" "" "" "${tmpdir}" "${remotebuildfilename}" "nochmodx" "norun" "forcedl" "${remotebuildhash}" rm -rf "${serverfiles:?}/assets" fn_dl_extract "${tmpdir}" "${remotebuildfilename}" "${serverfiles}" fn_clear_tmp diff --git a/lgsm/modules/update_xnt.sh b/lgsm/modules/update_xnt.sh index 831f63325e..751709e8bf 100755 --- a/lgsm/modules/update_xnt.sh +++ b/lgsm/modules/update_xnt.sh @@ -9,7 +9,7 @@ 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" "${remotebuildhash}" + fn_fetch_file "${remotebuildurl}" "" "" "" "${tmpdir}" "${remotebuildfilename}" "nochmodx" "norun" "forcedl" "${remotebuildhash}" fn_dl_extract "${tmpdir}" "${remotebuildfilename}" "${serverfiles}" "Xonotic" fn_clear_tmp } From 5107135cac37be80e11a2ff6ed87792334dd68ac Mon Sep 17 00:00:00 2001 From: BorzakA <1230402+borzaka@users.noreply.github.com> Date: Fri, 30 Oct 2026 12:19:42 +0100 Subject: [PATCH 125/164] feat(core): add extraparams to append custom start parameters (#4970) Add an extraparams setting that appends custom start parameters to the end of the start parameters, so users no longer have to copy and override the whole startparameters line to add a flag. extraparams is appended once in fn_reload_startparameters, only when set, so it works for every game server and also when startparameters is overridden. Every _default.cfg lists extraparams="" in an "Extra Parameters" entry so users can find it; the startparameters lines are unchanged. Fixes #2183 Supersedes #2120 Co-authored-by: borzaka <1230402+borzaka@users.noreply.github.com> Co-authored-by: Frisasky --- lgsm/config-default/config-lgsm/acserver/_default.cfg | 4 ++++ lgsm/config-default/config-lgsm/ahl2server/_default.cfg | 4 ++++ lgsm/config-default/config-lgsm/ahlserver/_default.cfg | 4 ++++ lgsm/config-default/config-lgsm/arkserver/_default.cfg | 4 ++++ lgsm/config-default/config-lgsm/arma3server/_default.cfg | 4 ++++ lgsm/config-default/config-lgsm/armarserver/_default.cfg | 4 ++++ lgsm/config-default/config-lgsm/atsserver/_default.cfg | 4 ++++ lgsm/config-default/config-lgsm/avserver/_default.cfg | 4 ++++ lgsm/config-default/config-lgsm/bb2server/_default.cfg | 4 ++++ lgsm/config-default/config-lgsm/bbserver/_default.cfg | 4 ++++ lgsm/config-default/config-lgsm/bdserver/_default.cfg | 4 ++++ lgsm/config-default/config-lgsm/bf1942server/_default.cfg | 4 ++++ lgsm/config-default/config-lgsm/bfvserver/_default.cfg | 4 ++++ lgsm/config-default/config-lgsm/bmdmserver/_default.cfg | 4 ++++ lgsm/config-default/config-lgsm/boserver/_default.cfg | 4 ++++ lgsm/config-default/config-lgsm/bsserver/_default.cfg | 4 ++++ lgsm/config-default/config-lgsm/btlserver/_default.cfg | 4 ++++ lgsm/config-default/config-lgsm/btserver/_default.cfg | 4 ++++ lgsm/config-default/config-lgsm/ccserver/_default.cfg | 4 ++++ lgsm/config-default/config-lgsm/ceserver/_default.cfg | 4 ++++ lgsm/config-default/config-lgsm/ckserver/_default.cfg | 4 ++++ lgsm/config-default/config-lgsm/cmwserver/_default.cfg | 4 ++++ lgsm/config-default/config-lgsm/cod2server/_default.cfg | 4 ++++ lgsm/config-default/config-lgsm/cod4server/_default.cfg | 4 ++++ lgsm/config-default/config-lgsm/codserver/_default.cfg | 4 ++++ lgsm/config-default/config-lgsm/coduoserver/_default.cfg | 4 ++++ lgsm/config-default/config-lgsm/codwawserver/_default.cfg | 4 ++++ lgsm/config-default/config-lgsm/colserver/_default.cfg | 4 ++++ lgsm/config-default/config-lgsm/cs2server/_default.cfg | 4 ++++ lgsm/config-default/config-lgsm/csczserver/_default.cfg | 4 ++++ lgsm/config-default/config-lgsm/csgoserver/_default.cfg | 4 ++++ lgsm/config-default/config-lgsm/csserver/_default.cfg | 4 ++++ lgsm/config-default/config-lgsm/cssserver/_default.cfg | 4 ++++ lgsm/config-default/config-lgsm/cswonserver/_default.cfg | 4 ++++ lgsm/config-default/config-lgsm/ctserver/_default.cfg | 4 ++++ lgsm/config-default/config-lgsm/dabserver/_default.cfg | 4 ++++ lgsm/config-default/config-lgsm/dayzserver/_default.cfg | 4 ++++ lgsm/config-default/config-lgsm/dmcserver/_default.cfg | 4 ++++ lgsm/config-default/config-lgsm/dodrserver/_default.cfg | 4 ++++ lgsm/config-default/config-lgsm/dodserver/_default.cfg | 4 ++++ lgsm/config-default/config-lgsm/dodsserver/_default.cfg | 4 ++++ lgsm/config-default/config-lgsm/doiserver/_default.cfg | 4 ++++ lgsm/config-default/config-lgsm/dstserver/_default.cfg | 4 ++++ lgsm/config-default/config-lgsm/dysserver/_default.cfg | 4 ++++ lgsm/config-default/config-lgsm/ecoserver/_default.cfg | 4 ++++ lgsm/config-default/config-lgsm/emserver/_default.cfg | 4 ++++ lgsm/config-default/config-lgsm/etlserver/_default.cfg | 4 ++++ lgsm/config-default/config-lgsm/ets2server/_default.cfg | 4 ++++ lgsm/config-default/config-lgsm/fctrserver/_default.cfg | 4 ++++ lgsm/config-default/config-lgsm/fofserver/_default.cfg | 4 ++++ lgsm/config-default/config-lgsm/gmodserver/_default.cfg | 4 ++++ lgsm/config-default/config-lgsm/hcuserver/_default.cfg | 4 ++++ lgsm/config-default/config-lgsm/hl2dmserver/_default.cfg | 4 ++++ lgsm/config-default/config-lgsm/hldmserver/_default.cfg | 4 ++++ lgsm/config-default/config-lgsm/hldmsserver/_default.cfg | 4 ++++ lgsm/config-default/config-lgsm/hlwonserver/_default.cfg | 4 ++++ lgsm/config-default/config-lgsm/hwserver/_default.cfg | 4 ++++ lgsm/config-default/config-lgsm/hytserver/_default.cfg | 4 ++++ lgsm/config-default/config-lgsm/hzserver/_default.cfg | 4 ++++ lgsm/config-default/config-lgsm/insserver/_default.cfg | 4 ++++ lgsm/config-default/config-lgsm/inssserver/_default.cfg | 4 ++++ lgsm/config-default/config-lgsm/iosserver/_default.cfg | 4 ++++ lgsm/config-default/config-lgsm/jbep3server/_default.cfg | 4 ++++ lgsm/config-default/config-lgsm/jc2server/_default.cfg | 4 ++++ lgsm/config-default/config-lgsm/jc3server/_default.cfg | 4 ++++ lgsm/config-default/config-lgsm/jk2server/_default.cfg | 4 ++++ lgsm/config-default/config-lgsm/jk3server/_default.cfg | 4 ++++ lgsm/config-default/config-lgsm/kf2server/_default.cfg | 4 ++++ lgsm/config-default/config-lgsm/kfserver/_default.cfg | 4 ++++ lgsm/config-default/config-lgsm/l4d2server/_default.cfg | 4 ++++ lgsm/config-default/config-lgsm/l4dserver/_default.cfg | 4 ++++ lgsm/config-default/config-lgsm/mcbserver/_default.cfg | 4 ++++ lgsm/config-default/config-lgsm/mcserver/_default.cfg | 4 ++++ lgsm/config-default/config-lgsm/mcvserver/_default.cfg | 4 ++++ lgsm/config-default/config-lgsm/mhserver/_default.cfg | 4 ++++ lgsm/config-default/config-lgsm/mohaaserver/_default.cfg | 4 ++++ lgsm/config-default/config-lgsm/momserver/_default.cfg | 4 ++++ lgsm/config-default/config-lgsm/mtaserver/_default.cfg | 4 ++++ lgsm/config-default/config-lgsm/ndserver/_default.cfg | 4 ++++ lgsm/config-default/config-lgsm/necserver/_default.cfg | 4 ++++ lgsm/config-default/config-lgsm/nmrihserver/_default.cfg | 4 ++++ lgsm/config-default/config-lgsm/ns2cserver/_default.cfg | 4 ++++ lgsm/config-default/config-lgsm/ns2server/_default.cfg | 4 ++++ lgsm/config-default/config-lgsm/nsserver/_default.cfg | 4 ++++ lgsm/config-default/config-lgsm/ohdserver/_default.cfg | 4 ++++ lgsm/config-default/config-lgsm/onsetserver/_default.cfg | 4 ++++ lgsm/config-default/config-lgsm/opforserver/_default.cfg | 4 ++++ lgsm/config-default/config-lgsm/pc2server/_default.cfg | 4 ++++ lgsm/config-default/config-lgsm/pcserver/_default.cfg | 4 ++++ lgsm/config-default/config-lgsm/pmcserver/_default.cfg | 4 ++++ lgsm/config-default/config-lgsm/pvkiiserver/_default.cfg | 4 ++++ lgsm/config-default/config-lgsm/pvrserver/_default.cfg | 4 ++++ lgsm/config-default/config-lgsm/pwserver/_default.cfg | 4 ++++ lgsm/config-default/config-lgsm/pzserver/_default.cfg | 4 ++++ lgsm/config-default/config-lgsm/q2server/_default.cfg | 4 ++++ lgsm/config-default/config-lgsm/q3server/_default.cfg | 4 ++++ lgsm/config-default/config-lgsm/q4server/_default.cfg | 4 ++++ lgsm/config-default/config-lgsm/qlserver/_default.cfg | 4 ++++ lgsm/config-default/config-lgsm/qwserver/_default.cfg | 4 ++++ lgsm/config-default/config-lgsm/ricochetserver/_default.cfg | 4 ++++ lgsm/config-default/config-lgsm/roserver/_default.cfg | 4 ++++ lgsm/config-default/config-lgsm/rsdwserver/_default.cfg | 4 ++++ lgsm/config-default/config-lgsm/rtcwserver/_default.cfg | 4 ++++ lgsm/config-default/config-lgsm/rustserver/_default.cfg | 4 ++++ lgsm/config-default/config-lgsm/rwrserver/_default.cfg | 4 ++++ lgsm/config-default/config-lgsm/rwserver/_default.cfg | 4 ++++ lgsm/config-default/config-lgsm/sampserver/_default.cfg | 4 ++++ lgsm/config-default/config-lgsm/sbotsserver/_default.cfg | 4 ++++ lgsm/config-default/config-lgsm/sbserver/_default.cfg | 4 ++++ lgsm/config-default/config-lgsm/scpslserver/_default.cfg | 4 ++++ lgsm/config-default/config-lgsm/sdtdserver/_default.cfg | 4 ++++ lgsm/config-default/config-lgsm/sfcserver/_default.cfg | 4 ++++ lgsm/config-default/config-lgsm/sfserver/_default.cfg | 4 ++++ lgsm/config-default/config-lgsm/smserver/_default.cfg | 4 ++++ lgsm/config-default/config-lgsm/sof2server/_default.cfg | 4 ++++ lgsm/config-default/config-lgsm/solserver/_default.cfg | 4 ++++ lgsm/config-default/config-lgsm/squad44server/_default.cfg | 4 ++++ lgsm/config-default/config-lgsm/squadserver/_default.cfg | 4 ++++ lgsm/config-default/config-lgsm/stnserver/_default.cfg | 4 ++++ lgsm/config-default/config-lgsm/stserver/_default.cfg | 4 ++++ lgsm/config-default/config-lgsm/svenserver/_default.cfg | 4 ++++ lgsm/config-default/config-lgsm/terrariaserver/_default.cfg | 4 ++++ lgsm/config-default/config-lgsm/tf2cserver/_default.cfg | 4 ++++ lgsm/config-default/config-lgsm/tf2server/_default.cfg | 4 ++++ lgsm/config-default/config-lgsm/tfcserver/_default.cfg | 4 ++++ lgsm/config-default/config-lgsm/tfserver/_default.cfg | 4 ++++ lgsm/config-default/config-lgsm/tiserver/_default.cfg | 4 ++++ lgsm/config-default/config-lgsm/ts3server/_default.cfg | 4 ++++ lgsm/config-default/config-lgsm/tsserver/_default.cfg | 4 ++++ lgsm/config-default/config-lgsm/tuserver/_default.cfg | 4 ++++ lgsm/config-default/config-lgsm/twserver/_default.cfg | 4 ++++ lgsm/config-default/config-lgsm/untserver/_default.cfg | 4 ++++ lgsm/config-default/config-lgsm/ut2k4server/_default.cfg | 4 ++++ lgsm/config-default/config-lgsm/ut3server/_default.cfg | 4 ++++ lgsm/config-default/config-lgsm/ut99server/_default.cfg | 4 ++++ lgsm/config-default/config-lgsm/utserver/_default.cfg | 4 ++++ lgsm/config-default/config-lgsm/vhserver/_default.cfg | 4 ++++ lgsm/config-default/config-lgsm/vintsserver/_default.cfg | 4 ++++ lgsm/config-default/config-lgsm/vpmcserver/_default.cfg | 4 ++++ lgsm/config-default/config-lgsm/vsserver/_default.cfg | 4 ++++ lgsm/config-default/config-lgsm/wetserver/_default.cfg | 4 ++++ lgsm/config-default/config-lgsm/wfserver/_default.cfg | 4 ++++ lgsm/config-default/config-lgsm/wmcserver/_default.cfg | 4 ++++ lgsm/config-default/config-lgsm/wurmserver/_default.cfg | 4 ++++ lgsm/config-default/config-lgsm/xntserver/_default.cfg | 4 ++++ lgsm/config-default/config-lgsm/zmrserver/_default.cfg | 4 ++++ lgsm/config-default/config-lgsm/zpsserver/_default.cfg | 4 ++++ linuxgsm.sh | 3 +++ 148 files changed, 591 insertions(+) diff --git a/lgsm/config-default/config-lgsm/acserver/_default.cfg b/lgsm/config-default/config-lgsm/acserver/_default.cfg index 46453984b3..015f989d67 100644 --- a/lgsm/config-default/config-lgsm/acserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/acserver/_default.cfg @@ -15,6 +15,10 @@ steampass='password' ## Server Parameters | https://docs.linuxgsm.com/configuration/start-parameters#additional-parameters startparameters="-c ${servercfgfullpath}" +## Extra Parameters | https://docs.linuxgsm.com/configuration/start-parameters#extra-parameters +# Added to the end of startparameters. +extraparams="" + #### LinuxGSM Settings #### ## LinuxGSM Stats diff --git a/lgsm/config-default/config-lgsm/ahl2server/_default.cfg b/lgsm/config-default/config-lgsm/ahl2server/_default.cfg index d70b96b90c..289a7a2f39 100644 --- a/lgsm/config-default/config-lgsm/ahl2server/_default.cfg +++ b/lgsm/config-default/config-lgsm/ahl2server/_default.cfg @@ -23,6 +23,10 @@ maxplayers="20" ## Server Parameters | https://docs.linuxgsm.com/configuration/start-parameters#additional-parameters startparameters="-game ahl2 -strictportbind -ip ${ip} -port ${port} +clientport ${clientport} +tv_port ${sourcetvport} +map ${defaultmap} +servercfgfile ${servercfg} -maxplayers ${maxplayers}" +## Extra Parameters | https://docs.linuxgsm.com/configuration/start-parameters#extra-parameters +# Added to the end of startparameters. +extraparams="" + #### LinuxGSM Settings #### ## LinuxGSM Stats diff --git a/lgsm/config-default/config-lgsm/ahlserver/_default.cfg b/lgsm/config-default/config-lgsm/ahlserver/_default.cfg index 182f20ee2d..8fe39e1107 100644 --- a/lgsm/config-default/config-lgsm/ahlserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/ahlserver/_default.cfg @@ -18,6 +18,10 @@ maxplayers="16" ## Server Parameters | https://docs.linuxgsm.com/configuration/start-parameters#additional-parameters startparameters="-game action -strictportbind +ip ${ip} -port ${port} +clientport ${clientport} +map ${defaultmap} +servercfgfile ${servercfg} -maxplayers ${maxplayers} " +## Extra Parameters | https://docs.linuxgsm.com/configuration/start-parameters#extra-parameters +# Added to the end of startparameters. +extraparams="" + #### LinuxGSM Settings #### ## LinuxGSM Stats diff --git a/lgsm/config-default/config-lgsm/arkserver/_default.cfg b/lgsm/config-default/config-lgsm/arkserver/_default.cfg index 583f7e8bd9..1c2bf36a29 100644 --- a/lgsm/config-default/config-lgsm/arkserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/arkserver/_default.cfg @@ -20,6 +20,10 @@ altsavedirectoryname="${defaultmap}" ## Game Server Docs | https://ark.wiki.gg/wiki/Server_configuration startparameters="${defaultmap}?AltSaveDirectoryName=${altsavedirectoryname} -MultiHome=${ip} -Port=${port} -QueryPort=${queryport} -AutoManagedMods -Crossplay -PublicIPForEpic=${publicip}" +## Extra Parameters | https://docs.linuxgsm.com/configuration/start-parameters#extra-parameters +# Added to the end of startparameters. +extraparams="" + #### LinuxGSM Settings #### ## LinuxGSM Stats diff --git a/lgsm/config-default/config-lgsm/arma3server/_default.cfg b/lgsm/config-default/config-lgsm/arma3server/_default.cfg index 31f9111108..989874843d 100644 --- a/lgsm/config-default/config-lgsm/arma3server/_default.cfg +++ b/lgsm/config-default/config-lgsm/arma3server/_default.cfg @@ -41,6 +41,10 @@ bepath="" ## Server Parameters | https://docs.linuxgsm.com/configuration/start-parameters#additional-parameters startparameters="-ip=${ip} -port=${port} -cfg=${networkcfgfullpath} -config=${servercfgfullpath} -mod=${mods} -servermod=${servermods} -bepath=${bepath} -autoinit -loadmissiontomemory" +## Extra Parameters | https://docs.linuxgsm.com/configuration/start-parameters#extra-parameters +# Added to the end of startparameters. +extraparams="" + #### LinuxGSM Settings #### ## LinuxGSM Stats diff --git a/lgsm/config-default/config-lgsm/armarserver/_default.cfg b/lgsm/config-default/config-lgsm/armarserver/_default.cfg index a17fdf978b..add29e732e 100644 --- a/lgsm/config-default/config-lgsm/armarserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/armarserver/_default.cfg @@ -19,6 +19,10 @@ serverprofilefullpath="${serverfiles}/profiles/${serverprofile}" ## Server Parameters | https://docs.linuxgsm.com/configuration/start-parameters#additional-parameters startparameters="-config ${servercfgfullpath} -profile ${serverprofilefullpath} -maxFPS ${maxfps}" +## Extra Parameters | https://docs.linuxgsm.com/configuration/start-parameters#extra-parameters +# Added to the end of startparameters. +extraparams="" + #### LinuxGSM Settings #### ## LinuxGSM Stats diff --git a/lgsm/config-default/config-lgsm/atsserver/_default.cfg b/lgsm/config-default/config-lgsm/atsserver/_default.cfg index 04b2290861..307cf9d858 100644 --- a/lgsm/config-default/config-lgsm/atsserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/atsserver/_default.cfg @@ -11,6 +11,10 @@ ## Server Parameters | https://docs.linuxgsm.com/configuration/start-parameters#additional-parameters startparameters="-nosingle" +## Extra Parameters | https://docs.linuxgsm.com/configuration/start-parameters#extra-parameters +# Added to the end of startparameters. +extraparams="" + #### LinuxGSM Settings #### ## LinuxGSM Stats diff --git a/lgsm/config-default/config-lgsm/avserver/_default.cfg b/lgsm/config-default/config-lgsm/avserver/_default.cfg index 9319196511..1905581b08 100644 --- a/lgsm/config-default/config-lgsm/avserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/avserver/_default.cfg @@ -11,6 +11,10 @@ ## Server Parameters | https://docs.linuxgsm.com/configuration/start-parameters#additional-parameters startparameters="--galaxy-name ${selfname} --ip ${ip} --datapath ${avdatapath}" +## Extra Parameters | https://docs.linuxgsm.com/configuration/start-parameters#extra-parameters +# Added to the end of startparameters. +extraparams="" + #### LinuxGSM Settings #### ## LinuxGSM Stats diff --git a/lgsm/config-default/config-lgsm/bb2server/_default.cfg b/lgsm/config-default/config-lgsm/bb2server/_default.cfg index 9b936f0da7..0cac42cd8e 100644 --- a/lgsm/config-default/config-lgsm/bb2server/_default.cfg +++ b/lgsm/config-default/config-lgsm/bb2server/_default.cfg @@ -24,6 +24,10 @@ gslt="" ## Server Parameters | https://docs.linuxgsm.com/configuration/start-parameters#additional-parameters startparameters="-game brainbread2 -strictportbind -ip ${ip} -port ${port} +clientport ${clientport} +tv_port ${sourcetvport} +sv_setsteamaccount ${gslt} +map ${defaultmap} +servercfgfile ${servercfg} -maxplayers ${maxplayers}" +## Extra Parameters | https://docs.linuxgsm.com/configuration/start-parameters#extra-parameters +# Added to the end of startparameters. +extraparams="" + #### LinuxGSM Settings #### ## LinuxGSM Stats diff --git a/lgsm/config-default/config-lgsm/bbserver/_default.cfg b/lgsm/config-default/config-lgsm/bbserver/_default.cfg index 9fb311e91d..720ed8307c 100644 --- a/lgsm/config-default/config-lgsm/bbserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/bbserver/_default.cfg @@ -18,6 +18,10 @@ maxplayers="16" ## Server Parameters | https://docs.linuxgsm.com/configuration/start-parameters#additional-parameters startparameters="-game brainbread -strictportbind +ip ${ip} -port ${port} +clientport ${clientport} +map ${defaultmap} +servercfgfile ${servercfg} -maxplayers ${maxplayers}" +## Extra Parameters | https://docs.linuxgsm.com/configuration/start-parameters#extra-parameters +# Added to the end of startparameters. +extraparams="" + #### LinuxGSM Settings #### ## LinuxGSM Stats diff --git a/lgsm/config-default/config-lgsm/bdserver/_default.cfg b/lgsm/config-default/config-lgsm/bdserver/_default.cfg index fdd4c47a5a..c567bf6f25 100644 --- a/lgsm/config-default/config-lgsm/bdserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/bdserver/_default.cfg @@ -18,6 +18,10 @@ maxplayers="3" ## Server Parameters | https://docs.linuxgsm.com/configuration/start-parameters#additional-parameters startparameters="-game bdef -strictportbind +ip ${ip} -port ${port} +clientport ${clientport} +map ${defaultmap} +servercfgfile ${servercfg} -maxplayers ${maxplayers}" +## Extra Parameters | https://docs.linuxgsm.com/configuration/start-parameters#extra-parameters +# Added to the end of startparameters. +extraparams="" + #### LinuxGSM Settings #### ## LinuxGSM Stats diff --git a/lgsm/config-default/config-lgsm/bf1942server/_default.cfg b/lgsm/config-default/config-lgsm/bf1942server/_default.cfg index 158770c5a7..d89d8922e8 100644 --- a/lgsm/config-default/config-lgsm/bf1942server/_default.cfg +++ b/lgsm/config-default/config-lgsm/bf1942server/_default.cfg @@ -11,6 +11,10 @@ ## Server Parameters | https://docs.linuxgsm.com/configuration/start-parameters#additional-parameters startparameters="+hostServer 1 +dedicated 1" +## Extra Parameters | https://docs.linuxgsm.com/configuration/start-parameters#extra-parameters +# Added to the end of startparameters. +extraparams="" + #### LinuxGSM Settings #### ## LinuxGSM Stats diff --git a/lgsm/config-default/config-lgsm/bfvserver/_default.cfg b/lgsm/config-default/config-lgsm/bfvserver/_default.cfg index bb5e000970..760f3051e7 100644 --- a/lgsm/config-default/config-lgsm/bfvserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/bfvserver/_default.cfg @@ -11,6 +11,10 @@ ## Server Parameters | https://docs.linuxgsm.com/configuration/start-parameters#additional-parameters startparameters="+statusMonitor 1" +## Extra Parameters | https://docs.linuxgsm.com/configuration/start-parameters#extra-parameters +# Added to the end of startparameters. +extraparams="" + #### LinuxGSM Settings #### ## LinuxGSM Stats diff --git a/lgsm/config-default/config-lgsm/bmdmserver/_default.cfg b/lgsm/config-default/config-lgsm/bmdmserver/_default.cfg index 436be070c1..395429efb8 100644 --- a/lgsm/config-default/config-lgsm/bmdmserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/bmdmserver/_default.cfg @@ -24,6 +24,10 @@ gslt="" ## Server Parameters | https://docs.linuxgsm.com/configuration/start-parameters#additional-parameters startparameters="-game bms -strictportbind -ip ${ip} -port ${port} +clientport ${clientport} +tv_port ${sourcetvport} +sv_setsteamaccount ${gslt} +map ${defaultmap} +servercfgfile ${servercfg} -maxplayers ${maxplayers}" +## Extra Parameters | https://docs.linuxgsm.com/configuration/start-parameters#extra-parameters +# Added to the end of startparameters. +extraparams="" + #### LinuxGSM Settings #### ## LinuxGSM Stats diff --git a/lgsm/config-default/config-lgsm/boserver/_default.cfg b/lgsm/config-default/config-lgsm/boserver/_default.cfg index 9246898ba2..b1d6f96a36 100644 --- a/lgsm/config-default/config-lgsm/boserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/boserver/_default.cfg @@ -16,6 +16,10 @@ gslt="" ## Server Parameters | https://docs.linuxgsm.com/configuration/start-parameters#additional-parameters startparameters="-batchmode -nographics -dedicated -configfile=${servercfgfullpath}" +## Extra Parameters | https://docs.linuxgsm.com/configuration/start-parameters#extra-parameters +# Added to the end of startparameters. +extraparams="" + #### LinuxGSM Settings #### ## LinuxGSM Stats diff --git a/lgsm/config-default/config-lgsm/bsserver/_default.cfg b/lgsm/config-default/config-lgsm/bsserver/_default.cfg index 17b34602c7..b1aa971ae0 100644 --- a/lgsm/config-default/config-lgsm/bsserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/bsserver/_default.cfg @@ -28,6 +28,10 @@ gslt="" ## Server Parameters | https://docs.linuxgsm.com/configuration/start-parameters#additional-parameters startparameters="-game "${serverfiles}/berimbau" -autoupdate -strictportbind -ip ${ip} -port ${port} +clientport ${clientport} +tv_port ${sourcetvport} +sv_setsteamaccount ${gslt} +map ${defaultmap} +servercfgfile ${servercfg} -maxplayers ${maxplayers}" +## Extra Parameters | https://docs.linuxgsm.com/configuration/start-parameters#extra-parameters +# Added to the end of startparameters. +extraparams="" + #### LinuxGSM Settings #### ## LinuxGSM Stats diff --git a/lgsm/config-default/config-lgsm/btlserver/_default.cfg b/lgsm/config-default/config-lgsm/btlserver/_default.cfg index 59d68eb51a..8424637498 100644 --- a/lgsm/config-default/config-lgsm/btlserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/btlserver/_default.cfg @@ -16,6 +16,10 @@ queryport="7780" ## Server Parameters | https://docs.linuxgsm.com/configuration/start-parameters#additional-parameters startparameters="-Port=${port} -QueryPort=${queryport} -BroadcastIp=${publicip} -log" +## Extra Parameters | https://docs.linuxgsm.com/configuration/start-parameters#extra-parameters +# Added to the end of startparameters. +extraparams="" + #### LinuxGSM Settings #### ## LinuxGSM Stats diff --git a/lgsm/config-default/config-lgsm/btserver/_default.cfg b/lgsm/config-default/config-lgsm/btserver/_default.cfg index f7dc2a116c..5b29357396 100644 --- a/lgsm/config-default/config-lgsm/btserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/btserver/_default.cfg @@ -11,6 +11,10 @@ ## Server Parameters | https://docs.linuxgsm.com/configuration/start-parameters#additional-parameters startparameters="" +## Extra Parameters | https://docs.linuxgsm.com/configuration/start-parameters#extra-parameters +# Added to the end of startparameters. +extraparams="" + ## Steam Workshop Mods | https://docs.linuxgsm.com/steamcmd/workshop # Workshop item or collection IDs, separated by spaces. Collections are expanded. # Installed to LocalMods and enabled in config_player.xml. Run ./btserver workshop-update after changing, or let update apply it. diff --git a/lgsm/config-default/config-lgsm/ccserver/_default.cfg b/lgsm/config-default/config-lgsm/ccserver/_default.cfg index 78c567bcff..2e9616a2b5 100644 --- a/lgsm/config-default/config-lgsm/ccserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/ccserver/_default.cfg @@ -19,6 +19,10 @@ maxplayers="6" ## Server Parameters | https://docs.linuxgsm.com/configuration/start-parameters#additional-parameters startparameters="-game cure -strictportbind -ip ${ip} -port ${port} +clientport ${clientport} +tv_port ${sourcetvport} +map ${defaultmap} +servercfgfile ${servercfg} -maxplayers ${maxplayers}" +## Extra Parameters | https://docs.linuxgsm.com/configuration/start-parameters#extra-parameters +# Added to the end of startparameters. +extraparams="" + #### LinuxGSM Settings #### ## LinuxGSM Stats diff --git a/lgsm/config-default/config-lgsm/ceserver/_default.cfg b/lgsm/config-default/config-lgsm/ceserver/_default.cfg index 5dbde6730b..64c89d845c 100644 --- a/lgsm/config-default/config-lgsm/ceserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/ceserver/_default.cfg @@ -18,6 +18,10 @@ maxplayers="40" ## Server Parameters | https://docs.linuxgsm.com/configuration/start-parameters#additional-parameters startparameters="ConanSandbox -log -MULTIHOME=${ip} -Port=${port} -QueryPort=${queryport} -ServerName='${servername}' -MaxPlayers=${maxplayers}" +## Extra Parameters | https://docs.linuxgsm.com/configuration/start-parameters#extra-parameters +# Added to the end of startparameters. +extraparams="" + #### LinuxGSM Settings #### ## LinuxGSM Stats diff --git a/lgsm/config-default/config-lgsm/ckserver/_default.cfg b/lgsm/config-default/config-lgsm/ckserver/_default.cfg index 6be4b1c2c1..8ed388435c 100644 --- a/lgsm/config-default/config-lgsm/ckserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/ckserver/_default.cfg @@ -15,6 +15,10 @@ port="1234" ## Server Parameters | https://docs.linuxgsm.com/configuration/start-parameters#additional-parameters startparameters="-batchmode -ip ${ip} -port ${port} -datapath ${servercfgdir} -logfile ${gamelog}" +## Extra Parameters | https://docs.linuxgsm.com/configuration/start-parameters#extra-parameters +# Added to the end of startparameters. +extraparams="" + #### LinuxGSM Settings #### ## LinuxGSM Stats diff --git a/lgsm/config-default/config-lgsm/cmwserver/_default.cfg b/lgsm/config-default/config-lgsm/cmwserver/_default.cfg index f6812662c1..77e68f9483 100644 --- a/lgsm/config-default/config-lgsm/cmwserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/cmwserver/_default.cfg @@ -17,6 +17,10 @@ defaultmap="AOCTD-Frigid_p" ## Server Parameters | https://docs.linuxgsm.com/configuration/start-parameters#additional-parameters startparameters="${defaultmap}?steamsockets -multihome=${ip} -Port=${port} -QueryPort=${queryport} -seekfreeloadingserver -configsubdir=${selfname} -log=${gamelog}" +## Extra Parameters | https://docs.linuxgsm.com/configuration/start-parameters#extra-parameters +# Added to the end of startparameters. +extraparams="" + #### LinuxGSM Settings #### ## LinuxGSM Stats diff --git a/lgsm/config-default/config-lgsm/cod2server/_default.cfg b/lgsm/config-default/config-lgsm/cod2server/_default.cfg index 199907018e..f5943b7144 100644 --- a/lgsm/config-default/config-lgsm/cod2server/_default.cfg +++ b/lgsm/config-default/config-lgsm/cod2server/_default.cfg @@ -17,6 +17,10 @@ maxplayers="20" ## Server Parameters | https://docs.linuxgsm.com/configuration/start-parameters#additional-parameters startparameters="+set sv_punkbuster 0 +set fs_basepath ${serverfiles} +set dedicated 2 +set net_ip ${ip} +set net_port ${port} +set sv_maxclients ${maxplayers} +map ${defaultmap} +exec ${servercfg}" +## Extra Parameters | https://docs.linuxgsm.com/configuration/start-parameters#extra-parameters +# Added to the end of startparameters. +extraparams="" + #### LinuxGSM Settings #### ## LinuxGSM Stats diff --git a/lgsm/config-default/config-lgsm/cod4server/_default.cfg b/lgsm/config-default/config-lgsm/cod4server/_default.cfg index 4476697f97..45df4fc4f9 100644 --- a/lgsm/config-default/config-lgsm/cod4server/_default.cfg +++ b/lgsm/config-default/config-lgsm/cod4server/_default.cfg @@ -17,6 +17,10 @@ maxplayers="32" ## Server Parameters | https://docs.linuxgsm.com/configuration/start-parameters#additional-parameters startparameters="+set sv_punkbuster 0 +set fs_basepath ${serverfiles} +set fs_homepath ${serverfiles} +set sv_authorizemode "-1" +set dedicated 2 +set net_ip ${ip} +set net_port ${port} +set sv_maxclients ${maxplayers} +map ${defaultmap} +exec ${servercfg}" +## Extra Parameters | https://docs.linuxgsm.com/configuration/start-parameters#extra-parameters +# Added to the end of startparameters. +extraparams="" + #### LinuxGSM Settings #### ## LinuxGSM Stats diff --git a/lgsm/config-default/config-lgsm/codserver/_default.cfg b/lgsm/config-default/config-lgsm/codserver/_default.cfg index 07568a3356..a31139ab0c 100644 --- a/lgsm/config-default/config-lgsm/codserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/codserver/_default.cfg @@ -17,6 +17,10 @@ maxplayers="20" ## Server Parameters | https://docs.linuxgsm.com/configuration/start-parameters#additional-parameters startparameters="+set sv_punkbuster 0 +set fs_basepath ${serverfiles} +set dedicated 2 +set net_ip ${ip} +set net_port ${port} +set sv_maxclients ${maxplayers} +map ${defaultmap} +exec ${servercfg}" +## Extra Parameters | https://docs.linuxgsm.com/configuration/start-parameters#extra-parameters +# Added to the end of startparameters. +extraparams="" + #### LinuxGSM Settings #### ## LinuxGSM Stats diff --git a/lgsm/config-default/config-lgsm/coduoserver/_default.cfg b/lgsm/config-default/config-lgsm/coduoserver/_default.cfg index 97107dcbe1..102c557609 100644 --- a/lgsm/config-default/config-lgsm/coduoserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/coduoserver/_default.cfg @@ -17,6 +17,10 @@ maxplayers="20" ## Server Parameters | https://docs.linuxgsm.com/configuration/start-parameters#additional-parameters startparameters="+set sv_punkbuster 0 +set fs_basepath ${serverfiles} +set dedicated 2 +set net_ip ${ip} +set net_port ${port} +set sv_maxclients ${maxplayers} +map ${defaultmap} +exec ${servercfg}" +## Extra Parameters | https://docs.linuxgsm.com/configuration/start-parameters#extra-parameters +# Added to the end of startparameters. +extraparams="" + #### LinuxGSM Settings #### ## LinuxGSM Stats diff --git a/lgsm/config-default/config-lgsm/codwawserver/_default.cfg b/lgsm/config-default/config-lgsm/codwawserver/_default.cfg index b5b7519601..7836ea3e9f 100644 --- a/lgsm/config-default/config-lgsm/codwawserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/codwawserver/_default.cfg @@ -17,6 +17,10 @@ maxplayers="20" ## Server Parameters | https://docs.linuxgsm.com/configuration/start-parameters#additional-parameters startparameters="+set sv_punkbuster 0 +set fs_basepath ${serverfiles} +set dedicated 2 +set net_ip ${ip} +set net_port ${port} +set sv_maxclients ${maxplayers} +map ${defaultmap} +exec ${servercfg}" +## Extra Parameters | https://docs.linuxgsm.com/configuration/start-parameters#extra-parameters +# Added to the end of startparameters. +extraparams="" + #### LinuxGSM Settings #### ## LinuxGSM Stats diff --git a/lgsm/config-default/config-lgsm/colserver/_default.cfg b/lgsm/config-default/config-lgsm/colserver/_default.cfg index 1afd55b028..025090d7f0 100644 --- a/lgsm/config-default/config-lgsm/colserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/colserver/_default.cfg @@ -17,6 +17,10 @@ steampass='' ## https://colonysurvival.gamepedia.com/Dedicated_Server#Installation_.28Linux.29 startparameters="-batchmode -nographics +server.config ${servercfgfullpath}" +## Extra Parameters | https://docs.linuxgsm.com/configuration/start-parameters#extra-parameters +# Added to the end of startparameters. +extraparams="" + ## Steam Workshop Mods | https://docs.linuxgsm.com/steamcmd/workshop # Workshop item or collection IDs, separated by spaces. Collections are expanded. # Needs steamuser to own Colony Survival. Installed to gamedata/mods and enabled in each world's worldconfig.json. diff --git a/lgsm/config-default/config-lgsm/cs2server/_default.cfg b/lgsm/config-default/config-lgsm/cs2server/_default.cfg index 4a0a0fc4c9..dff480c13b 100644 --- a/lgsm/config-default/config-lgsm/cs2server/_default.cfg +++ b/lgsm/config-default/config-lgsm/cs2server/_default.cfg @@ -23,6 +23,10 @@ gslt="" ## Server Parameters | https://docs.linuxgsm.com/configuration/start-parameters#additional-parameters startparameters="-dedicated -ip ${ip} -port ${port} -maxplayers ${maxplayers} -authkey ${wsapikey} +exec ${selfname}.cfg" +## Extra Parameters | https://docs.linuxgsm.com/configuration/start-parameters#extra-parameters +# Added to the end of startparameters. +extraparams="" + #### LinuxGSM Settings #### ## LinuxGSM Stats diff --git a/lgsm/config-default/config-lgsm/csczserver/_default.cfg b/lgsm/config-default/config-lgsm/csczserver/_default.cfg index f8c90c52c2..93abb3a4da 100644 --- a/lgsm/config-default/config-lgsm/csczserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/csczserver/_default.cfg @@ -18,6 +18,10 @@ maxplayers="16" ## Server Parameters | https://docs.linuxgsm.com/configuration/start-parameters#additional-parameters startparameters="-game czero -strictportbind +ip ${ip} -port ${port} +clientport ${clientport} +map ${defaultmap} +servercfgfile ${servercfg} -maxplayers ${maxplayers}" +## Extra Parameters | https://docs.linuxgsm.com/configuration/start-parameters#extra-parameters +# Added to the end of startparameters. +extraparams="" + #### LinuxGSM Settings #### ## LinuxGSM Stats diff --git a/lgsm/config-default/config-lgsm/csgoserver/_default.cfg b/lgsm/config-default/config-lgsm/csgoserver/_default.cfg index 15df32d2ae..31fc9c836f 100644 --- a/lgsm/config-default/config-lgsm/csgoserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/csgoserver/_default.cfg @@ -56,6 +56,10 @@ wsstartmap="" ## Server Parameters | https://docs.linuxgsm.com/configuration/start-parameters#additional-parameters startparameters="-game csgo -usercon -strictportbind -ip ${ip} -port ${port} +clientport ${clientport} +tv_port ${sourcetvport} +sv_setsteamaccount ${gslt} -tickrate ${tickrate} +map ${defaultmap} +servercfgfile ${servercfg} -maxplayers_override ${maxplayers} +mapgroup ${mapgroup} +game_type ${gametype} +game_mode ${gamemode} +sv_game_mode_flags ${gamemodeflags} +sv_skirmish_id ${skirmishid} +host_workshop_collection ${wscollectionid} +workshop_start_map ${wsstartmap} -authkey ${wsapikey} -nobreakpad" +## Extra Parameters | https://docs.linuxgsm.com/configuration/start-parameters#extra-parameters +# Added to the end of startparameters. +extraparams="" + #### LinuxGSM Settings #### ## LinuxGSM Stats diff --git a/lgsm/config-default/config-lgsm/csserver/_default.cfg b/lgsm/config-default/config-lgsm/csserver/_default.cfg index 9f20d59150..a0f89e1735 100644 --- a/lgsm/config-default/config-lgsm/csserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/csserver/_default.cfg @@ -18,6 +18,10 @@ maxplayers="16" ## Server Parameters | https://docs.linuxgsm.com/configuration/start-parameters#additional-parameters startparameters="-game cstrike -strictportbind +ip ${ip} -port ${port} +clientport ${clientport} +map ${defaultmap} +servercfgfile ${servercfg} -maxplayers ${maxplayers}" +## Extra Parameters | https://docs.linuxgsm.com/configuration/start-parameters#extra-parameters +# Added to the end of startparameters. +extraparams="" + #### LinuxGSM Settings #### ## LinuxGSM Stats diff --git a/lgsm/config-default/config-lgsm/cssserver/_default.cfg b/lgsm/config-default/config-lgsm/cssserver/_default.cfg index aadc378380..085319420c 100644 --- a/lgsm/config-default/config-lgsm/cssserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/cssserver/_default.cfg @@ -24,6 +24,10 @@ gslt="" ## Server Parameters | https://docs.linuxgsm.com/configuration/start-parameters#additional-parameters startparameters="-game cstrike -strictportbind -ip ${ip} -port ${port} +clientport ${clientport} +tv_port ${sourcetvport} +sv_setsteamaccount ${gslt} +map ${defaultmap} +servercfgfile ${servercfg} -maxplayers ${maxplayers}" +## Extra Parameters | https://docs.linuxgsm.com/configuration/start-parameters#extra-parameters +# Added to the end of startparameters. +extraparams="" + #### LinuxGSM Settings #### ## LinuxGSM Stats diff --git a/lgsm/config-default/config-lgsm/cswonserver/_default.cfg b/lgsm/config-default/config-lgsm/cswonserver/_default.cfg index b4124087ca..7fe44a84c4 100644 --- a/lgsm/config-default/config-lgsm/cswonserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/cswonserver/_default.cfg @@ -18,6 +18,10 @@ maxplayers="16" ## Server Parameters | https://docs.linuxgsm.com/configuration/start-parameters#additional-parameters startparameters="-game cstrike -binary ./hlds_i686 -noipx -insecure +ip ${ip} -port ${port} +clientport ${clientport} +map ${defaultmap} +servercfgfile ${servercfg} -maxplayers ${maxplayers}" +## Extra Parameters | https://docs.linuxgsm.com/configuration/start-parameters#extra-parameters +# Added to the end of startparameters. +extraparams="" + #### LinuxGSM Settings #### ## LinuxGSM Stats diff --git a/lgsm/config-default/config-lgsm/ctserver/_default.cfg b/lgsm/config-default/config-lgsm/ctserver/_default.cfg index c56a7bf481..34295f21ab 100644 --- a/lgsm/config-default/config-lgsm/ctserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/ctserver/_default.cfg @@ -11,6 +11,10 @@ ## Server Parameters | https://docs.linuxgsm.com/configuration/start-parameters#additional-parameters startparameters="-batchmode -showlogs" +## Extra Parameters | https://docs.linuxgsm.com/configuration/start-parameters#extra-parameters +# Added to the end of startparameters. +extraparams="" + #### LinuxGSM Settings #### ## LinuxGSM Stats diff --git a/lgsm/config-default/config-lgsm/dabserver/_default.cfg b/lgsm/config-default/config-lgsm/dabserver/_default.cfg index 385152099f..e347f3e246 100644 --- a/lgsm/config-default/config-lgsm/dabserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/dabserver/_default.cfg @@ -19,6 +19,10 @@ maxplayers="10" ## Server Parameters | https://docs.linuxgsm.com/configuration/start-parameters#additional-parameters startparameters="-strictportbind -ip ${ip} -port ${port} +clientport ${clientport} +tv_port ${sourcetvport} +map ${defaultmap} +servercfgfile ${servercfg} -maxplayers ${maxplayers}" +## Extra Parameters | https://docs.linuxgsm.com/configuration/start-parameters#extra-parameters +# Added to the end of startparameters. +extraparams="" + #### LinuxGSM Settings #### ## LinuxGSM Stats diff --git a/lgsm/config-default/config-lgsm/dayzserver/_default.cfg b/lgsm/config-default/config-lgsm/dayzserver/_default.cfg index 20f2132072..2520c59909 100644 --- a/lgsm/config-default/config-lgsm/dayzserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/dayzserver/_default.cfg @@ -41,6 +41,10 @@ bepath="" ## Server Parameters | https://docs.linuxgsm.com/configuration/start-parameters#additional-parameters startparameters="-ip=${ip} -port=${port} -config=${servercfgfullpath} -mod=${mods} -servermod=${servermods} -bepath=${bepath} -limitFPS=60 -dologs -adminlog -freezeCheck" +## Extra Parameters | https://docs.linuxgsm.com/configuration/start-parameters#extra-parameters +# Added to the end of startparameters. +extraparams="" + #### LinuxGSM Settings #### ## LinuxGSM Stats diff --git a/lgsm/config-default/config-lgsm/dmcserver/_default.cfg b/lgsm/config-default/config-lgsm/dmcserver/_default.cfg index 8cfcd505f8..6a0cb7a3e9 100644 --- a/lgsm/config-default/config-lgsm/dmcserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/dmcserver/_default.cfg @@ -18,6 +18,10 @@ maxplayers="16" ## Server Parameters | https://docs.linuxgsm.com/configuration/start-parameters#additional-parameters startparameters="-game dmc -strictportbind +ip ${ip} -port ${port} +clientport ${clientport} +map ${defaultmap} +servercfgfile ${servercfg} -maxplayers ${maxplayers}" +## Extra Parameters | https://docs.linuxgsm.com/configuration/start-parameters#extra-parameters +# Added to the end of startparameters. +extraparams="" + #### LinuxGSM Settings #### ## LinuxGSM Stats diff --git a/lgsm/config-default/config-lgsm/dodrserver/_default.cfg b/lgsm/config-default/config-lgsm/dodrserver/_default.cfg index 655611e6f3..a4edba7f1a 100644 --- a/lgsm/config-default/config-lgsm/dodrserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/dodrserver/_default.cfg @@ -17,6 +17,10 @@ queryport="27015" ## Server Parameters | https://docs.linuxgsm.com/configuration/start-parameters#additional-parameters startparameters="-MultiHome=${ip} -Port=${port} -QueryPort=${queryport} -SteamServerName='${servername}' -log" +## Extra Parameters | https://docs.linuxgsm.com/configuration/start-parameters#extra-parameters +# Added to the end of startparameters. +extraparams="" + #### LinuxGSM Settings #### ## LinuxGSM Stats diff --git a/lgsm/config-default/config-lgsm/dodserver/_default.cfg b/lgsm/config-default/config-lgsm/dodserver/_default.cfg index d2f8daba58..7df687ae86 100644 --- a/lgsm/config-default/config-lgsm/dodserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/dodserver/_default.cfg @@ -18,6 +18,10 @@ maxplayers="16" ## Server Parameters | https://docs.linuxgsm.com/configuration/start-parameters#additional-parameters startparameters="-game dod -strictportbind +ip ${ip} -port ${port} +clientport ${clientport} +map ${defaultmap} +servercfgfile ${servercfg} -maxplayers ${maxplayers}" +## Extra Parameters | https://docs.linuxgsm.com/configuration/start-parameters#extra-parameters +# Added to the end of startparameters. +extraparams="" + #### LinuxGSM Settings #### ## LinuxGSM Stats diff --git a/lgsm/config-default/config-lgsm/dodsserver/_default.cfg b/lgsm/config-default/config-lgsm/dodsserver/_default.cfg index 1fa0f3c1e1..5205da64d5 100644 --- a/lgsm/config-default/config-lgsm/dodsserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/dodsserver/_default.cfg @@ -19,6 +19,10 @@ maxplayers="16" ## Server Parameters | https://docs.linuxgsm.com/configuration/start-parameters#additional-parameters startparameters="-game dod -strictportbind -ip ${ip} -port ${port} +clientport ${clientport} +tv_port ${sourcetvport} +map ${defaultmap} +servercfgfile ${servercfg} -maxplayers ${maxplayers}" +## Extra Parameters | https://docs.linuxgsm.com/configuration/start-parameters#extra-parameters +# Added to the end of startparameters. +extraparams="" + #### LinuxGSM Settings #### ## LinuxGSM Stats diff --git a/lgsm/config-default/config-lgsm/doiserver/_default.cfg b/lgsm/config-default/config-lgsm/doiserver/_default.cfg index 9ee92a76f9..dc568296e5 100644 --- a/lgsm/config-default/config-lgsm/doiserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/doiserver/_default.cfg @@ -20,6 +20,10 @@ tickrate="64" ## Server Parameters | https://docs.linuxgsm.com/configuration/start-parameters#additional-parameters startparameters="-game doi -strictportbind -ip ${ip} -port ${port} +clientport ${clientport} +tv_port ${sourcetvport} -tickrate ${tickrate} +map ${defaultmap} +servercfgfile ${servercfg} -maxplayers ${maxplayers} -workshop -norestart" +## Extra Parameters | https://docs.linuxgsm.com/configuration/start-parameters#extra-parameters +# Added to the end of startparameters. +extraparams="" + #### LinuxGSM Settings #### ## LinuxGSM Stats diff --git a/lgsm/config-default/config-lgsm/dstserver/_default.cfg b/lgsm/config-default/config-lgsm/dstserver/_default.cfg index c0d0882ba9..35e954829c 100644 --- a/lgsm/config-default/config-lgsm/dstserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/dstserver/_default.cfg @@ -21,6 +21,10 @@ confdir="DoNotStarveTogether" ## Server Parameters | https://docs.linuxgsm.com/configuration/start-parameters#additional-parameters startparameters="-persistent_storage_root ${persistentstorageroot} -conf_dir ${confdir} -cluster ${cluster} -shard ${shard}" +## Extra Parameters | https://docs.linuxgsm.com/configuration/start-parameters#extra-parameters +# Added to the end of startparameters. +extraparams="" + #### LinuxGSM Settings #### ## LinuxGSM Stats diff --git a/lgsm/config-default/config-lgsm/dysserver/_default.cfg b/lgsm/config-default/config-lgsm/dysserver/_default.cfg index 567c338fcb..ee2b9c3715 100644 --- a/lgsm/config-default/config-lgsm/dysserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/dysserver/_default.cfg @@ -24,6 +24,10 @@ gslt="" ## Server Parameters | https://docs.linuxgsm.com/configuration/start-parameters#additional-parameters startparameters="-game "${serverfiles}/dystopia" -strictportbind -ip ${ip} -port ${port} +clientport ${clientport} +tv_port ${sourcetvport} +map ${defaultmap} +sv_setsteamaccount ${gslt} +servercfgfile ${servercfg} -maxplayers ${maxplayers}" +## Extra Parameters | https://docs.linuxgsm.com/configuration/start-parameters#extra-parameters +# Added to the end of startparameters. +extraparams="" + #### LinuxGSM Settings #### ## LinuxGSM Stats diff --git a/lgsm/config-default/config-lgsm/ecoserver/_default.cfg b/lgsm/config-default/config-lgsm/ecoserver/_default.cfg index 522b8f8f6e..0514f10195 100644 --- a/lgsm/config-default/config-lgsm/ecoserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/ecoserver/_default.cfg @@ -14,6 +14,10 @@ usertoken="" ## Server Parameters | https://docs.linuxgsm.com/configuration/start-parameters#additional-parameters startparameters="-nogui -userToken=${usertoken}" +## Extra Parameters | https://docs.linuxgsm.com/configuration/start-parameters#extra-parameters +# Added to the end of startparameters. +extraparams="" + #### LinuxGSM Settings #### ## LinuxGSM Stats diff --git a/lgsm/config-default/config-lgsm/emserver/_default.cfg b/lgsm/config-default/config-lgsm/emserver/_default.cfg index 7fd98d437f..e8b6eff462 100644 --- a/lgsm/config-default/config-lgsm/emserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/emserver/_default.cfg @@ -24,6 +24,10 @@ gslt="" ## Server Parameters | https://docs.linuxgsm.com/configuration/start-parameters#additional-parameters startparameters="-game empires -strictportbind -ip ${ip} -port ${port} +clientport ${clientport} +tv_port ${sourcetvport} +map ${defaultmap} +servercfgfile ${servercfg} -maxplayers ${maxplayers}" +## Extra Parameters | https://docs.linuxgsm.com/configuration/start-parameters#extra-parameters +# Added to the end of startparameters. +extraparams="" + #### LinuxGSM Settings #### ## LinuxGSM Stats diff --git a/lgsm/config-default/config-lgsm/etlserver/_default.cfg b/lgsm/config-default/config-lgsm/etlserver/_default.cfg index 2bf1eb3dba..3f8a3ebf6e 100644 --- a/lgsm/config-default/config-lgsm/etlserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/etlserver/_default.cfg @@ -11,6 +11,10 @@ ## Server Parameters | https://docs.linuxgsm.com/configuration/start-parameters#additional-parameters startparameters="+set net_strict 1 +set fs_homepath ${serverfiles} +exec ${servercfg}" +## Extra Parameters | https://docs.linuxgsm.com/configuration/start-parameters#extra-parameters +# Added to the end of startparameters. +extraparams="" + #### LinuxGSM Settings #### ## LinuxGSM Stats diff --git a/lgsm/config-default/config-lgsm/ets2server/_default.cfg b/lgsm/config-default/config-lgsm/ets2server/_default.cfg index c65803e5dd..a3eeb9f000 100644 --- a/lgsm/config-default/config-lgsm/ets2server/_default.cfg +++ b/lgsm/config-default/config-lgsm/ets2server/_default.cfg @@ -11,6 +11,10 @@ ## Server Parameters | https://docs.linuxgsm.com/configuration/start-parameters#additional-parameters startparameters="-nosingle" +## Extra Parameters | https://docs.linuxgsm.com/configuration/start-parameters#extra-parameters +# Added to the end of startparameters. +extraparams="" + #### LinuxGSM Settings #### ## LinuxGSM Stats diff --git a/lgsm/config-default/config-lgsm/fctrserver/_default.cfg b/lgsm/config-default/config-lgsm/fctrserver/_default.cfg index 08f751b8f0..ef803e113d 100644 --- a/lgsm/config-default/config-lgsm/fctrserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/fctrserver/_default.cfg @@ -18,6 +18,10 @@ branch="stable" # values: stable, experimental ## Server Parameters | https://docs.linuxgsm.com/configuration/start-parameters#additional-parameters startparameters="--bind ${ip} --start-server-load-latest --server-settings ${servercfgfullpath} --port ${port} --rcon-port ${rconport} --rcon-password ${rconpassword}" +## Extra Parameters | https://docs.linuxgsm.com/configuration/start-parameters#extra-parameters +# Added to the end of startparameters. +extraparams="" + #### LinuxGSM Settings #### ## LinuxGSM Stats diff --git a/lgsm/config-default/config-lgsm/fofserver/_default.cfg b/lgsm/config-default/config-lgsm/fofserver/_default.cfg index a4a2f2e670..9947ec4117 100644 --- a/lgsm/config-default/config-lgsm/fofserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/fofserver/_default.cfg @@ -19,6 +19,10 @@ maxplayers="20" ## Server Parameters | https://docs.linuxgsm.com/configuration/start-parameters#additional-parameters startparameters="-game fof -strictportbind -ip ${ip} -port ${port} +clientport ${clientport} +tv_port ${sourcetvport} +map ${defaultmap} +servercfgfile ${servercfg} -maxplayers ${maxplayers}" +## Extra Parameters | https://docs.linuxgsm.com/configuration/start-parameters#extra-parameters +# Added to the end of startparameters. +extraparams="" + #### LinuxGSM Settings #### ## LinuxGSM Stats diff --git a/lgsm/config-default/config-lgsm/gmodserver/_default.cfg b/lgsm/config-default/config-lgsm/gmodserver/_default.cfg index ccae6e6422..3760313844 100644 --- a/lgsm/config-default/config-lgsm/gmodserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/gmodserver/_default.cfg @@ -29,6 +29,10 @@ gslt="" ## Server Parameters | https://docs.linuxgsm.com/configuration/start-parameters#additional-parameters startparameters="-game garrysmod -strictportbind -ip ${ip} -port ${port} -tickrate ${tickrate} +host_workshop_collection ${wscollectionid} +clientport ${clientport} +tv_port ${sourcetvport} +gamemode ${gamemode} +map ${defaultmap} +sv_setsteamaccount ${gslt} +servercfgfile ${servercfg} -maxplayers ${maxplayers} -disableluarefresh" +## Extra Parameters | https://docs.linuxgsm.com/configuration/start-parameters#extra-parameters +# Added to the end of startparameters. +extraparams="" + #### LinuxGSM Settings #### ## LinuxGSM Stats diff --git a/lgsm/config-default/config-lgsm/hcuserver/_default.cfg b/lgsm/config-default/config-lgsm/hcuserver/_default.cfg index c389135246..7e0fc55867 100644 --- a/lgsm/config-default/config-lgsm/hcuserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/hcuserver/_default.cfg @@ -19,6 +19,10 @@ servername="LinuxGSM" ## Server Parameters | https://docs.linuxgsm.com/configuration/start-parameters#additional-parameters startparameters="${defaultmap}?MaxPlayers=${maxplayers} -ServerName='${servername}' -Port=${port} -QueryPort=${queryport}" +## Extra Parameters | https://docs.linuxgsm.com/configuration/start-parameters#extra-parameters +# Added to the end of startparameters. +extraparams="" + ## Server Parameters for Plague mode #startparameters="${defaultmap}?Game=PL?MapList=KidsBedroom,Garden,Hallway_Simple,Attic_Daytime,Garage,Shed,Kitchen,Hallway_Hard,ToyPalace,Bathroom?MaxPlayers=${maxplayers}?WeaponTypes=7?TimeLimit=600 -ServerName='${servername}' -Port=${port} -QueryPort=${queryport} -NOCONSOLE -unattended" diff --git a/lgsm/config-default/config-lgsm/hl2dmserver/_default.cfg b/lgsm/config-default/config-lgsm/hl2dmserver/_default.cfg index a1d6e4390c..914f83759f 100644 --- a/lgsm/config-default/config-lgsm/hl2dmserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/hl2dmserver/_default.cfg @@ -21,6 +21,10 @@ maxplayers="16" ## Server Parameters | https://docs.linuxgsm.com/configuration/start-parameters#additional-parameters startparameters="-game hl2mp -strictportbind -ip ${ip} -port ${port} +clientport ${clientport} +tv_port ${sourcetvport} +map ${defaultmap} +servercfgfile ${servercfg} -maxplayers ${maxplayers}" +## Extra Parameters | https://docs.linuxgsm.com/configuration/start-parameters#extra-parameters +# Added to the end of startparameters. +extraparams="" + #### LinuxGSM Settings #### ## LinuxGSM Stats diff --git a/lgsm/config-default/config-lgsm/hldmserver/_default.cfg b/lgsm/config-default/config-lgsm/hldmserver/_default.cfg index 69ee4dddbd..98bafb2903 100644 --- a/lgsm/config-default/config-lgsm/hldmserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/hldmserver/_default.cfg @@ -18,6 +18,10 @@ maxplayers="16" ## Server Parameters | https://docs.linuxgsm.com/configuration/start-parameters#additional-parameters startparameters="-game valve -strictportbind +ip ${ip} -port ${port} +clientport ${clientport} +map ${defaultmap} +servercfgfile ${servercfg} -maxplayers ${maxplayers}" +## Extra Parameters | https://docs.linuxgsm.com/configuration/start-parameters#extra-parameters +# Added to the end of startparameters. +extraparams="" + #### LinuxGSM Settings #### ## LinuxGSM Stats diff --git a/lgsm/config-default/config-lgsm/hldmsserver/_default.cfg b/lgsm/config-default/config-lgsm/hldmsserver/_default.cfg index 8fb2e338d0..7153d9c761 100644 --- a/lgsm/config-default/config-lgsm/hldmsserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/hldmsserver/_default.cfg @@ -19,6 +19,10 @@ maxplayers="16" ## Server Parameters | https://docs.linuxgsm.com/configuration/start-parameters#additional-parameters startparameters="-game hl1mp -strictportbind -ip ${ip} -port ${port} +clientport ${clientport} +tv_port ${sourcetvport} +map ${defaultmap} +servercfgfile ${servercfg} -maxplayers ${maxplayers}" +## Extra Parameters | https://docs.linuxgsm.com/configuration/start-parameters#extra-parameters +# Added to the end of startparameters. +extraparams="" + #### LinuxGSM Settings #### ## LinuxGSM Stats diff --git a/lgsm/config-default/config-lgsm/hlwonserver/_default.cfg b/lgsm/config-default/config-lgsm/hlwonserver/_default.cfg index db21837476..0cefba9d37 100644 --- a/lgsm/config-default/config-lgsm/hlwonserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/hlwonserver/_default.cfg @@ -18,6 +18,10 @@ maxplayers="16" ## Server Parameters | https://docs.linuxgsm.com/configuration/start-parameters#additional-parameters startparameters="-game valve -binary ./hlds_i686 -noipx -insecure +ip ${ip} -port ${port} +clientport ${clientport} +map ${defaultmap} +servercfgfile ${servercfg} -maxplayers ${maxplayers}" +## Extra Parameters | https://docs.linuxgsm.com/configuration/start-parameters#extra-parameters +# Added to the end of startparameters. +extraparams="" + #### LinuxGSM Settings #### ## LinuxGSM Stats diff --git a/lgsm/config-default/config-lgsm/hwserver/_default.cfg b/lgsm/config-default/config-lgsm/hwserver/_default.cfg index 2dab091f68..24762aa772 100644 --- a/lgsm/config-default/config-lgsm/hwserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/hwserver/_default.cfg @@ -29,6 +29,10 @@ loadsave="" # http://hurtworld.wikia.com/wiki/Hosting_A_Server startparameters="-batchmode -nographics -logfile ${gamelog} -exec \"host ${port} ${defaultmap} ${loadsave};queryport ${queryport};maxplayers ${maxplayers};servername ${servername};creativemode ${creativemode}${workshoploadmods};addadmin ${admins}\"" +## Extra Parameters | https://docs.linuxgsm.com/configuration/start-parameters#extra-parameters +# Added to the end of startparameters. +extraparams="" + ## Steam Workshop Mods | https://docs.linuxgsm.com/steamcmd/workshop # Workshop item or collection IDs, separated by spaces. Collections are expanded. # Downloaded with SteamCMD and loaded with loadmod on start. If you set your own startparameters, keep ${workshoploadmods} in -exec. diff --git a/lgsm/config-default/config-lgsm/hytserver/_default.cfg b/lgsm/config-default/config-lgsm/hytserver/_default.cfg index 074e24b3bd..d98174c77c 100644 --- a/lgsm/config-default/config-lgsm/hytserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/hytserver/_default.cfg @@ -22,6 +22,10 @@ port="5520" ## Server Parameters | https://docs.linuxgsm.com/configuration/start-parameters#additional-parameters startparameters="--bind ${ip}:${port}" +## Extra Parameters | https://docs.linuxgsm.com/configuration/start-parameters#extra-parameters +# Added to the end of startparameters. +extraparams="" + ## Release Settings # Patchline (release|pre-release) hytalepatchline="release" diff --git a/lgsm/config-default/config-lgsm/hzserver/_default.cfg b/lgsm/config-default/config-lgsm/hzserver/_default.cfg index 9653944b75..12f5c5af11 100644 --- a/lgsm/config-default/config-lgsm/hzserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/hzserver/_default.cfg @@ -16,6 +16,10 @@ queryport="27015" ## Server Parameters | https://docs.linuxgsm.com/configuration/start-parameters#additional-parameters startparameters="-log -port=${port} -queryport=${queryport} -steamservername=${servername}" +## Extra Parameters | https://docs.linuxgsm.com/configuration/start-parameters#extra-parameters +# Added to the end of startparameters. +extraparams="" + #### LinuxGSM Settings #### ## LinuxGSM Stats diff --git a/lgsm/config-default/config-lgsm/insserver/_default.cfg b/lgsm/config-default/config-lgsm/insserver/_default.cfg index 8bde6ab8e4..e377685b41 100644 --- a/lgsm/config-default/config-lgsm/insserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/insserver/_default.cfg @@ -25,6 +25,10 @@ gslt="" ## Server Parameters | https://docs.linuxgsm.com/configuration/start-parameters#additional-parameters startparameters="-game insurgency -strictportbind -ip ${ip} -port ${port} +clientport ${clientport} +tv_port ${sourcetvport} -tickrate ${tickrate} +sv_setsteamaccount ${gslt} +map ${defaultmap} +servercfgfile ${servercfg} -maxplayers ${maxplayers} -workshop -norestart" +## Extra Parameters | https://docs.linuxgsm.com/configuration/start-parameters#extra-parameters +# Added to the end of startparameters. +extraparams="" + #### LinuxGSM Settings #### ## LinuxGSM Stats diff --git a/lgsm/config-default/config-lgsm/inssserver/_default.cfg b/lgsm/config-default/config-lgsm/inssserver/_default.cfg index d854cbc0db..ebd573677d 100644 --- a/lgsm/config-default/config-lgsm/inssserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/inssserver/_default.cfg @@ -28,6 +28,10 @@ gslt="" ## Game Server Docs | https://mod.io/g/insurgencysandstorm/r/server-admin-guide startparameters="${defaultmap}?Scenario=${defaultscenario}?MaxPlayers=${maxplayers} -Port=${port} -QueryPort=${queryport} -hostname='${servername}' -Rcon -RconPassword=${rconpassword} -RconListenPort=${rconport} -GSLTToken=${gslt} -log" +## Extra Parameters | https://docs.linuxgsm.com/configuration/start-parameters#extra-parameters +# Added to the end of startparameters. +extraparams="" + #### LinuxGSM Settings #### ## LinuxGSM Stats diff --git a/lgsm/config-default/config-lgsm/iosserver/_default.cfg b/lgsm/config-default/config-lgsm/iosserver/_default.cfg index 1e42b23be4..e6be819052 100644 --- a/lgsm/config-default/config-lgsm/iosserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/iosserver/_default.cfg @@ -19,6 +19,10 @@ maxplayers="32" ## Server Parameters | https://docs.linuxgsm.com/configuration/start-parameters#additional-parameters startparameters="-game iosoccer -strictportbind -ip ${ip} -port ${port} +clientport ${clientport} +tv_port ${sourcetvport} +map ${defaultmap} +servercfgfile ${servercfg} -maxplayers ${maxplayers}" +## Extra Parameters | https://docs.linuxgsm.com/configuration/start-parameters#extra-parameters +# Added to the end of startparameters. +extraparams="" + #### LinuxGSM Settings #### ## LinuxGSM Stats diff --git a/lgsm/config-default/config-lgsm/jbep3server/_default.cfg b/lgsm/config-default/config-lgsm/jbep3server/_default.cfg index 1025826a29..53dc1aab3c 100644 --- a/lgsm/config-default/config-lgsm/jbep3server/_default.cfg +++ b/lgsm/config-default/config-lgsm/jbep3server/_default.cfg @@ -19,6 +19,10 @@ maxplayers="24" ## Server Parameters | https://docs.linuxgsm.com/configuration/start-parameters#additional-parameters startparameters="-game jbep3 -strictportbind -ip ${ip} -port ${port} +clientport ${clientport} +tv_port ${sourcetvport} +map ${defaultmap} +servercfgfile ${servercfg} -maxplayers ${maxplayers}" +## Extra Parameters | https://docs.linuxgsm.com/configuration/start-parameters#extra-parameters +# Added to the end of startparameters. +extraparams="" + #### LinuxGSM Settings #### ## LinuxGSM Stats diff --git a/lgsm/config-default/config-lgsm/jc2server/_default.cfg b/lgsm/config-default/config-lgsm/jc2server/_default.cfg index 7ffde3756b..eb9f356b7f 100644 --- a/lgsm/config-default/config-lgsm/jc2server/_default.cfg +++ b/lgsm/config-default/config-lgsm/jc2server/_default.cfg @@ -11,6 +11,10 @@ ## Server Parameters | https://docs.linuxgsm.com/configuration/start-parameters#additional-parameters startparameters="" +## Extra Parameters | https://docs.linuxgsm.com/configuration/start-parameters#extra-parameters +# Added to the end of startparameters. +extraparams="" + #### LinuxGSM Settings #### ## LinuxGSM Stats diff --git a/lgsm/config-default/config-lgsm/jc3server/_default.cfg b/lgsm/config-default/config-lgsm/jc3server/_default.cfg index 66a54035af..3f4138a266 100644 --- a/lgsm/config-default/config-lgsm/jc3server/_default.cfg +++ b/lgsm/config-default/config-lgsm/jc3server/_default.cfg @@ -11,6 +11,10 @@ ## Server Parameters | https://docs.linuxgsm.com/configuration/start-parameters#additional-parameters startparameters="" +## Extra Parameters | https://docs.linuxgsm.com/configuration/start-parameters#extra-parameters +# Added to the end of startparameters. +extraparams="" + #### LinuxGSM Settings #### ## LinuxGSM Stats diff --git a/lgsm/config-default/config-lgsm/jk2server/_default.cfg b/lgsm/config-default/config-lgsm/jk2server/_default.cfg index de036f81c0..22844d9a86 100644 --- a/lgsm/config-default/config-lgsm/jk2server/_default.cfg +++ b/lgsm/config-default/config-lgsm/jk2server/_default.cfg @@ -20,6 +20,10 @@ defaultmap="ffa_bespin" ## Server Parameters | https://docs.linuxgsm.com/configuration/start-parameters#additional-parameters startparameters="+set sv_punkbuster 0 +set fs_basepath ${serverfiles} +set net_ip ${ip} +set net_port ${port} +map ${defaultmap} +exec ${servercfg}" +## Extra Parameters | https://docs.linuxgsm.com/configuration/start-parameters#extra-parameters +# Added to the end of startparameters. +extraparams="" + #### LinuxGSM Settings #### ## LinuxGSM Stats diff --git a/lgsm/config-default/config-lgsm/jk3server/_default.cfg b/lgsm/config-default/config-lgsm/jk3server/_default.cfg index 576b1e0a33..5bf9ff838c 100644 --- a/lgsm/config-default/config-lgsm/jk3server/_default.cfg +++ b/lgsm/config-default/config-lgsm/jk3server/_default.cfg @@ -21,6 +21,10 @@ defaultmap="mp/ffa3" ## Server Parameters | https://docs.linuxgsm.com/configuration/start-parameters#additional-parameters startparameters="+set dedicated 2 +set fs_basepath \"${systemdir}\" +set fs_homepath \"${systemdir}\" +set net_ip ${ip} +set net_port ${port} +exec ${servercfg} +map ${defaultmap}" +## Extra Parameters | https://docs.linuxgsm.com/configuration/start-parameters#extra-parameters +# Added to the end of startparameters. +extraparams="" + #### LinuxGSM Settings #### ## LinuxGSM Stats diff --git a/lgsm/config-default/config-lgsm/kf2server/_default.cfg b/lgsm/config-default/config-lgsm/kf2server/_default.cfg index 1dbea1f6e6..24335c67e7 100644 --- a/lgsm/config-default/config-lgsm/kf2server/_default.cfg +++ b/lgsm/config-default/config-lgsm/kf2server/_default.cfg @@ -17,6 +17,10 @@ gamemode="KFGameContent.KFGameInfo_VersusSurvival" ## Server Parameters | https://docs.linuxgsm.com/configuration/start-parameters#additional-parameters startparameters="\"${defaultmap}?Game=${gamemode}?ConfigSubDir=${selfname} -QueryPort=${queryport}\"" +## Extra Parameters | https://docs.linuxgsm.com/configuration/start-parameters#extra-parameters +# Added to the end of startparameters. +extraparams="" + #### LinuxGSM Settings #### ## LinuxGSM Stats diff --git a/lgsm/config-default/config-lgsm/kfserver/_default.cfg b/lgsm/config-default/config-lgsm/kfserver/_default.cfg index 90d4f0e066..0dc0e7bc0b 100644 --- a/lgsm/config-default/config-lgsm/kfserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/kfserver/_default.cfg @@ -19,6 +19,10 @@ defaultmap="KF-BioticsLab.rom" ## Server Parameters | https://docs.linuxgsm.com/configuration/start-parameters#additional-parameters startparameters="server ${defaultmap}?game=KFmod.KFGameType?VACSecured=true -nohomedir ini=${servercfg} log=${gamelog}" +## Extra Parameters | https://docs.linuxgsm.com/configuration/start-parameters#extra-parameters +# Added to the end of startparameters. +extraparams="" + ## Server Parameters for Objective mode #defaultmap="KFO-Steamland" #startparameters="server ${defaultmap}?Game=KFStoryGame.KFStoryGame?VACSecured=true -nohomedir ini=${servercfg} log=${gamelog}" diff --git a/lgsm/config-default/config-lgsm/l4d2server/_default.cfg b/lgsm/config-default/config-lgsm/l4d2server/_default.cfg index d525c4b387..8e8cf5767a 100644 --- a/lgsm/config-default/config-lgsm/l4d2server/_default.cfg +++ b/lgsm/config-default/config-lgsm/l4d2server/_default.cfg @@ -18,6 +18,10 @@ maxplayers="8" ## Server Parameters | https://docs.linuxgsm.com/configuration/start-parameters#additional-parameters startparameters="-game left4dead2 -strictportbind -ip ${ip} -port ${port} +clientport ${clientport} +map ${defaultmap} +servercfgfile ${servercfg} -maxplayers ${maxplayers}" +## Extra Parameters | https://docs.linuxgsm.com/configuration/start-parameters#extra-parameters +# Added to the end of startparameters. +extraparams="" + ## Steam Workshop Mods | https://docs.linuxgsm.com/steamcmd/workshop # Workshop item or collection IDs, separated by spaces. Collections are expanded. # Installed to serverfiles/workshop and linked into left4dead2/addons. Run ./l4d2server workshop-update after changing, or let update apply it. diff --git a/lgsm/config-default/config-lgsm/l4dserver/_default.cfg b/lgsm/config-default/config-lgsm/l4dserver/_default.cfg index ba0322710a..ed163f8633 100644 --- a/lgsm/config-default/config-lgsm/l4dserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/l4dserver/_default.cfg @@ -18,6 +18,10 @@ maxplayers="8" ## Server Parameters | https://docs.linuxgsm.com/configuration/start-parameters#additional-parameters startparameters="-game left4dead -strictportbind -ip ${ip} -port ${port} +clientport ${clientport} +map ${defaultmap} -maxplayers ${maxplayers}" +## Extra Parameters | https://docs.linuxgsm.com/configuration/start-parameters#extra-parameters +# Added to the end of startparameters. +extraparams="" + #### LinuxGSM Settings #### ## LinuxGSM Stats diff --git a/lgsm/config-default/config-lgsm/mcbserver/_default.cfg b/lgsm/config-default/config-lgsm/mcbserver/_default.cfg index 1f79054791..954c42e965 100644 --- a/lgsm/config-default/config-lgsm/mcbserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/mcbserver/_default.cfg @@ -11,6 +11,10 @@ ## Server Parameters | https://docs.linuxgsm.com/configuration/start-parameters#additional-parameters startparameters="" +## Extra Parameters | https://docs.linuxgsm.com/configuration/start-parameters#extra-parameters +# Added to the end of startparameters. +extraparams="" + # Version (latest|1.18.33.02) mcversion="latest" diff --git a/lgsm/config-default/config-lgsm/mcserver/_default.cfg b/lgsm/config-default/config-lgsm/mcserver/_default.cfg index daf0ef423b..ee7d871ef9 100644 --- a/lgsm/config-default/config-lgsm/mcserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/mcserver/_default.cfg @@ -14,6 +14,10 @@ javaram="1024" # -Xmx$1024M ## Server Parameters | https://docs.linuxgsm.com/configuration/start-parameters#additional-parameters startparameters="nogui" +## Extra Parameters | https://docs.linuxgsm.com/configuration/start-parameters#extra-parameters +# Added to the end of startparameters. +extraparams="" + ## Release Settings | https://docs.linuxgsm.com/game-servers/minecraft#release-settings # Branch (release|snapshot) branch="release" diff --git a/lgsm/config-default/config-lgsm/mcvserver/_default.cfg b/lgsm/config-default/config-lgsm/mcvserver/_default.cfg index 907ce818fa..135900b2f2 100644 --- a/lgsm/config-default/config-lgsm/mcvserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/mcvserver/_default.cfg @@ -22,6 +22,10 @@ tickrate="64" ## Server Parameters | https://docs.linuxgsm.com/configuration/start-parameters#additional-parameters startparameters="-game vietnam -usercon -strictportbind -ip ${ip} -port ${port} +clientport ${clientport} +tv_port ${sourcetvport} -tickrate ${tickrate} +map ${defaultmap} +servercfgfile ${servercfg} -maxplayers_override ${maxplayers} +game_type ${game_type} +game_mode ${game_mode} -nobreakpad" +## Extra Parameters | https://docs.linuxgsm.com/configuration/start-parameters#extra-parameters +# Added to the end of startparameters. +extraparams="" + #### LinuxGSM Settings #### ## LinuxGSM Stats diff --git a/lgsm/config-default/config-lgsm/mhserver/_default.cfg b/lgsm/config-default/config-lgsm/mhserver/_default.cfg index 04d50aeb03..d7ec8d55dd 100644 --- a/lgsm/config-default/config-lgsm/mhserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/mhserver/_default.cfg @@ -20,6 +20,10 @@ defaultmap="FFA_ThePit" ## Game Server Docs | https://mordhau.fandom.com/wiki/Dedicated_Server_Hosting_Guide startparameters="Mordhau ${defaultmap} -MultiHome=${ip} -Port=${port} -BeaconPort=${beaconport} -QueryPort=${queryport} -GameIni=${servercfgfullpath} -log" +## Extra Parameters | https://docs.linuxgsm.com/configuration/start-parameters#extra-parameters +# Added to the end of startparameters. +extraparams="" + #### LinuxGSM Settings #### ## LinuxGSM Stats diff --git a/lgsm/config-default/config-lgsm/mohaaserver/_default.cfg b/lgsm/config-default/config-lgsm/mohaaserver/_default.cfg index 69ae5b81d6..c43978c53b 100644 --- a/lgsm/config-default/config-lgsm/mohaaserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/mohaaserver/_default.cfg @@ -16,6 +16,10 @@ defaultmap="dm/mohdm1" ## Server Parameters | https://docs.linuxgsm.com/configuration/start-parameters#additional-parameters startparameters="+set sv_punkbuster 0 +set fs_basepath ${serverfiles} +set fs_outputpath ${gamelogdir} +set dedicated 2 +set net_ip ${ip} +set net_port ${port} +map ${defaultmap} +exec ${servercfg} " +## Extra Parameters | https://docs.linuxgsm.com/configuration/start-parameters#extra-parameters +# Added to the end of startparameters. +extraparams="" + #### LinuxGSM Settings #### ## LinuxGSM Stats diff --git a/lgsm/config-default/config-lgsm/momserver/_default.cfg b/lgsm/config-default/config-lgsm/momserver/_default.cfg index 3b92ccbfbe..9096e7d098 100644 --- a/lgsm/config-default/config-lgsm/momserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/momserver/_default.cfg @@ -17,6 +17,10 @@ beaconport="15000" ## Game Server Docs | https://memoriesofmars.fandom.com/wiki/Dedicated_Servers startparameters="-MultiHome=${ip} -Port=${port} -BeaconPort=${beaconport} -log" +## Extra Parameters | https://docs.linuxgsm.com/configuration/start-parameters#extra-parameters +# Added to the end of startparameters. +extraparams="" + #### LinuxGSM Settings #### ## LinuxGSM Stats diff --git a/lgsm/config-default/config-lgsm/mtaserver/_default.cfg b/lgsm/config-default/config-lgsm/mtaserver/_default.cfg index eedd83fbd5..f6546e092a 100644 --- a/lgsm/config-default/config-lgsm/mtaserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/mtaserver/_default.cfg @@ -14,6 +14,10 @@ ip="0.0.0.0" ## Server Parameters | https://docs.linuxgsm.com/configuration/start-parameters#additional-parameters startparameters="" +## Extra Parameters | https://docs.linuxgsm.com/configuration/start-parameters#extra-parameters +# Added to the end of startparameters. +extraparams="" + #### LinuxGSM Settings #### ## LinuxGSM Stats diff --git a/lgsm/config-default/config-lgsm/ndserver/_default.cfg b/lgsm/config-default/config-lgsm/ndserver/_default.cfg index 322a5a3fc5..93df86fd6d 100644 --- a/lgsm/config-default/config-lgsm/ndserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/ndserver/_default.cfg @@ -24,6 +24,10 @@ maxplayers="32" ## Server Parameters | https://docs.linuxgsm.com/configuration/start-parameters#additional-parameters startparameters="-game nucleardawn -strictportbind -ip ${ip} -port ${port} +clientport ${clientport} +tv_port ${sourcetvport} +map ${defaultmap} +servercfgfile ${servercfg} -maxplayers ${maxplayers}" +## Extra Parameters | https://docs.linuxgsm.com/configuration/start-parameters#extra-parameters +# Added to the end of startparameters. +extraparams="" + #### LinuxGSM Settings #### ## LinuxGSM Stats diff --git a/lgsm/config-default/config-lgsm/necserver/_default.cfg b/lgsm/config-default/config-lgsm/necserver/_default.cfg index 555d0cf008..10132c1876 100644 --- a/lgsm/config-default/config-lgsm/necserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/necserver/_default.cfg @@ -14,6 +14,10 @@ worldname="MyWorld" ## Server Parameters | https://docs.linuxgsm.com/configuration/start-parameters#additional-parameters startparameters="-localdir -world ${worldname}" +## Extra Parameters | https://docs.linuxgsm.com/configuration/start-parameters#extra-parameters +# Added to the end of startparameters. +extraparams="" + #### LinuxGSM Settings #### ## LinuxGSM Stats diff --git a/lgsm/config-default/config-lgsm/nmrihserver/_default.cfg b/lgsm/config-default/config-lgsm/nmrihserver/_default.cfg index 8ab45a0106..5fe65c0d31 100644 --- a/lgsm/config-default/config-lgsm/nmrihserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/nmrihserver/_default.cfg @@ -24,6 +24,10 @@ gslt="" ## Server Parameters | https://docs.linuxgsm.com/configuration/start-parameters#additional-parameters startparameters="-game nmrih -strictportbind -ip ${ip} -port ${port} +clientport ${clientport} +tv_port ${sourcetvport} +map ${defaultmap} +sv_setsteamaccount ${gslt} +servercfgfile ${servercfg} -maxplayers ${maxplayers}" +## Extra Parameters | https://docs.linuxgsm.com/configuration/start-parameters#extra-parameters +# Added to the end of startparameters. +extraparams="" + #### LinuxGSM Settings #### ## LinuxGSM Stats diff --git a/lgsm/config-default/config-lgsm/ns2cserver/_default.cfg b/lgsm/config-default/config-lgsm/ns2cserver/_default.cfg index 75236bf2a4..6fc341a382 100644 --- a/lgsm/config-default/config-lgsm/ns2cserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/ns2cserver/_default.cfg @@ -26,6 +26,10 @@ serverpassword="" ## Server Parameters | https://docs.linuxgsm.com/configuration/start-parameters#additional-parameters startparameters="-name '${servername}' -port ${port} -webadmin -webdomain ${ip} -webuser ${httpuser} -webpassword '${httppassword}' -webport ${httpport} -map ${defaultmap} -limit ${maxplayers} -config_path '${servercfgdir}' -modstorage '${modstoragedir}' -mods '${mods}'" +## Extra Parameters | https://docs.linuxgsm.com/configuration/start-parameters#extra-parameters +# Added to the end of startparameters. +extraparams="" + #### LinuxGSM Settings #### ## LinuxGSM Stats diff --git a/lgsm/config-default/config-lgsm/ns2server/_default.cfg b/lgsm/config-default/config-lgsm/ns2server/_default.cfg index 4e9e83cb16..5eeb8d7a80 100644 --- a/lgsm/config-default/config-lgsm/ns2server/_default.cfg +++ b/lgsm/config-default/config-lgsm/ns2server/_default.cfg @@ -27,6 +27,10 @@ serverpassword="" ## Server Parameters | https://docs.linuxgsm.com/configuration/start-parameters#additional-parameters startparameters="-name '${servername}' -port ${port} -webadmin -webdomain ${ip} -webuser ${httpuser} -webpassword '${httppassword}' -webport ${httpport} -startmodserver -modserverport ${modserverport} -map ${defaultmap} -limit ${maxplayers} -speclimit ${maxspectators} -config_path '${servercfgdir}' -logdir '${gamelogdir}' -modstorage '${modstoragedir}'" +## Extra Parameters | https://docs.linuxgsm.com/configuration/start-parameters#extra-parameters +# Added to the end of startparameters. +extraparams="" + #### LinuxGSM Settings #### ## LinuxGSM Stats diff --git a/lgsm/config-default/config-lgsm/nsserver/_default.cfg b/lgsm/config-default/config-lgsm/nsserver/_default.cfg index 2c3c24cc40..826d1273c4 100644 --- a/lgsm/config-default/config-lgsm/nsserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/nsserver/_default.cfg @@ -18,6 +18,10 @@ maxplayers="16" ## Server Parameters | https://docs.linuxgsm.com/configuration/start-parameters#additional-parameters startparameters="-game ns -strictportbind +ip ${ip} -port ${port} +clientport ${clientport} +map ${defaultmap} +servercfgfile ${servercfg} -maxplayers ${maxplayers}" +## Extra Parameters | https://docs.linuxgsm.com/configuration/start-parameters#extra-parameters +# Added to the end of startparameters. +extraparams="" + #### LinuxGSM Settings #### ## LinuxGSM Stats diff --git a/lgsm/config-default/config-lgsm/ohdserver/_default.cfg b/lgsm/config-default/config-lgsm/ohdserver/_default.cfg index 68b0f3bb60..947f70ec12 100644 --- a/lgsm/config-default/config-lgsm/ohdserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/ohdserver/_default.cfg @@ -21,6 +21,10 @@ maxplayers="16" ## Server Parameters | https://docs.linuxgsm.com/configuration/start-parameters#additional-parameters startparameters="${defaultmap}?MaxPlayers=${maxplayers} -MultiHome=${ip} -Port=${port} -QueryPort=${queryport} -RconPort=${rconport} -SteamServerName='${servername}' -log" +## Extra Parameters | https://docs.linuxgsm.com/configuration/start-parameters#extra-parameters +# Added to the end of startparameters. +extraparams="" + ## Steam Workshop Mods | https://docs.linuxgsm.com/steamcmd/workshop # Workshop item or collection IDs, separated by spaces. Collections are expanded. # Installed to HarshDoorstop/Mods. Select mod maps and modes with defaultmap or startparameters. diff --git a/lgsm/config-default/config-lgsm/onsetserver/_default.cfg b/lgsm/config-default/config-lgsm/onsetserver/_default.cfg index d6ed8626f0..bfe543607a 100644 --- a/lgsm/config-default/config-lgsm/onsetserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/onsetserver/_default.cfg @@ -12,6 +12,10 @@ ## Game Server Docs | https://dev.playonset.com/wiki/DedicatedServer startparameters="--config ${servercfgfullpath}" +## Extra Parameters | https://docs.linuxgsm.com/configuration/start-parameters#extra-parameters +# Added to the end of startparameters. +extraparams="" + #### LinuxGSM Settings #### ## LinuxGSM Stats diff --git a/lgsm/config-default/config-lgsm/opforserver/_default.cfg b/lgsm/config-default/config-lgsm/opforserver/_default.cfg index c55598b917..05a0d62a84 100644 --- a/lgsm/config-default/config-lgsm/opforserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/opforserver/_default.cfg @@ -18,6 +18,10 @@ maxplayers="16" ## Server Parameters | https://docs.linuxgsm.com/configuration/start-parameters#additional-parameters startparameters="-game gearbox -strictportbind +ip ${ip} -port ${port} +clientport ${clientport} +map ${defaultmap} +servercfgfile ${servercfg} -maxplayers ${maxplayers}" +## Extra Parameters | https://docs.linuxgsm.com/configuration/start-parameters#extra-parameters +# Added to the end of startparameters. +extraparams="" + #### LinuxGSM Settings #### ## LinuxGSM Stats diff --git a/lgsm/config-default/config-lgsm/pc2server/_default.cfg b/lgsm/config-default/config-lgsm/pc2server/_default.cfg index dc39d4f908..d13e8e87af 100644 --- a/lgsm/config-default/config-lgsm/pc2server/_default.cfg +++ b/lgsm/config-default/config-lgsm/pc2server/_default.cfg @@ -15,6 +15,10 @@ steampass='password' ## Server Parameters | https://docs.linuxgsm.com/configuration/start-parameters#additional-parameters startparameters="--config ${servercfg}" +## Extra Parameters | https://docs.linuxgsm.com/configuration/start-parameters#extra-parameters +# Added to the end of startparameters. +extraparams="" + #### LinuxGSM Settings #### ## LinuxGSM Stats diff --git a/lgsm/config-default/config-lgsm/pcserver/_default.cfg b/lgsm/config-default/config-lgsm/pcserver/_default.cfg index 3417df9a86..2eb2d9d9b2 100644 --- a/lgsm/config-default/config-lgsm/pcserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/pcserver/_default.cfg @@ -11,6 +11,10 @@ ## Server Parameters | https://docs.linuxgsm.com/configuration/start-parameters#additional-parameters startparameters="--config ${servercfg}" +## Extra Parameters | https://docs.linuxgsm.com/configuration/start-parameters#extra-parameters +# Added to the end of startparameters. +extraparams="" + #### LinuxGSM Settings #### ## LinuxGSM Stats diff --git a/lgsm/config-default/config-lgsm/pmcserver/_default.cfg b/lgsm/config-default/config-lgsm/pmcserver/_default.cfg index 4da2891aec..c70c7d65a0 100644 --- a/lgsm/config-default/config-lgsm/pmcserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/pmcserver/_default.cfg @@ -14,6 +14,10 @@ javaram="1024" # -Xmx$1024M ## Server Parameters | https://docs.linuxgsm.com/configuration/start-parameters#additional-parameters startparameters="nogui" +## Extra Parameters | https://docs.linuxgsm.com/configuration/start-parameters#extra-parameters +# Added to the end of startparameters. +extraparams="" + ## Release Settings | https://docs.linuxgsm.com/game-servers/minecraft#release-settings # Version (latest|1.16.5) mcversion="latest" diff --git a/lgsm/config-default/config-lgsm/pvkiiserver/_default.cfg b/lgsm/config-default/config-lgsm/pvkiiserver/_default.cfg index 81ff3fd340..a16e02fee0 100644 --- a/lgsm/config-default/config-lgsm/pvkiiserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/pvkiiserver/_default.cfg @@ -19,6 +19,10 @@ maxplayers="24" ## Server Parameters | https://docs.linuxgsm.com/configuration/start-parameters#additional-parameters startparameters="-game pvkii -strictportbind -ip ${ip} -port ${port} +clientport ${clientport} +tv_port ${sourcetvport} +map ${defaultmap} +servercfgfile ${servercfg} -maxplayers ${maxplayers}" +## Extra Parameters | https://docs.linuxgsm.com/configuration/start-parameters#extra-parameters +# Added to the end of startparameters. +extraparams="" + #### LinuxGSM Settings #### ## LinuxGSM Stats diff --git a/lgsm/config-default/config-lgsm/pvrserver/_default.cfg b/lgsm/config-default/config-lgsm/pvrserver/_default.cfg index ebf0ae8697..c1719a9116 100644 --- a/lgsm/config-default/config-lgsm/pvrserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/pvrserver/_default.cfg @@ -20,6 +20,10 @@ apikey="" ## Game Server Docs | http://pavlovwiki.com/index.php/Setting_up_a_dedicated_server startparameters="Pavlov ${defaultmap} -MultiHome=${ip} -Port=${port} ApiKey=${apikey} -log" +## Extra Parameters | https://docs.linuxgsm.com/configuration/start-parameters#extra-parameters +# Added to the end of startparameters. +extraparams="" + #### LinuxGSM Settings #### ## LinuxGSM Stats diff --git a/lgsm/config-default/config-lgsm/pwserver/_default.cfg b/lgsm/config-default/config-lgsm/pwserver/_default.cfg index 9ee1461acd..f312c9c0f0 100644 --- a/lgsm/config-default/config-lgsm/pwserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/pwserver/_default.cfg @@ -19,6 +19,10 @@ steamport="27015" ## Game Server Docs | https://tech.palworldgame.com/settings-and-operation/arguments startparameters="-publiclobby -useperfthreads -NoAsyncLoadingThread -UseMultithreadForDS -servername='${servername}' -port='${port}' -queryport='${steamport}'" +## Extra Parameters | https://docs.linuxgsm.com/configuration/start-parameters#extra-parameters +# Added to the end of startparameters. +extraparams="" + #### LinuxGSM Settings #### ## LinuxGSM Stats diff --git a/lgsm/config-default/config-lgsm/pzserver/_default.cfg b/lgsm/config-default/config-lgsm/pzserver/_default.cfg index 1f430c776b..19313b9009 100644 --- a/lgsm/config-default/config-lgsm/pzserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/pzserver/_default.cfg @@ -15,6 +15,10 @@ adminpassword="CHANGE_ME" ## Server Parameters | https://docs.linuxgsm.com/configuration/start-parameters#additional-parameters startparameters="-servername ${selfname} -adminpassword ${adminpassword}" +## Extra Parameters | https://docs.linuxgsm.com/configuration/start-parameters#extra-parameters +# Added to the end of startparameters. +extraparams="" + #### LinuxGSM Settings #### ## LinuxGSM Stats diff --git a/lgsm/config-default/config-lgsm/q2server/_default.cfg b/lgsm/config-default/config-lgsm/q2server/_default.cfg index bac93bb137..8a1b1896d9 100644 --- a/lgsm/config-default/config-lgsm/q2server/_default.cfg +++ b/lgsm/config-default/config-lgsm/q2server/_default.cfg @@ -16,6 +16,10 @@ defaultmap="q2dm1" ## Server Parameters | https://docs.linuxgsm.com/configuration/start-parameters#additional-parameters startparameters="+set dedicated 1 +set ip ${ip} +set port ${port} +exec ${servercfg} +set deathmatch 1 +map ${defaultmap}" +## Extra Parameters | https://docs.linuxgsm.com/configuration/start-parameters#extra-parameters +# Added to the end of startparameters. +extraparams="" + #### LinuxGSM Settings #### ## LinuxGSM Stats diff --git a/lgsm/config-default/config-lgsm/q3server/_default.cfg b/lgsm/config-default/config-lgsm/q3server/_default.cfg index e21dc0fdb4..175ac5aca8 100644 --- a/lgsm/config-default/config-lgsm/q3server/_default.cfg +++ b/lgsm/config-default/config-lgsm/q3server/_default.cfg @@ -16,6 +16,10 @@ defaultmap="q3dm17" ## Server Parameters | https://docs.linuxgsm.com/configuration/start-parameters#additional-parameters startparameters="+set sv_punkbuster 0 +set fs_basepath ${serverfiles} +set dedicated 2 +set com_hunkMegs 32 +set net_ip ${ip} +set net_port ${port} +map ${defaultmap} +exec ${servercfg}" +## Extra Parameters | https://docs.linuxgsm.com/configuration/start-parameters#extra-parameters +# Added to the end of startparameters. +extraparams="" + #### LinuxGSM Settings #### ## LinuxGSM Stats diff --git a/lgsm/config-default/config-lgsm/q4server/_default.cfg b/lgsm/config-default/config-lgsm/q4server/_default.cfg index 0be2a39066..c274ae12c1 100644 --- a/lgsm/config-default/config-lgsm/q4server/_default.cfg +++ b/lgsm/config-default/config-lgsm/q4server/_default.cfg @@ -18,6 +18,10 @@ port="28004" ## Server Parameters | https://docs.linuxgsm.com/configuration/start-parameters#additional-parameters startparameters="+set sv_punkbuster 0 +set fs_basepath ${serverfiles} +set net_port ${port} +exec ${servercfg}" +## Extra Parameters | https://docs.linuxgsm.com/configuration/start-parameters#extra-parameters +# Added to the end of startparameters. +extraparams="" + #### LinuxGSM Settings #### ## LinuxGSM Stats diff --git a/lgsm/config-default/config-lgsm/qlserver/_default.cfg b/lgsm/config-default/config-lgsm/qlserver/_default.cfg index 05ff7a340a..cc5b1d502e 100644 --- a/lgsm/config-default/config-lgsm/qlserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/qlserver/_default.cfg @@ -11,6 +11,10 @@ ## Server Parameters | https://docs.linuxgsm.com/configuration/start-parameters#additional-parameters startparameters="+exec ${servercfg}" +## Extra Parameters | https://docs.linuxgsm.com/configuration/start-parameters#extra-parameters +# Added to the end of startparameters. +extraparams="" + #### LinuxGSM Settings #### ## LinuxGSM Stats diff --git a/lgsm/config-default/config-lgsm/qwserver/_default.cfg b/lgsm/config-default/config-lgsm/qwserver/_default.cfg index 1b9d9d1cb0..481ff17911 100644 --- a/lgsm/config-default/config-lgsm/qwserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/qwserver/_default.cfg @@ -15,6 +15,10 @@ port="27500" ## Server Parameters | https://docs.linuxgsm.com/configuration/start-parameters#additional-parameters startparameters="-port ${port} -game ktx +exec ${servercfg}" +## Extra Parameters | https://docs.linuxgsm.com/configuration/start-parameters#extra-parameters +# Added to the end of startparameters. +extraparams="" + #### LinuxGSM Settings #### ## LinuxGSM Stats diff --git a/lgsm/config-default/config-lgsm/ricochetserver/_default.cfg b/lgsm/config-default/config-lgsm/ricochetserver/_default.cfg index f8002b0a19..fedb17b9ae 100644 --- a/lgsm/config-default/config-lgsm/ricochetserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/ricochetserver/_default.cfg @@ -18,6 +18,10 @@ maxplayers="16" ## Server Parameters | https://docs.linuxgsm.com/configuration/start-parameters#additional-parameters startparameters="-game ricochet -strictportbind +ip ${ip} -port ${port} +clientport ${clientport} +map ${defaultmap} +servercfgfile ${servercfg} -maxplayers ${maxplayers}" +## Extra Parameters | https://docs.linuxgsm.com/configuration/start-parameters#extra-parameters +# Added to the end of startparameters. +extraparams="" + #### LinuxGSM Settings #### ## LinuxGSM Stats diff --git a/lgsm/config-default/config-lgsm/roserver/_default.cfg b/lgsm/config-default/config-lgsm/roserver/_default.cfg index b4c92d66c8..92daaa4d3f 100644 --- a/lgsm/config-default/config-lgsm/roserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/roserver/_default.cfg @@ -19,6 +19,10 @@ defaultmap="RO-Arad.rom" ## Server Parameters | https://docs.linuxgsm.com/configuration/start-parameters#additional-parameters startparameters="server ${defaultmap}?game=ROGame.ROTeamGame?VACSecured=true -nohomedir ini=${servercfg} log=${gamelog}" +## Extra Parameters | https://docs.linuxgsm.com/configuration/start-parameters#extra-parameters +# Added to the end of startparameters. +extraparams="" + #### LinuxGSM Settings #### ## LinuxGSM Stats diff --git a/lgsm/config-default/config-lgsm/rsdwserver/_default.cfg b/lgsm/config-default/config-lgsm/rsdwserver/_default.cfg index 081d8dee48..a335bccfef 100644 --- a/lgsm/config-default/config-lgsm/rsdwserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/rsdwserver/_default.cfg @@ -20,6 +20,10 @@ port="7777" ## Game Server Docs | https://dragonwilds.runescape.wiki/w/Dedicated_Servers startparameters="-Port=${port} -log" +## Extra Parameters | https://docs.linuxgsm.com/configuration/start-parameters#extra-parameters +# Added to the end of startparameters. +extraparams="" + #### LinuxGSM Settings #### ## LinuxGSM Stats diff --git a/lgsm/config-default/config-lgsm/rtcwserver/_default.cfg b/lgsm/config-default/config-lgsm/rtcwserver/_default.cfg index 2241a144bf..be719a5355 100644 --- a/lgsm/config-default/config-lgsm/rtcwserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/rtcwserver/_default.cfg @@ -16,6 +16,10 @@ defaultmap="mp_beach" ## Server Parameters | https://docs.linuxgsm.com/configuration/start-parameters#additional-parameters startparameters="+set sv_punkbuster 0 +set fs_basepath ${serverfiles} +set dedicated 1 +set net_ip ${ip} +set net_port ${port} +exec ${servercfg} +map ${defaultmap}" +## Extra Parameters | https://docs.linuxgsm.com/configuration/start-parameters#extra-parameters +# Added to the end of startparameters. +extraparams="" + #### LinuxGSM Settings #### ## LinuxGSM Stats diff --git a/lgsm/config-default/config-lgsm/rustserver/_default.cfg b/lgsm/config-default/config-lgsm/rustserver/_default.cfg index f6dab1f4fa..105f7d36d4 100644 --- a/lgsm/config-default/config-lgsm/rustserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/rustserver/_default.cfg @@ -31,6 +31,10 @@ tags="" # values: monthly, biweekly, weekly, vanilla, hardcore, softc ## Server Parameters | https://docs.linuxgsm.com/configuration/start-parameters#additional-parameters startparameters="-batchmode +app.listenip ${ip} +app.port ${appport} +server.ip ${ip} +server.port ${port} +server.queryport ${queryport} +server.tickrate ${tickrate} +server.hostname \"${servername}\" +server.identity \"${selfname}\" +server.gamemode ${gamemode} +server.level \"${serverlevel}\" +server.seed ${seed} +server.salt ${salt} +server.maxplayers ${maxplayers} +server.worldsize ${worldsize} +server.saveinterval ${saveinterval} +rcon.web ${rconweb} +rcon.ip ${ip} +rcon.port ${rconport} +rcon.password \"${rconpassword}\" +server.tags ${tags} -logfile ${gamelog}" +## Extra Parameters | https://docs.linuxgsm.com/configuration/start-parameters#extra-parameters +# Added to the end of startparameters. +extraparams="" + #### LinuxGSM Settings #### ## LinuxGSM Stats diff --git a/lgsm/config-default/config-lgsm/rwrserver/_default.cfg b/lgsm/config-default/config-lgsm/rwrserver/_default.cfg index cf01d2b0b9..b2d4ee4b40 100644 --- a/lgsm/config-default/config-lgsm/rwrserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/rwrserver/_default.cfg @@ -26,6 +26,10 @@ startscript="${selfname}.as" ## Game Server Docs | https://runningwithrifles.fandom.com/wiki/How_to_host_a_different_game_mode_as_dedicated_server startparameters="" +## Extra Parameters | https://docs.linuxgsm.com/configuration/start-parameters#extra-parameters +# Added to the end of startparameters. +extraparams="" + #### LinuxGSM Settings #### ## LinuxGSM Stats diff --git a/lgsm/config-default/config-lgsm/rwserver/_default.cfg b/lgsm/config-default/config-lgsm/rwserver/_default.cfg index 5536e1a686..242e468169 100644 --- a/lgsm/config-default/config-lgsm/rwserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/rwserver/_default.cfg @@ -11,6 +11,10 @@ ## Server Parameters | https://docs.linuxgsm.com/configuration/start-parameters#additional-parameters startparameters="" +## Extra Parameters | https://docs.linuxgsm.com/configuration/start-parameters#extra-parameters +# Added to the end of startparameters. +extraparams="" + #### LinuxGSM Settings #### ## LinuxGSM Stats diff --git a/lgsm/config-default/config-lgsm/sampserver/_default.cfg b/lgsm/config-default/config-lgsm/sampserver/_default.cfg index ab2ae30364..6b54804860 100644 --- a/lgsm/config-default/config-lgsm/sampserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/sampserver/_default.cfg @@ -15,6 +15,10 @@ port="7777" ## Server Parameters | https://docs.linuxgsm.com/configuration/start-parameters#additional-parameters startparameters="" +## Extra Parameters | https://docs.linuxgsm.com/configuration/start-parameters#extra-parameters +# Added to the end of startparameters. +extraparams="" + #### LinuxGSM Settings #### ## LinuxGSM Stats diff --git a/lgsm/config-default/config-lgsm/sbotsserver/_default.cfg b/lgsm/config-default/config-lgsm/sbotsserver/_default.cfg index ad73ede403..5fc7e61ce3 100644 --- a/lgsm/config-default/config-lgsm/sbotsserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/sbotsserver/_default.cfg @@ -17,6 +17,10 @@ servername="LinuxGSM" ## Server Parameters | https://docs.linuxgsm.com/configuration/start-parameters#additional-parameters startparameters="-MultiHome=${ip} -Port=${port} -QueryPort=${queryport} -startup_map ${defaultmap} -server_name '${servername}'" +## Extra Parameters | https://docs.linuxgsm.com/configuration/start-parameters#extra-parameters +# Added to the end of startparameters. +extraparams="" + #### LinuxGSM Settings #### ## LinuxGSM Stats diff --git a/lgsm/config-default/config-lgsm/sbserver/_default.cfg b/lgsm/config-default/config-lgsm/sbserver/_default.cfg index c61d87fc56..bad8fe6874 100644 --- a/lgsm/config-default/config-lgsm/sbserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/sbserver/_default.cfg @@ -18,6 +18,10 @@ ip="0.0.0.0" ## Server Parameters | https://docs.linuxgsm.com/configuration/start-parameters#additional-parameters startparameters="" +## Extra Parameters | https://docs.linuxgsm.com/configuration/start-parameters#extra-parameters +# Added to the end of startparameters. +extraparams="" + ## Steam Workshop Mods | https://docs.linuxgsm.com/steamcmd/workshop # Workshop item or collection IDs, separated by spaces. Collections are expanded. # Installed to serverfiles/workshop and linked into serverfiles/mods. Run ./sbserver workshop-update after changing, or let update apply it. diff --git a/lgsm/config-default/config-lgsm/scpslserver/_default.cfg b/lgsm/config-default/config-lgsm/scpslserver/_default.cfg index 9c82bc9528..2c5dfbf717 100644 --- a/lgsm/config-default/config-lgsm/scpslserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/scpslserver/_default.cfg @@ -16,6 +16,10 @@ port="7777" ## Server Parameters | https://docs.linuxgsm.com/configuration/start-parameters#additional-parameters startparameters="${port} --acceptEULA" +## Extra Parameters | https://docs.linuxgsm.com/configuration/start-parameters#extra-parameters +# Added to the end of startparameters. +extraparams="" + #### LinuxGSM Settings #### ## LinuxGSM Stats diff --git a/lgsm/config-default/config-lgsm/sdtdserver/_default.cfg b/lgsm/config-default/config-lgsm/sdtdserver/_default.cfg index f4cc7c1146..16f45922a8 100644 --- a/lgsm/config-default/config-lgsm/sdtdserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/sdtdserver/_default.cfg @@ -14,6 +14,10 @@ ip="0.0.0.0" ## Server Parameters | https://docs.linuxgsm.com/configuration/start-parameters#additional-parameters startparameters="-quit -batchmode -nographics -dedicated -configfile=${servercfgfullpath}" +## Extra Parameters | https://docs.linuxgsm.com/configuration/start-parameters#extra-parameters +# Added to the end of startparameters. +extraparams="" + #### LinuxGSM Settings #### ## LinuxGSM Stats diff --git a/lgsm/config-default/config-lgsm/sfcserver/_default.cfg b/lgsm/config-default/config-lgsm/sfcserver/_default.cfg index 99562af6ab..950fddb375 100644 --- a/lgsm/config-default/config-lgsm/sfcserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/sfcserver/_default.cfg @@ -19,6 +19,10 @@ maxplayers="32" ## Server Parameters | https://docs.linuxgsm.com/configuration/start-parameters#additional-parameters startparameters="-game sfclassic -strictportbind -ip ${ip} -port ${port} +clientport ${clientport} +tv_port ${sourcetvport} +map ${defaultmap} +servercfgfile ${servercfg} -maxplayers ${maxplayers}" +## Extra Parameters | https://docs.linuxgsm.com/configuration/start-parameters#extra-parameters +# Added to the end of startparameters. +extraparams="" + #### LinuxGSM Settings #### ## LinuxGSM Stats diff --git a/lgsm/config-default/config-lgsm/sfserver/_default.cfg b/lgsm/config-default/config-lgsm/sfserver/_default.cfg index ed51b6e8ea..5ed2e6f286 100644 --- a/lgsm/config-default/config-lgsm/sfserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/sfserver/_default.cfg @@ -18,6 +18,10 @@ reliableport="8888" ## Game Server Docs | https://satisfactory.fandom.com/wiki/Dedicated_servers startparameters="FactoryGame -Port=${port} -ReliablePort=${reliableport} -log" +## Extra Parameters | https://docs.linuxgsm.com/configuration/start-parameters#extra-parameters +# Added to the end of startparameters. +extraparams="" + #### LinuxGSM Settings #### ## LinuxGSM Stats diff --git a/lgsm/config-default/config-lgsm/smserver/_default.cfg b/lgsm/config-default/config-lgsm/smserver/_default.cfg index b70c383a94..311c5f07d6 100644 --- a/lgsm/config-default/config-lgsm/smserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/smserver/_default.cfg @@ -22,6 +22,10 @@ defaultmap="Level01_Main" ## Server Parameters | https://docs.linuxgsm.com/configuration/start-parameters#additional-parameters startparameters="WS ${defaultmap} -MultiHome=${ip} -Port=${port} -EchoPort=${telnetport} -QueryPort=${queryport} -SteamServerName='${servername}' -PSW='${serverpassword}' -adminpsw='${adminpassword}' -MaxPlayers=${maxplayers} -initbackup -backupinterval=${backupinterval} -UTF8Output -forcepassthrough -log" +## Extra Parameters | https://docs.linuxgsm.com/configuration/start-parameters#extra-parameters +# Added to the end of startparameters. +extraparams="" + #### LinuxGSM Settings #### ## LinuxGSM Stats diff --git a/lgsm/config-default/config-lgsm/sof2server/_default.cfg b/lgsm/config-default/config-lgsm/sof2server/_default.cfg index d2dfc2e508..9f3742f6b8 100644 --- a/lgsm/config-default/config-lgsm/sof2server/_default.cfg +++ b/lgsm/config-default/config-lgsm/sof2server/_default.cfg @@ -16,6 +16,10 @@ defaultmap="mp_shop" ## Server Parameters | https://docs.linuxgsm.com/configuration/start-parameters#additional-parameters startparameters="+set sv_punkbuster 0 +set dedicated 2 +set net_ip ${ip} +set net_port ${port} +exec ${servercfg} +map ${defaultmap}" +## Extra Parameters | https://docs.linuxgsm.com/configuration/start-parameters#extra-parameters +# Added to the end of startparameters. +extraparams="" + #### LinuxGSM Settings #### ## LinuxGSM Stats diff --git a/lgsm/config-default/config-lgsm/solserver/_default.cfg b/lgsm/config-default/config-lgsm/solserver/_default.cfg index f934703942..b04ffaca0c 100644 --- a/lgsm/config-default/config-lgsm/solserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/solserver/_default.cfg @@ -15,6 +15,10 @@ maplist="mapslist.txt" ## Server Parameters | https://docs.linuxgsm.com/configuration/start-parameters#additional-parameters startparameters="-b ${ip} -m ${maplist} -c ${servercfg}" +## Extra Parameters | https://docs.linuxgsm.com/configuration/start-parameters#extra-parameters +# Added to the end of startparameters. +extraparams="" + ## Steam Workshop Mods | https://docs.linuxgsm.com/steamcmd/workshop # Workshop item or collection IDs, separated by spaces. Collections are expanded. # Installed to serverfiles/workshop and linked into maps, textures and scenery-gfx. Add the maps you want to mapslist.txt. diff --git a/lgsm/config-default/config-lgsm/squad44server/_default.cfg b/lgsm/config-default/config-lgsm/squad44server/_default.cfg index 8483e308e7..43c5c327fb 100644 --- a/lgsm/config-default/config-lgsm/squad44server/_default.cfg +++ b/lgsm/config-default/config-lgsm/squad44server/_default.cfg @@ -16,6 +16,10 @@ queryport="10037" ## Server Parameters | https://docs.linuxgsm.com/configuration/start-parameters#additional-parameters startparameters="-MultiHome=${ip} -Port=${port} -QueryPort=${queryport} -log" +## Extra Parameters | https://docs.linuxgsm.com/configuration/start-parameters#extra-parameters +# Added to the end of startparameters. +extraparams="" + ## Steam Workshop Mods | https://docs.linuxgsm.com/steamcmd/workshop # Workshop item or collection IDs, separated by spaces. Collections are expanded. # Installed to PostScriptum/Plugins/Mods. Run ./squad44server workshop-update after changing, or let update apply it. diff --git a/lgsm/config-default/config-lgsm/squadserver/_default.cfg b/lgsm/config-default/config-lgsm/squadserver/_default.cfg index ae14cf30e2..7615e606ba 100644 --- a/lgsm/config-default/config-lgsm/squadserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/squadserver/_default.cfg @@ -16,6 +16,10 @@ queryport="27165" ## Game Server Docs | https://squad.fandom.com/wiki/Dedicated_server startparameters="-MultiHome=${ip} -Port=${port} -QueryPort=${queryport}" +## Extra Parameters | https://docs.linuxgsm.com/configuration/start-parameters#extra-parameters +# Added to the end of startparameters. +extraparams="" + ## Steam Workshop Mods | https://docs.linuxgsm.com/steamcmd/workshop # Workshop item or collection IDs, separated by spaces. Collections are expanded. # Installed to SquadGame/Plugins/Mods. Run ./squadserver workshop-update after changing, or let update apply it. diff --git a/lgsm/config-default/config-lgsm/stnserver/_default.cfg b/lgsm/config-default/config-lgsm/stnserver/_default.cfg index 50c7753578..eab5fa6d55 100644 --- a/lgsm/config-default/config-lgsm/stnserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/stnserver/_default.cfg @@ -15,6 +15,10 @@ region="0" # https://colonysurvival.gamepedia.com/Dedicated_Server#Installation_.28Linux.29 startparameters="-mc ${maxplayers} -r ${region}" +## Extra Parameters | https://docs.linuxgsm.com/configuration/start-parameters#extra-parameters +# Added to the end of startparameters. +extraparams="" + #### LinuxGSM Settings #### ## LinuxGSM Stats diff --git a/lgsm/config-default/config-lgsm/stserver/_default.cfg b/lgsm/config-default/config-lgsm/stserver/_default.cfg index 60e26ffe23..90a49c76fe 100644 --- a/lgsm/config-default/config-lgsm/stserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/stserver/_default.cfg @@ -15,6 +15,10 @@ worldtype="Moon" ## Server Parameters | https://docs.linuxgsm.com/configuration/start-parameters#additional-parameters startparameters="-LOAD ${worldsave} ${worldtype}" +## Extra Parameters | https://docs.linuxgsm.com/configuration/start-parameters#extra-parameters +# Added to the end of startparameters. +extraparams="" + ## Steam Workshop Mods | https://docs.linuxgsm.com/steamcmd/workshop # Workshop item or collection IDs, separated by spaces. Collections are expanded. # Installed to mods, where the server enables them. Run ./stserver workshop-update after changing, or let update apply it. diff --git a/lgsm/config-default/config-lgsm/svenserver/_default.cfg b/lgsm/config-default/config-lgsm/svenserver/_default.cfg index 362cfe6032..01f299309d 100644 --- a/lgsm/config-default/config-lgsm/svenserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/svenserver/_default.cfg @@ -18,6 +18,10 @@ maxplayers="16" ## Server Parameters | https://docs.linuxgsm.com/configuration/start-parameters#additional-parameters startparameters="-game svencoop -strictportbind +ip ${ip} -port ${port} +clientport ${clientport} +map ${defaultmap} +servercfgfile ${servercfg} +maxplayers ${maxplayers}" +## Extra Parameters | https://docs.linuxgsm.com/configuration/start-parameters#extra-parameters +# Added to the end of startparameters. +extraparams="" + #### LinuxGSM Settings #### ## LinuxGSM Stats diff --git a/lgsm/config-default/config-lgsm/terrariaserver/_default.cfg b/lgsm/config-default/config-lgsm/terrariaserver/_default.cfg index 19aa0dc5ef..f5aa4607df 100644 --- a/lgsm/config-default/config-lgsm/terrariaserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/terrariaserver/_default.cfg @@ -18,6 +18,10 @@ ip="0.0.0.0" ## Server Parameters | https://docs.linuxgsm.com/configuration/start-parameters#additional-parameters startparameters="-config ${servercfgfullpath}" +## Extra Parameters | https://docs.linuxgsm.com/configuration/start-parameters#extra-parameters +# Added to the end of startparameters. +extraparams="" + #### LinuxGSM Settings #### ## LinuxGSM Stats diff --git a/lgsm/config-default/config-lgsm/tf2cserver/_default.cfg b/lgsm/config-default/config-lgsm/tf2cserver/_default.cfg index adb83a2574..1ce0d66e29 100644 --- a/lgsm/config-default/config-lgsm/tf2cserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/tf2cserver/_default.cfg @@ -26,6 +26,10 @@ gslt="" ## Server Parameters | https://docs.linuxgsm.com/configuration/start-parameters#additional-parameters startparameters="-game tf2classified -tf_path ${supportdir} -strictportbind -ip ${ip} -port ${port} +clientport ${clientport} +tv_port ${sourcetvport} +map ${defaultmap} +sv_setsteamaccount ${gslt} +servercfgfile ${servercfg} -maxplayers ${maxplayers}" +## Extra Parameters | https://docs.linuxgsm.com/configuration/start-parameters#extra-parameters +# Added to the end of startparameters. +extraparams="" + #### LinuxGSM Settings #### ## LinuxGSM Stats diff --git a/lgsm/config-default/config-lgsm/tf2server/_default.cfg b/lgsm/config-default/config-lgsm/tf2server/_default.cfg index 021574d7fd..355994fba0 100644 --- a/lgsm/config-default/config-lgsm/tf2server/_default.cfg +++ b/lgsm/config-default/config-lgsm/tf2server/_default.cfg @@ -26,6 +26,10 @@ gslt="" ## Server Parameters | https://docs.linuxgsm.com/configuration/start-parameters#additional-parameters startparameters="-game tf -strictportbind -ip ${ip} -port ${port} +clientport ${clientport} +tv_port ${sourcetvport} +map ${defaultmap} +sv_setsteamaccount ${gslt} +servercfgfile ${servercfg} -maxplayers ${maxplayers} -norestart" +## Extra Parameters | https://docs.linuxgsm.com/configuration/start-parameters#extra-parameters +# Added to the end of startparameters. +extraparams="" + #### LinuxGSM Settings #### ## LinuxGSM Stats diff --git a/lgsm/config-default/config-lgsm/tfcserver/_default.cfg b/lgsm/config-default/config-lgsm/tfcserver/_default.cfg index acae133c13..7d644d116b 100644 --- a/lgsm/config-default/config-lgsm/tfcserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/tfcserver/_default.cfg @@ -18,6 +18,10 @@ maxplayers="16" ## Server Parameters | https://docs.linuxgsm.com/configuration/start-parameters#additional-parameters startparameters="-game tfc -strictportbind +ip ${ip} -port ${port} +clientport ${clientport} +map ${defaultmap} +servercfgfile ${servercfg} -maxplayers ${maxplayers}" +## Extra Parameters | https://docs.linuxgsm.com/configuration/start-parameters#extra-parameters +# Added to the end of startparameters. +extraparams="" + #### LinuxGSM Settings #### ## LinuxGSM Stats diff --git a/lgsm/config-default/config-lgsm/tfserver/_default.cfg b/lgsm/config-default/config-lgsm/tfserver/_default.cfg index 04af34bbab..49584cac87 100644 --- a/lgsm/config-default/config-lgsm/tfserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/tfserver/_default.cfg @@ -35,6 +35,10 @@ steamsocket="0" # Use Steam Socket. 0 = off; 1 = on. Use Steam Servers for netwo ## Server Parameters | https://docs.linuxgsm.com/configuration/start-parameters#additional-parameters startparameters="ProjectWar_Start?DedicatedServer?MaxPlayers=${maxplayers} -server -game -log -MultiHome=${ip} -Port=${port} -QueryPort=${queryport} -BeaconPort=${beaconport} -ShutDownServicePort=${shutdownport} -ConfigServerName='${selfname}' -OutIPAddress=${publicip} -ServerTags='${servertags}' -UseSteamSocket=${steamsocket} -UserDir='${serverfiles}/${selfname}' -ServerName='${servername}' -EnableParallelCharacterMovementTickFunction -EnableParallelCharacterTickFunction -UseDynamicPhysicsScene -Game.PhysicsVehicle=false -ansimalloc -Game.MaxFrameRate=35 -MaxQueueSize=${maxqueuesize} -QueueValidTime=${queuevalidtime} -QueueThreshold=${maxplayers} -ServerFightModeType=${gamemode} -IsCanSelfDamage=${damageself} -IsCanFriendDamage=${damageallies} -SaveWorldInterval=${saveinterval} -GMOverlapRatio=2 -GreenHand=${greenhand} -SensitiveWords=${allowsensitivewords} -UseEAC=${anticheat} -ServerAdminAccounts='${serveradmins}' -IsShowGmTitle=${adminlabel} -ServerPassword='${serverpassword}'" +## Extra Parameters | https://docs.linuxgsm.com/configuration/start-parameters#extra-parameters +# Added to the end of startparameters. +extraparams="" + #### LinuxGSM Settings #### ## LinuxGSM Stats diff --git a/lgsm/config-default/config-lgsm/tiserver/_default.cfg b/lgsm/config-default/config-lgsm/tiserver/_default.cfg index 1be16d9616..34dc148964 100644 --- a/lgsm/config-default/config-lgsm/tiserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/tiserver/_default.cfg @@ -21,6 +21,10 @@ eosclientsecret="pKWl6t5i9NJK8gTpVlAxzENZ65P8hYzodV8Dqe5Rlc8" ## Game Server Docs | https://isle.fandom.com/wiki/The_Isle_Server_Settings_and_Configuration startparameters="${defaultmap} -Port=${port} -log -ini:Engine:[EpicOnlineServices]:DedicatedServerClientId=${eosclientid} -ini:Engine:[EpicOnlineServices]:DedicatedServerClientSecret=${eosclientsecret}" +## Extra Parameters | https://docs.linuxgsm.com/configuration/start-parameters#extra-parameters +# Added to the end of startparameters. +extraparams="" + #### LinuxGSM Settings #### ## LinuxGSM Stats diff --git a/lgsm/config-default/config-lgsm/ts3server/_default.cfg b/lgsm/config-default/config-lgsm/ts3server/_default.cfg index 8c5738d73a..0e77d9077f 100644 --- a/lgsm/config-default/config-lgsm/ts3server/_default.cfg +++ b/lgsm/config-default/config-lgsm/ts3server/_default.cfg @@ -11,6 +11,10 @@ ## Server Parameters | https://docs.linuxgsm.com/configuration/start-parameters#additional-parameters startparameters="inifile=${servercfgfullpath} pid_file=ts3server.pid" +## Extra Parameters | https://docs.linuxgsm.com/configuration/start-parameters#extra-parameters +# Added to the end of startparameters. +extraparams="" + #### LinuxGSM Settings #### ## LinuxGSM Stats diff --git a/lgsm/config-default/config-lgsm/tsserver/_default.cfg b/lgsm/config-default/config-lgsm/tsserver/_default.cfg index ba59e0071c..6ba1035261 100644 --- a/lgsm/config-default/config-lgsm/tsserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/tsserver/_default.cfg @@ -18,6 +18,10 @@ maxplayers="32" ## Server Parameters | https://docs.linuxgsm.com/configuration/start-parameters#additional-parameters startparameters="-game ts -strictportbind +ip ${ip} -port ${port} +clientport ${clientport} +map ${defaultmap} +servercfgfile ${servercfg} -maxplayers ${maxplayers} " +## Extra Parameters | https://docs.linuxgsm.com/configuration/start-parameters#extra-parameters +# Added to the end of startparameters. +extraparams="" + #### LinuxGSM Settings #### ## LinuxGSM Stats diff --git a/lgsm/config-default/config-lgsm/tuserver/_default.cfg b/lgsm/config-default/config-lgsm/tuserver/_default.cfg index 102b948b41..18682d40b3 100644 --- a/lgsm/config-default/config-lgsm/tuserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/tuserver/_default.cfg @@ -21,6 +21,10 @@ gslt="" ## Server Parameters | https://docs.linuxgsm.com/configuration/start-parameters#additional-parameters startparameters="-MultiHome=${ip} -Port=${port} -QueryPort=${queryport} -TowerServerINI=${selfname}.ini -log" +## Extra Parameters | https://docs.linuxgsm.com/configuration/start-parameters#extra-parameters +# Added to the end of startparameters. +extraparams="" + #### LinuxGSM Settings #### ## LinuxGSM Stats diff --git a/lgsm/config-default/config-lgsm/twserver/_default.cfg b/lgsm/config-default/config-lgsm/twserver/_default.cfg index 4923f24392..96057e6148 100644 --- a/lgsm/config-default/config-lgsm/twserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/twserver/_default.cfg @@ -18,6 +18,10 @@ ip="0.0.0.0" ## Server Parameters | https://docs.linuxgsm.com/configuration/start-parameters#additional-parameters startparameters="-f ${servercfg}" +## Extra Parameters | https://docs.linuxgsm.com/configuration/start-parameters#extra-parameters +# Added to the end of startparameters. +extraparams="" + #### LinuxGSM Settings #### ## LinuxGSM Stats diff --git a/lgsm/config-default/config-lgsm/untserver/_default.cfg b/lgsm/config-default/config-lgsm/untserver/_default.cfg index a2a0308208..577c2f12f3 100644 --- a/lgsm/config-default/config-lgsm/untserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/untserver/_default.cfg @@ -25,6 +25,10 @@ gslt="" ## Server Parameters | https://docs.linuxgsm.com/configuration/start-parameters#additional-parameters startparameters="-nographics -batchmode -bind ${ip} -port ${port} -maxplayers ${maxplayers} -perspective ${perspective} -mode ${gamemode} -name ${servername} -map ${defaultmap} -gslt ${gslt} +InternetServer/${selfname}" +## Extra Parameters | https://docs.linuxgsm.com/configuration/start-parameters#extra-parameters +# Added to the end of startparameters. +extraparams="" + #### LinuxGSM Settings #### ## LinuxGSM Stats diff --git a/lgsm/config-default/config-lgsm/ut2k4server/_default.cfg b/lgsm/config-default/config-lgsm/ut2k4server/_default.cfg index 00cf8ad5ae..85e186a243 100644 --- a/lgsm/config-default/config-lgsm/ut2k4server/_default.cfg +++ b/lgsm/config-default/config-lgsm/ut2k4server/_default.cfg @@ -15,6 +15,10 @@ ip="0.0.0.0" ## Server Parameters | https://docs.linuxgsm.com/configuration/start-parameters#additional-parameters startparameters="server ${defaultmap}?game=XGame.xDeathMatch -nohomedir ini=${servercfg} log=${gamelog}" +## Extra Parameters | https://docs.linuxgsm.com/configuration/start-parameters#extra-parameters +# Added to the end of startparameters. +extraparams="" + #### LinuxGSM Settings #### ## LinuxGSM Stats diff --git a/lgsm/config-default/config-lgsm/ut3server/_default.cfg b/lgsm/config-default/config-lgsm/ut3server/_default.cfg index 9a77eeadd9..df1d297f04 100644 --- a/lgsm/config-default/config-lgsm/ut3server/_default.cfg +++ b/lgsm/config-default/config-lgsm/ut3server/_default.cfg @@ -31,6 +31,10 @@ gspassword="" # List of game types and mutators: https://docs.linuxgsm.com/game-servers/unreal-tournament-3 startparameters="server ${defaultmap}?Game=${game}?bIsDedicated=${isdedicated}?bIsLanMatch=${islanmatch}?bUsesStats=${usesstats}?bShouldAdvertise=${shouldadvertise}?PureServer=${pureserver}?bAllowJoinInProgress=${allowjoininprogress}?Mutator=${mutators}?ConfigSubDir=${selfname} -login=${gsusername} -password=${gspassword} -multihome=${ip} -port=${port} -queryport=${queryport} -nohomedir -unattended -log=${gamelog}" +## Extra Parameters | https://docs.linuxgsm.com/configuration/start-parameters#extra-parameters +# Added to the end of startparameters. +extraparams="" + #### LinuxGSM Settings #### ## LinuxGSM Stats diff --git a/lgsm/config-default/config-lgsm/ut99server/_default.cfg b/lgsm/config-default/config-lgsm/ut99server/_default.cfg index e23a6d51b5..0b9006faa9 100644 --- a/lgsm/config-default/config-lgsm/ut99server/_default.cfg +++ b/lgsm/config-default/config-lgsm/ut99server/_default.cfg @@ -15,6 +15,10 @@ ip="0.0.0.0" ## Server Parameters | https://docs.linuxgsm.com/configuration/start-parameters#additional-parameters startparameters="server ${defaultmap}.unr ini=${servercfgfullpath}" +## Extra Parameters | https://docs.linuxgsm.com/configuration/start-parameters#extra-parameters +# Added to the end of startparameters. +extraparams="" + #### LinuxGSM Settings #### ## LinuxGSM Stats diff --git a/lgsm/config-default/config-lgsm/utserver/_default.cfg b/lgsm/config-default/config-lgsm/utserver/_default.cfg index 59341032e7..3875d1dd9b 100644 --- a/lgsm/config-default/config-lgsm/utserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/utserver/_default.cfg @@ -19,6 +19,10 @@ timelimit="10" ## Server Parameters | https://docs.linuxgsm.com/configuration/start-parameters#additional-parameters startparameters="UnrealTournament ${defaultmap}?Game=${gametype}?TimeLimit=${timelimit} -port=${port}" +## Extra Parameters | https://docs.linuxgsm.com/configuration/start-parameters#extra-parameters +# Added to the end of startparameters. +extraparams="" + #### LinuxGSM Settings #### ## LinuxGSM Stats diff --git a/lgsm/config-default/config-lgsm/vhserver/_default.cfg b/lgsm/config-default/config-lgsm/vhserver/_default.cfg index 7506613fcc..d1b0916fd6 100644 --- a/lgsm/config-default/config-lgsm/vhserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/vhserver/_default.cfg @@ -55,6 +55,10 @@ worldmodifiers="" # https://docs.linuxgsm.com/game-servers/valheim#crossplay startparameters="-name '${servername}' -password ${serverpassword} -port ${port} -world ${worldname} -public ${public} -savedir '${savedir}' -saveinterval ${saveinterval} -backups ${backups} -backupshort ${backupshort} -backuplong ${backuplong} -crossplay -instanceid ${instanceid} ${logFile:+ -logFile '${logFile}'} ${worldmodifiers:+ ${worldmodifiers}}" +## Extra Parameters | https://docs.linuxgsm.com/configuration/start-parameters#extra-parameters +# Added to the end of startparameters. +extraparams="" + #### LinuxGSM Settings #### ## LinuxGSM Stats diff --git a/lgsm/config-default/config-lgsm/vintsserver/_default.cfg b/lgsm/config-default/config-lgsm/vintsserver/_default.cfg index fb44ecefb5..2dcf839049 100644 --- a/lgsm/config-default/config-lgsm/vintsserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/vintsserver/_default.cfg @@ -11,6 +11,10 @@ ## Server Parameters | https://docs.linuxgsm.com/configuration/start-parameters#additional-parameters startparameters="--dataPath ${servercfgdir}" +## Extra Parameters | https://docs.linuxgsm.com/configuration/start-parameters#extra-parameters +# Added to the end of startparameters. +extraparams="" + ## Release Settings | https://docs.linuxgsm.com/game-servers/vintagestory#release-settings # Branch (stable|unstable|) branch="stable" diff --git a/lgsm/config-default/config-lgsm/vpmcserver/_default.cfg b/lgsm/config-default/config-lgsm/vpmcserver/_default.cfg index 488a412cd0..90678422fd 100644 --- a/lgsm/config-default/config-lgsm/vpmcserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/vpmcserver/_default.cfg @@ -14,6 +14,10 @@ javaram="1024" # -Xmx$1024M ## Server Parameters | https://docs.linuxgsm.com/configuration/start-parameters#additional-parameters startparameters="" +## Extra Parameters | https://docs.linuxgsm.com/configuration/start-parameters#extra-parameters +# Added to the end of startparameters. +extraparams="" + ## Release Settings | https://docs.linuxgsm.com/game-servers/minecraft#release-settings # Version (latest|3.1.1) mcversion="latest" diff --git a/lgsm/config-default/config-lgsm/vsserver/_default.cfg b/lgsm/config-default/config-lgsm/vsserver/_default.cfg index 529054a535..2944bd1586 100644 --- a/lgsm/config-default/config-lgsm/vsserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/vsserver/_default.cfg @@ -18,6 +18,10 @@ maxplayers="16" ## Server Parameters | https://docs.linuxgsm.com/configuration/start-parameters#additional-parameters startparameters="-game vs -strictportbind +ip ${ip} -port ${port} +clientport ${clientport} +map ${defaultmap} +servercfgfile ${servercfg} -maxplayers ${maxplayers}" +## Extra Parameters | https://docs.linuxgsm.com/configuration/start-parameters#extra-parameters +# Added to the end of startparameters. +extraparams="" + #### LinuxGSM Settings #### ## LinuxGSM Stats diff --git a/lgsm/config-default/config-lgsm/wetserver/_default.cfg b/lgsm/config-default/config-lgsm/wetserver/_default.cfg index 6f1e1446ed..715c723f04 100644 --- a/lgsm/config-default/config-lgsm/wetserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/wetserver/_default.cfg @@ -11,6 +11,10 @@ ## Server Parameters | https://docs.linuxgsm.com/configuration/start-parameters#additional-parameters startparameters="+set net_strict 1 +set fs_homepath ${serverfiles} +exec ${servercfg}" +## Extra Parameters | https://docs.linuxgsm.com/configuration/start-parameters#extra-parameters +# Added to the end of startparameters. +extraparams="" + #### LinuxGSM Settings #### ## LinuxGSM Stats diff --git a/lgsm/config-default/config-lgsm/wfserver/_default.cfg b/lgsm/config-default/config-lgsm/wfserver/_default.cfg index bd8fc55c3e..d450eb0b2f 100644 --- a/lgsm/config-default/config-lgsm/wfserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/wfserver/_default.cfg @@ -16,6 +16,10 @@ httpport="44444" ## Server Parameters | https://docs.linuxgsm.com/configuration/start-parameters#additional-parameters startparameters="+exec ${servercfg} +sv_http_ip ${ip} +set sv_http_port ${httpport} +sv_ip ${ip} +sv_port ${port}" +## Extra Parameters | https://docs.linuxgsm.com/configuration/start-parameters#extra-parameters +# Added to the end of startparameters. +extraparams="" + #### LinuxGSM Settings #### ## LinuxGSM Stats diff --git a/lgsm/config-default/config-lgsm/wmcserver/_default.cfg b/lgsm/config-default/config-lgsm/wmcserver/_default.cfg index d54aa9897e..b130a535bc 100644 --- a/lgsm/config-default/config-lgsm/wmcserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/wmcserver/_default.cfg @@ -14,6 +14,10 @@ javaram="1024" # -Xmx$1024M ## Server Parameters | https://docs.linuxgsm.com/configuration/start-parameters#additional-parameters startparameters="nogui" +## Extra Parameters | https://docs.linuxgsm.com/configuration/start-parameters#extra-parameters +# Added to the end of startparameters. +extraparams="" + ## Release Settings | https://docs.linuxgsm.com/game-servers/minecraft#release-settings # Version (latest|1.16.5) mcversion="latest" diff --git a/lgsm/config-default/config-lgsm/wurmserver/_default.cfg b/lgsm/config-default/config-lgsm/wurmserver/_default.cfg index b8c2736d17..f1053e514e 100644 --- a/lgsm/config-default/config-lgsm/wurmserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/wurmserver/_default.cfg @@ -55,6 +55,10 @@ queryport="27016" # Parameters are edited in the game server config file. startparameters="start=${gamemode} adminpwd='${adminpassword}' epicsettings='${epicsettings}' externalport='${port}' homeserver='${homeserver}' homekingdom='${homekingdom}' loginserver='${loginserver}' maxplayers='${maxplayers}' queryport='${queryport}' rmiport='${rmiport}' rmiregport='${rmiregport}' servername='${servername}' serverpassword='${serverpassword}' ip='${ip}'" +## Extra Parameters | https://docs.linuxgsm.com/configuration/start-parameters#extra-parameters +# Added to the end of startparameters. +extraparams="" + #### LinuxGSM Settings #### ## LinuxGSM Stats diff --git a/lgsm/config-default/config-lgsm/xntserver/_default.cfg b/lgsm/config-default/config-lgsm/xntserver/_default.cfg index 6d362f5d45..76949d7560 100644 --- a/lgsm/config-default/config-lgsm/xntserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/xntserver/_default.cfg @@ -13,6 +13,10 @@ ## Server Parameters | https://docs.linuxgsm.com/configuration/start-parameters#additional-parameters startparameters="-userdir ${systemdir}/${selfname}" +## Extra Parameters | https://docs.linuxgsm.com/configuration/start-parameters#extra-parameters +# Added to the end of startparameters. +extraparams="" + #### LinuxGSM Settings #### ## LinuxGSM Stats diff --git a/lgsm/config-default/config-lgsm/zmrserver/_default.cfg b/lgsm/config-default/config-lgsm/zmrserver/_default.cfg index 04a987deae..3d4e19851f 100644 --- a/lgsm/config-default/config-lgsm/zmrserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/zmrserver/_default.cfg @@ -19,6 +19,10 @@ maxplayers="16" ## Server Parameters | https://docs.linuxgsm.com/configuration/start-parameters#additional-parameters startparameters="-game zombie_master_reborn -strictportbind -ip ${ip} -port ${port} +clientport ${clientport} +tv_port ${sourcetvport} +map ${defaultmap} +servercfgfile ${servercfg} -maxplayers ${maxplayers}" +## Extra Parameters | https://docs.linuxgsm.com/configuration/start-parameters#extra-parameters +# Added to the end of startparameters. +extraparams="" + #### LinuxGSM Settings #### ## LinuxGSM Stats diff --git a/lgsm/config-default/config-lgsm/zpsserver/_default.cfg b/lgsm/config-default/config-lgsm/zpsserver/_default.cfg index eb2d2fe0cf..70eb4b7b25 100644 --- a/lgsm/config-default/config-lgsm/zpsserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/zpsserver/_default.cfg @@ -24,6 +24,10 @@ gslt="" ## Server Parameters | https://docs.linuxgsm.com/configuration/start-parameters#additional-parameters startparameters="-game zps -strictportbind -ip ${ip} -port ${port} +clientport ${clientport} +tv_port ${sourcetvport} +map ${defaultmap} +servercfgfile ${servercfg} -maxplayers ${maxplayers}" +## Extra Parameters | https://docs.linuxgsm.com/configuration/start-parameters#extra-parameters +# Added to the end of startparameters. +extraparams="" + #### LinuxGSM Settings #### ## LinuxGSM Stats diff --git a/linuxgsm.sh b/linuxgsm.sh index cfc4258c45..83f0ca5a88 100755 --- a/linuxgsm.sh +++ b/linuxgsm.sh @@ -553,6 +553,9 @@ else elif grep -qE "^[[:blank:]]*startparameters=" "${configdirserver}/_default.cfg"; then eval startparameters="$(sed -nr 's/^ *startparameters=(.*)$/\1/p' "${configdirserver}/_default.cfg")" fi + if [ -n "${extraparams}" ]; then + startparameters="${startparameters} ${extraparams}" + fi # reload preexecutable. if grep -qE "^[[:blank:]]*preexecutable=" "${configdirserver}/secrets-${selfname}.cfg"; then From 68d26976d8bad7d23004ef71c1bd37486fc4b10c Mon Sep 17 00:00:00 2001 From: Daniel Gibbs Date: Sat, 31 Oct 2026 01:25:55 +0000 Subject: [PATCH 126/164] feat(core): use plain line-based output when stdout is not a terminal (#5117) Output captured by systemd/journald, cron, pipes or redirected files was full of colour codes, carriage returns and erase-line sequences, and in-place progress messages overwrote each other instead of producing complete lines. When stdout is not a terminal, LinuxGSM now omits all terminal control sequences. In-place status messages are held until they are replaced, completed by an end-of-line status or flushed, so each step is written as one complete line showing its final result. Held messages are flushed before headers, prompts and on exit. ansi="off" now consistently disables ANSI formatting: the erase-line sequence is no longer re-added unconditionally and text styles are only set when ANSI is enabled. Direct terminal control outside the shared helpers is also skipped in plain mode: the download progress bar, the dependency install spinner and tput cursor handling in fastdl and mods-remove. --- lgsm/modules/check_deps.sh | 32 ++++--- lgsm/modules/command_fastdl.sh | 50 ++++++++--- lgsm/modules/command_mods_remove.sh | 10 ++- lgsm/modules/core_dl.sh | 21 +++-- lgsm/modules/core_exit.sh | 2 + lgsm/modules/core_messages.sh | 127 +++++++++++++++++++--------- 6 files changed, 165 insertions(+), 77 deletions(-) diff --git a/lgsm/modules/check_deps.sh b/lgsm/modules/check_deps.sh index bbd3e5747d..3d5c4c8ec1 100755 --- a/lgsm/modules/check_deps.sh +++ b/lgsm/modules/check_deps.sh @@ -39,13 +39,15 @@ fn_install_mono_repo() { if [ "${autodepinstall}" == "0" ]; then fn_print_information_nl "Automatically adding Mono repository." fn_script_log_info "Automatically adding Mono repository." - echo -en ".\r" - fn_sleep_time_1 - echo -en "..\r" - fn_sleep_time_1 - echo -en "...\r" - fn_sleep_time_1 - echo -en " \r" + if [ -z "${plainoutput}" ]; then + echo -en ".\r" + fn_sleep_time_1 + echo -en "..\r" + fn_sleep_time_1 + echo -en "...\r" + fn_sleep_time_1 + echo -en " \r" + fi if [ "${distroid}" == "ubuntu" ]; then if [ "${distroversion}" == "22.04" ]; then cmd="sudo apt-get install gnupg ca-certificates;sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys 3FA7E0328081BFF6A14DA29AA6A19B38D3D831EF;echo 'deb https://download.mono-project.com/repo/ubuntu stable-jammy main' | sudo tee /etc/apt/sources.list.d/mono-official-stable.list;sudo apt update" @@ -201,13 +203,15 @@ fn_install_missing_deps() { if [ "${autodepinstall}" == "0" ]; then fn_print_information_nl "Automatically installing missing dependencies." fn_script_log_info "Automatically installing missing dependencies." - echo -en ".\r" - fn_sleep_time_1 - echo -en "..\r" - fn_sleep_time_1 - echo -en "...\r" - fn_sleep_time_1 - echo -en " \r" + if [ -z "${plainoutput}" ]; then + echo -en ".\r" + fn_sleep_time_1 + echo -en "..\r" + fn_sleep_time_1 + echo -en "...\r" + fn_sleep_time_1 + echo -en " \r" + fi if [ "$(command -v apt 2> /dev/null)" ]; then cmd="echo steamcmd steam/question select \"I AGREE\" | sudo debconf-set-selections; echo steamcmd steam/license note '' | sudo debconf-set-selections; ${i386installcommand}sudo apt-get update; sudo apt-get -y install ${array_deps_missing[*]}" eval "${cmd}" diff --git a/lgsm/modules/command_fastdl.sh b/lgsm/modules/command_fastdl.sh index 67b0df0071..f9c3e64cc9 100755 --- a/lgsm/modules/command_fastdl.sh +++ b/lgsm/modules/command_fastdl.sh @@ -194,17 +194,23 @@ fn_fastdl_gather() { fi for allowed_extention in "${allowed_extentions_array[@]}"; do fileswc=0 - tput sc + if [ -z "${plainoutput}" ]; then + tput sc + fi while IFS=$'\t' read -r filesize filemtime fastdlfile; do ((fileswc++)) - tput rc - tput el - fn_print "gathering ${label} ${allowed_extention} : ${fileswc}" + if [ -z "${plainoutput}" ]; then + tput rc + tput el + fn_print "gathering ${label} ${allowed_extention} : ${fileswc}" + fi fastdlrelpath="${fastdlfile#"${basedir}/"}" printf '%s\t%s\t%s\t%s\t%s\n' "${priority}" "${fastdlrelpath#./}" "${filesize}" "${filemtime}" "${fastdlfile}" >> "${fastdlfilelist}" done < <(find "${basedir}/${directory}" "${fastdl_find_maxdepth[@]}" -type f -iname "${allowed_extention}" -printf '%s\t%T@\t%p\n') - tput rc - tput el + if [ -z "${plainoutput}" ]; then + tput rc + tput el + fi fn_print "gathering ${label} ${allowed_extention} : ${fileswc}" if [ ${fileswc} != 0 ]; then fn_print_ok_eol_nl @@ -220,12 +226,16 @@ fn_fastdl_gather_gmod() { allowed_extentions_array=("*.ain" "*.bsp" "*.mdl" "*.mp3" "*.ogg" "*.otf" "*.pcf" "*.phy" "*.png" "*.svg" "*.vtf" "*.vmt" "*.vtx" "*.vvd" "*.ttf" "*.wav") for allowed_extention in "${allowed_extentions_array[@]}"; do fileswc=0 - tput sc + if [ -z "${plainoutput}" ]; then + tput sc + fi while IFS=$'\t' read -r filesize filemtime fastdlfile; do ((fileswc++)) - tput rc - tput el - fn_print "gathering ${allowed_extention} : ${fileswc}" + if [ -z "${plainoutput}" ]; then + tput rc + tput el + fn_print "gathering ${allowed_extention} : ${fileswc}" + fi fastdlrelpath="${fastdlfile#./}" priority="2" if [[ "${fastdlrelpath}" == addons/* ]]; then @@ -242,6 +252,11 @@ fn_fastdl_gather_gmod() { printf '%s\t%s\t%s\t%s\t%s\n' "0" "${fastdlrelpath#lua/}" "${filesize}" "${filemtime}" "${systemdir}/${fastdlfile#./}" >> "${fastdlfilelist}" fi done < <(find . -type f -iname "${allowed_extention}" -printf '%s\t%T@\t%p\n') + if [ -z "${plainoutput}" ]; then + tput rc + tput el + fi + fn_print "gathering ${allowed_extention} : ${fileswc}" if [ ${fileswc} != 0 ]; then fn_print_ok_eol_nl else @@ -434,12 +449,16 @@ fn_fastdl_remove() { fn_fastdl_copy() { if [ -s "${fastdlupdatelist}" ]; then fileswc=0 - tput sc + if [ -z "${plainoutput}" ]; then + tput sc + fi while IFS=$'\t' read -r fastdlmode fastdlrelpath fastdlfile; do ((fileswc++)) - tput rc - tput el - fn_print "copying files : ${fileswc}/${updatefiles}" + if [ -z "${plainoutput}" ]; then + tput rc + tput el + fn_print "copying files : ${fileswc}/${updatefiles}" + fi fastdltarget="${fastdldir}/${fastdlrelpath}" mkdir -p "${fastdltarget%/*}" && cp -p "${fastdlfile}" "${fastdltarget}" exitcode=$? @@ -454,6 +473,9 @@ fn_fastdl_copy() { printf '%s\0' "${fastdltarget}" >> "${fastdlcompresslist}" fi done < "${fastdlupdatelist}" + if [ -n "${plainoutput}" ]; then + fn_print "copying files : ${fileswc}/${updatefiles}" + fi fn_print_ok_eol_nl fi } diff --git a/lgsm/modules/command_mods_remove.sh b/lgsm/modules/command_mods_remove.sh index 821451dab9..ad3ee95279 100755 --- a/lgsm/modules/command_mods_remove.sh +++ b/lgsm/modules/command_mods_remove.sh @@ -82,7 +82,9 @@ echo -e "* location: ${modinstalldir}" fn_sleep_time_1 # Go through every file and remove it. modfileline="1" -tput sc +if [ -z "${plainoutput}" ]; then + tput sc +fi while [ "${modfileline}" -le "${modsfilelistsize}" ]; do # Current line defines current file to remove. currentfileremove=$(sed "${modfileline}q;d" "${modsdir}/${modcommand}-files.txt") @@ -98,8 +100,10 @@ while [ "${modfileline}" -le "${modsfilelistsize}" ]; do fn_script_log_pass "Removing ${modinstalldir}/${currentfileremove}" fi fi - tput rc - tput el + if [ -z "${plainoutput}" ]; then + tput rc + tput el + fi echo -e "removing ${modprettyname} ${modfileline} / ${modsfilelistsize} : ${currentfileremove}..." ((modfileline++)) done diff --git a/lgsm/modules/core_dl.sh b/lgsm/modules/core_dl.sh index e22766f7cd..02b458c105 100755 --- a/lgsm/modules/core_dl.sh +++ b/lgsm/modules/core_dl.sh @@ -428,8 +428,12 @@ fn_check_file() { fi fi else - fn_print_ok_eol - echo -en "\033[2K\\r" + if [ -n "${plainoutput}" ]; then + fn_print_ok_eol_nl + else + fn_print_ok_eol + echo -en "\033[2K\\r" + fi if [ -f "${lgsmlog}" ]; then fn_script_log_pass "Checking ${remote_filename}" checkflag=0 @@ -496,10 +500,15 @@ fn_fetch_file() { local exitcode="" large_files=("bz2" "gz" "zip" "jar" "xz") if grep -qE "(^|\s)${local_filename##*.}(\s|$)" <<< "${large_files[@]}"; then - echo -e "downloading file [ ${italic}${local_filename}${default} ]" - fn_sleep_time - "${curlcmd[@]}" --progress-bar "${fileurl}" 2>&1 - exitcode=$? + if [ -n "${plainoutput}" ]; then + "${curlcmd[@]}" --silent --show-error "${fileurl}" 2>&1 + exitcode=$? + else + echo -e "downloading file [ ${italic}${local_filename}${default} ]" + fn_sleep_time + "${curlcmd[@]}" --progress-bar "${fileurl}" 2>&1 + exitcode=$? + fi echo -en "downloading file [ ${italic}${local_filename}${default} ]" else echo -en "fetching ${fileurl_name} [ ${italic}${local_filename}${default} ]\c" diff --git a/lgsm/modules/core_exit.sh b/lgsm/modules/core_exit.sh index 1dd6e2f460..274c847d7c 100755 --- a/lgsm/modules/core_exit.sh +++ b/lgsm/modules/core_exit.sh @@ -19,6 +19,8 @@ fn_exit_dev_debug() { fi } +fn_print_plain_flush + # If running dependency check as root will remove any files that belong to root user. if [ "$(whoami)" == "root" ]; then find "${lgsmdir}"/ -group root -prune -exec rm -rf {} + > /dev/null 2>&1 diff --git a/lgsm/modules/core_messages.sh b/lgsm/modules/core_messages.sh index bcf3abe2ca..447eb4d0d5 100755 --- a/lgsm/modules/core_messages.sh +++ b/lgsm/modules/core_messages.sh @@ -10,9 +10,16 @@ moduleselfname="$(basename "$(readlink -f "${BASH_SOURCE[0]}")")" # nl: new line: message is following by a new line. # eol: end of line: message is placed at the end of the current line. fn_ansi_loader() { + # plain: stdout is not a terminal, output complete lines with no terminal control sequences. + unset plainoutput plainpending + if [ ! -t 1 ]; then + plainoutput="1" + fi # carriage return. creeol="\r" - if [ "${ansi}" != "off" ]; then + if [ -n "${plainoutput}" ]; then + creeol="" + elif [ "${ansi}" != "off" ]; then # echo colors default="\e[0m" black="\e[30m" @@ -33,15 +40,21 @@ fn_ansi_loader() { white="\e[97m" # erase to end of line. creeol+="\033[K" + # text styles + bold="\e[1m" + dim="\e[2m" + italic="\e[3m" + underline="\e[4m" + reverse="\e[7m" fi - # carriage return & erase to end of line. - creeol="\r\033[K" +} - bold="\e[1m" - dim="\e[2m" - italic="\e[3m" - underline="\e[4m" - reverse="\e[7m" +# plain: print any held in-place message as its own line. +fn_print_plain_flush() { + if [ -n "${plainpending}" ]; then + echo -e "${plainpending}" + unset plainpending + fi } fn_sleep_time() { @@ -110,22 +123,31 @@ fn_script_log_info() { ################################## fn_print() { + fn_print_plain_flush echo -en "$*${default}" } fn_print_nl() { + fn_print_plain_flush echo -e "$*${default}" } # Helper function to print messages with a specific format and color +# plain: in-place messages are held until replaced, completed by an eol message or flushed. fn_print_message() { local type="$1" local color="$2" local message="$3" + local line if [ "${commandaction}" ]; then - echo -en "${bold}${creeol}[${color} ${type} ${default}]${default} ${commandaction} ${selfname}: ${message}${default}" + line="[${color} ${type} ${default}]${default} ${commandaction} ${selfname}: ${message}${default}" + else + line="[${color} ${type} ${default}]${default} ${message}${default}" + fi + if [ -n "${plainoutput}" ]; then + plainpending="${line}" else - echo -en "${bold}${cree}[${color} ${type} ${default}]${default} ${message}${default}" + echo -en "${bold}${creeol}${line}" fi fn_sleep_time } @@ -134,6 +156,7 @@ fn_print_message_nl() { local type="$1" local color="$2" local message="$3" + unset plainpending if [ "${commandaction}" ]; then echo -e "${bold}${creeol}[${color} ${type} ${default}]${default} ${commandaction} ${selfname}: ${message}${default}" else @@ -142,6 +165,28 @@ fn_print_message_nl() { fn_sleep_time } +# Helper function to print eol messages with a specific color +fn_print_eol() { + local type="$1" + local color="$2" + if [ -n "${plainpending}" ]; then + plainpending+=" ... ${type}" + else + echo -en " ... ${color}${type}${default}" + fi +} + +fn_print_eol_nl() { + local type="$1" + local color="$2" + if [ -n "${plainpending}" ]; then + echo -e "${plainpending} ... ${type}" + unset plainpending + else + echo -e " ... ${color}${type}${default}" + fi +} + # [ .... ] fn_print_dots() { fn_print_message "...." "${default}" "$*" @@ -234,6 +279,7 @@ fn_messages_separator() { # No More Room in Hell Debug # ================================= fn_print_header() { + fn_print_plain_flush echo -e "" echo -e "${bold}${lightyellow}${gamename} ${commandaction}${default}" fn_messages_separator @@ -307,6 +353,7 @@ fn_print_skip2_nl() { # Y/N Prompt fn_prompt_yn() { + fn_print_plain_flush echo -e "" local prompt="$1" local initial="$2" @@ -356,166 +403,166 @@ fn_prompt_message() { # YES fn_print_yes_eol() { - echo -en " ... ${cyan}YES${default}" + fn_print_eol "YES" "${cyan}" fn_sleep_time } fn_print_yes_eol_nl() { - echo -e " ... ${cyan}YES${default}" + fn_print_eol_nl "YES" "${cyan}" fn_sleep_time } # NO fn_print_no_eol() { - echo -en " ... ${red}NO${default}" + fn_print_eol "NO" "${red}" fn_sleep_time } fn_print_no_eol_nl() { - echo -e " ... ${red}NO${default}" + fn_print_eol_nl "NO" "${red}" fn_sleep_time } # OK fn_print_ok_eol() { - echo -en " ... ${green}OK${default}" + fn_print_eol "OK" "${green}" fn_sleep_time } fn_print_ok_eol_nl() { - echo -e " ... ${green}OK${default}" + fn_print_eol_nl "OK" "${green}" fn_sleep_time } # FAIL fn_print_fail_eol() { - echo -en " ... ${red}FAIL${default}" + fn_print_eol "FAIL" "${red}" fn_sleep_time } fn_print_fail_eol_nl() { - echo -e " ... ${red}FAIL${default}" + fn_print_eol_nl "FAIL" "${red}" fn_sleep_time } # ERROR fn_print_error_eol() { - echo -en " ... ${red}ERROR${default}" + fn_print_eol "ERROR" "${red}" fn_sleep_time } fn_print_error_eol_nl() { - echo -e " ... ${red}ERROR${default}" + fn_print_eol_nl "ERROR" "${red}" fn_sleep_time } # WAIT fn_print_wait_eol() { - echo -en " ... ${cyan}WAIT${default}" + fn_print_eol "WAIT" "${cyan}" fn_sleep_time } fn_print_wait_eol_nl() { - echo -e " ... ${cyan}WAIT${default}" + fn_print_eol_nl "WAIT" "${cyan}" fn_sleep_time } # WARN fn_print_warn_eol() { - echo -en " ... ${lightyellow}WARN${default}" + fn_print_eol "WARN" "${lightyellow}" fn_sleep_time } fn_print_warn_eol_nl() { - echo -e " ... ${lightyellow}WARN${default}" + fn_print_eol_nl "WARN" "${lightyellow}" fn_sleep_time } # INFO fn_print_info_eol() { - echo -en " ... ${cyan}INFO${default}" + fn_print_eol "INFO" "${cyan}" fn_sleep_time } fn_print_info_eol_nl() { - echo -e " ... ${cyan}INFO${default}" + fn_print_eol_nl "INFO" "${cyan}" fn_sleep_time } # QUERYING fn_print_querying_eol() { - echo -en " ... ${cyan}QUERYING${default}" + fn_print_eol "QUERYING" "${cyan}" fn_sleep_time_1 } fn_print_querying_eol_nl() { - echo -e " ... ${cyan}QUERYING${default}" + fn_print_eol_nl "QUERYING" "${cyan}" fn_sleep_time_1 } # CHECKING fn_print_checking_eol() { - echo -en " ... ${cyan}CHECKING${default}" + fn_print_eol "CHECKING" "${cyan}" fn_sleep_time_1 } fn_print_checking_eol_nl() { - echo -e " ... ${cyan}CHECKING${default}" + fn_print_eol_nl "CHECKING" "${cyan}" fn_sleep_time_1 } # DELAY fn_print_delay_eol() { - echo -en " ... ${green}DELAY${default}" + fn_print_eol "DELAY" "${green}" fn_sleep_time_1 } fn_print_delay_eol_nl() { - echo -e " ... ${green}DELAY${default}" + fn_print_eol_nl "DELAY" "${green}" fn_sleep_time_1 } # CANCELED fn_print_canceled_eol() { - echo -en " ... ${lightyellow}CANCELED${default}" + fn_print_eol "CANCELED" "${lightyellow}" fn_sleep_time_1 } fn_print_canceled_eol_nl() { - echo -e " ... ${lightyellow}CANCELED${default}" + fn_print_eol_nl "CANCELED" "${lightyellow}" fn_sleep_time_1 } # REMOVED fn_print_removed_eol() { - echo -en " ... ${red}REMOVED${default}" + fn_print_eol "REMOVED" "${red}" fn_sleep_time_1 } fn_print_removed_eol_nl() { - echo -e " ... ${red}REMOVED${default}" + fn_print_eol_nl "REMOVED" "${red}" fn_sleep_time_1 } # UPDATE fn_print_update_eol() { - echo -en " ... ${lightblue}UPDATE${default}" + fn_print_eol "UPDATE" "${lightblue}" fn_sleep_time } fn_print_update_eol_nl() { - echo -e " ... ${lightblue}UPDATE${default}" + fn_print_eol_nl "UPDATE" "${lightblue}" fn_sleep_time } # SKIP fn_print_skip_eol() { - echo -en " ... ${cyan}SKIP${default}" + fn_print_eol "SKIP" "${cyan}" fn_sleep_time } fn_print_skip_eol_nl() { - echo -e " ... ${cyan}SKIP${default}" + fn_print_eol_nl "SKIP" "${cyan}" fn_sleep_time } From a3b92f79f5a170727a66852618a5e6485385e2bf Mon Sep 17 00:00:00 2001 From: Daniel Gibbs Date: Sat, 31 Oct 2026 11:38:40 +0000 Subject: [PATCH 127/164] fix(update-lgsm): build updated game script in tmpdir and restore backup on failure (#5118) * fix(update-lgsm): build updated game script in tmpdir and restore backup on failure sed -i writes its temporary file next to the target, so editing the game script in place needed write access to rootdir itself. Without it the copy from linuxgsm.sh succeeded but the substitutions failed, leaving the script with the "core" placeholders ("unknown game server"). Only the last sed call was checked, and the backup taken just before was never restored. The script is now assembled in tmpdir with a single sed call and copied over the existing file, which only needs write access to the file. If that copy fails, the backup is restored. The backup path is computed once so the logged location matches the file actually written. Fixes #3060 * fix(update-lgsm): restore executable bit on command_update_linuxgsm.sh --- lgsm/modules/command_update_linuxgsm.sh | 43 ++++++++++++++++++------- 1 file changed, 32 insertions(+), 11 deletions(-) diff --git a/lgsm/modules/command_update_linuxgsm.sh b/lgsm/modules/command_update_linuxgsm.sh index 80ff74cfb9..0d4d0ab911 100755 --- a/lgsm/modules/command_update_linuxgsm.sh +++ b/lgsm/modules/command_update_linuxgsm.sh @@ -90,7 +90,8 @@ if [ "${script_diff}" != "" ]; then if [ ! -d "${backupdir}/script" ]; then mkdir -p "${backupdir}/script" fi - cp "${rootdir}/${selfname}" "${backupdir}/script/${selfname}-$(date +"%m_%d_%Y_%M").bak" + scriptbackup="${backupdir}/script/${selfname}-$(date +"%m_%d_%Y_%M").bak" + cp "${rootdir}/${selfname}" "${scriptbackup}" exitcode=$? if [ "${exitcode}" -ne 0 ]; then fn_print_fail_eol_nl @@ -98,25 +99,45 @@ if [ "${script_diff}" != "" ]; then core_exit.sh else fn_print_ok_eol_nl - fn_script_log_pass "Backup script${selfname}" - echo -e "backup location [ ${backupdir}/script/${selfname}-$(date +"%m_%d_%Y_%M").bak ]" - fn_script_log_pass "Backup location ${backupdir}/script/${selfname}-$(date +"%m_%d_%Y_%M").bak" + fn_script_log_pass "Backup script ${selfname}" + echo -e "backup location [ ${scriptbackup} ]" + fn_script_log_pass "Backup location ${scriptbackup}" fi echo -en "copying ${selfname}" fn_script_log_info "Copying ${selfname}" - cp "${tmpdir}/linuxgsm.sh" "${rootdir}/${selfname}" - sed -i "s+shortname=\"core\"+shortname=\"${shortname}\"+g" "${rootdir}/${selfname}" - sed -i "s+gameservername=\"core\"+gameservername=\"${gameservername}\"+g" "${rootdir}/${selfname}" - sed -i "s+gamename=\"core\"+gamename=\"${gamename}\"+g" "${rootdir}/${selfname}" - sed -i "s+githubuser=\"GameServerManagers\"+githubuser=\"${githubuser}\"+g" "${rootdir}/${selfname}" - sed -i "s+githubrepo=\"LinuxGSM\"+githubrepo=\"${githubrepo}\"+g" "${rootdir}/${selfname}" - sed -i "s+githubbranch=\"master\"+githubbranch=\"${githubbranch}\"+g" "${rootdir}/${selfname}" + cp "${tmpdir}/linuxgsm.sh" "${tmpdir}/${selfname}.update" \ + && sed -i \ + -e "s+shortname=\"core\"+shortname=\"${shortname}\"+g" \ + -e "s+gameservername=\"core\"+gameservername=\"${gameservername}\"+g" \ + -e "s+gamename=\"core\"+gamename=\"${gamename}\"+g" \ + -e "s+githubuser=\"GameServerManagers\"+githubuser=\"${githubuser}\"+g" \ + -e "s+githubrepo=\"LinuxGSM\"+githubrepo=\"${githubrepo}\"+g" \ + -e "s+githubbranch=\"master\"+githubbranch=\"${githubbranch}\"+g" \ + "${tmpdir}/${selfname}.update" + exitcode=$? + if [ "${exitcode}" -ne 0 ]; then + fn_print_fail_eol_nl + fn_script_log_fail "Preparing ${selfname} in ${tmpdir}" + rm -f "${tmpdir:?}/${selfname}.update" + core_exit.sh + fi + cp "${tmpdir}/${selfname}.update" "${rootdir}/${selfname}" exitcode=$? + rm -f "${tmpdir:?}/${selfname}.update" if [ "${exitcode}" -ne 0 ]; then fn_print_fail_eol_nl fn_script_log_fail "copying ${selfname}" + echo -en "restoring ${selfname} from backup\c" + fn_script_log_info "Restoring ${selfname} from ${scriptbackup}" + if cp "${scriptbackup}" "${rootdir}/${selfname}"; then + fn_print_ok_eol_nl + fn_script_log_pass "Restoring ${selfname} from backup" + else + fn_print_fail_eol_nl + fn_script_log_fail "Restoring ${selfname} from backup ${scriptbackup}" + fi core_exit.sh else fn_print_ok_eol_nl From a1bdac13a638f24bdd33dcae9e3fbf66b44f1df4 Mon Sep 17 00:00:00 2001 From: Nikolay Asenov <10465782+nasenov@users.noreply.github.com> Date: Sat, 31 Oct 2026 17:18:55 +0200 Subject: [PATCH 128/164] fix(mods_list): update AMX Mod X version to latest release (#5115) Update the AMX Mod X base package and the cstrike, dod, tfc, ns and ts addons from 1.9.0-git5303 to the 1.10.0-git5487 release. --- lgsm/modules/mods_list.sh | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/lgsm/modules/mods_list.sh b/lgsm/modules/mods_list.sh index 9f997c13ac..e1bf2a810d 100755 --- a/lgsm/modules/mods_list.sh +++ b/lgsm/modules/mods_list.sh @@ -19,40 +19,40 @@ metamodlatestfile="metamod-${metamodversion}.zip" metamoddownloadurl="https://www.amxmodx.org/release/${metamodlatestfile}" metamodurl="${metamoddownloadurl}" # AMX Mod X: Base -amxxbaseversion="1.9.0-git5303" +amxxbaseversion="1.10.0-git5487" amxxbasemod="base" amxxbaselatestfile="amxmodx-${amxxbaseversion}-${amxxbasemod}-linux.tar.gz" -amxxbasedownloadurl="https://github.com/alliedmodders/amxmodx/releases/download/1.9.0.5303/${amxxbaselatestfile}" +amxxbasedownloadurl="https://github.com/alliedmodders/amxmodx/releases/download/1.10.0.5487/${amxxbaselatestfile}" amxxbaseurl="${amxxbasedownloadurl}" # AMX Mod X: Counter-Strike -amxxcsversion="1.9.0-git5303" +amxxcsversion="1.10.0-git5487" amxxcsmod="cstrike" amxxcslatestfile="amxmodx-${amxxbaseversion}-${amxxcsmod}-linux.tar.gz" -amxxcsdownloadurl="https://github.com/alliedmodders/amxmodx/releases/download/1.9.0.5303/${amxxcslatestfile}" +amxxcsdownloadurl="https://github.com/alliedmodders/amxmodx/releases/download/1.10.0.5487/${amxxcslatestfile}" amxxcsurl="${amxxcsdownloadurl}" # AMX Mod X: Day of Defeat -amxxdodversion="1.9.0-git5303" +amxxdodversion="1.10.0-git5487" amxxdodmod="dod" amxxdodlatestfile="amxmodx-${amxxdodversion}-${amxxdodmod}-linux.tar.gz" -amxxdoddownloadurl="https://github.com/alliedmodders/amxmodx/releases/download/1.9.0.5303/${amxxdodlatestfile}" +amxxdoddownloadurl="https://github.com/alliedmodders/amxmodx/releases/download/1.10.0.5487/${amxxdodlatestfile}" amxxdodurl="${amxxdoddownloadurl}" # AMX Mod X: Team Fortress Classic -amxxtfcversion="1.9.0-git5303" +amxxtfcversion="1.10.0-git5487" amxxtfcmod="tfc" amxxtfclatestfile="amxmodx-${amxxtfcversion}-${amxxtfcmod}-linux.tar.gz" -amxxtfcdownloadurl="https://github.com/alliedmodders/amxmodx/releases/download/1.9.0.5303/${amxxtfclatestfile}" +amxxtfcdownloadurl="https://github.com/alliedmodders/amxmodx/releases/download/1.10.0.5487/${amxxtfclatestfile}" amxxtfcurl="${amxxtfcdownloadurl}" # AMX Mod X: Natural Selection -amxxnsversion="1.9.0-git5303" +amxxnsversion="1.10.0-git5487" amxxnsmod="ns" amxxnslatestfile="amxmodx-${amxxnsversion}-${amxxnsmod}-linux.tar.gz" -amxxnsdownloadurl="https://github.com/alliedmodders/amxmodx/releases/download/1.9.0.5303/${amxxnslatestfile}" +amxxnsdownloadurl="https://github.com/alliedmodders/amxmodx/releases/download/1.10.0.5487/${amxxnslatestfile}" amxxnsurl="${amxxnsdownloadurl}" # AMX Mod X: The Specialists -amxxtsversion="1.9.0-git5303" +amxxtsversion="1.10.0-git5487" amxxtsmod="ts" amxxtslatestfile="amxmodx-${amxxtsversion}-${amxxtsmod}-linux.tar.gz" -amxxtsdownloadurl="https://github.com/alliedmodders/amxmodx/releases/download/1.9.0.5303/${amxxtslatestfile}" +amxxtsdownloadurl="https://github.com/alliedmodders/amxmodx/releases/download/1.10.0.5487/${amxxtslatestfile}" amxxtsurl="${amxxtsdownloadurl}" # Metamod:Source metamodsourceversion="1.12" From bd08affb7133d775956c111f65f55bded5fd115e Mon Sep 17 00:00:00 2001 From: Vladimir Mikhalev <10498744+heyvaldemar@users.noreply.github.com> Date: Sat, 31 Oct 2026 11:24:45 -0400 Subject: [PATCH 129/164] fix(kf2): create the KFGame/Cache map-load directory on install (#5108) The KF2 Linux dedicated server never creates KFGame/Cache, which it needs when it loads maps, Workshop maps included. Create it during install once KFGame exists. --- lgsm/modules/fix_kf2.sh | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/lgsm/modules/fix_kf2.sh b/lgsm/modules/fix_kf2.sh index 495e9d70ef..fe2667e62f 100755 --- a/lgsm/modules/fix_kf2.sh +++ b/lgsm/modules/fix_kf2.sh @@ -17,3 +17,14 @@ fn_sleep_time_10 exitbypass=1 command_stop.sh fn_firstcommand_reset + +# The KF2 Linux dedicated server does not create KFGame/Cache, the directory it +# uses when loading maps (including Workshop maps). The KF2 wiki lists this as a +# known Linux issue and the remedy as `mkdir -p KFGame/Cache`. Creating it after +# install, only once KFGame exists, keeps it present after every install. +if [ -d "${serverfiles}/KFGame" ] && [ ! -d "${serverfiles}/KFGame/Cache" ]; then + fixname="KFGame/Cache directory" + fn_fix_msg_start + mkdir -p "${serverfiles}/KFGame/Cache" + fn_fix_msg_end +fi From eed5036cbfcb2caf4fb49723616455976f1f8c60 Mon Sep 17 00:00:00 2001 From: BorzakA <1230402+borzaka@users.noreply.github.com> Date: Sat, 31 Oct 2026 16:27:29 +0100 Subject: [PATCH 130/164] fix(mods): resolve AMX Mod X packages from the latest 1.10 build (#5119) Resolve the AMX Mod X base package and the cstrike, dod, tfc, ns and ts addons from the latest 1.10 Linux build on amxmodx.org at mods-install and mods-update time, instead of pinning one release. The base and every addon use the same build, and the install stops with an error if the build cannot be resolved. --- lgsm/modules/mods_list.sh | 74 ++++++++++++++++++++------------------- 1 file changed, 38 insertions(+), 36 deletions(-) diff --git a/lgsm/modules/mods_list.sh b/lgsm/modules/mods_list.sh index e1bf2a810d..fd9a39d386 100755 --- a/lgsm/modules/mods_list.sh +++ b/lgsm/modules/mods_list.sh @@ -18,42 +18,44 @@ metamodversion="1.21.1-am" metamodlatestfile="metamod-${metamodversion}.zip" metamoddownloadurl="https://www.amxmodx.org/release/${metamodlatestfile}" metamodurl="${metamoddownloadurl}" -# AMX Mod X: Base -amxxbaseversion="1.10.0-git5487" -amxxbasemod="base" -amxxbaselatestfile="amxmodx-${amxxbaseversion}-${amxxbasemod}-linux.tar.gz" -amxxbasedownloadurl="https://github.com/alliedmodders/amxmodx/releases/download/1.10.0.5487/${amxxbaselatestfile}" -amxxbaseurl="${amxxbasedownloadurl}" -# AMX Mod X: Counter-Strike -amxxcsversion="1.10.0-git5487" -amxxcsmod="cstrike" -amxxcslatestfile="amxmodx-${amxxbaseversion}-${amxxcsmod}-linux.tar.gz" -amxxcsdownloadurl="https://github.com/alliedmodders/amxmodx/releases/download/1.10.0.5487/${amxxcslatestfile}" -amxxcsurl="${amxxcsdownloadurl}" -# AMX Mod X: Day of Defeat -amxxdodversion="1.10.0-git5487" -amxxdodmod="dod" -amxxdodlatestfile="amxmodx-${amxxdodversion}-${amxxdodmod}-linux.tar.gz" -amxxdoddownloadurl="https://github.com/alliedmodders/amxmodx/releases/download/1.10.0.5487/${amxxdodlatestfile}" -amxxdodurl="${amxxdoddownloadurl}" -# AMX Mod X: Team Fortress Classic -amxxtfcversion="1.10.0-git5487" -amxxtfcmod="tfc" -amxxtfclatestfile="amxmodx-${amxxtfcversion}-${amxxtfcmod}-linux.tar.gz" -amxxtfcdownloadurl="https://github.com/alliedmodders/amxmodx/releases/download/1.10.0.5487/${amxxtfclatestfile}" -amxxtfcurl="${amxxtfcdownloadurl}" -# AMX Mod X: Natural Selection -amxxnsversion="1.10.0-git5487" -amxxnsmod="ns" -amxxnslatestfile="amxmodx-${amxxnsversion}-${amxxnsmod}-linux.tar.gz" -amxxnsdownloadurl="https://github.com/alliedmodders/amxmodx/releases/download/1.10.0.5487/${amxxnslatestfile}" -amxxnsurl="${amxxnsdownloadurl}" -# AMX Mod X: The Specialists -amxxtsversion="1.10.0-git5487" -amxxtsmod="ts" -amxxtslatestfile="amxmodx-${amxxtsversion}-${amxxtsmod}-linux.tar.gz" -amxxtsdownloadurl="https://github.com/alliedmodders/amxmodx/releases/download/1.10.0.5487/${amxxtslatestfile}" -amxxtsurl="${amxxtsdownloadurl}" +# AMX Mod X: Resolve one build for the base and all game addons on install/update only. +amxxbranch="1.10" +amxxdownloadbase="https://www.amxmodx.org/amxxdrop/${amxxbranch}" +amxxscrapeurl="${amxxdownloadbase}/amxmodx-latest-base-linux" +if { [ "${commandname}" == "MODS-INSTALL" ] || [ "${commandname}" == "MODS-UPDATE" ]; } \ + && { [ "${shortname}" == "cs" ] || [ "${shortname}" == "dod" ] || [ "${shortname}" == "tfc" ] || [ "${shortname}" == "ns" ] || [ "${shortname}" == "ts" ] || [ "${shortname}" == "hldm" ]; }; then + if ! amxxlatestfile=$(curl --connect-timeout 3 --max-time 30 --fail --silent --show-error --location "${amxxscrapeurl}"); then + fn_print_fail_nl "Unable to get the latest AMX Mod X ${amxxbranch} Linux build: ${amxxscrapeurl}" + fn_script_log_fail "Unable to get the latest AMX Mod X ${amxxbranch} Linux build: ${amxxscrapeurl}" + exitcode=1 + core_exit.sh + fi + if [[ ! "${amxxlatestfile}" =~ ^amxmodx-("${amxxbranch}"\.[0-9]+-git[0-9]+)-base-linux\.tar\.gz$ ]]; then + fn_print_fail_nl "Invalid AMX Mod X ${amxxbranch} Linux build filename: ${amxxscrapeurl}" + fn_script_log_fail "Invalid AMX Mod X ${amxxbranch} Linux build filename: ${amxxscrapeurl}" + exitcode=1 + core_exit.sh + fi + amxxversion="${BASH_REMATCH[1]}" + # AMX Mod X: Base + amxxbaselatestfile="amxmodx-${amxxversion}-base-linux.tar.gz" + amxxbaseurl="${amxxdownloadbase}/${amxxbaselatestfile}" + # AMX Mod X: Counter-Strike + amxxcslatestfile="amxmodx-${amxxversion}-cstrike-linux.tar.gz" + amxxcsurl="${amxxdownloadbase}/${amxxcslatestfile}" + # AMX Mod X: Day of Defeat + amxxdodlatestfile="amxmodx-${amxxversion}-dod-linux.tar.gz" + amxxdodurl="${amxxdownloadbase}/${amxxdodlatestfile}" + # AMX Mod X: Team Fortress Classic + amxxtfclatestfile="amxmodx-${amxxversion}-tfc-linux.tar.gz" + amxxtfcurl="${amxxdownloadbase}/${amxxtfclatestfile}" + # AMX Mod X: Natural Selection + amxxnslatestfile="amxmodx-${amxxversion}-ns-linux.tar.gz" + amxxnsurl="${amxxdownloadbase}/${amxxnslatestfile}" + # AMX Mod X: The Specialists + amxxtslatestfile="amxmodx-${amxxversion}-ts-linux.tar.gz" + amxxtsurl="${amxxdownloadbase}/${amxxtslatestfile}" +fi # Metamod:Source metamodsourceversion="1.12" metamodsourcescrapeurl="https://mms.alliedmods.net/mmsdrop/${metamodsourceversion}/mmsource-latest-linux" From 637ded1c2267e7c7b5e6a00803fcb467d231a884 Mon Sep 17 00:00:00 2001 From: Breeze <271538431+BreezeDelegate@users.noreply.github.com> Date: Sat, 31 Oct 2026 16:30:14 +0100 Subject: [PATCH 131/164] feat(monitor): show local port state after query failures (#5111) When a monitor query fails, check the local query port with ss and add a hint to the output and log: either nothing is listening on the port, or the port is in use (naming the process when ss knows it). The monitor still retries and restarts exactly as before. --- .github/tests/monitor_query_port_hint.sh | 53 ++++++++++++++++++++++++ lgsm/modules/command_monitor.sh | 32 ++++++++++++++ 2 files changed, 85 insertions(+) create mode 100755 .github/tests/monitor_query_port_hint.sh diff --git a/.github/tests/monitor_query_port_hint.sh b/.github/tests/monitor_query_port_hint.sh new file mode 100755 index 0000000000..1d84c0b789 --- /dev/null +++ b/.github/tests/monitor_query_port_hint.sh @@ -0,0 +1,53 @@ +#!/bin/bash +set -euo pipefail +cd "$(dirname "$0")/../.." +# The monitor runs when sourced, so load only the helper under test. +# shellcheck source=/dev/null +source <(sed -n '/^fn_monitor_query_port_hint() {/,/^}/p' lgsm/modules/command_monitor.sh) + +tmp="$(mktemp -d)" +trap 'rm -rf "$tmp"' EXIT +fn_print_warn() { printf '%s\n' "$*" >> "$tmp/screen"; } +fn_print_warn_eol_nl() { :; } +fn_script_log_warn() { printf '%s\n' "$*" >> "$tmp/log"; } +queryport=27016 + +socket_state=absent +ss() { + case "$socket_state" in + absent) printf '%s\n' 'udp UNCONN 0 0 0.0.0.0:270160 0.0.0.0:*' ;; + used) printf '%s\n' 'tcp LISTEN 0 128 0.0.0.0:27016 0.0.0.0:* users:(("srcds",pid=123,fd=5))' ;; + no_process) printf '%s\n' 'udp UNCONN 0 0 0.0.0.0:27016 0.0.0.0:*' ;; + unavailable) return 1 ;; + esac +} +check_output() { + grep -Fq "$1" "$tmp/log" + grep -Fq "$1" "$tmp/screen" + [ "$(wc -l < "$tmp/log")" -eq 1 ] + [ "$(wc -l < "$tmp/screen")" -eq 1 ] +} +: > "$tmp/log" +: > "$tmp/screen" +fn_monitor_query_port_hint +check_output 'No local TCP/UDP listener on port 27016' + +: > "$tmp/log" +: > "$tmp/screen" +socket_state=used +fn_monitor_query_port_hint +check_output 'Local TCP/UDP port 27016 is in use by srcds' + +: > "$tmp/log" +: > "$tmp/screen" +socket_state=no_process +fn_monitor_query_port_hint +check_output 'Local TCP/UDP port 27016 is in use; check the query port and protocol' + +: > "$tmp/log" +: > "$tmp/screen" +socket_state=unavailable +fn_monitor_query_port_hint +[ ! -s "$tmp/log" ] +[ ! -s "$tmp/screen" ] +printf '%s\n' 'monitor query port hints: 4 checks passed' diff --git a/lgsm/modules/command_monitor.sh b/lgsm/modules/command_monitor.sh index 78690f9c4d..40c5d73688 100755 --- a/lgsm/modules/command_monitor.sh +++ b/lgsm/modules/command_monitor.sh @@ -359,6 +359,37 @@ fn_query_tcp() { querystatus="$?" } +# Explain a failed query without changing the monitor's retry/restart decision. +fn_monitor_query_port_hint() { + local sockets protocol state recvq sendq address peer details + local listener="" process="" hint="" + + command -v ss > /dev/null 2>&1 || return 0 + sockets="$(ss -H -lntup 2> /dev/null)" || return 0 + + while read -r protocol state recvq sendq address peer details; do + if [ "${address##*:}" == "${queryport}" ]; then + listener=1 + process="$(sed -nE 's/.*users:\(\("([^"]+)".*/\1/p' <<< "${details}")" + break + fi + done <<< "${sockets}" + + if [ -z "${listener}" ]; then + hint="No local TCP/UDP listener on port ${queryport}; check startup and port settings" + else + hint="Local TCP/UDP port ${queryport} is in use" + if [ -n "${process}" ]; then + hint+=" by ${process}" + fi + hint+="; check the query port and protocol" + fi + + fn_print_warn "Query port: ${hint}" + fn_print_warn_eol_nl + fn_script_log_warn "Query port: ${hint}" +} + fn_monitor_query() { # Will loop and query up to 5 times every 15 seconds. # Query will wait up to 60 seconds to confirm server is down as server can become non-responsive during map changes. @@ -432,6 +463,7 @@ fn_monitor_query() { fn_print_fail "Querying port: ${querymethod}: ${queryip}:${queryport} : ${totalseconds}/${queryattempt}" fn_print_fail_eol_nl fn_script_log_warn "Querying port: ${querymethod}: ${queryip}:${queryport} : ${queryattempt} : FAIL" + fn_monitor_query_port_hint fn_monitor_check_backup_update # Send alert if enabled. alert="monitor-query" From 5d5bd40e5e0e86634d32bac74c853d875974458f Mon Sep 17 00:00:00 2001 From: BorzakA <1230402+borzaka@users.noreply.github.com> Date: Sat, 31 Oct 2026 16:32:56 +0100 Subject: [PATCH 132/164] feat(cs2server): add MatchZy mod (#5088) Add MatchZy as a CS2 mod. It installs the plugin-only release archive and requires CounterStrikeSharp. Removing it keeps the shared CounterStrikeSharp directories in place. --- lgsm/modules/command_mods_install.sh | 5 +++++ lgsm/modules/mods_core.sh | 7 +++++++ lgsm/modules/mods_list.sh | 8 +++++++- 3 files changed, 19 insertions(+), 1 deletion(-) diff --git a/lgsm/modules/command_mods_install.sh b/lgsm/modules/command_mods_install.sh index 09bc4ce270..857bd347c5 100755 --- a/lgsm/modules/command_mods_install.sh +++ b/lgsm/modules/command_mods_install.sh @@ -120,6 +120,11 @@ if [ "${modcommand}" == "counterstrikesharp" ]; then fn_mod_exist "metamodsource2" fi +# MatchZy requires CounterStrikeSharp. +if [ "${modcommand}" == "matchzy" ]; then + fn_mod_exist "counterstrikesharp" +fi + # If amxmodx check if metamod exists first if [ "${modcommand}" == "amxmodx" ]; then fn_mod_exist "metamod" diff --git a/lgsm/modules/mods_core.sh b/lgsm/modules/mods_core.sh index daec8e367d..00c81a3439 100755 --- a/lgsm/modules/mods_core.sh +++ b/lgsm/modules/mods_core.sh @@ -200,6 +200,13 @@ fn_mod_tidy_files_list() { sed -i "/^addons\/metamod$/d" "${modsdir}/${modcommand}-files.txt" fi + # Remove common CounterStrikeSharp paths from deletion list (Add your CounterStrikeSharp plugin here) + if [ "${modcommand}" == "matchzy" ]; then + sed -i "/^addons\/counterstrikesharp$/d" "${modsdir}/${modcommand}-files.txt" + sed -i "/^addons\/counterstrikesharp\/gamedata$/d" "${modsdir}/${modcommand}-files.txt" + sed -i "/^addons\/counterstrikesharp\/plugins$/d" "${modsdir}/${modcommand}-files.txt" + fi + # Remove common paths from deletion list (Add your sourcemod mod here) if [ "${modcommand}" == "gokz" ] || [ "${modcommand}" == "ttt" ] || [ "${modcommand}" == "steamworks" ] || [ "${modcommand}" == "get5" ] || [ "${modcommand}" == "nolobbyreservation" ]; then sed -i "/^addons\/sourcemod$/d" "${modsdir}/${modcommand}-files.txt" diff --git a/lgsm/modules/mods_list.sh b/lgsm/modules/mods_list.sh index fd9a39d386..32ef44c024 100755 --- a/lgsm/modules/mods_list.sh +++ b/lgsm/modules/mods_list.sh @@ -104,6 +104,11 @@ if [ "${shortname}" == "cs2" ]; then counterstrikesharplastbuild=$(printf '%s\n' "${counterstrikesharprelease}" | jq '.assets[]? | select(.name | startswith("counterstrikesharp-with-runtime-linux-") and endswith(".zip"))' 2> /dev/null) counterstrikesharplatestfile=$(printf '%s\n' "${counterstrikesharplastbuild}" | jq -r '.name') counterstrikesharplatestlink=$(printf '%s\n' "${counterstrikesharplastbuild}" | jq -r '.browser_download_url') + # MatchZy: use the plugin-only archive, CounterStrikeSharp is installed as its own mod. + matchzyrelease=$(curl --connect-timeout 3 -sL https://api.github.com/repos/shobhit-pathak/MatchZy/releases/latest) + matchzylastbuild=$(printf '%s\n' "${matchzyrelease}" | jq '.assets[]? | select(.name | startswith("MatchZy-") and endswith(".zip") and (contains("with-cssharp") | not))' 2> /dev/null) + matchzylatestfile=$(printf '%s\n' "${matchzylastbuild}" | jq -r '.name') + matchzylatestlink=$(printf '%s\n' "${matchzylastbuild}" | jq -r '.browser_download_url') fi # CS:GO Mods @@ -200,6 +205,7 @@ mod_info_stripper=(MOD "stripper" "Stripper Source" "${stripperurl}" "${stripper # CS2 Mods mod_info_metamodsource2=(MOD "metamodsource2" "Metamod:Source 2.0" "${metamodsource2url}" "${metamodsource2latestfile}" "0" "LowercaseOff" "${systemdir}" "addons/metamod/metaplugins.ini;" "ENGINES" "Counter-Strike 2;" "NOTGAMES" "https://www.metamodsource.net" "Plugins Framework (Dev Build)") mod_info_counterstrikesharp=(MOD "counterstrikesharp" "CounterStrikeSharp" "${counterstrikesharplatestlink}" "${counterstrikesharplatestfile}" "0" "LowercaseOff" "${systemdir}" "OVERWRITE" "ENGINES" "Counter-Strike 2;" "NOTGAMES" "https://docs.cssharp.dev/" "Write server plugins in C# (requires Metamod:Source 2.0)") +mod_info_matchzy=(MOD "matchzy" "MatchZy" "${matchzylatestlink}" "${matchzylatestfile}" "0" "LowercaseOff" "${systemdir}" "OVERWRITE" "ENGINES" "Counter-Strike 2;" "NOTGAMES" "https://github.com/shobhit-pathak/MatchZy" "Plugin for practice, pugs, scrims and matches (requires CounterStrikeSharp)") # CS:GO Mods # NoLobbyReservation is pinned to a reviewed commit: it has no releases and is compiled from source on install. @@ -258,4 +264,4 @@ mod_info_valheimplus=(MOD "valheimplus" "Valheim PLUS" "${valheimpluslatestlink} mod_info_bepinexvh=(MOD "bepinexvh" "BepInEx Valheim" "${bepinexvhlatestlink}" "denikson-BepInExPack_Valheim.zip" "BepInExPack_Valheim" "LowercaseOff" "${systemdir}" "OVERWRITE" "ENGINES" "Valheim;" "NOTGAMES" "https://valheim.thunderstore.io/package/denikson/BepInExPack_Valheim/" "Unity / XNA game patcher and plugin framework") # REQUIRED: Set all mods info into the global array -mods_global_array=("${mod_info_metamod[@]}" "${mod_info_base_amxx[@]}" "${mod_info_cs_amxx[@]}" "${mod_info_dod_amxx[@]}" "${mod_info_tfc_amxx[@]}" "${mod_info_ns_amxx[@]}" "${mod_info_ts_amxx[@]}" "${mod_info_metamodsource[@]}" "${mod_info_metamodsource2[@]}" "${mod_info_counterstrikesharp[@]}" "${mod_info_sourcemod[@]}" "${mod_info_nolobbyreservation[@]}" "${mod_info_steamworks[@]}" "${mod_info_gokz[@]}" "${mod_info_ttt[@]}" "${mod_info_get5[@]}" "${mod_info_prac[@]}" "${mod_info_pug[@]}" "${mod_info_dhook[@]}" "${mod_info_movement[@]}" "${mod_info_cleaner[@]}" "${mod_info_ulib[@]}" "${mod_info_ulx[@]}" "${mod_info_utime[@]}" "${mod_info_uclip[@]}" "${mod_info_acf[@]}" "${mod_info_acf_missiles[@]}" "${mod_info_acf_sweps[@]}" "${mod_info_advdupe2[@]}" "${mod_info_pac3[@]}" "${mod_info_wiremod[@]}" "${mod_info_wiremodextras[@]}" "${mod_info_darkrp[@]}" "${mod_info_darkrpmodification[@]}" "${mod_info_rustcarbon[@]}" "${mod_info_rustoxide[@]}" "${mod_info_hwoxide[@]}" "${mod_info_sdtdoxide[@]}" "${mod_info_advduplicator[@]}" "${mod_info_trackassemblytool[@]}" "${mod_info_physpropertiesadv[@]}" "${mod_info_controlsystemse2[@]}" "${mod_info_e2pistontiming[@]}" "${mod_info_propcannontool[@]}" "${mod_info_gearassemblytool[@]}" "${mod_info_spinnertool[@]}" "${mod_info_surfacefrictiontool[@]}" "${mod_info_magneticdipole[@]}" "${mod_info_environmentorganizer[@]}" "${mod_info_precision_alignment[@]}" "${mod_info_improved_stacker[@]}" "${mod_info_improved_weight[@]}" "${mod_info_improved_antinoclip[@]}" "${mod_info_laserstool[@]}" "${mod_info_valheimplus[@]}" "${mod_info_bepinexvh[@]}") +mods_global_array=("${mod_info_metamod[@]}" "${mod_info_base_amxx[@]}" "${mod_info_cs_amxx[@]}" "${mod_info_dod_amxx[@]}" "${mod_info_tfc_amxx[@]}" "${mod_info_ns_amxx[@]}" "${mod_info_ts_amxx[@]}" "${mod_info_metamodsource[@]}" "${mod_info_metamodsource2[@]}" "${mod_info_counterstrikesharp[@]}" "${mod_info_matchzy[@]}" "${mod_info_sourcemod[@]}" "${mod_info_nolobbyreservation[@]}" "${mod_info_steamworks[@]}" "${mod_info_gokz[@]}" "${mod_info_ttt[@]}" "${mod_info_get5[@]}" "${mod_info_prac[@]}" "${mod_info_pug[@]}" "${mod_info_dhook[@]}" "${mod_info_movement[@]}" "${mod_info_cleaner[@]}" "${mod_info_ulib[@]}" "${mod_info_ulx[@]}" "${mod_info_utime[@]}" "${mod_info_uclip[@]}" "${mod_info_acf[@]}" "${mod_info_acf_missiles[@]}" "${mod_info_acf_sweps[@]}" "${mod_info_advdupe2[@]}" "${mod_info_pac3[@]}" "${mod_info_wiremod[@]}" "${mod_info_wiremodextras[@]}" "${mod_info_darkrp[@]}" "${mod_info_darkrpmodification[@]}" "${mod_info_rustcarbon[@]}" "${mod_info_rustoxide[@]}" "${mod_info_hwoxide[@]}" "${mod_info_sdtdoxide[@]}" "${mod_info_advduplicator[@]}" "${mod_info_trackassemblytool[@]}" "${mod_info_physpropertiesadv[@]}" "${mod_info_controlsystemse2[@]}" "${mod_info_e2pistontiming[@]}" "${mod_info_propcannontool[@]}" "${mod_info_gearassemblytool[@]}" "${mod_info_spinnertool[@]}" "${mod_info_surfacefrictiontool[@]}" "${mod_info_magneticdipole[@]}" "${mod_info_environmentorganizer[@]}" "${mod_info_precision_alignment[@]}" "${mod_info_improved_stacker[@]}" "${mod_info_improved_weight[@]}" "${mod_info_improved_antinoclip[@]}" "${mod_info_laserstool[@]}" "${mod_info_valheimplus[@]}" "${mod_info_bepinexvh[@]}") From c763125cd5a2935bda7f597958b83cbdd2ea0809 Mon Sep 17 00:00:00 2001 From: Daniel Gibbs Date: Sat, 31 Oct 2026 15:40:58 +0000 Subject: [PATCH 133/164] revert: fix(kf2): create the KFGame/Cache map-load directory on install (#5108) This reverts commit bd08affb7133d775956c111f65f55bded5fd115e. On the current KF2 server build (10897) the server creates KFGame/Cache itself when it first downloads a Workshop item, so the directory is not missing. The map-load crash comes from starting directly on a Workshop map that has not been downloaded yet, which this change does not affect. --- lgsm/modules/fix_kf2.sh | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/lgsm/modules/fix_kf2.sh b/lgsm/modules/fix_kf2.sh index fe2667e62f..495e9d70ef 100755 --- a/lgsm/modules/fix_kf2.sh +++ b/lgsm/modules/fix_kf2.sh @@ -17,14 +17,3 @@ fn_sleep_time_10 exitbypass=1 command_stop.sh fn_firstcommand_reset - -# The KF2 Linux dedicated server does not create KFGame/Cache, the directory it -# uses when loading maps (including Workshop maps). The KF2 wiki lists this as a -# known Linux issue and the remedy as `mkdir -p KFGame/Cache`. Creating it after -# install, only once KFGame exists, keeps it present after every install. -if [ -d "${serverfiles}/KFGame" ] && [ ! -d "${serverfiles}/KFGame/Cache" ]; then - fixname="KFGame/Cache directory" - fn_fix_msg_start - mkdir -p "${serverfiles}/KFGame/Cache" - fn_fix_msg_end -fi From 5bf2e7441223f20ec1ca6380368b3cab8225c9a7 Mon Sep 17 00:00:00 2001 From: Daniel Gibbs Date: Sat, 31 Oct 2026 16:18:30 +0000 Subject: [PATCH 134/164] fix(monitor): tell a hung server apart from a port conflict in the query hint (#5120) When the query port is held by the game server's own process tree, say the server did not answer and may be hung, instead of pointing at the port settings. Name another process as a port conflict, show the real protocols from ss instead of "TCP/UDP", and drop the unused test script. --- .github/tests/monitor_query_port_hint.sh | 53 ------------------------ lgsm/modules/command_monitor.sh | 40 ++++++++++++------ 2 files changed, 27 insertions(+), 66 deletions(-) delete mode 100755 .github/tests/monitor_query_port_hint.sh diff --git a/.github/tests/monitor_query_port_hint.sh b/.github/tests/monitor_query_port_hint.sh deleted file mode 100755 index 1d84c0b789..0000000000 --- a/.github/tests/monitor_query_port_hint.sh +++ /dev/null @@ -1,53 +0,0 @@ -#!/bin/bash -set -euo pipefail -cd "$(dirname "$0")/../.." -# The monitor runs when sourced, so load only the helper under test. -# shellcheck source=/dev/null -source <(sed -n '/^fn_monitor_query_port_hint() {/,/^}/p' lgsm/modules/command_monitor.sh) - -tmp="$(mktemp -d)" -trap 'rm -rf "$tmp"' EXIT -fn_print_warn() { printf '%s\n' "$*" >> "$tmp/screen"; } -fn_print_warn_eol_nl() { :; } -fn_script_log_warn() { printf '%s\n' "$*" >> "$tmp/log"; } -queryport=27016 - -socket_state=absent -ss() { - case "$socket_state" in - absent) printf '%s\n' 'udp UNCONN 0 0 0.0.0.0:270160 0.0.0.0:*' ;; - used) printf '%s\n' 'tcp LISTEN 0 128 0.0.0.0:27016 0.0.0.0:* users:(("srcds",pid=123,fd=5))' ;; - no_process) printf '%s\n' 'udp UNCONN 0 0 0.0.0.0:27016 0.0.0.0:*' ;; - unavailable) return 1 ;; - esac -} -check_output() { - grep -Fq "$1" "$tmp/log" - grep -Fq "$1" "$tmp/screen" - [ "$(wc -l < "$tmp/log")" -eq 1 ] - [ "$(wc -l < "$tmp/screen")" -eq 1 ] -} -: > "$tmp/log" -: > "$tmp/screen" -fn_monitor_query_port_hint -check_output 'No local TCP/UDP listener on port 27016' - -: > "$tmp/log" -: > "$tmp/screen" -socket_state=used -fn_monitor_query_port_hint -check_output 'Local TCP/UDP port 27016 is in use by srcds' - -: > "$tmp/log" -: > "$tmp/screen" -socket_state=no_process -fn_monitor_query_port_hint -check_output 'Local TCP/UDP port 27016 is in use; check the query port and protocol' - -: > "$tmp/log" -: > "$tmp/screen" -socket_state=unavailable -fn_monitor_query_port_hint -[ ! -s "$tmp/log" ] -[ ! -s "$tmp/screen" ] -printf '%s\n' 'monitor query port hints: 4 checks passed' diff --git a/lgsm/modules/command_monitor.sh b/lgsm/modules/command_monitor.sh index 40c5d73688..82a7227551 100755 --- a/lgsm/modules/command_monitor.sh +++ b/lgsm/modules/command_monitor.sh @@ -359,30 +359,44 @@ fn_query_tcp() { querystatus="$?" } -# Explain a failed query without changing the monitor's retry/restart decision. fn_monitor_query_port_hint() { local sockets protocol state recvq sendq address peer details - local listener="" process="" hint="" + local serverpid="" protocols="" process="" pid="" ancestor="" serverprocess="" otherprocess="" hint="" command -v ss > /dev/null 2>&1 || return 0 sockets="$(ss -H -lntup 2> /dev/null)" || return 0 + serverpid="$(TERM=screen tmux -L "${socketname}" list-sessions -F "#{session_name} #{pane_pid}" 2> /dev/null | awk -v session="${sessionname}" '$1 == session {print $2}')" while read -r protocol state recvq sendq address peer details; do - if [ "${address##*:}" == "${queryport}" ]; then - listener=1 - process="$(sed -nE 's/.*users:\(\("([^"]+)".*/\1/p' <<< "${details}")" - break + if [ "${address##*:}" != "${queryport}" ]; then + continue + fi + if [[ " ${protocols//\// } " != *" ${protocol} "* ]]; then + protocols+="${protocols:+/}${protocol}" + fi + process="$(sed -nE 's/.*users:\(\("([^"]+)".*/\1/p' <<< "${details}")" + pid="$(sed -nE 's/.*users:\(\("[^"]+",pid=([0-9]+).*/\1/p' <<< "${details}")" + ancestor="${pid}" + while [ -n "${serverpid}" ] && [ -n "${ancestor}" ] && [ "${ancestor}" -gt 1 ]; do + if [ "${ancestor}" == "${serverpid}" ]; then + serverprocess="${process}" + break + fi + ancestor="$(ps -o ppid= -p "${ancestor}" 2> /dev/null | tr -d ' ')" + done + if [ -z "${serverprocess}" ] && [ -z "${otherprocess}" ]; then + otherprocess="${process}" fi done <<< "${sockets}" - if [ -z "${listener}" ]; then - hint="No local TCP/UDP listener on port ${queryport}; check startup and port settings" + if [ -z "${protocols}" ]; then + hint="Nothing is listening on port ${queryport}; check the server started and the port settings" + elif [ -n "${serverprocess}" ]; then + hint="Port ${queryport}/${protocols} is open by the game server (${serverprocess}) but it did not answer; the server may be hung, or the query port or type may not match" + elif [ -n "${otherprocess}" ]; then + hint="Port ${queryport}/${protocols} is in use by another process (${otherprocess}); check for a port conflict" else - hint="Local TCP/UDP port ${queryport} is in use" - if [ -n "${process}" ]; then - hint+=" by ${process}" - fi - hint+="; check the query port and protocol" + hint="Port ${queryport}/${protocols} is in use by a process owned by another user; check for a port conflict" fi fn_print_warn "Query port: ${hint}" From 3c6b78f714cd07c43636f2d8dc516efd9a5c1412 Mon Sep 17 00:00:00 2001 From: Daniel Gibbs Date: Sat, 31 Oct 2026 17:40:32 +0000 Subject: [PATCH 135/164] fix(cs2server): add libicu dependency for CounterStrikeSharp (#5121) CounterStrikeSharp ships its own .NET runtime, which aborts at startup when no ICU library is installed, taking the server down with it. Add each distro's versioned ICU runtime package to cs2 in every dependency list. --- lgsm/data/almalinux-8.csv | 2 +- lgsm/data/almalinux-9.csv | 2 +- lgsm/data/centos-7.csv | 2 +- lgsm/data/centos-8.csv | 2 +- lgsm/data/centos-9.csv | 2 +- lgsm/data/debian-10.csv | 2 +- lgsm/data/debian-11.csv | 2 +- lgsm/data/debian-12.csv | 2 +- lgsm/data/debian-13.csv | 2 +- lgsm/data/debian-9.csv | 2 +- lgsm/data/rhel-7.csv | 2 +- lgsm/data/rhel-8.csv | 2 +- lgsm/data/rhel-9.csv | 2 +- lgsm/data/rocky-8.csv | 2 +- lgsm/data/rocky-9.csv | 2 +- lgsm/data/ubuntu-16.04.csv | 2 +- lgsm/data/ubuntu-18.04.csv | 2 +- lgsm/data/ubuntu-20.04.csv | 2 +- lgsm/data/ubuntu-22.04.csv | 2 +- lgsm/data/ubuntu-23.04.csv | 2 +- lgsm/data/ubuntu-23.10.csv | 2 +- lgsm/data/ubuntu-24.04.csv | 2 +- lgsm/data/ubuntu-26.04.csv | 2 +- 23 files changed, 23 insertions(+), 23 deletions(-) diff --git a/lgsm/data/almalinux-8.csv b/lgsm/data/almalinux-8.csv index 23b23936da..b3bb682320 100644 --- a/lgsm/data/almalinux-8.csv +++ b/lgsm/data/almalinux-8.csv @@ -29,7 +29,7 @@ coduo codwaw col cs -cs2 +cs2,libicu cscz csgo css,ncurses-libs.i686 diff --git a/lgsm/data/almalinux-9.csv b/lgsm/data/almalinux-9.csv index 3b541a77a7..babcf2aca3 100644 --- a/lgsm/data/almalinux-9.csv +++ b/lgsm/data/almalinux-9.csv @@ -29,7 +29,7 @@ coduo codwaw col cs -cs2 +cs2,libicu cscz csgo css,ncurses-libs.i686 diff --git a/lgsm/data/centos-7.csv b/lgsm/data/centos-7.csv index 5af075d201..13b0b37f2f 100644 --- a/lgsm/data/centos-7.csv +++ b/lgsm/data/centos-7.csv @@ -29,7 +29,7 @@ coduo,compat-libstdc++-33.i686 codwaw col cs -cs2 +cs2,libicu cscz csgo css,ncurses-libs.i686 diff --git a/lgsm/data/centos-8.csv b/lgsm/data/centos-8.csv index 1d50e811fd..2407943db7 100644 --- a/lgsm/data/centos-8.csv +++ b/lgsm/data/centos-8.csv @@ -29,7 +29,7 @@ coduo codwaw col cs -cs2 +cs2,libicu cscz csgo css,ncurses-libs.i686 diff --git a/lgsm/data/centos-9.csv b/lgsm/data/centos-9.csv index 90683ee310..0b7bac5eca 100644 --- a/lgsm/data/centos-9.csv +++ b/lgsm/data/centos-9.csv @@ -29,7 +29,7 @@ coduo codwaw col cs -cs2 +cs2,libicu cscz csgo css,ncurses-libs.i686 diff --git a/lgsm/data/debian-10.csv b/lgsm/data/debian-10.csv index f2b484645a..762544b882 100644 --- a/lgsm/data/debian-10.csv +++ b/lgsm/data/debian-10.csv @@ -28,7 +28,7 @@ coduo,libstdc++5:i386 codwaw col cs -cs2 +cs2,libicu63 cscz csgo css,libtinfo5:i386 diff --git a/lgsm/data/debian-11.csv b/lgsm/data/debian-11.csv index 13c3e81e2c..7b165f76a3 100644 --- a/lgsm/data/debian-11.csv +++ b/lgsm/data/debian-11.csv @@ -29,7 +29,7 @@ coduo,libstdc++5:i386 codwaw col cs -cs2 +cs2,libicu67 cscz csgo css,libtinfo5:i386 diff --git a/lgsm/data/debian-12.csv b/lgsm/data/debian-12.csv index 2b67c76eab..1145cdbb6c 100644 --- a/lgsm/data/debian-12.csv +++ b/lgsm/data/debian-12.csv @@ -29,7 +29,7 @@ coduo,libstdc++5:i386 codwaw col cs -cs2 +cs2,libicu72 cscz csgo css,libtinfo5:i386 diff --git a/lgsm/data/debian-13.csv b/lgsm/data/debian-13.csv index 48c733479d..d35910ceb0 100644 --- a/lgsm/data/debian-13.csv +++ b/lgsm/data/debian-13.csv @@ -29,7 +29,7 @@ coduo,libc6:i386 codwaw col cs -cs2 +cs2,libicu76 cscz csgo css diff --git a/lgsm/data/debian-9.csv b/lgsm/data/debian-9.csv index 3a305dcd41..e1c42b6057 100644 --- a/lgsm/data/debian-9.csv +++ b/lgsm/data/debian-9.csv @@ -29,7 +29,7 @@ coduo,libstdc++5:i386 codwaw col cs -cs2 +cs2,libicu57 cscz csgo css,libtinfo5:i386 diff --git a/lgsm/data/rhel-7.csv b/lgsm/data/rhel-7.csv index 8931345341..2b2143dc5a 100644 --- a/lgsm/data/rhel-7.csv +++ b/lgsm/data/rhel-7.csv @@ -30,7 +30,7 @@ coduo,compat-libstdc++-33.i686 codwaw col cs -cs2 +cs2,libicu cscz csgo css,ncurses-libs.i686 diff --git a/lgsm/data/rhel-8.csv b/lgsm/data/rhel-8.csv index 5dc7584bed..f84b55e097 100644 --- a/lgsm/data/rhel-8.csv +++ b/lgsm/data/rhel-8.csv @@ -29,7 +29,7 @@ coduo codwaw col cs -cs2 +cs2,libicu cscz csgo css,ncurses-libs.i686 diff --git a/lgsm/data/rhel-9.csv b/lgsm/data/rhel-9.csv index 3b541a77a7..babcf2aca3 100644 --- a/lgsm/data/rhel-9.csv +++ b/lgsm/data/rhel-9.csv @@ -29,7 +29,7 @@ coduo codwaw col cs -cs2 +cs2,libicu cscz csgo css,ncurses-libs.i686 diff --git a/lgsm/data/rocky-8.csv b/lgsm/data/rocky-8.csv index 5dc7584bed..f84b55e097 100644 --- a/lgsm/data/rocky-8.csv +++ b/lgsm/data/rocky-8.csv @@ -29,7 +29,7 @@ coduo codwaw col cs -cs2 +cs2,libicu cscz csgo css,ncurses-libs.i686 diff --git a/lgsm/data/rocky-9.csv b/lgsm/data/rocky-9.csv index 3b541a77a7..babcf2aca3 100644 --- a/lgsm/data/rocky-9.csv +++ b/lgsm/data/rocky-9.csv @@ -29,7 +29,7 @@ coduo codwaw col cs -cs2 +cs2,libicu cscz csgo css,ncurses-libs.i686 diff --git a/lgsm/data/ubuntu-16.04.csv b/lgsm/data/ubuntu-16.04.csv index bb21193591..7924d16612 100644 --- a/lgsm/data/ubuntu-16.04.csv +++ b/lgsm/data/ubuntu-16.04.csv @@ -30,7 +30,7 @@ coduo,libstdc++5:i386 codwaw col cs -cs2 +cs2,libicu55 cscz csgo css,libtinfo5:i386 diff --git a/lgsm/data/ubuntu-18.04.csv b/lgsm/data/ubuntu-18.04.csv index 834fefdf5e..44435c1de5 100644 --- a/lgsm/data/ubuntu-18.04.csv +++ b/lgsm/data/ubuntu-18.04.csv @@ -30,7 +30,7 @@ coduo,libstdc++5:i386 codwaw col cs -cs2 +cs2,libicu60 cscz csgo css,libtinfo5:i386 diff --git a/lgsm/data/ubuntu-20.04.csv b/lgsm/data/ubuntu-20.04.csv index 92e0482c6a..d224c0426c 100644 --- a/lgsm/data/ubuntu-20.04.csv +++ b/lgsm/data/ubuntu-20.04.csv @@ -29,7 +29,7 @@ coduo,libstdc++5:i386 codwaw col cs -cs2 +cs2,libicu66 cscz csgo css,libtinfo5:i386 diff --git a/lgsm/data/ubuntu-22.04.csv b/lgsm/data/ubuntu-22.04.csv index 164d204a73..774c194200 100644 --- a/lgsm/data/ubuntu-22.04.csv +++ b/lgsm/data/ubuntu-22.04.csv @@ -29,7 +29,7 @@ coduo,libstdc++5:i386 codwaw col cs -cs2 +cs2,libicu70 cscz csgo css,libtinfo5:i386 diff --git a/lgsm/data/ubuntu-23.04.csv b/lgsm/data/ubuntu-23.04.csv index 9259c2f390..73da2cdf92 100644 --- a/lgsm/data/ubuntu-23.04.csv +++ b/lgsm/data/ubuntu-23.04.csv @@ -29,7 +29,7 @@ coduo,libstdc++5:i386 codwaw col cs -cs2 +cs2,libicu72 cscz csgo css,libtinfo5:i386 diff --git a/lgsm/data/ubuntu-23.10.csv b/lgsm/data/ubuntu-23.10.csv index 9259c2f390..73da2cdf92 100644 --- a/lgsm/data/ubuntu-23.10.csv +++ b/lgsm/data/ubuntu-23.10.csv @@ -29,7 +29,7 @@ coduo,libstdc++5:i386 codwaw col cs -cs2 +cs2,libicu72 cscz csgo css,libtinfo5:i386 diff --git a/lgsm/data/ubuntu-24.04.csv b/lgsm/data/ubuntu-24.04.csv index 001114017f..c0df29dc53 100644 --- a/lgsm/data/ubuntu-24.04.csv +++ b/lgsm/data/ubuntu-24.04.csv @@ -29,7 +29,7 @@ coduo,libstdc++5:i386 codwaw col cs -cs2 +cs2,libicu74 cscz csgo css diff --git a/lgsm/data/ubuntu-26.04.csv b/lgsm/data/ubuntu-26.04.csv index 6f69d6c172..ccaa2fa19f 100644 --- a/lgsm/data/ubuntu-26.04.csv +++ b/lgsm/data/ubuntu-26.04.csv @@ -29,7 +29,7 @@ coduo,libc6:i386 codwaw col cs -cs2 +cs2,libicu78 cscz csgo css From b9bcc88b810a301936ec5c6b332f8d64dd9417d6 Mon Sep 17 00:00:00 2001 From: Daniel Gibbs Date: Sat, 31 Oct 2026 17:44:17 +0000 Subject: [PATCH 136/164] fix(btserver): use the versioned ICU runtime instead of libicu-dev (#5122) The Barotrauma dedicated server only needs the ICU runtime library, not the development headers and tools that libicu-dev pulls in. Use each distro's versioned ICU runtime package for bt on Debian and Ubuntu, matching cs2 and scpsl. --- lgsm/data/debian-10.csv | 2 +- lgsm/data/debian-11.csv | 2 +- lgsm/data/debian-12.csv | 2 +- lgsm/data/debian-13.csv | 2 +- lgsm/data/debian-9.csv | 2 +- lgsm/data/ubuntu-16.04.csv | 2 +- lgsm/data/ubuntu-18.04.csv | 2 +- lgsm/data/ubuntu-20.04.csv | 2 +- lgsm/data/ubuntu-22.04.csv | 2 +- lgsm/data/ubuntu-23.04.csv | 2 +- lgsm/data/ubuntu-23.10.csv | 2 +- lgsm/data/ubuntu-24.04.csv | 2 +- lgsm/data/ubuntu-26.04.csv | 2 +- 13 files changed, 13 insertions(+), 13 deletions(-) diff --git a/lgsm/data/debian-10.csv b/lgsm/data/debian-10.csv index 762544b882..bcfa78ad25 100644 --- a/lgsm/data/debian-10.csv +++ b/lgsm/data/debian-10.csv @@ -15,7 +15,7 @@ bfv,libc6:i386 bmdm,libncurses5:i386 bo bs -bt,libicu-dev,dos2unix,libxml2-utils +bt,libicu63,dos2unix,libxml2-utils btl cc ce diff --git a/lgsm/data/debian-11.csv b/lgsm/data/debian-11.csv index 7b165f76a3..864749f69b 100644 --- a/lgsm/data/debian-11.csv +++ b/lgsm/data/debian-11.csv @@ -16,7 +16,7 @@ bfv,libc6:i386 bmdm,libncurses5:i386 bo bs -bt,libicu-dev,dos2unix,libxml2-utils +bt,libicu67,dos2unix,libxml2-utils btl cc ce diff --git a/lgsm/data/debian-12.csv b/lgsm/data/debian-12.csv index 1145cdbb6c..95b93b0d00 100644 --- a/lgsm/data/debian-12.csv +++ b/lgsm/data/debian-12.csv @@ -16,7 +16,7 @@ bfv,libc6:i386 bmdm,libncurses5:i386 bo bs -bt,libicu-dev,dos2unix,libxml2-utils +bt,libicu72,dos2unix,libxml2-utils btl cc ce diff --git a/lgsm/data/debian-13.csv b/lgsm/data/debian-13.csv index d35910ceb0..00423ae3de 100644 --- a/lgsm/data/debian-13.csv +++ b/lgsm/data/debian-13.csv @@ -16,7 +16,7 @@ bfv,libc6:i386 bmdm bo bs -bt,libicu-dev,dos2unix,libxml2 +bt,libicu76,dos2unix,libxml2 btl cc ce diff --git a/lgsm/data/debian-9.csv b/lgsm/data/debian-9.csv index e1c42b6057..96fce61d98 100644 --- a/lgsm/data/debian-9.csv +++ b/lgsm/data/debian-9.csv @@ -16,7 +16,7 @@ bfv,libc6:i386 bmdm,libncurses5:i386 bo bs -bt,libicu-dev,dos2unix,libxml2-utils +bt,libicu57,dos2unix,libxml2-utils btl cc ce diff --git a/lgsm/data/ubuntu-16.04.csv b/lgsm/data/ubuntu-16.04.csv index 7924d16612..1da2198f44 100644 --- a/lgsm/data/ubuntu-16.04.csv +++ b/lgsm/data/ubuntu-16.04.csv @@ -17,7 +17,7 @@ bfv,libc6:i386 bmdm,libncurses5:i386 bo bs -bt,libicu-dev,dos2unix,libxml2-utils +bt,libicu55,dos2unix,libxml2-utils btl cc ce diff --git a/lgsm/data/ubuntu-18.04.csv b/lgsm/data/ubuntu-18.04.csv index 44435c1de5..82bac862ce 100644 --- a/lgsm/data/ubuntu-18.04.csv +++ b/lgsm/data/ubuntu-18.04.csv @@ -17,7 +17,7 @@ bfv,libc6:i386 bmdm,libncurses5:i386 bo bs -bt,libicu-dev,dos2unix,libxml2-utils +bt,libicu60,dos2unix,libxml2-utils btl cc ce diff --git a/lgsm/data/ubuntu-20.04.csv b/lgsm/data/ubuntu-20.04.csv index d224c0426c..eece3c1b80 100644 --- a/lgsm/data/ubuntu-20.04.csv +++ b/lgsm/data/ubuntu-20.04.csv @@ -16,7 +16,7 @@ bfv,libc6:i386 bmdm,libncurses5:i386 bo bs -bt,libicu-dev,dos2unix,libxml2-utils +bt,libicu66,dos2unix,libxml2-utils btl cc ce diff --git a/lgsm/data/ubuntu-22.04.csv b/lgsm/data/ubuntu-22.04.csv index 774c194200..647a670b8d 100644 --- a/lgsm/data/ubuntu-22.04.csv +++ b/lgsm/data/ubuntu-22.04.csv @@ -16,7 +16,7 @@ bfv,libc6:i386 bmdm,libncurses5:i386 bo bs -bt,libicu-dev,dos2unix,libxml2-utils +bt,libicu70,dos2unix,libxml2-utils btl cc ce diff --git a/lgsm/data/ubuntu-23.04.csv b/lgsm/data/ubuntu-23.04.csv index 73da2cdf92..e948555a3c 100644 --- a/lgsm/data/ubuntu-23.04.csv +++ b/lgsm/data/ubuntu-23.04.csv @@ -16,7 +16,7 @@ bfv,libc6:i386 bmdm,libncurses5:i386 bo bs -bt,libicu-dev,dos2unix,libxml2-utils +bt,libicu72,dos2unix,libxml2-utils btl cc ce diff --git a/lgsm/data/ubuntu-23.10.csv b/lgsm/data/ubuntu-23.10.csv index 73da2cdf92..e948555a3c 100644 --- a/lgsm/data/ubuntu-23.10.csv +++ b/lgsm/data/ubuntu-23.10.csv @@ -16,7 +16,7 @@ bfv,libc6:i386 bmdm,libncurses5:i386 bo bs -bt,libicu-dev,dos2unix,libxml2-utils +bt,libicu72,dos2unix,libxml2-utils btl cc ce diff --git a/lgsm/data/ubuntu-24.04.csv b/lgsm/data/ubuntu-24.04.csv index c0df29dc53..983b4be4c5 100644 --- a/lgsm/data/ubuntu-24.04.csv +++ b/lgsm/data/ubuntu-24.04.csv @@ -16,7 +16,7 @@ bfv,libc6:i386 bmdm bo bs -bt,libicu-dev,dos2unix,libxml2-utils +bt,libicu74,dos2unix,libxml2-utils btl cc ce diff --git a/lgsm/data/ubuntu-26.04.csv b/lgsm/data/ubuntu-26.04.csv index ccaa2fa19f..99deaee4ca 100644 --- a/lgsm/data/ubuntu-26.04.csv +++ b/lgsm/data/ubuntu-26.04.csv @@ -16,7 +16,7 @@ bfv,libc6:i386 bmdm bo bs -bt,libicu-dev,dos2unix,libxml2-utils +bt,libicu78,dos2unix,libxml2-utils btl cc ce From 65aeb3fd5b36563b39f5a5abb40cc169b2c249fc Mon Sep 17 00:00:00 2001 From: Daniel Gibbs Date: Sat, 31 Oct 2026 19:09:37 +0000 Subject: [PATCH 137/164] fix(alerts): show Matrix and ntfy alerts in details and stats (#5123) Both alert types are dispatched by alert.sh but were never added to the details output or the stats report, so an enabled Matrix or ntfy alert was invisible in details and uncounted in stats. --- lgsm/modules/info_messages.sh | 10 ++++++++++ lgsm/modules/info_stats.sh | 10 ++++++++++ 2 files changed, 20 insertions(+) diff --git a/lgsm/modules/info_messages.sh b/lgsm/modules/info_messages.sh index 7bd94c50ce..d8c390c502 100755 --- a/lgsm/modules/info_messages.sh +++ b/lgsm/modules/info_messages.sh @@ -557,6 +557,8 @@ fn_info_messages_script() { # Email alert: off # Gotify alert: off # IFTTT alert: off + # Matrix alert: off + # ntfy alert: off # Pushbullet alert: off # Pushover alert: off # Rocketchat alert: off @@ -608,6 +610,14 @@ fn_info_messages_script() { if [ "${iftttalert}" == "on" ]; then echo -e "${lightblue}IFTTT alert:\t${default}${iftttalert}" fi + # Matrix alert + if [ "${matrixalert}" == "on" ]; then + echo -e "${lightblue}Matrix alert:\t${default}${matrixalert}" + fi + # ntfy alert + if [ "${ntfyalert}" == "on" ]; then + echo -e "${lightblue}ntfy alert:\t${default}${ntfyalert}" + fi # Pushbullet alert if [ "${pushbulletalert}" == "on" ]; then echo -e "${lightblue}Pushbullet alert:\t${default}${pushbulletalert}" diff --git a/lgsm/modules/info_stats.sh b/lgsm/modules/info_stats.sh index 168388d64b..927c85ae78 100755 --- a/lgsm/modules/info_stats.sh +++ b/lgsm/modules/info_stats.sh @@ -132,6 +132,16 @@ if [ "${iftttalert}" == "on" ]; then fn_alert_payload curl -X POST "https://www.google-analytics.com/mp/collect?api_secret=${apisecret}&measurement_id=${measurementid}" -H "Content-Type: application/json" -d "${alertpayload}" fi +if [ "${matrixalert}" == "on" ]; then + alerttype="matrix" + fn_alert_payload + curl -X POST "https://www.google-analytics.com/mp/collect?api_secret=${apisecret}&measurement_id=${measurementid}" -H "Content-Type: application/json" -d "${alertpayload}" +fi +if [ "${ntfyalert}" == "on" ]; then + alerttype="ntfy" + fn_alert_payload + curl -X POST "https://www.google-analytics.com/mp/collect?api_secret=${apisecret}&measurement_id=${measurementid}" -H "Content-Type: application/json" -d "${alertpayload}" +fi if [ "${pushbulletalert}" == "on" ]; then alerttype="pushbullet" fn_alert_payload From 9065a30b6dbc817f8277f06cf3739f5117b2003f Mon Sep 17 00:00:00 2001 From: Daniel Gibbs Date: Sat, 31 Oct 2026 19:52:48 +0000 Subject: [PATCH 138/164] fix(btserver): drop the ICU dependency (#5124) The Barotrauma dedicated server is built with InvariantGlobalization enabled (LinuxServer.csproj, continuously since v0.19.3 in 2022), so its bundled .NET 8 runtime never loads ICU. The libicu dependency dates from #3083, when the server still needed it. --- lgsm/data/almalinux-8.csv | 2 +- lgsm/data/almalinux-9.csv | 2 +- lgsm/data/centos-7.csv | 2 +- lgsm/data/centos-8.csv | 2 +- lgsm/data/centos-9.csv | 2 +- lgsm/data/debian-10.csv | 2 +- lgsm/data/debian-11.csv | 2 +- lgsm/data/debian-12.csv | 2 +- lgsm/data/debian-13.csv | 2 +- lgsm/data/debian-9.csv | 2 +- lgsm/data/rhel-7.csv | 2 +- lgsm/data/rhel-8.csv | 2 +- lgsm/data/rhel-9.csv | 2 +- lgsm/data/rocky-8.csv | 2 +- lgsm/data/rocky-9.csv | 2 +- lgsm/data/ubuntu-16.04.csv | 2 +- lgsm/data/ubuntu-18.04.csv | 2 +- lgsm/data/ubuntu-20.04.csv | 2 +- lgsm/data/ubuntu-22.04.csv | 2 +- lgsm/data/ubuntu-23.04.csv | 2 +- lgsm/data/ubuntu-23.10.csv | 2 +- lgsm/data/ubuntu-24.04.csv | 2 +- lgsm/data/ubuntu-26.04.csv | 2 +- 23 files changed, 23 insertions(+), 23 deletions(-) diff --git a/lgsm/data/almalinux-8.csv b/lgsm/data/almalinux-8.csv index b3bb682320..e70576c9dc 100644 --- a/lgsm/data/almalinux-8.csv +++ b/lgsm/data/almalinux-8.csv @@ -16,7 +16,7 @@ bfv,glibc.i686 bmdm,ncurses-libs.i686 bo bs -bt,libicu,dos2unix,libxml2 +bt,dos2unix,libxml2 btl cc ce diff --git a/lgsm/data/almalinux-9.csv b/lgsm/data/almalinux-9.csv index babcf2aca3..f0a95404f0 100644 --- a/lgsm/data/almalinux-9.csv +++ b/lgsm/data/almalinux-9.csv @@ -16,7 +16,7 @@ bfv,glibc.i686 bmdm,ncurses-libs.i686 bo bs -bt,libicu,dos2unix,libxml2 +bt,dos2unix,libxml2 btl cc ce diff --git a/lgsm/data/centos-7.csv b/lgsm/data/centos-7.csv index 13b0b37f2f..5558ab2a95 100644 --- a/lgsm/data/centos-7.csv +++ b/lgsm/data/centos-7.csv @@ -16,7 +16,7 @@ bfv,glibc.i686 bmdm,ncurses-libs.i686 bo bs -bt,libicu,dos2unix,libxml2 +bt,dos2unix,libxml2 btl cc ce diff --git a/lgsm/data/centos-8.csv b/lgsm/data/centos-8.csv index 2407943db7..17f9a30d30 100644 --- a/lgsm/data/centos-8.csv +++ b/lgsm/data/centos-8.csv @@ -16,7 +16,7 @@ bfv,glibc.i686 bmdm,ncurses-libs.i686 bo bs -bt,libicu,dos2unix,libxml2 +bt,dos2unix,libxml2 btl cc ce diff --git a/lgsm/data/centos-9.csv b/lgsm/data/centos-9.csv index 0b7bac5eca..e0d4706049 100644 --- a/lgsm/data/centos-9.csv +++ b/lgsm/data/centos-9.csv @@ -16,7 +16,7 @@ bfv,glibc.i686 bmdm,ncurses-libs.i686 bo bs -bt,libicu,dos2unix,libxml2 +bt,dos2unix,libxml2 btl cc ce diff --git a/lgsm/data/debian-10.csv b/lgsm/data/debian-10.csv index bcfa78ad25..08f714965e 100644 --- a/lgsm/data/debian-10.csv +++ b/lgsm/data/debian-10.csv @@ -15,7 +15,7 @@ bfv,libc6:i386 bmdm,libncurses5:i386 bo bs -bt,libicu63,dos2unix,libxml2-utils +bt,dos2unix,libxml2-utils btl cc ce diff --git a/lgsm/data/debian-11.csv b/lgsm/data/debian-11.csv index 864749f69b..10a64fbdee 100644 --- a/lgsm/data/debian-11.csv +++ b/lgsm/data/debian-11.csv @@ -16,7 +16,7 @@ bfv,libc6:i386 bmdm,libncurses5:i386 bo bs -bt,libicu67,dos2unix,libxml2-utils +bt,dos2unix,libxml2-utils btl cc ce diff --git a/lgsm/data/debian-12.csv b/lgsm/data/debian-12.csv index 95b93b0d00..100abaefae 100644 --- a/lgsm/data/debian-12.csv +++ b/lgsm/data/debian-12.csv @@ -16,7 +16,7 @@ bfv,libc6:i386 bmdm,libncurses5:i386 bo bs -bt,libicu72,dos2unix,libxml2-utils +bt,dos2unix,libxml2-utils btl cc ce diff --git a/lgsm/data/debian-13.csv b/lgsm/data/debian-13.csv index 00423ae3de..fb1c08fae1 100644 --- a/lgsm/data/debian-13.csv +++ b/lgsm/data/debian-13.csv @@ -16,7 +16,7 @@ bfv,libc6:i386 bmdm bo bs -bt,libicu76,dos2unix,libxml2 +bt,dos2unix,libxml2 btl cc ce diff --git a/lgsm/data/debian-9.csv b/lgsm/data/debian-9.csv index 96fce61d98..cd27669e83 100644 --- a/lgsm/data/debian-9.csv +++ b/lgsm/data/debian-9.csv @@ -16,7 +16,7 @@ bfv,libc6:i386 bmdm,libncurses5:i386 bo bs -bt,libicu57,dos2unix,libxml2-utils +bt,dos2unix,libxml2-utils btl cc ce diff --git a/lgsm/data/rhel-7.csv b/lgsm/data/rhel-7.csv index 2b2143dc5a..7a2909701b 100644 --- a/lgsm/data/rhel-7.csv +++ b/lgsm/data/rhel-7.csv @@ -17,7 +17,7 @@ bfv,glibc.i686 bmdm,ncurses-libs.i686 bo bs -bt,libicu,dos2unix,libxml2 +bt,dos2unix,libxml2 btl cc ce diff --git a/lgsm/data/rhel-8.csv b/lgsm/data/rhel-8.csv index f84b55e097..ba51211203 100644 --- a/lgsm/data/rhel-8.csv +++ b/lgsm/data/rhel-8.csv @@ -16,7 +16,7 @@ bfv,glibc.i686 bmdm,ncurses-libs.i686 bo bs -bt,libicu,dos2unix,libxml2 +bt,dos2unix,libxml2 btl cc ce diff --git a/lgsm/data/rhel-9.csv b/lgsm/data/rhel-9.csv index babcf2aca3..f0a95404f0 100644 --- a/lgsm/data/rhel-9.csv +++ b/lgsm/data/rhel-9.csv @@ -16,7 +16,7 @@ bfv,glibc.i686 bmdm,ncurses-libs.i686 bo bs -bt,libicu,dos2unix,libxml2 +bt,dos2unix,libxml2 btl cc ce diff --git a/lgsm/data/rocky-8.csv b/lgsm/data/rocky-8.csv index f84b55e097..ba51211203 100644 --- a/lgsm/data/rocky-8.csv +++ b/lgsm/data/rocky-8.csv @@ -16,7 +16,7 @@ bfv,glibc.i686 bmdm,ncurses-libs.i686 bo bs -bt,libicu,dos2unix,libxml2 +bt,dos2unix,libxml2 btl cc ce diff --git a/lgsm/data/rocky-9.csv b/lgsm/data/rocky-9.csv index babcf2aca3..f0a95404f0 100644 --- a/lgsm/data/rocky-9.csv +++ b/lgsm/data/rocky-9.csv @@ -16,7 +16,7 @@ bfv,glibc.i686 bmdm,ncurses-libs.i686 bo bs -bt,libicu,dos2unix,libxml2 +bt,dos2unix,libxml2 btl cc ce diff --git a/lgsm/data/ubuntu-16.04.csv b/lgsm/data/ubuntu-16.04.csv index 1da2198f44..3775cc7eb8 100644 --- a/lgsm/data/ubuntu-16.04.csv +++ b/lgsm/data/ubuntu-16.04.csv @@ -17,7 +17,7 @@ bfv,libc6:i386 bmdm,libncurses5:i386 bo bs -bt,libicu55,dos2unix,libxml2-utils +bt,dos2unix,libxml2-utils btl cc ce diff --git a/lgsm/data/ubuntu-18.04.csv b/lgsm/data/ubuntu-18.04.csv index 82bac862ce..e6a52bd5a7 100644 --- a/lgsm/data/ubuntu-18.04.csv +++ b/lgsm/data/ubuntu-18.04.csv @@ -17,7 +17,7 @@ bfv,libc6:i386 bmdm,libncurses5:i386 bo bs -bt,libicu60,dos2unix,libxml2-utils +bt,dos2unix,libxml2-utils btl cc ce diff --git a/lgsm/data/ubuntu-20.04.csv b/lgsm/data/ubuntu-20.04.csv index eece3c1b80..9fdcd9a3bd 100644 --- a/lgsm/data/ubuntu-20.04.csv +++ b/lgsm/data/ubuntu-20.04.csv @@ -16,7 +16,7 @@ bfv,libc6:i386 bmdm,libncurses5:i386 bo bs -bt,libicu66,dos2unix,libxml2-utils +bt,dos2unix,libxml2-utils btl cc ce diff --git a/lgsm/data/ubuntu-22.04.csv b/lgsm/data/ubuntu-22.04.csv index 647a670b8d..e045227cb1 100644 --- a/lgsm/data/ubuntu-22.04.csv +++ b/lgsm/data/ubuntu-22.04.csv @@ -16,7 +16,7 @@ bfv,libc6:i386 bmdm,libncurses5:i386 bo bs -bt,libicu70,dos2unix,libxml2-utils +bt,dos2unix,libxml2-utils btl cc ce diff --git a/lgsm/data/ubuntu-23.04.csv b/lgsm/data/ubuntu-23.04.csv index e948555a3c..bbb4d26f46 100644 --- a/lgsm/data/ubuntu-23.04.csv +++ b/lgsm/data/ubuntu-23.04.csv @@ -16,7 +16,7 @@ bfv,libc6:i386 bmdm,libncurses5:i386 bo bs -bt,libicu72,dos2unix,libxml2-utils +bt,dos2unix,libxml2-utils btl cc ce diff --git a/lgsm/data/ubuntu-23.10.csv b/lgsm/data/ubuntu-23.10.csv index e948555a3c..bbb4d26f46 100644 --- a/lgsm/data/ubuntu-23.10.csv +++ b/lgsm/data/ubuntu-23.10.csv @@ -16,7 +16,7 @@ bfv,libc6:i386 bmdm,libncurses5:i386 bo bs -bt,libicu72,dos2unix,libxml2-utils +bt,dos2unix,libxml2-utils btl cc ce diff --git a/lgsm/data/ubuntu-24.04.csv b/lgsm/data/ubuntu-24.04.csv index 983b4be4c5..919344f8d1 100644 --- a/lgsm/data/ubuntu-24.04.csv +++ b/lgsm/data/ubuntu-24.04.csv @@ -16,7 +16,7 @@ bfv,libc6:i386 bmdm bo bs -bt,libicu74,dos2unix,libxml2-utils +bt,dos2unix,libxml2-utils btl cc ce diff --git a/lgsm/data/ubuntu-26.04.csv b/lgsm/data/ubuntu-26.04.csv index 99deaee4ca..0db57cabdf 100644 --- a/lgsm/data/ubuntu-26.04.csv +++ b/lgsm/data/ubuntu-26.04.csv @@ -16,7 +16,7 @@ bfv,libc6:i386 bmdm bo bs -bt,libicu78,dos2unix,libxml2-utils +bt,dos2unix,libxml2-utils btl cc ce From cfbf7bbf8883b814d509aff53a35161eb0b57604 Mon Sep 17 00:00:00 2001 From: Daniel Gibbs Date: Sat, 31 Oct 2026 20:07:31 +0000 Subject: [PATCH 139/164] fix(deps): add procps so pgrep and ps are always installed (#5125) monitor, backup and details call pgrep and ps, but no distro dependency list included procps. Minimal images such as debian:13 do not ship it, so on those systems pgrep is missing, the "is install running" check in monitor always reads as true, and monitor exits with "LinuxGSM is installing" without checking the server. Add procps to the Debian and Ubuntu lists and procps-ng to the RHEL-family lists. --- lgsm/data/almalinux-8.csv | 2 +- lgsm/data/almalinux-9.csv | 2 +- lgsm/data/centos-7.csv | 2 +- lgsm/data/centos-8.csv | 2 +- lgsm/data/centos-9.csv | 2 +- lgsm/data/debian-10.csv | 2 +- lgsm/data/debian-11.csv | 2 +- lgsm/data/debian-12.csv | 2 +- lgsm/data/debian-13.csv | 2 +- lgsm/data/debian-9.csv | 2 +- lgsm/data/rhel-7.csv | 2 +- lgsm/data/rhel-8.csv | 2 +- lgsm/data/rhel-9.csv | 2 +- lgsm/data/rocky-8.csv | 2 +- lgsm/data/rocky-9.csv | 2 +- lgsm/data/ubuntu-16.04.csv | 2 +- lgsm/data/ubuntu-18.04.csv | 2 +- lgsm/data/ubuntu-20.04.csv | 2 +- lgsm/data/ubuntu-22.04.csv | 2 +- lgsm/data/ubuntu-23.04.csv | 2 +- lgsm/data/ubuntu-23.10.csv | 2 +- lgsm/data/ubuntu-24.04.csv | 2 +- lgsm/data/ubuntu-26.04.csv | 2 +- 23 files changed, 23 insertions(+), 23 deletions(-) diff --git a/lgsm/data/almalinux-8.csv b/lgsm/data/almalinux-8.csv index e70576c9dc..12ae5589ba 100644 --- a/lgsm/data/almalinux-8.csv +++ b/lgsm/data/almalinux-8.csv @@ -1,4 +1,4 @@ -all,bc,binutils,bzip2,cpio,curl,epel-release,file,glibc.i686,gzip,hostname,jq,libstdc++,libstdc++.i686,nmap-ncat,pigz,python36,tar,tmux,unzip,util-linux,wget,xz +all,bc,binutils,bzip2,cpio,curl,epel-release,file,glibc.i686,gzip,hostname,jq,libstdc++,libstdc++.i686,nmap-ncat,pigz,procps-ng,python36,tar,tmux,unzip,util-linux,wget,xz steamcmd,glibc.i686,libstdc++.i686 ac ahl diff --git a/lgsm/data/almalinux-9.csv b/lgsm/data/almalinux-9.csv index f0a95404f0..e60e450933 100644 --- a/lgsm/data/almalinux-9.csv +++ b/lgsm/data/almalinux-9.csv @@ -1,4 +1,4 @@ -all,bc,binutils,bzip2,cpio,curl,epel-release,file,glibc.i686,gzip,hostname,jq,libstdc++,libstdc++.i686,nmap-ncat,pigz,python3,tar,tmux,unzip,util-linux,wget,xz +all,bc,binutils,bzip2,cpio,curl,epel-release,file,glibc.i686,gzip,hostname,jq,libstdc++,libstdc++.i686,nmap-ncat,pigz,procps-ng,python3,tar,tmux,unzip,util-linux,wget,xz steamcmd,glibc.i686,libstdc++.i686 ac ahl diff --git a/lgsm/data/centos-7.csv b/lgsm/data/centos-7.csv index 5558ab2a95..d4c4cf21d7 100644 --- a/lgsm/data/centos-7.csv +++ b/lgsm/data/centos-7.csv @@ -1,4 +1,4 @@ -all,bc,binutils,bzip2,cpio,curl,epel-release,file,glibc.i686,gzip,hostname,jq,libstdc++,libstdc++.i686,nmap-ncat,pigz,python3,tar,tmux,unzip,util-linux,wget,xz +all,bc,binutils,bzip2,cpio,curl,epel-release,file,glibc.i686,gzip,hostname,jq,libstdc++,libstdc++.i686,nmap-ncat,pigz,procps-ng,python3,tar,tmux,unzip,util-linux,wget,xz steamcmd,glibc.i686,libstdc++.i686 ac ahl diff --git a/lgsm/data/centos-8.csv b/lgsm/data/centos-8.csv index 17f9a30d30..fc2d63e33d 100644 --- a/lgsm/data/centos-8.csv +++ b/lgsm/data/centos-8.csv @@ -1,4 +1,4 @@ -all,bc,binutils,bzip2,cpio,curl,epel-release,file,glibc.i686,gzip,hostname,jq,libstdc++,libstdc++.i686,nmap-ncat,pigz,python36,tar,tmux,unzip,util-linux,wget,xz +all,bc,binutils,bzip2,cpio,curl,epel-release,file,glibc.i686,gzip,hostname,jq,libstdc++,libstdc++.i686,nmap-ncat,pigz,procps-ng,python36,tar,tmux,unzip,util-linux,wget,xz steamcmd,glibc.i686,libstdc++.i686 ac ahl diff --git a/lgsm/data/centos-9.csv b/lgsm/data/centos-9.csv index e0d4706049..61f1da70f3 100644 --- a/lgsm/data/centos-9.csv +++ b/lgsm/data/centos-9.csv @@ -1,4 +1,4 @@ -all,bc,binutils,bzip2,cpio,curl,epel-release,file,glibc.i686,gzip,hostname,jq,libstdc++,libstdc++.i686,nmap-ncat,pigz,python3,tar,tmux,unzip,util-linux,wget,xz +all,bc,binutils,bzip2,cpio,curl,epel-release,file,glibc.i686,gzip,hostname,jq,libstdc++,libstdc++.i686,nmap-ncat,pigz,procps-ng,python3,tar,tmux,unzip,util-linux,wget,xz steamcmd,glibc.i686,libstdc++.i686 ac ahl diff --git a/lgsm/data/debian-10.csv b/lgsm/data/debian-10.csv index 08f714965e..a4a30ed54a 100644 --- a/lgsm/data/debian-10.csv +++ b/lgsm/data/debian-10.csv @@ -1,7 +1,7 @@ ac ahl ahl2 -all,bc,binutils,bsdmainutils,bzip2,ca-certificates,cpio,curl,distro-info,file,gzip,hostname,jq,lib32gcc1,lib32stdc++6,netcat,pigz,python3,tar,tmux,unzip,util-linux,uuid-runtime,wget,xz-utils +all,bc,binutils,bsdmainutils,bzip2,ca-certificates,cpio,curl,distro-info,file,gzip,hostname,jq,lib32gcc1,lib32stdc++6,netcat,pigz,procps,python3,tar,tmux,unzip,util-linux,uuid-runtime,wget,xz-utils ark arma3 armar,libcurl4 diff --git a/lgsm/data/debian-11.csv b/lgsm/data/debian-11.csv index 10a64fbdee..8746c794ee 100644 --- a/lgsm/data/debian-11.csv +++ b/lgsm/data/debian-11.csv @@ -1,4 +1,4 @@ -all,bc,binutils,bsdmainutils,bzip2,ca-certificates,cpio,curl,distro-info,file,gzip,hostname,jq,lib32gcc-s1,lib32stdc++6,netcat,pigz,python3,tar,tmux,unzip,util-linux,uuid-runtime,wget,xz-utils +all,bc,binutils,bsdmainutils,bzip2,ca-certificates,cpio,curl,distro-info,file,gzip,hostname,jq,lib32gcc-s1,lib32stdc++6,netcat,pigz,procps,python3,tar,tmux,unzip,util-linux,uuid-runtime,wget,xz-utils steamcmd,lib32gcc-s1,lib32stdc++6,libsdl2-2.0-0:i386,steamcmd ac ahl diff --git a/lgsm/data/debian-12.csv b/lgsm/data/debian-12.csv index 100abaefae..3acadda70c 100644 --- a/lgsm/data/debian-12.csv +++ b/lgsm/data/debian-12.csv @@ -1,4 +1,4 @@ -all,bc,binutils,bsdmainutils,bzip2,ca-certificates,cpio,curl,distro-info,file,gzip,hostname,jq,lib32gcc-s1,lib32stdc++6,netcat-openbsd,pigz,python3,tar,tmux,unzip,util-linux,uuid-runtime,wget,xz-utils +all,bc,binutils,bsdmainutils,bzip2,ca-certificates,cpio,curl,distro-info,file,gzip,hostname,jq,lib32gcc-s1,lib32stdc++6,netcat-openbsd,pigz,procps,python3,tar,tmux,unzip,util-linux,uuid-runtime,wget,xz-utils steamcmd,lib32gcc-s1,lib32stdc++6,libsdl2-2.0-0:i386,steamcmd ac ahl diff --git a/lgsm/data/debian-13.csv b/lgsm/data/debian-13.csv index fb1c08fae1..5b1f8bd4a6 100644 --- a/lgsm/data/debian-13.csv +++ b/lgsm/data/debian-13.csv @@ -1,4 +1,4 @@ -all,bc,binutils,bsdmainutils,bzip2,ca-certificates,cpio,curl,distro-info,file,gzip,hostname,jq,lib32gcc-s1,lib32stdc++6,netcat-openbsd,pigz,python3,tar,tmux,unzip,util-linux,uuid-runtime,wget,xz-utils +all,bc,binutils,bsdmainutils,bzip2,ca-certificates,cpio,curl,distro-info,file,gzip,hostname,jq,lib32gcc-s1,lib32stdc++6,netcat-openbsd,pigz,procps,python3,tar,tmux,unzip,util-linux,uuid-runtime,wget,xz-utils steamcmd,lib32gcc-s1,lib32stdc++6,libsdl2-2.0-0:i386,steamcmd ac ahl diff --git a/lgsm/data/debian-9.csv b/lgsm/data/debian-9.csv index cd27669e83..cd10789d68 100644 --- a/lgsm/data/debian-9.csv +++ b/lgsm/data/debian-9.csv @@ -1,4 +1,4 @@ -all,bc,binutils,bsdmainutils,bzip2,ca-certificates,cpio,curl,distro-info,file,gzip,hostname,jq,lib32gcc1,lib32stdc++6,netcat,pigz,python3,tar,tmux,unzip,util-linux,wget,xz-utils +all,bc,binutils,bsdmainutils,bzip2,ca-certificates,cpio,curl,distro-info,file,gzip,hostname,jq,lib32gcc1,lib32stdc++6,netcat,pigz,procps,python3,tar,tmux,unzip,util-linux,wget,xz-utils steamcmd,lib32gcc1,lib32stdc++6,libsdl2-2.0-0:i386,steamcmd ac ahl diff --git a/lgsm/data/rhel-7.csv b/lgsm/data/rhel-7.csv index 7a2909701b..d9912561df 100644 --- a/lgsm/data/rhel-7.csv +++ b/lgsm/data/rhel-7.csv @@ -1,4 +1,4 @@ -all,bc,binutils,bzip2,cpio,curl,epel-release,file,glibc.i686,gzip,hostname,jq,libstdc++,libstdc++.i686,nmap-ncat,pigz,python36,tar,tmux,unzip,util-linux,wget,xz +all,bc,binutils,bzip2,cpio,curl,epel-release,file,glibc.i686,gzip,hostname,jq,libstdc++,libstdc++.i686,nmap-ncat,pigz,procps-ng,python36,tar,tmux,unzip,util-linux,wget,xz steamcmd,glibc.i686,libstdc++.i686 ac ahl diff --git a/lgsm/data/rhel-8.csv b/lgsm/data/rhel-8.csv index ba51211203..1a1579f268 100644 --- a/lgsm/data/rhel-8.csv +++ b/lgsm/data/rhel-8.csv @@ -1,4 +1,4 @@ -all,bc,binutils,bzip2,cpio,curl,epel-release,file,glibc.i686,gzip,hostname,jq,libstdc++,libstdc++.i686,nmap-ncat,pigz,python36,tar,tmux,unzip,util-linux,wget,xz +all,bc,binutils,bzip2,cpio,curl,epel-release,file,glibc.i686,gzip,hostname,jq,libstdc++,libstdc++.i686,nmap-ncat,pigz,procps-ng,python36,tar,tmux,unzip,util-linux,wget,xz steamcmd,glibc.i686,libstdc++.i686 ac ahl diff --git a/lgsm/data/rhel-9.csv b/lgsm/data/rhel-9.csv index f0a95404f0..e60e450933 100644 --- a/lgsm/data/rhel-9.csv +++ b/lgsm/data/rhel-9.csv @@ -1,4 +1,4 @@ -all,bc,binutils,bzip2,cpio,curl,epel-release,file,glibc.i686,gzip,hostname,jq,libstdc++,libstdc++.i686,nmap-ncat,pigz,python3,tar,tmux,unzip,util-linux,wget,xz +all,bc,binutils,bzip2,cpio,curl,epel-release,file,glibc.i686,gzip,hostname,jq,libstdc++,libstdc++.i686,nmap-ncat,pigz,procps-ng,python3,tar,tmux,unzip,util-linux,wget,xz steamcmd,glibc.i686,libstdc++.i686 ac ahl diff --git a/lgsm/data/rocky-8.csv b/lgsm/data/rocky-8.csv index ba51211203..1a1579f268 100644 --- a/lgsm/data/rocky-8.csv +++ b/lgsm/data/rocky-8.csv @@ -1,4 +1,4 @@ -all,bc,binutils,bzip2,cpio,curl,epel-release,file,glibc.i686,gzip,hostname,jq,libstdc++,libstdc++.i686,nmap-ncat,pigz,python36,tar,tmux,unzip,util-linux,wget,xz +all,bc,binutils,bzip2,cpio,curl,epel-release,file,glibc.i686,gzip,hostname,jq,libstdc++,libstdc++.i686,nmap-ncat,pigz,procps-ng,python36,tar,tmux,unzip,util-linux,wget,xz steamcmd,glibc.i686,libstdc++.i686 ac ahl diff --git a/lgsm/data/rocky-9.csv b/lgsm/data/rocky-9.csv index f0a95404f0..e60e450933 100644 --- a/lgsm/data/rocky-9.csv +++ b/lgsm/data/rocky-9.csv @@ -1,4 +1,4 @@ -all,bc,binutils,bzip2,cpio,curl,epel-release,file,glibc.i686,gzip,hostname,jq,libstdc++,libstdc++.i686,nmap-ncat,pigz,python3,tar,tmux,unzip,util-linux,wget,xz +all,bc,binutils,bzip2,cpio,curl,epel-release,file,glibc.i686,gzip,hostname,jq,libstdc++,libstdc++.i686,nmap-ncat,pigz,procps-ng,python3,tar,tmux,unzip,util-linux,wget,xz steamcmd,glibc.i686,libstdc++.i686 ac ahl diff --git a/lgsm/data/ubuntu-16.04.csv b/lgsm/data/ubuntu-16.04.csv index 3775cc7eb8..de4b8e3cc7 100644 --- a/lgsm/data/ubuntu-16.04.csv +++ b/lgsm/data/ubuntu-16.04.csv @@ -1,4 +1,4 @@ -all,bc,binutils,bsdmainutils,bzip2,ca-certificates,cpio,curl,file,gzip,hostname,jq,lib32gcc1,lib32stdc++6,netcat,pigz,python3,tar,tmux,unzip,util-linux,uuid-runtime,wget,xz-utils +all,bc,binutils,bsdmainutils,bzip2,ca-certificates,cpio,curl,file,gzip,hostname,jq,lib32gcc1,lib32stdc++6,netcat,pigz,procps,python3,tar,tmux,unzip,util-linux,uuid-runtime,wget,xz-utils steamcmd,lib32gcc1,lib32stdc++6,libsdl2-2.0-0:i386,steamcmd ac ahl diff --git a/lgsm/data/ubuntu-18.04.csv b/lgsm/data/ubuntu-18.04.csv index e6a52bd5a7..9c6810e625 100644 --- a/lgsm/data/ubuntu-18.04.csv +++ b/lgsm/data/ubuntu-18.04.csv @@ -1,4 +1,4 @@ -all,bc,binutils,bsdmainutils,bzip2,ca-certificates,cpio,curl,distro-info,file,gzip,hostname,jq,lib32gcc1,lib32stdc++6,netcat,pigz,python3,tar,tmux,unzip,util-linux,uuid-runtime,wget,xz-utils +all,bc,binutils,bsdmainutils,bzip2,ca-certificates,cpio,curl,distro-info,file,gzip,hostname,jq,lib32gcc1,lib32stdc++6,netcat,pigz,procps,python3,tar,tmux,unzip,util-linux,uuid-runtime,wget,xz-utils steamcmd,lib32gcc1,lib32stdc++6,libsdl2-2.0-0:i386,steamcmd ac ahl diff --git a/lgsm/data/ubuntu-20.04.csv b/lgsm/data/ubuntu-20.04.csv index 9fdcd9a3bd..1ae3ba0507 100644 --- a/lgsm/data/ubuntu-20.04.csv +++ b/lgsm/data/ubuntu-20.04.csv @@ -1,4 +1,4 @@ -all,bc,binutils,bsdmainutils,bzip2,ca-certificates,cpio,curl,distro-info,file,gzip,hostname,jq,lib32gcc1,lib32stdc++6,netcat,pigz,python3,tar,tmux,unzip,util-linux,uuid-runtime,wget,xz-utils +all,bc,binutils,bsdmainutils,bzip2,ca-certificates,cpio,curl,distro-info,file,gzip,hostname,jq,lib32gcc1,lib32stdc++6,netcat,pigz,procps,python3,tar,tmux,unzip,util-linux,uuid-runtime,wget,xz-utils steamcmd,lib32gcc1,lib32stdc++6,libsdl2-2.0-0:i386,steamcmd ac ahl diff --git a/lgsm/data/ubuntu-22.04.csv b/lgsm/data/ubuntu-22.04.csv index e045227cb1..52e6af203a 100644 --- a/lgsm/data/ubuntu-22.04.csv +++ b/lgsm/data/ubuntu-22.04.csv @@ -1,4 +1,4 @@ -all,bc,binutils,bsdmainutils,bzip2,ca-certificates,cpio,curl,distro-info,file,gzip,hostname,jq,lib32gcc-s1,lib32stdc++6,netcat,pigz,python3,tar,tmux,unzip,util-linux,uuid-runtime,wget,xz-utils +all,bc,binutils,bsdmainutils,bzip2,ca-certificates,cpio,curl,distro-info,file,gzip,hostname,jq,lib32gcc-s1,lib32stdc++6,netcat,pigz,procps,python3,tar,tmux,unzip,util-linux,uuid-runtime,wget,xz-utils steamcmd,lib32gcc-s1,lib32stdc++6,libsdl2-2.0-0:i386,steamcmd ac ahl diff --git a/lgsm/data/ubuntu-23.04.csv b/lgsm/data/ubuntu-23.04.csv index bbb4d26f46..5010b8bb83 100644 --- a/lgsm/data/ubuntu-23.04.csv +++ b/lgsm/data/ubuntu-23.04.csv @@ -1,4 +1,4 @@ -all,bc,binutils,bsdmainutils,bzip2,ca-certificates,cpio,curl,distro-info,file,gzip,hostname,jq,lib32gcc-s1,lib32stdc++6,netcat-openbsd,pigz,python3,tar,tmux,unzip,util-linux,uuid-runtime,wget,xz-utils +all,bc,binutils,bsdmainutils,bzip2,ca-certificates,cpio,curl,distro-info,file,gzip,hostname,jq,lib32gcc-s1,lib32stdc++6,netcat-openbsd,pigz,procps,python3,tar,tmux,unzip,util-linux,uuid-runtime,wget,xz-utils steamcmd,lib32gcc-s1,lib32stdc++6,libsdl2-2.0-0:i386,steamcmd ac ahl diff --git a/lgsm/data/ubuntu-23.10.csv b/lgsm/data/ubuntu-23.10.csv index bbb4d26f46..5010b8bb83 100644 --- a/lgsm/data/ubuntu-23.10.csv +++ b/lgsm/data/ubuntu-23.10.csv @@ -1,4 +1,4 @@ -all,bc,binutils,bsdmainutils,bzip2,ca-certificates,cpio,curl,distro-info,file,gzip,hostname,jq,lib32gcc-s1,lib32stdc++6,netcat-openbsd,pigz,python3,tar,tmux,unzip,util-linux,uuid-runtime,wget,xz-utils +all,bc,binutils,bsdmainutils,bzip2,ca-certificates,cpio,curl,distro-info,file,gzip,hostname,jq,lib32gcc-s1,lib32stdc++6,netcat-openbsd,pigz,procps,python3,tar,tmux,unzip,util-linux,uuid-runtime,wget,xz-utils steamcmd,lib32gcc-s1,lib32stdc++6,libsdl2-2.0-0:i386,steamcmd ac ahl diff --git a/lgsm/data/ubuntu-24.04.csv b/lgsm/data/ubuntu-24.04.csv index 919344f8d1..4753353f1c 100644 --- a/lgsm/data/ubuntu-24.04.csv +++ b/lgsm/data/ubuntu-24.04.csv @@ -1,4 +1,4 @@ -all,bc,binutils,bsdmainutils,bzip2,ca-certificates,cpio,curl,distro-info,file,gzip,hostname,jq,lib32gcc-s1,lib32stdc++6,netcat-openbsd,pigz,python3,tar,tmux,unzip,util-linux,uuid-runtime,wget,xz-utils +all,bc,binutils,bsdmainutils,bzip2,ca-certificates,cpio,curl,distro-info,file,gzip,hostname,jq,lib32gcc-s1,lib32stdc++6,netcat-openbsd,pigz,procps,python3,tar,tmux,unzip,util-linux,uuid-runtime,wget,xz-utils steamcmd,lib32gcc-s1,lib32stdc++6,libsdl2-2.0-0:i386,steamcmd ac ahl diff --git a/lgsm/data/ubuntu-26.04.csv b/lgsm/data/ubuntu-26.04.csv index 0db57cabdf..53f19220b5 100644 --- a/lgsm/data/ubuntu-26.04.csv +++ b/lgsm/data/ubuntu-26.04.csv @@ -1,4 +1,4 @@ -all,bc,binutils,bsdmainutils,bzip2,ca-certificates,cpio,curl,distro-info,file,gzip,hostname,jq,lib32gcc-s1,lib32stdc++6,netcat-openbsd,pigz,python3,tar,tmux,unzip,util-linux,uuid-runtime,wget,xz-utils +all,bc,binutils,bsdmainutils,bzip2,ca-certificates,cpio,curl,distro-info,file,gzip,hostname,jq,lib32gcc-s1,lib32stdc++6,netcat-openbsd,pigz,procps,python3,tar,tmux,unzip,util-linux,uuid-runtime,wget,xz-utils steamcmd,lib32gcc-s1,lib32stdc++6,libsdl2-2.0-0:i386,steamcmd ac ahl From cbc0f74303c5a2101a43df9732ad7178ff3c2e90 Mon Sep 17 00:00:00 2001 From: Daniel Gibbs Date: Sat, 31 Oct 2026 20:21:20 +0000 Subject: [PATCH 140/164] fix(deps): install libxml2-utils for xmllint on Debian 13 (#5126) The Debian 13 dependency list had libxml2 for bt, mta, sdtd and st, where every other Debian and Ubuntu list has libxml2-utils. libxml2 is only the library; xmllint is in libxml2-utils. Without it fn_info_game_xml prints "xmllint: command not found" on every details and monitor run, and the ports and names read from the XML config come out empty. The RHEL-family lists keep libxml2, which ships xmllint there. --- lgsm/data/debian-13.csv | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lgsm/data/debian-13.csv b/lgsm/data/debian-13.csv index 5b1f8bd4a6..373ff498e1 100644 --- a/lgsm/data/debian-13.csv +++ b/lgsm/data/debian-13.csv @@ -16,7 +16,7 @@ bfv,libc6:i386 bmdm bo bs -bt,dos2unix,libxml2 +bt,dos2unix,libxml2-utils btl cc ce @@ -76,7 +76,7 @@ mcb mcv mh mohaa,libc6:i386 -mta,libncursesw6,libxml2 +mta,libncursesw6,libxml2-utils nd nec nmrih @@ -110,14 +110,14 @@ samp sb sbots scpsl,mono-complete,libicu76 -sdtd,libxml2 +sdtd,libxml2-utils sf sfc sm sof2 sol squad -st,libxml2 +st,libxml2-utils stn sven,zlib1g:i386 terraria From 79d0fbb7c2db72b1170b6b3b674364a184d30bf6 Mon Sep 17 00:00:00 2001 From: Alexandre Almeida <1251067+Xinayder@users.noreply.github.com> Date: Sat, 31 Oct 2026 21:38:08 +0100 Subject: [PATCH 141/164] feat: add HTML formatting to Matrix alert messages (#5087) Matrix alerts are now sent as m.notice messages with an HTML formatted_body: section headings are bold and the "Is my Game Server Online?" and "More info" links are clickable. The plain-text body is kept as the fallback for clients that do not render HTML. All values are escaped with jq's @html before being placed in the HTML, and apostrophes use the numeric ' entity. --- lgsm/modules/alert_matrix.sh | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/lgsm/modules/alert_matrix.sh b/lgsm/modules/alert_matrix.sh index 34d226f1f1..8938b8cdd9 100755 --- a/lgsm/modules/alert_matrix.sh +++ b/lgsm/modules/alert_matrix.sh @@ -18,6 +18,8 @@ matrixroomencoded="$(jq -rn --arg room "${matrixroom}" '$room|@uri')" matrixtxnid="$(date +%s%N)" matrixurl="${matrixbase}/_matrix/client/v3/rooms/${matrixroomencoded}/send/m.room.message/${matrixtxnid}" +alerttime="$(date)" + message="${alerttitle} Server Name @@ -33,13 +35,14 @@ Server IP ${alertip}:${port} Server Time -$(date)" +${alerttime}" if [ -n "${querytype}" ]; then + imgsourl="https://ismygameserver.online/${imgsoquerytype}/${alertip}:${queryport}" message+=" Is my Game Server Online? -https://ismygameserver.online/${imgsoquerytype}/${alertip}:${queryport}" +${imgsourl}" fi if [ -n "${alerturl}" ]; then @@ -49,7 +52,21 @@ More info ${alerturl}" fi -json="$(jq -cn --arg body "${message}" '{msgtype: "m.notice", body: $body}')" +json="$(jq -cn \ + --arg body "${message}" \ + --arg title "${alerttitle}" \ + --arg servername "${servername}" \ + --arg information "${alertmessage}" \ + --arg game "${gamename}" \ + --arg serverip "${alertip}:${port}" \ + --arg servertime "${alerttime}" \ + --arg imgsourl "${imgsourl}" \ + --arg alerturl "${alerturl}" \ + '(@html "\($title)

Server Name
\($servername)

Information
\($information)

Game
\($game)

Server IP
\($serverip)

Server Time
\($servertime)") + + (if $imgsourl != "" then @html "

Is my Game Server Online?
Check here" else "" end) + + (if $alerturl != "" then @html "

More info
\($alerturl)" else "" end) + | gsub("'"; "'") + | {msgtype: "m.notice", body: $body, format: "org.matrix.custom.html", formatted_body: .}')" fn_print_dots "Sending Matrix alert" From 1e403746f6eae48e2b1352f22fcd4e08d84078da Mon Sep 17 00:00:00 2001 From: Daniel Gibbs Date: Sat, 31 Oct 2026 20:56:45 +0000 Subject: [PATCH 142/164] feat(orarserver): add OpenRA Red Alert dedicated server (#5102) Adds orarserver for OpenRA: Red Alert using the official stable Linux x86_64 AppImage. LinuxGSM extracts the package so installation does not require FUSE, manages start/stop, checks the TCP game port and updates from the upstream stable GitHub release. Updates stage and validate the new package before replacing the old one, restoring the previous engine if the swap fails. Instance data is stored outside the replaceable engine directory. orar is added to the shared Update Check matrix. Related to #2233. --- .github/workflows/action-update-check.yml | 2 +- .../config-lgsm/orarserver/_default.cfg | 208 ++++++++++++++++++ lgsm/data/almalinux-8.csv | 1 + lgsm/data/almalinux-9.csv | 1 + lgsm/data/centos-7.csv | 1 + lgsm/data/centos-8.csv | 1 + lgsm/data/centos-9.csv | 1 + lgsm/data/debian-10.csv | 1 + lgsm/data/debian-11.csv | 1 + lgsm/data/debian-12.csv | 1 + lgsm/data/debian-13.csv | 1 + lgsm/data/debian-9.csv | 1 + lgsm/data/gameicons/orar-icon.png | Bin 0 -> 1127 bytes lgsm/data/rhel-7.csv | 1 + lgsm/data/rhel-8.csv | 1 + lgsm/data/rhel-9.csv | 1 + lgsm/data/rocky-8.csv | 1 + lgsm/data/rocky-9.csv | 1 + lgsm/data/serverlist.csv | 1 + lgsm/data/ubuntu-16.04.csv | 1 + lgsm/data/ubuntu-18.04.csv | 1 + lgsm/data/ubuntu-20.04.csv | 1 + lgsm/data/ubuntu-22.04.csv | 1 + lgsm/data/ubuntu-23.04.csv | 1 + lgsm/data/ubuntu-23.10.csv | 1 + lgsm/data/ubuntu-24.04.csv | 1 + lgsm/data/ubuntu-26.04.csv | 1 + lgsm/modules/check_config.sh | 4 + lgsm/modules/command_check_update.sh | 2 + lgsm/modules/command_update.sh | 2 + lgsm/modules/core_modules.sh | 5 + lgsm/modules/info_game.sh | 9 + lgsm/modules/info_messages.sh | 11 +- lgsm/modules/install_config.sh | 5 +- lgsm/modules/install_server_files.sh | 2 + lgsm/modules/update_openra.sh | 155 +++++++++++++ 36 files changed, 426 insertions(+), 3 deletions(-) create mode 100644 lgsm/config-default/config-lgsm/orarserver/_default.cfg create mode 100644 lgsm/data/gameicons/orar-icon.png create mode 100755 lgsm/modules/update_openra.sh diff --git a/.github/workflows/action-update-check.yml b/.github/workflows/action-update-check.yml index bf62a720f6..45cefe3f88 100644 --- a/.github/workflows/action-update-check.yml +++ b/.github/workflows/action-update-check.yml @@ -22,7 +22,7 @@ jobs: strategy: fail-fast: false matrix: - shortname: [css, fctr, jk2, mc, mcb, mta, pmc, ts3, ut99, vints, xnt] + shortname: [css, fctr, jk2, mc, mcb, mta, orar, pmc, ts3, ut99, vints, xnt] steps: - name: Download linuxgsm.sh diff --git a/lgsm/config-default/config-lgsm/orarserver/_default.cfg b/lgsm/config-default/config-lgsm/orarserver/_default.cfg new file mode 100644 index 0000000000..2e73cd1be1 --- /dev/null +++ b/lgsm/config-default/config-lgsm/orarserver/_default.cfg @@ -0,0 +1,208 @@ +################################## +######## Default Settings ######## +################################## +# DO NOT EDIT, ANY CHANGES WILL BE OVERWRITTEN! +# Copy settings from here and use them in either: +# common.cfg - applies settings to every instance. +# [instance].cfg - applies settings to a specific instance. + +#### Game Server Settings #### + +servername="LinuxGSM" +serverpassword="" +port="1234" +advertiseonline="True" +advertiseonlocalnetwork="True" +enablesingleplayer="True" +recordreplays="False" + +## Server Parameters | https://docs.linuxgsm.com/configuration/start-parameters#additional-parameters +startparameters="--server Server.Name=\"${servername}\" Server.Password=\"${serverpassword}\" Server.ListenPort=${port} Server.AdvertiseOnline=${advertiseonline} Server.AdvertiseOnLocalNetwork=${advertiseonlocalnetwork} Server.EnableSingleplayer=${enablesingleplayer} Server.RecordReplays=${recordreplays} Engine.SupportDir=\"${servercfgdir}\"" + +## Extra Parameters | https://docs.linuxgsm.com/configuration/start-parameters#extra-parameters +# Added to the end of startparameters. +extraparams="" + +#### LinuxGSM Settings #### + +## LinuxGSM Stats +# Send useful stats to LinuxGSM developers. +# https://docs.linuxgsm.com/configuration/linuxgsm-stats +# (on|off) +stats="off" + +## Notification Alerts +# (on|off) + +# Display IP | https://docs.linuxgsm.com/alerts#display-ip +displayip="" + +# More info | https://docs.linuxgsm.com/alerts#more-info +postalert="off" + +# Alert on Start/Stop/Restart +statusalert="off" + +# Discord Alerts | https://docs.linuxgsm.com/alerts/discord +discordalert="off" +discordwebhook="webhook" + +# Email Alerts | https://docs.linuxgsm.com/alerts/email +emailalert="off" +email="email@example.com" +emailfrom="" + +# Gotify Alerts | https://docs.linuxgsm.com/alerts/gotify +gotifyalert="off" +gotifytoken="token" +gotifywebhook="webhook" + +# IFTTT Alerts | https://docs.linuxgsm.com/alerts/ifttt +iftttalert="off" +ifttttoken="accesstoken" +iftttevent="linuxgsm_alert" + +# ntfy Alerts | https://docs.linuxgsm.com/alerts/ntfy +ntfyalert="off" +ntfytopic="LinuxGSM" +ntfyserver="https://ntfy.sh" +ntfytoken="" +ntfyusername="" +ntfypassword="" +ntfypriority="" +ntfytags="" + +# Matrix Alerts | https://docs.linuxgsm.com/alerts/matrix +matrixalert="off" +matrixhomeserver="matrix.org" +matrixtoken="accesstoken" +matrixroom="" + +# Pushbullet Alerts | https://docs.linuxgsm.com/alerts/pushbullet +pushbulletalert="off" +pushbullettoken="accesstoken" +channeltag="" + +# Pushover Alerts | https://docs.linuxgsm.com/alerts/pushover +pushoveralert="off" +pushovertoken="accesstoken" +pushoveruserkey="userkey" + +# Rocket.Chat Alerts | https://docs.linuxgsm.com/alerts/rocket.chat +rocketchatalert="off" +rocketchatwebhook="webhook" + +# Slack Alerts | https://docs.linuxgsm.com/alerts/slack +slackalert="off" +slackwebhook="webhook" + +# Telegram Alerts | https://docs.linuxgsm.com/alerts/telegram +# You can add a custom cURL string eg proxy (useful in Russia) in "curlcustomstring". +# For example "--socks5 ipaddr:port" for socks5 proxy see more in "curl --help all". +telegramapi="api.telegram.org" +telegramalert="off" +telegramtoken="accesstoken" +telegramchatid="" +telegramthreadid="" +telegramsilentnotification="false" +curlcustomstring="" + +## Stop | https://docs.linuxgsm.com/commands/start-stop-restart +stoponlyifnoplayers="off" +stoponlyifnoplayersallcommands="on" + +## Player Warnings | https://docs.linuxgsm.com/features/player-warnings +# Minutes to warn players in-game before a stop, restart or update. 0 to disable. +# e.g. 15 warns at 15, 10, 5, 3 and 1 minutes. +warnplayerstimer="0" + +## Updating | https://docs.linuxgsm.com/commands/update +updateonstart="off" + +## Backup | https://docs.linuxgsm.com/commands/backup +maxbackups="4" +maxbackupdays="30" +stoponbackup="on" + +## Logging | https://docs.linuxgsm.com/features/logging +consolelogging="on" +logdays="7" + +## Monitor | https://docs.linuxgsm.com/commands/monitor +# Query delay time +querydelay="1" + +## ANSI Colors | https://docs.linuxgsm.com/features/ansi-colors +ansi="on" + +#### Advanced Settings #### + +## Message Display Time | https://docs.linuxgsm.com/features/message-display-time +sleeptime="0.5" + +## Stop Mode | https://docs.linuxgsm.com/features/stop-mode +# 1: tmux kill +# 2: CTRL+c +# 3: quit +# 4: quit 120s +# 5: stop +# 6: q +# 7: exit +# 8: 7 Days to Die +# 9: GoldSrc +# 10: Avorion +# 11: end +stopmode="2" + +## Query mode +# 1: session only +# 2: gamedig (gsquery fallback) +# 3: gamedig +# 4: gsquery +# 5: tcp +querymode="5" +querytype="" + +## Console type +consoleverbose="yes" +consoleinteract="no" + +## Game Server Details +# Do not edit +gamename="OpenRA: Red Alert" +engine="openra" +glibc="2.17" + +#### Directories #### +# Edit with care + +## Game Server Directories +systemdir="${serverfiles}" +executabledir="${serverfiles}/openra" +preexecutable="" +executable="./AppRun" +servercfgdir="${serverfiles}/data/${selfname}" +servercfg="" +servercfgdefault="" +servercfgfullpath="" + +## Backup Directory +backupdir="${lgsmdir}/backup" + +## Logging Directories +[ -n "${LGSM_LOGDIR}" ] && logdir="${LGSM_LOGDIR}" || logdir="${rootdir}/log" +gamelogdir="${servercfgdir}/Logs" +lgsmlogdir="${logdir}/script" +consolelogdir="${logdir}/console" +lgsmlog="${lgsmlogdir}/${selfname}-script.log" +consolelog="${consolelogdir}/${selfname}-console.log" +alertlog="${lgsmlogdir}/${selfname}-alert.log" +postdetailslog="${lgsmlogdir}/${selfname}-postdetails.log" + +## Logs Naming +lgsmlogdate="${lgsmlogdir}/${selfname}-script-$(date '+%Y-%m-%d-%H:%M:%S').log" +consolelogdate="${consolelogdir}/${selfname}-console-$(date '+%Y-%m-%d-%H:%M:%S').log" + +## Log Parameters +logtimestamp="off" +logtimestampformat="%Y-%m-%d %H:%M:%S" diff --git a/lgsm/data/almalinux-8.csv b/lgsm/data/almalinux-8.csv index 12ae5589ba..e592a934ff 100644 --- a/lgsm/data/almalinux-8.csv +++ b/lgsm/data/almalinux-8.csv @@ -85,6 +85,7 @@ ns2,speex,tbb ns2c,speex.i686,tbb.i686 ohd onset,mariadb-connector-c +orar,libicu,openssl-libs,zlib opfor pc pc2 diff --git a/lgsm/data/almalinux-9.csv b/lgsm/data/almalinux-9.csv index e60e450933..19d1e5e20a 100644 --- a/lgsm/data/almalinux-9.csv +++ b/lgsm/data/almalinux-9.csv @@ -85,6 +85,7 @@ ns2,speex,tbb ns2c,speex.i686,tbb.i686 ohd onset,mariadb-connector-c +orar,libicu,openssl-libs,zlib opfor pc pc2 diff --git a/lgsm/data/centos-7.csv b/lgsm/data/centos-7.csv index d4c4cf21d7..6076098b7f 100644 --- a/lgsm/data/centos-7.csv +++ b/lgsm/data/centos-7.csv @@ -85,6 +85,7 @@ ns2,speex,tbb ns2c,speex.i686,tbb.i686 ohd onset,mariadb-connector-c +orar opfor pc pc2 diff --git a/lgsm/data/centos-8.csv b/lgsm/data/centos-8.csv index fc2d63e33d..3578adda9d 100644 --- a/lgsm/data/centos-8.csv +++ b/lgsm/data/centos-8.csv @@ -85,6 +85,7 @@ ns2,speex,tbb ns2c,speex.i686,tbb.i686 ohd onset,mariadb-connector-c +orar opfor pc pc2 diff --git a/lgsm/data/centos-9.csv b/lgsm/data/centos-9.csv index 61f1da70f3..533194ab38 100644 --- a/lgsm/data/centos-9.csv +++ b/lgsm/data/centos-9.csv @@ -85,6 +85,7 @@ ns2,speex,tbb ns2c,speex.i686,tbb.i686 ohd onset,mariadb-connector-c +orar opfor pc pc2 diff --git a/lgsm/data/debian-10.csv b/lgsm/data/debian-10.csv index a4a30ed54a..e15b010b31 100644 --- a/lgsm/data/debian-10.csv +++ b/lgsm/data/debian-10.csv @@ -84,6 +84,7 @@ ns2,speex,libtbb2 ns2c,speex:i386,libtbb2 ohd onset,libmariadb-dev +orar opfor pc pc2 diff --git a/lgsm/data/debian-11.csv b/lgsm/data/debian-11.csv index 8746c794ee..69ef90c4fe 100644 --- a/lgsm/data/debian-11.csv +++ b/lgsm/data/debian-11.csv @@ -85,6 +85,7 @@ ns2,speex,libtbb2 ns2c,speex:i386,libtbb2 ohd onset,libmariadb-dev +orar,libicu67,libssl1.1,zlib1g opfor pc pc2 diff --git a/lgsm/data/debian-12.csv b/lgsm/data/debian-12.csv index 3acadda70c..65652bdd9b 100644 --- a/lgsm/data/debian-12.csv +++ b/lgsm/data/debian-12.csv @@ -85,6 +85,7 @@ ns2,speex,libtbb12 ns2c,speex:i386,libtbb12 ohd onset,libmariadb-dev +orar,libicu72,libssl3,zlib1g opfor pc pc2 diff --git a/lgsm/data/debian-13.csv b/lgsm/data/debian-13.csv index 373ff498e1..47e584a860 100644 --- a/lgsm/data/debian-13.csv +++ b/lgsm/data/debian-13.csv @@ -85,6 +85,7 @@ ns2,speex,libtbb12 ns2c,speex:i386,libtbb12 ohd onset,libmariadb-dev +orar,libicu76,libssl3t64,zlib1g opfor pc pc2 diff --git a/lgsm/data/debian-9.csv b/lgsm/data/debian-9.csv index cd10789d68..c946633e6e 100644 --- a/lgsm/data/debian-9.csv +++ b/lgsm/data/debian-9.csv @@ -85,6 +85,7 @@ ns2,speex,libtbb2 ns2c,speex:i386,libtbb2 ohd onset,libmariadb-dev +orar opfor pc pc2 diff --git a/lgsm/data/gameicons/orar-icon.png b/lgsm/data/gameicons/orar-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..f2562b38109e737cffb114e7630706c8c32501c8 GIT binary patch literal 1127 zcmV-t1ep7YP)Nv55D9gy60NQsWBF{VSQuK z`b|7;Z0XE1HB>Nxv0&0>1~13Y^=xlUD{JLDudkKR+pVooRUgDO`g(qf7UaS2ph_hYpl&`^&n0<@~a2wxHw% zdFXsY`%U3Y|G|o7j%?RPurxy`vF5o4nDL2fJ}wTQS}xO`O}rsU?oUAy^#BO`M5rLQW&+k;@h3 zMsf$)r%euC_m|-Ia>L>LLZOZo zn)u-uMufyK<@^-5W{cM<#;S)HMc ze2H28gK=88a3X$ufrLC)lHHap&i>q;WYG!b-CKW|#2(AZ)n$2~Y&4y`eXYEFsjM-D z+)VoOQxlJ&mw&5)b({I|Vk#l8mSw#Ga!H$fMb?;1KD}2e&&iLE$|m#3rS-D@%<|Hu z^3=Jq)Kt>K&t;B6ohnS%%*X39@%gO%TeV_BG()!6Zdw7j+%9# zS&rD=km9`M(tTu$p7IEJid}9A08>r z{G(foZ7(j|Z^N(JTh882ChqA4)mnCbFSLgbdq$R?L2e>vG|0+> /dev/null) || [ ! -x "${extractdir}/squashfs-root/usr/lib/openra/OpenRA.Server" ] || [ ! -x "${extractdir}/squashfs-root/AppRun" ]; then + fn_print_fail_nl "Extracting OpenRA server files" + fn_script_log_fail "Extracting OpenRA server files" + exitcode=1 + core_exit.sh + fi + printf '%s\n' "${remotebuild}" > "${extractdir}/squashfs-root/build.txt" || exit 1 + if [ -d "${serverfiles}/openra" ]; then + mv "${serverfiles}/openra" "${extractdir}/previous" || exit 1 + fi + if ! mv "${extractdir}/squashfs-root" "${serverfiles}/openra"; then + if [ -d "${extractdir}/previous" ]; then + mv "${extractdir}/previous" "${serverfiles}/openra" + fi + exitcode=1 + core_exit.sh + fi + fn_clear_tmp +} + +fn_update_localbuild() { + fn_print_dots "Checking local build: ${remotelocation}" + localbuild="0" + if [ -x "${serverfiles}/openra/AppRun" ] && [ -x "${serverfiles}/openra/usr/lib/openra/OpenRA.Server" ]; then + localbuild=$(head -n 1 "${serverfiles}/openra/build.txt" 2> /dev/null) + fi + if [ -z "${localbuild}" ]; then + fn_print_error "Checking local build: ${remotelocation}: missing local build info" + fn_script_log_error "Missing local build info" + localbuild="0" + else + fn_print_ok "Checking local build: ${remotelocation}" + fn_script_log_pass "Checking local build" + fi +} + +fn_update_remotebuild() { + if [ "$(uname -m)" != "x86_64" ]; then + fn_print_fail_nl "OpenRA requires an x86_64 Linux server" + fn_script_log_fail "OpenRA requires an x86_64 Linux server" + exitcode=1 + core_exit.sh + fi + apiurl="https://api.github.com/repos/OpenRA/OpenRA/releases/latest" + if ! remotebuildresponse=$(curl --fail --location --silent --show-error --connect-timeout 10 --max-time 60 "${apiurl}"); then + fn_print_fail_nl "Checking remote build: ${remotelocation}" + fn_script_log_fail "Checking remote build: ${apiurl}" + exitcode=1 + core_exit.sh + fi + remotebuildfilename="OpenRA-Red-Alert-x86_64.AppImage" + remotebuild=$(echo "${remotebuildresponse}" | jq -er '.tag_name | select(test("^release-[0-9]+$"))') + remotebuildurl=$(echo "${remotebuildresponse}" | jq -er --arg filename "${remotebuildfilename}" '[.assets[] | select(.name == $filename)] | select(length == 1) | .[0].browser_download_url') + if [ -z "${remotebuild}" ] || [[ "${remotebuildurl}" != https://github.com/OpenRA/OpenRA/releases/download/* ]]; then + fn_print_fail_nl "Unable to get OpenRA release asset" + fn_script_log_fail "Unable to get OpenRA release asset" + exitcode=1 + core_exit.sh + fi + fn_print_ok "Checking remote build: ${remotelocation}" + fn_script_log_pass "Checking remote build: ${remotebuild}" +} + +fn_update_compare() { + fn_print_dots "Checking for update: ${remotelocation}" + # Update has been found or force update. + 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}${remotebuild}${default}" + if [ -n "${branch}" ]; then + fn_print_nl "* Branch: ${branch}" + fi + if [ -f "${rootdir}/.dev-debug" ]; then + 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 + fn_print "\n" + fn_script_log_info "Update available" + fn_script_log_info "Local build: ${localbuild}" + fn_script_log_info "Remote build: ${remotebuild}" + if [ -n "${branch}" ]; then + fn_script_log_info "Branch: ${branch}" + fi + fn_script_log_info "${localbuild} > ${remotebuild}" + + if [ "${commandname}" == "UPDATE" ]; then + unset updateonstart + fn_update_apply fn_update_dl + unset exitbypass + alert="update" + elif [ "${commandname}" == "CHECK-UPDATE" ]; then + alert="check-update" + fi + alert.sh + else + fn_print_ok_nl "Checking for update: ${remotelocation}" + 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 + fn_print_nl "* Branch: ${branch}" + fi + fn_print "\n" + fn_script_log_info "No update available" + fn_script_log_info "Local build: ${localbuild}" + fn_script_log_info "Remote build: ${remotebuild}" + if [ -n "${branch}" ]; then + fn_script_log_info "Branch: ${branch}" + fi + if [ -f "${rootdir}/.dev-debug" ]; then + 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 +} + +# The location where the builds are checked and downloaded. +remotelocation="github.com/OpenRA/OpenRA" + +if [ "${firstcommandname}" == "INSTALL" ]; then + fn_update_remotebuild + fn_update_dl +else + fn_print_dots "Checking for update" + fn_print_dots "Checking for update: ${remotelocation}" + fn_script_log_info "Checking for update: ${remotelocation}" + fn_update_localbuild + fn_update_remotebuild + fn_update_compare +fi From 0592b98f2158cd75877b60bc9bf6e0ade77c5ddd Mon Sep 17 00:00:00 2001 From: Daniel Gibbs Date: Sat, 31 Oct 2026 22:27:47 +0000 Subject: [PATCH 143/164] feat(luanti): add Luanti server support (#5101) Adds Luanti (formerly Minetest) as luantiserver, with installation, engine updates, details, session monitoring and graceful shutdown. Fresh installs include Minetest Game and a separate instance config; engine updates preserve games, mods, worlds and instance settings. Uses the portable headless builds from rollerozxa/luantiserver, as recommended by the official Luanti Linux server documentation, selecting x86_64 or aarch64 assets and verifying SHA256 checksums. Adds dependency entries and the upstream game icon, with its attribution in a new Third-party assets section of LICENSE.md. Fixes #2303 --- LICENSE.md | 6 + .../config-lgsm/luantiserver/_default.cfg | 205 ++++++++++++++++++ lgsm/data/almalinux-8.csv | 1 + lgsm/data/almalinux-9.csv | 1 + lgsm/data/centos-7.csv | 1 + lgsm/data/centos-8.csv | 1 + lgsm/data/centos-9.csv | 1 + lgsm/data/debian-10.csv | 1 + lgsm/data/debian-11.csv | 1 + lgsm/data/debian-12.csv | 1 + lgsm/data/debian-13.csv | 1 + lgsm/data/debian-9.csv | 1 + lgsm/data/gameicons/luanti-icon.png | Bin 0 -> 587 bytes lgsm/data/rhel-7.csv | 1 + lgsm/data/rhel-8.csv | 1 + lgsm/data/rhel-9.csv | 1 + lgsm/data/rocky-8.csv | 1 + lgsm/data/rocky-9.csv | 1 + lgsm/data/serverlist.csv | 1 + lgsm/data/ubuntu-16.04.csv | 1 + lgsm/data/ubuntu-18.04.csv | 1 + lgsm/data/ubuntu-20.04.csv | 1 + lgsm/data/ubuntu-22.04.csv | 1 + lgsm/data/ubuntu-23.04.csv | 1 + lgsm/data/ubuntu-23.10.csv | 1 + lgsm/data/ubuntu-24.04.csv | 1 + lgsm/data/ubuntu-26.04.csv | 1 + lgsm/modules/command_check_update.sh | 2 + lgsm/modules/command_update.sh | 2 + lgsm/modules/core_modules.sh | 5 + lgsm/modules/info_game.sh | 18 ++ lgsm/modules/info_messages.sh | 11 +- lgsm/modules/install_config.sh | 15 +- lgsm/modules/install_server_files.sh | 2 + lgsm/modules/update_luanti.sh | 162 ++++++++++++++ 35 files changed, 450 insertions(+), 2 deletions(-) create mode 100644 lgsm/config-default/config-lgsm/luantiserver/_default.cfg create mode 100644 lgsm/data/gameicons/luanti-icon.png create mode 100755 lgsm/modules/update_luanti.sh diff --git a/LICENSE.md b/LICENSE.md index c138f40712..c58e808eb2 100644 --- a/LICENSE.md +++ b/LICENSE.md @@ -19,3 +19,9 @@ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +## Third-party assets + +The following files are not covered by the MIT License above and remain under their own licenses. + +- `lgsm/data/gameicons/luanti-icon.png`: Luanti icon by erle, licensed under [CC BY-SA 3.0](https://creativecommons.org/licenses/by-sa/3.0/). Copied without modification from [Luanti 5.17.0](https://github.com/luanti-org/luanti/blob/5.17.0/misc/luanti-icon-24x24.png); see the [upstream license and attribution](https://github.com/luanti-org/luanti/blob/5.17.0/LICENSE.txt). diff --git a/lgsm/config-default/config-lgsm/luantiserver/_default.cfg b/lgsm/config-default/config-lgsm/luantiserver/_default.cfg new file mode 100644 index 0000000000..fd35a5b7b5 --- /dev/null +++ b/lgsm/config-default/config-lgsm/luantiserver/_default.cfg @@ -0,0 +1,205 @@ +################################## +######## Default Settings ######## +################################## +# DO NOT EDIT, ANY CHANGES WILL BE OVERWRITTEN! +# Copy settings from here and use them in either: +# common.cfg - applies settings to every instance. +# [instance].cfg - applies settings to a specific instance. + +#### Game Server Settings #### + +## Predefined Parameters | https://docs.linuxgsm.com/configuration/start-parameters +ip="0.0.0.0" +port="30000" +gameid="minetest" +worldname="world" + +## Server Parameters | https://docs.linuxgsm.com/configuration/start-parameters#additional-parameters +startparameters="--config ${servercfgfullpath} --world ${serverfiles}/worlds/${worldname} --gameid ${gameid} --port ${port} --logfile ${gamelogdir}/${selfname}-game.log --terminal" + +## Extra Parameters | https://docs.linuxgsm.com/configuration/start-parameters#extra-parameters +# Added to the end of startparameters. +extraparams="" + +#### LinuxGSM Settings #### + +## LinuxGSM Stats +# Send useful stats to LinuxGSM developers. +# https://docs.linuxgsm.com/configuration/linuxgsm-stats +# (on|off) +stats="off" + +## Notification Alerts +# (on|off) + +# Display IP | https://docs.linuxgsm.com/alerts#display-ip +displayip="" + +# More info | https://docs.linuxgsm.com/alerts#more-info +postalert="off" + +# Alert on Start/Stop/Restart +statusalert="off" + +# Discord Alerts | https://docs.linuxgsm.com/alerts/discord +discordalert="off" +discordwebhook="webhook" + +# Email Alerts | https://docs.linuxgsm.com/alerts/email +emailalert="off" +email="email@example.com" +emailfrom="" + +# Gotify Alerts | https://docs.linuxgsm.com/alerts/gotify +gotifyalert="off" +gotifytoken="token" +gotifywebhook="webhook" + +# IFTTT Alerts | https://docs.linuxgsm.com/alerts/ifttt +iftttalert="off" +ifttttoken="accesstoken" +iftttevent="linuxgsm_alert" + +# ntfy Alerts | https://docs.linuxgsm.com/alerts/ntfy +ntfyalert="off" +ntfytopic="LinuxGSM" +ntfyserver="https://ntfy.sh" +ntfytoken="" +ntfyusername="" +ntfypassword="" +ntfypriority="" +ntfytags="" + +# Matrix Alerts | https://docs.linuxgsm.com/alerts/matrix +matrixalert="off" +matrixhomeserver="matrix.org" +matrixtoken="accesstoken" +matrixroom="" + +# Pushbullet Alerts | https://docs.linuxgsm.com/alerts/pushbullet +pushbulletalert="off" +pushbullettoken="accesstoken" +channeltag="" + +# Pushover Alerts | https://docs.linuxgsm.com/alerts/pushover +pushoveralert="off" +pushovertoken="accesstoken" +pushoveruserkey="userkey" + +# Rocket.Chat Alerts | https://docs.linuxgsm.com/alerts/rocket.chat +rocketchatalert="off" +rocketchatwebhook="webhook" + +# Slack Alerts | https://docs.linuxgsm.com/alerts/slack +slackalert="off" +slackwebhook="webhook" + +# Telegram Alerts | https://docs.linuxgsm.com/alerts/telegram +# You can add a custom cURL string eg proxy (useful in Russia) in "curlcustomstring". +# For example "--socks5 ipaddr:port" for socks5 proxy see more in "curl --help all". +telegramapi="api.telegram.org" +telegramalert="off" +telegramtoken="accesstoken" +telegramchatid="" +telegramthreadid="" +telegramsilentnotification="false" +curlcustomstring="" + +## Stop | https://docs.linuxgsm.com/commands/start-stop-restart +stoponlyifnoplayers="off" +stoponlyifnoplayersallcommands="on" + +## Player Warnings | https://docs.linuxgsm.com/features/player-warnings +# Minutes to warn players in-game before a stop, restart or update. 0 to disable. +# e.g. 15 warns at 15, 10, 5, 3 and 1 minutes. +warnplayerstimer="0" + +## Updating | https://docs.linuxgsm.com/commands/update +updateonstart="off" + +## Backup | https://docs.linuxgsm.com/commands/backup +maxbackups="4" +maxbackupdays="30" +stoponbackup="on" + +## Logging | https://docs.linuxgsm.com/features/logging +consolelogging="on" +logdays="7" + +## Monitor | https://docs.linuxgsm.com/commands/monitor +# Query delay time +querydelay="1" + +## ANSI Colors | https://docs.linuxgsm.com/features/ansi-colors +ansi="on" + +#### Advanced Settings #### + +## Message Display Time | https://docs.linuxgsm.com/features/message-display-time +sleeptime="0.5" + +## Stop Mode | https://docs.linuxgsm.com/features/stop-mode +# 1: tmux kill +# 2: CTRL+c +# 3: quit +# 4: quit 120s +# 5: stop +# 6: q +# 7: exit +# 8: 7 Days to Die +# 9: GoldSrc +# 10: Avorion +# 11: end +stopmode="2" + +## Query mode +# 1: session only +# 2: gamedig (gsquery fallback) +# 3: gamedig +# 4: gsquery +# 5: tcp +querymode="1" +querytype="" + +## Console type +consoleverbose="yes" +consoleinteract="yes" + +## Game Server Details +# Do not edit +gamename="Luanti" +engine="luanti" +glibc="2.31" + +#### Directories #### +# Edit with care + +## Game Server Directories +systemdir="${serverfiles}" +executabledir="${serverfiles}/bin" +executable="./luantiserver" +servercfgdir="${systemdir}" +servercfg="${selfname}.cfg" +servercfgdefault="minetest.conf.example" +servercfgfullpath="${servercfgdir}/${servercfg}" + +## Backup Directory +backupdir="${lgsmdir}/backup" + +## Logging Directories +[ -n "${LGSM_LOGDIR}" ] && logdir="${LGSM_LOGDIR}" || logdir="${rootdir}/log" +gamelogdir="${logdir}/server" +lgsmlogdir="${logdir}/script" +consolelogdir="${logdir}/console" +lgsmlog="${lgsmlogdir}/${selfname}-script.log" +consolelog="${consolelogdir}/${selfname}-console.log" +alertlog="${lgsmlogdir}/${selfname}-alert.log" +postdetailslog="${lgsmlogdir}/${selfname}-postdetails.log" + +## Logs Naming +lgsmlogdate="${lgsmlogdir}/${selfname}-script-$(date '+%Y-%m-%d-%H:%M:%S').log" +consolelogdate="${consolelogdir}/${selfname}-console-$(date '+%Y-%m-%d-%H:%M:%S').log" + +## Log Parameters +logtimestamp="off" +logtimestampformat="%Y-%m-%d %H:%M:%S" diff --git a/lgsm/data/almalinux-8.csv b/lgsm/data/almalinux-8.csv index e592a934ff..e290c3b395 100644 --- a/lgsm/data/almalinux-8.csv +++ b/lgsm/data/almalinux-8.csv @@ -71,6 +71,7 @@ kf kf2 l4d l4d2 +luanti,libcurl,libstdc++,libzstd,ncurses-libs,sqlite-libs,zlib mc,java-21-openjdk mcb,libnsl mcv diff --git a/lgsm/data/almalinux-9.csv b/lgsm/data/almalinux-9.csv index 19d1e5e20a..d50f05f883 100644 --- a/lgsm/data/almalinux-9.csv +++ b/lgsm/data/almalinux-9.csv @@ -71,6 +71,7 @@ kf kf2 l4d l4d2 +luanti,libcurl,libstdc++,libzstd,ncurses-libs,sqlite-libs,zlib mc,java-25-openjdk mcb,libnsl mcv diff --git a/lgsm/data/centos-7.csv b/lgsm/data/centos-7.csv index 6076098b7f..348c30470e 100644 --- a/lgsm/data/centos-7.csv +++ b/lgsm/data/centos-7.csv @@ -71,6 +71,7 @@ kf kf2 l4d l4d2 +luanti,libcurl,libstdc++,libzstd,ncurses-libs,sqlite-libs,zlib mc,java-21-openjdk mcb,libnsl mcv diff --git a/lgsm/data/centos-8.csv b/lgsm/data/centos-8.csv index 3578adda9d..d14ae75a68 100644 --- a/lgsm/data/centos-8.csv +++ b/lgsm/data/centos-8.csv @@ -71,6 +71,7 @@ kf kf2 l4d l4d2 +luanti,libcurl,libstdc++,libzstd,ncurses-libs,sqlite-libs,zlib mc,java-21-openjdk mcb,libnsl mcv diff --git a/lgsm/data/centos-9.csv b/lgsm/data/centos-9.csv index 533194ab38..eb161e00b6 100644 --- a/lgsm/data/centos-9.csv +++ b/lgsm/data/centos-9.csv @@ -71,6 +71,7 @@ kf kf2 l4d l4d2 +luanti,libcurl,libstdc++,libzstd,ncurses-libs,sqlite-libs,zlib mc,java-25-openjdk mcb,libnsl mcv diff --git a/lgsm/data/debian-10.csv b/lgsm/data/debian-10.csv index e15b010b31..b44d1ead57 100644 --- a/lgsm/data/debian-10.csv +++ b/lgsm/data/debian-10.csv @@ -70,6 +70,7 @@ kf kf2 l4d l4d2 +luanti,libcurl4,libncursesw6,libsqlite3-0,libstdc++6,libzstd1,zlib1g mc,openjdk-11-jre mcb mcv diff --git a/lgsm/data/debian-11.csv b/lgsm/data/debian-11.csv index 69ef90c4fe..6f3a6b17f1 100644 --- a/lgsm/data/debian-11.csv +++ b/lgsm/data/debian-11.csv @@ -71,6 +71,7 @@ kf kf2 l4d l4d2 +luanti,libcurl4,libncursesw6,libsqlite3-0,libstdc++6,libzstd1,zlib1g mc,openjdk-17-jre mcb mcv diff --git a/lgsm/data/debian-12.csv b/lgsm/data/debian-12.csv index 65652bdd9b..bd145c415a 100644 --- a/lgsm/data/debian-12.csv +++ b/lgsm/data/debian-12.csv @@ -71,6 +71,7 @@ kf kf2 l4d l4d2 +luanti,libcurl4,libncursesw6,libsqlite3-0,libstdc++6,libzstd1,zlib1g mc,openjdk-17-jre mcb mcv diff --git a/lgsm/data/debian-13.csv b/lgsm/data/debian-13.csv index 47e584a860..757ec4e371 100644 --- a/lgsm/data/debian-13.csv +++ b/lgsm/data/debian-13.csv @@ -71,6 +71,7 @@ kf kf2 l4d l4d2 +luanti,libcurl4t64,libncursesw6,libsqlite3-0,libstdc++6,libzstd1,zlib1g mc,openjdk-25-jre mcb mcv diff --git a/lgsm/data/debian-9.csv b/lgsm/data/debian-9.csv index c946633e6e..5362fa6fe1 100644 --- a/lgsm/data/debian-9.csv +++ b/lgsm/data/debian-9.csv @@ -71,6 +71,7 @@ kf kf2 l4d l4d2 +luanti,libcurl4,libncursesw6,libsqlite3-0,libstdc++6,libzstd1,zlib1g mc,openjdk-8-jre mcb mcv diff --git a/lgsm/data/gameicons/luanti-icon.png b/lgsm/data/gameicons/luanti-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..334e2f6d61cb8c8ffcfac839b2bacbd653e1af07 GIT binary patch literal 587 zcmV-R0<`^!P)l7Iw80du}LvetL+Cg^yVR#GnAjzC_EtO3c1V(ZxsI%S7U| zZRECV<+g3*w{7RQZ0NXc=+j2&xo-60PWI$a{OM1{7as%w000nlQchC<0tN{Q3=R$y z6c!fw{QmwGd1BEQSwA%Idf|g;kvKWc z2HpoLGjj{%FM^hjZoL> "${servercfgfullpath}" + fi + fn_list_config_locations +elif [ "${shortname}" == "orar" ]; then fn_check_cfgdir fn_list_config_locations elif [ "${shortname}" == "sdtd" ]; then diff --git a/lgsm/modules/install_server_files.sh b/lgsm/modules/install_server_files.sh index f9dca5b8ef..3bee586a3e 100755 --- a/lgsm/modules/install_server_files.sh +++ b/lgsm/modules/install_server_files.sh @@ -279,6 +279,8 @@ elif [ "${shortname}" == "jk2" ]; then update_jk2.sh elif [ "${shortname}" == "jk3" ]; then update_jk3.sh +elif [ "${shortname}" == "luanti" ]; then + update_luanti.sh elif [ "${shortname}" == "orar" ]; then update_openra.sh elif [ "${shortname}" == "vints" ]; then diff --git a/lgsm/modules/update_luanti.sh b/lgsm/modules/update_luanti.sh new file mode 100755 index 0000000000..c80a146027 --- /dev/null +++ b/lgsm/modules/update_luanti.sh @@ -0,0 +1,162 @@ +#!/bin/bash +# LinuxGSM update_luanti.sh module +# Author: Daniel Gibbs +# Contributors: https://linuxgsm.com/contrib +# Website: https://linuxgsm.com +# Description: Handles updating of Luanti servers. + +moduleselfname="$(basename "$(readlink -f "${BASH_SOURCE[0]}")")" + +fn_update_dl() { + fn_fetch_file "${remotebuildurl}" "" "" "" "${tmpdir}" "${remotebuildfilename}" "nochmodx" "norun" "force" "${remotebuildhash}" + fn_dl_extract "${tmpdir}" "${remotebuildfilename}" "${serverfiles}" "luanti" + if [ "${firstcommandname}" == "INSTALL" ] && [ ! -d "${serverfiles}/games/minetest" ]; then + fn_fetch_file "https://github.com/luanti-org/minetest_game/archive/refs/tags/5.8.0.tar.gz" "" "" "" "${tmpdir}" "minetest_game-5.8.0.tar.gz" "nochmodx" "norun" "force" "33a3bb43b08497a0bdb2f49f140a2829e582d5c16c0ad52be1595c803f706912" + mkdir -p "${serverfiles}/games/minetest" + fn_dl_extract "${tmpdir}" "minetest_game-5.8.0.tar.gz" "${serverfiles}/games/minetest" "minetest_game-5.8.0" + fi + fn_clear_tmp +} + +fn_update_localbuild() { + local mode="${1:-}" + if [ "${mode}" != "silent" ]; then + fn_print_dots "Checking local build: ${remotelocation}" + fi + localbuild=$("${executabledir}/${executable#./}" --version 2> /dev/null | awk '/^Luanti / {print $2; exit}') + localbuild="${localbuild:-0}" + if [ "${mode}" != "silent" ]; then + fn_print_ok "Checking local build: ${remotelocation}" + fi +} + +fn_update_remotebuild() { + case "$(uname -m)" in + x86_64) luantiarch="x86_64" ;; + aarch64) luantiarch="aarch64" ;; + *) + fn_print_fail_nl "Unsupported Luanti architecture: $(uname -m)" + fn_script_log_fail "Unsupported Luanti architecture: $(uname -m)" + core_exit.sh + ;; + esac + apiurl="https://api.github.com/repos/rollerozxa/luantiserver/releases/latest" + remotebuildresponse=$(curl -fsSL --retry 3 "${apiurl}") + remotebuild=$(echo "${remotebuildresponse}" | jq -r '.tag_name // empty') + remotebuildfilename="luantiserver-${remotebuild}-${luantiarch}.tar.gz" + remotebuildurl=$(echo "${remotebuildresponse}" | jq -r --arg name "${remotebuildfilename}" '.assets[]? | select(.name == $name) | .browser_download_url') + remotebuildhash=$(echo "${remotebuildresponse}" | jq -r --arg name "${remotebuildfilename}" '.assets[]? | select(.name == $name) | .digest // empty' | sed 's/^sha256://') + if [ -z "${remotebuild}" ] || [ -z "${remotebuildurl}" ] || [[ ! "${remotebuildhash}" =~ ^[0-9a-f]{64}$ ]]; then + fn_print_fail_nl "Unable to get Luanti release, download URL or SHA256 checksum" + fn_script_log_fail "Unable to get Luanti release, download URL or SHA256 checksum" + core_exit.sh + fi +} + +fn_update_compare() { + fn_print_dots "Checking for update: ${remotelocation}" + # Update has been found or force update. + 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}${remotebuild}${default}" + if [ -n "${branch}" ]; then + fn_print_nl "* Branch: ${branch}" + fi + if [ -f "${rootdir}/.dev-debug" ]; then + 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 + fn_print "\n" + fn_script_log_info "Update available" + fn_script_log_info "Local build: ${localbuild}" + fn_script_log_info "Remote build: ${remotebuild}" + if [ -n "${branch}" ]; then + fn_script_log_info "Branch: ${branch}" + fi + fn_script_log_info "${localbuild} > ${remotebuild}" + + if [ "${commandname}" == "UPDATE" ]; then + # Keep track of the build before updating for alert purposes. + previousbuild="${localbuild}" + unset updateonstart + fn_update_apply fn_update_dl + if [ "${updatestatus}" == "0" ] && [ "${localbuild}" == "0" ]; then + exitbypass=1 + command_start.sh + fn_firstcommand_reset + exitbypass=1 + fn_sleep_time_5 + command_stop.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 + alert="check-update" + fi + alert.sh + else + fn_print_ok_nl "Checking for update: ${remotelocation}" + 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 + fn_print_nl "* Branch: ${branch}" + fi + fn_print "\n" + fn_script_log_info "No update available" + fn_script_log_info "Local build: ${localbuild}" + fn_script_log_info "Remote build: ${remotebuild}" + if [ -n "${branch}" ]; then + fn_script_log_info "Branch: ${branch}" + fi + if [ -f "${rootdir}/.dev-debug" ]; then + 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 +} + +# The location where the builds are checked and downloaded. +remotelocation="github.com/rollerozxa/luantiserver" + +if [ "${firstcommandname}" == "INSTALL" ]; then + fn_update_remotebuild + fn_update_dl +else + fn_print_dots "Checking for update" + fn_print_dots "Checking for update: ${remotelocation}" + fn_script_log_info "Checking for update: ${remotelocation}" + fn_update_localbuild + fn_update_remotebuild + fn_update_compare +fi From 71f16e541c7e34e60a26094e79d29884ea372407 Mon Sep 17 00:00:00 2001 From: Daniel Gibbs Date: Sat, 31 Oct 2026 22:52:59 +0000 Subject: [PATCH 144/164] feat(bfeserver): add Battlefront Eternal server (#5116) Adds Battlefront Eternal as a new server: bfeserver, shortname bfe. The server runs on Node.js 24, installed into serverfiles/node from nodejs.org and checked for updates on every update run. The retail game data comes from SteamCMD (app 1058020, needs an account that owns the game) and is prepared with the release's own tools. Fixes #5112 --- .../config-lgsm/bfeserver/_default.cfg | 224 +++++++++++++++ lgsm/data/almalinux-8.csv | 1 + lgsm/data/almalinux-9.csv | 1 + lgsm/data/centos-7.csv | 1 + lgsm/data/centos-8.csv | 1 + lgsm/data/centos-9.csv | 1 + lgsm/data/debian-10.csv | 1 + lgsm/data/debian-11.csv | 1 + lgsm/data/debian-12.csv | 1 + lgsm/data/debian-13.csv | 1 + lgsm/data/debian-9.csv | 1 + lgsm/data/gameicons/bfe-icon.png | Bin 0 -> 846 bytes lgsm/data/rhel-7.csv | 1 + lgsm/data/rhel-8.csv | 1 + lgsm/data/rhel-9.csv | 1 + lgsm/data/rocky-8.csv | 1 + lgsm/data/rocky-9.csv | 1 + lgsm/data/serverlist.csv | 1 + lgsm/data/ubuntu-16.04.csv | 1 + lgsm/data/ubuntu-18.04.csv | 1 + lgsm/data/ubuntu-20.04.csv | 1 + lgsm/data/ubuntu-22.04.csv | 1 + lgsm/data/ubuntu-23.04.csv | 1 + lgsm/data/ubuntu-23.10.csv | 1 + lgsm/data/ubuntu-24.04.csv | 1 + lgsm/data/ubuntu-26.04.csv | 1 + lgsm/modules/check_system_requirements.sh | 2 + lgsm/modules/command_check_update.sh | 2 + lgsm/modules/command_update.sh | 2 + lgsm/modules/core_modules.sh | 5 + lgsm/modules/fix_steamcmd.sh | 50 ++-- lgsm/modules/info_game.sh | 23 ++ lgsm/modules/info_messages.sh | 15 +- lgsm/modules/install_config.sh | 5 + lgsm/modules/install_server_files.sh | 2 + lgsm/modules/update_bfe.sh | 256 ++++++++++++++++++ 36 files changed, 579 insertions(+), 31 deletions(-) create mode 100644 lgsm/config-default/config-lgsm/bfeserver/_default.cfg create mode 100644 lgsm/data/gameicons/bfe-icon.png create mode 100755 lgsm/modules/update_bfe.sh diff --git a/lgsm/config-default/config-lgsm/bfeserver/_default.cfg b/lgsm/config-default/config-lgsm/bfeserver/_default.cfg new file mode 100644 index 0000000000..7e167bbfb8 --- /dev/null +++ b/lgsm/config-default/config-lgsm/bfeserver/_default.cfg @@ -0,0 +1,224 @@ +################################## +######## Default Settings ######## +################################## +# DO NOT EDIT, ANY CHANGES WILL BE OVERWRITTEN! +# Copy settings from here and use them in either: +# common.cfg - applies settings to every instance. +# [instance].cfg - applies settings to a specific instance. + +#### Game Server Settings #### + +## SteamCMD Login | https://docs.linuxgsm.com/steamcmd#steamcmd-login +# The Steam account must own STAR WARS Battlefront (Classic, 2004). +# Battlefront Eternal prepares its game data from this copy. +steamuser="username" +steampass='password' + +## Health Port +# Local health and admin endpoint. Each instance needs its own. +healthport="18450" + +## Server Parameters | https://docs.linuxgsm.com/configuration/start-parameters#additional-parameters +## Game Server Docs | https://battlefronteternal.com/servers/ +# Server name, port, max players and playlist are set in config.json. +startparameters="${serverfiles}/bfe/host-runtime/server/src/main.js --serve" + +## Extra Parameters | https://docs.linuxgsm.com/configuration/start-parameters#extra-parameters +# Added to the end of startparameters. +extraparams="" + +#### LinuxGSM Settings #### + +## LinuxGSM Stats +# Send useful stats to LinuxGSM developers. +# https://docs.linuxgsm.com/configuration/linuxgsm-stats +# (on|off) +stats="off" + +## Notification Alerts +# (on|off) + +# Display IP | https://docs.linuxgsm.com/alerts#display-ip +displayip="" + +# More info | https://docs.linuxgsm.com/alerts#more-info +postalert="off" + +# Alert on Start/Stop/Restart +statusalert="off" + +# Discord Alerts | https://docs.linuxgsm.com/alerts/discord +discordalert="off" +discordwebhook="webhook" + +# Email Alerts | https://docs.linuxgsm.com/alerts/email +emailalert="off" +email="email@example.com" +emailfrom="" + +# Gotify Alerts | https://docs.linuxgsm.com/alerts/gotify +gotifyalert="off" +gotifytoken="token" +gotifywebhook="webhook" + +# IFTTT Alerts | https://docs.linuxgsm.com/alerts/ifttt +iftttalert="off" +ifttttoken="accesstoken" +iftttevent="linuxgsm_alert" + +# ntfy Alerts | https://docs.linuxgsm.com/alerts/ntfy +ntfyalert="off" +ntfytopic="LinuxGSM" +ntfyserver="https://ntfy.sh" +ntfytoken="" +ntfyusername="" +ntfypassword="" +ntfypriority="" +ntfytags="" + +# Matrix Alerts | https://docs.linuxgsm.com/alerts/matrix +matrixalert="off" +matrixhomeserver="matrix.org" +matrixtoken="accesstoken" +matrixroom="" + +# Pushbullet Alerts | https://docs.linuxgsm.com/alerts/pushbullet +pushbulletalert="off" +pushbullettoken="accesstoken" +channeltag="" + +# Pushover Alerts | https://docs.linuxgsm.com/alerts/pushover +pushoveralert="off" +pushovertoken="accesstoken" +pushoveruserkey="userkey" + +# Rocket.Chat Alerts | https://docs.linuxgsm.com/alerts/rocket.chat +rocketchatalert="off" +rocketchatwebhook="webhook" + +# Slack Alerts | https://docs.linuxgsm.com/alerts/slack +slackalert="off" +slackwebhook="webhook" + +# Telegram Alerts | https://docs.linuxgsm.com/alerts/telegram +# You can add a custom cURL string eg proxy (useful in Russia) in "curlcustomstring". +# For example "--socks5 ipaddr:port" for socks5 proxy see more in "curl --help all". +telegramapi="api.telegram.org" +telegramalert="off" +telegramtoken="accesstoken" +telegramchatid="" +telegramthreadid="" +telegramsilentnotification="false" +curlcustomstring="" + +## Stop | https://docs.linuxgsm.com/commands/start-stop-restart +stoponlyifnoplayers="off" +stoponlyifnoplayersallcommands="on" + +## Player Warnings | https://docs.linuxgsm.com/features/player-warnings +# Minutes to warn players in-game before a stop, restart or update. 0 to disable. +# e.g. 15 warns at 15, 10, 5, 3 and 1 minutes. +warnplayerstimer="0" + +## Updating | https://docs.linuxgsm.com/commands/update +updateonstart="off" + +## Backup | https://docs.linuxgsm.com/commands/backup +maxbackups="4" +maxbackupdays="30" +stoponbackup="on" + +## Logging | https://docs.linuxgsm.com/features/logging +consolelogging="on" +logdays="7" + +## Monitor | https://docs.linuxgsm.com/commands/monitor +# Query delay time +querydelay="5" + +## ANSI Colors | https://docs.linuxgsm.com/features/ansi-colors +ansi="on" + +#### Advanced Settings #### + +## Message Display Time | https://docs.linuxgsm.com/features/message-display-time +sleeptime="0.5" + +## SteamCMD Settings | https://docs.linuxgsm.com/steamcmd +# Server appid +appid="1058020" +steamcmdforcewindows="yes" +# SteamCMD Branch | https://docs.linuxgsm.com/steamcmd/branch +branch="" +betapassword="" +# Master Server | https://docs.linuxgsm.com/steamcmd/steam-master-server +steammaster="false" + +## Stop Mode | https://docs.linuxgsm.com/features/stop-mode +# 1: tmux kill +# 2: CTRL+c +# 3: quit +# 4: quit 120s +# 5: stop +# 6: q +# 7: exit +# 8: 7 Days to Die +# 9: GoldSrc +# 10: Avorion +# 11: end +# 12: shutdown +# 13: soulmask +# 14: Running With Rifles +stopmode="2" + +## Query mode +# 1: session only +# 2: gamedig (gsquery fallback) +# 3: gamedig +# 4: gsquery +# 5: tcp +querymode="5" +querytype="" + +## Console type +consoleverbose="yes" +consoleinteract="no" + +## Game Server Details +# Do not edit +gamename="Battlefront Eternal" +engine="bfe" +glibc="2.28" + +#### Directories #### +# Edit with care + +## Game Server Directories +systemdir="${serverfiles}" +executabledir="${serverfiles}/node/bin" +executable="./node" +servercfgdir="${systemdir}/bfe-state" +servercfg="config.json" +servercfgdefault="config.json" +servercfgfullpath="${servercfgdir}/${servercfg}" +preexecutable="env BFE_STATE_DIR=${servercfgdir} BFE_ENGINE_DIR=${systemdir}/bfe/host-runtime/engine BFE_DATA_DIR=${systemdir}/bfe-data PORT=${healthport}" + +## Backup Directory +backupdir="${lgsmdir}/backup" + +## Logging Directories +[ -n "${LGSM_LOGDIR}" ] && logdir="${LGSM_LOGDIR}" || logdir="${rootdir}/log" +lgsmlogdir="${logdir}/script" +consolelogdir="${logdir}/console" +lgsmlog="${lgsmlogdir}/${selfname}-script.log" +consolelog="${consolelogdir}/${selfname}-console.log" +alertlog="${lgsmlogdir}/${selfname}-alert.log" +postdetailslog="${lgsmlogdir}/${selfname}-postdetails.log" + +## Logs Naming +lgsmlogdate="${lgsmlogdir}/${selfname}-script-$(date '+%Y-%m-%d-%H:%M:%S').log" +consolelogdate="${consolelogdir}/${selfname}-console-$(date '+%Y-%m-%d-%H:%M:%S').log" + +## Log Parameters +logtimestamp="off" +logtimestampformat="%Y-%m-%d %H:%M:%S" diff --git a/lgsm/data/almalinux-8.csv b/lgsm/data/almalinux-8.csv index e290c3b395..68d6923cb1 100644 --- a/lgsm/data/almalinux-8.csv +++ b/lgsm/data/almalinux-8.csv @@ -12,6 +12,7 @@ bb bb2,libcurl.i686 bd bf1942,ncurses-libs.i686 +bfe bfv,glibc.i686 bmdm,ncurses-libs.i686 bo diff --git a/lgsm/data/almalinux-9.csv b/lgsm/data/almalinux-9.csv index d50f05f883..58efd58b6d 100644 --- a/lgsm/data/almalinux-9.csv +++ b/lgsm/data/almalinux-9.csv @@ -12,6 +12,7 @@ bb bb2,libcurl.i686 bd bf1942,ncurses-libs.i686 +bfe bfv,glibc.i686 bmdm,ncurses-libs.i686 bo diff --git a/lgsm/data/centos-7.csv b/lgsm/data/centos-7.csv index 348c30470e..5ab23dd6ff 100644 --- a/lgsm/data/centos-7.csv +++ b/lgsm/data/centos-7.csv @@ -12,6 +12,7 @@ bb bb2,libcurl.i686 bd bf1942,ncurses-libs.i686 +bfe bfv,glibc.i686 bmdm,ncurses-libs.i686 bo diff --git a/lgsm/data/centos-8.csv b/lgsm/data/centos-8.csv index d14ae75a68..1dd0820b37 100644 --- a/lgsm/data/centos-8.csv +++ b/lgsm/data/centos-8.csv @@ -12,6 +12,7 @@ bb bb2,libcurl.i686 bd bf1942,ncurses-libs.i686 +bfe bfv,glibc.i686 bmdm,ncurses-libs.i686 bo diff --git a/lgsm/data/centos-9.csv b/lgsm/data/centos-9.csv index eb161e00b6..85048bc5a9 100644 --- a/lgsm/data/centos-9.csv +++ b/lgsm/data/centos-9.csv @@ -12,6 +12,7 @@ bb bb2,libcurl.i686 bd bf1942,ncurses-libs.i686 +bfe bfv,glibc.i686 bmdm,ncurses-libs.i686 bo diff --git a/lgsm/data/debian-10.csv b/lgsm/data/debian-10.csv index b44d1ead57..5827871c09 100644 --- a/lgsm/data/debian-10.csv +++ b/lgsm/data/debian-10.csv @@ -11,6 +11,7 @@ bb bb2,libcurl4-gnutls-dev:i386 bd bf1942,libc6:i386 +bfe bfv,libc6:i386 bmdm,libncurses5:i386 bo diff --git a/lgsm/data/debian-11.csv b/lgsm/data/debian-11.csv index 6f3a6b17f1..e7a43d7cfd 100644 --- a/lgsm/data/debian-11.csv +++ b/lgsm/data/debian-11.csv @@ -12,6 +12,7 @@ bb bb2,libcurl4-gnutls-dev:i386 bd bf1942,libc6:i386 +bfe bfv,libc6:i386 bmdm,libncurses5:i386 bo diff --git a/lgsm/data/debian-12.csv b/lgsm/data/debian-12.csv index bd145c415a..8bfd2d09e9 100644 --- a/lgsm/data/debian-12.csv +++ b/lgsm/data/debian-12.csv @@ -12,6 +12,7 @@ bb bb2,libcurl4-gnutls-dev:i386 bd bf1942,libc6:i386 +bfe bfv,libc6:i386 bmdm,libncurses5:i386 bo diff --git a/lgsm/data/debian-13.csv b/lgsm/data/debian-13.csv index 757ec4e371..bee026499c 100644 --- a/lgsm/data/debian-13.csv +++ b/lgsm/data/debian-13.csv @@ -12,6 +12,7 @@ bb bb2,libcurl4-gnutls-dev:i386 bd bf1942,libc6:i386 +bfe bfv,libc6:i386 bmdm bo diff --git a/lgsm/data/debian-9.csv b/lgsm/data/debian-9.csv index 5362fa6fe1..78875ea9c4 100644 --- a/lgsm/data/debian-9.csv +++ b/lgsm/data/debian-9.csv @@ -12,6 +12,7 @@ bb bb2,libcurl4-gnutls-dev:i386 bd bf1942,libc6:i386 +bfe bfv,libc6:i386 bmdm,libncurses5:i386 bo diff --git a/lgsm/data/gameicons/bfe-icon.png b/lgsm/data/gameicons/bfe-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..b6a660b6c48ff35d772d12d890f96e495ef63e7a GIT binary patch literal 846 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1SJ1Ryj=|9Bzpw;GB8xBF)%c=FfjZA3N^f7 zU???UV0e|lz+g3lfkC`r&aOZkpaffzx4R3&e-K=-cll(X2xoyuWHAE+V*?n=KRK-g z6l5>)^mS!_#U;nB#q;{>(bYg9)e_f;l9a@fRIB8oR3OD*WME{bYiOWrY!G5-Xk}t# zWoV>rU|?ln@Lb@UH;RVb{FKbJO57Tz`R08GYS4h&P?DLOT3nKtTYy{7!3cj11_mZc zPZ!4!kK=Er?9UDk6gj^C`Mo3Jv%)pZGFP%#W$OG`9K4!3k27CDO89>F!*5^jK33T3y5;-TXS`kMb~Se2=fxj6 z$UQwwej{m|KI!edw=ntRh)iY zU47kY=l1@4Gj`pKvuZHl5uZNotzY!DS7(cUCRe|-m(kWveQ6phz*5M;U?LT-;$o!s z>$||lOaHkSxhPd>85=V+Feqg$Z;+g2skzdc*Ky0Ol&$BQlrqmSr5RKhsO$5pxBXhG zV6kqWwfr94_A@yp0q*H(zk32cC-~WEMKISgNt>>^_T{JL*I&*Wt&Ry9M#k!@u`+%< zUpO-w7}=bjeCt|$e9|^o>Dr&kj2Gq}3)p`ojE_;u{aa^@cqX&`p&49CKUW)hC`6f4btS!#8TXD_g$+O4VcIWqSzS3>W>`J-x%Aju1 zrA7C-9kY44MQy)ky=@g%I&^I2aS;aN?6%y%b=@ona|`y0mR?li+?K`AG51cF z>>Z_FXDxE&>;Lck$Iha8x+{EweT9NuRepZIgtl1F$`F|n&D4iqG=G-7>wNy3yW2bJ zby=8O$3$UJC<_`_&-mdKI;Vst0MtlHUjP6A literal 0 HcmV?d00001 diff --git a/lgsm/data/rhel-7.csv b/lgsm/data/rhel-7.csv index bd8d00452e..894b7856df 100644 --- a/lgsm/data/rhel-7.csv +++ b/lgsm/data/rhel-7.csv @@ -14,6 +14,7 @@ pw bb2,libcurl.i686 bd bf1942,ncurses-libs.i686 +bfe bfv,glibc.i686 bmdm,ncurses-libs.i686 bo diff --git a/lgsm/data/rhel-8.csv b/lgsm/data/rhel-8.csv index ce98226453..78293ca904 100644 --- a/lgsm/data/rhel-8.csv +++ b/lgsm/data/rhel-8.csv @@ -12,6 +12,7 @@ bb bb2,libcurl.i686 bd bf1942,ncurses-libs.i686 +bfe bfv,glibc.i686 bmdm,ncurses-libs.i686 bo diff --git a/lgsm/data/rhel-9.csv b/lgsm/data/rhel-9.csv index d50f05f883..58efd58b6d 100644 --- a/lgsm/data/rhel-9.csv +++ b/lgsm/data/rhel-9.csv @@ -12,6 +12,7 @@ bb bb2,libcurl.i686 bd bf1942,ncurses-libs.i686 +bfe bfv,glibc.i686 bmdm,ncurses-libs.i686 bo diff --git a/lgsm/data/rocky-8.csv b/lgsm/data/rocky-8.csv index ce98226453..78293ca904 100644 --- a/lgsm/data/rocky-8.csv +++ b/lgsm/data/rocky-8.csv @@ -12,6 +12,7 @@ bb bb2,libcurl.i686 bd bf1942,ncurses-libs.i686 +bfe bfv,glibc.i686 bmdm,ncurses-libs.i686 bo diff --git a/lgsm/data/rocky-9.csv b/lgsm/data/rocky-9.csv index d50f05f883..58efd58b6d 100644 --- a/lgsm/data/rocky-9.csv +++ b/lgsm/data/rocky-9.csv @@ -12,6 +12,7 @@ bb bb2,libcurl.i686 bd bf1942,ncurses-libs.i686 +bfe bfv,glibc.i686 bmdm,ncurses-libs.i686 bo diff --git a/lgsm/data/serverlist.csv b/lgsm/data/serverlist.csv index 60a75cf120..0e9167f8cf 100644 --- a/lgsm/data/serverlist.csv +++ b/lgsm/data/serverlist.csv @@ -11,6 +11,7 @@ bb,bbserver,BrainBread,ubuntu-26.04 bb2,bb2server,BrainBread 2,ubuntu-26.04 bd,bdserver,Base Defense,ubuntu-26.04 bf1942,bf1942server,Battlefield 1942,ubuntu-26.04 +bfe,bfeserver,Battlefront Eternal,ubuntu-26.04 bfv,bfvserver,Battlefield: Vietnam,ubuntu-26.04 bmdm,bmdmserver,Black Mesa: Deathmatch,ubuntu-26.04 bo,boserver,Ballistic Overkill,ubuntu-26.04 diff --git a/lgsm/data/ubuntu-16.04.csv b/lgsm/data/ubuntu-16.04.csv index f4348aeb2c..3171162a9a 100644 --- a/lgsm/data/ubuntu-16.04.csv +++ b/lgsm/data/ubuntu-16.04.csv @@ -14,6 +14,7 @@ pw bb2,libcurl4-gnutls-dev:i386 bd bf1942,libc6:i386 +bfe bfv,libc6:i386 bmdm,libncurses5:i386 bo diff --git a/lgsm/data/ubuntu-18.04.csv b/lgsm/data/ubuntu-18.04.csv index a7e853e8e3..5833b5dfe3 100644 --- a/lgsm/data/ubuntu-18.04.csv +++ b/lgsm/data/ubuntu-18.04.csv @@ -14,6 +14,7 @@ bb bb2,libcurl4-gnutls-dev:i386 bd bf1942,libc6:i386 +bfe bfv,libc6:i386 bmdm,libncurses5:i386 bo diff --git a/lgsm/data/ubuntu-20.04.csv b/lgsm/data/ubuntu-20.04.csv index 9186092848..3f597b719d 100644 --- a/lgsm/data/ubuntu-20.04.csv +++ b/lgsm/data/ubuntu-20.04.csv @@ -12,6 +12,7 @@ bb bb2,libcurl4-gnutls-dev:i386 bd bf1942,libc6:i386 +bfe bfv,libc6:i386 bmdm,libncurses5:i386 bo diff --git a/lgsm/data/ubuntu-22.04.csv b/lgsm/data/ubuntu-22.04.csv index 34e9daec60..17551ecca0 100644 --- a/lgsm/data/ubuntu-22.04.csv +++ b/lgsm/data/ubuntu-22.04.csv @@ -12,6 +12,7 @@ bb bb2,libcurl4-gnutls-dev:i386 bd bf1942,libc6:i386 +bfe bfv,libc6:i386 bmdm,libncurses5:i386 bo diff --git a/lgsm/data/ubuntu-23.04.csv b/lgsm/data/ubuntu-23.04.csv index df97c59277..5592f27edf 100644 --- a/lgsm/data/ubuntu-23.04.csv +++ b/lgsm/data/ubuntu-23.04.csv @@ -12,6 +12,7 @@ bb bb2,libcurl4-gnutls-dev:i386 bd bf1942,libc6:i386 +bfe bfv,libc6:i386 bmdm,libncurses5:i386 bo diff --git a/lgsm/data/ubuntu-23.10.csv b/lgsm/data/ubuntu-23.10.csv index df97c59277..5592f27edf 100644 --- a/lgsm/data/ubuntu-23.10.csv +++ b/lgsm/data/ubuntu-23.10.csv @@ -12,6 +12,7 @@ bb bb2,libcurl4-gnutls-dev:i386 bd bf1942,libc6:i386 +bfe bfv,libc6:i386 bmdm,libncurses5:i386 bo diff --git a/lgsm/data/ubuntu-24.04.csv b/lgsm/data/ubuntu-24.04.csv index 3ead4eadad..724445f863 100644 --- a/lgsm/data/ubuntu-24.04.csv +++ b/lgsm/data/ubuntu-24.04.csv @@ -12,6 +12,7 @@ bb bb2,libcurl4-gnutls-dev:i386 bd bf1942,libc6:i386 +bfe bfv,libc6:i386 bmdm bo diff --git a/lgsm/data/ubuntu-26.04.csv b/lgsm/data/ubuntu-26.04.csv index 9d048c7ab2..d21b7304b3 100644 --- a/lgsm/data/ubuntu-26.04.csv +++ b/lgsm/data/ubuntu-26.04.csv @@ -12,6 +12,7 @@ bb bb2,libcurl4-gnutls-dev:i386 bd bf1942,libc6:i386 +bfe bfv,libc6:i386 bmdm bo diff --git a/lgsm/modules/check_system_requirements.sh b/lgsm/modules/check_system_requirements.sh index d80d7f0ba9..eb97b00a4a 100755 --- a/lgsm/modules/check_system_requirements.sh +++ b/lgsm/modules/check_system_requirements.sh @@ -51,6 +51,8 @@ elif [ "${shortname}" == "pz" ]; then ramrequirementgb="3" elif [ "${shortname}" == "rsdw" ]; then ramrequirementgb="2" +elif [ "${shortname}" == "bfe" ]; then + ramrequirementgb="2" elif [ "${shortname}" == "rwr" ]; then ramrequirementgb="1" elif [ "${shortname}" == "rust" ]; then diff --git a/lgsm/modules/command_check_update.sh b/lgsm/modules/command_check_update.sh index 310b3f34df..f4856aa6e7 100755 --- a/lgsm/modules/command_check_update.sh +++ b/lgsm/modules/command_check_update.sh @@ -38,6 +38,8 @@ elif [ "${shortname}" == "orar" ]; then update_openra.sh elif [ "${shortname}" == "vints" ]; then update_vints.sh +elif [ "${shortname}" == "bfe" ]; then + update_bfe.sh elif [ "${shortname}" == "bb" ]; then update_bb.sh elif [ "${shortname}" == "ut99" ]; then diff --git a/lgsm/modules/command_update.sh b/lgsm/modules/command_update.sh index 463bae4eb2..2462408b98 100755 --- a/lgsm/modules/command_update.sh +++ b/lgsm/modules/command_update.sh @@ -79,6 +79,8 @@ elif [ "${shortname}" == "orar" ]; then update_openra.sh elif [ "${shortname}" == "vints" ]; then update_vints.sh +elif [ "${shortname}" == "bfe" ]; then + update_bfe.sh elif [ "${shortname}" == "bb" ]; then update_bb.sh elif [ "${shortname}" == "ut99" ]; then diff --git a/lgsm/modules/core_modules.sh b/lgsm/modules/core_modules.sh index a8a23237b2..a7bda742aa 100755 --- a/lgsm/modules/core_modules.sh +++ b/lgsm/modules/core_modules.sh @@ -787,6 +787,11 @@ update_ut99.sh() { fn_fetch_module } +update_bfe.sh() { + modulefile="${FUNCNAME[0]}" + fn_fetch_module +} + update_bb.sh() { modulefile="${FUNCNAME[0]}" fn_fetch_module diff --git a/lgsm/modules/fix_steamcmd.sh b/lgsm/modules/fix_steamcmd.sh index 36bc378ac7..e3fc22722a 100755 --- a/lgsm/modules/fix_steamcmd.sh +++ b/lgsm/modules/fix_steamcmd.sh @@ -65,21 +65,16 @@ fi # place new hardlink for the file to the disk if [ ! -f "${steamclientsdk64}" ]; then - fixname="steamclient.so sdk64 hardlink" - fn_fix_msg_start - if [ ! -d "${steamsdk64}" ]; then - mkdir -p "${steamsdk64}" - fi - if [ -f "${HOME}/.steam/steamcmd/linux64/steamclient.so" ]; then - ln "${HOME}/.steam/steamcmd/linux64/steamclient.so" "${steamclientsdk64}" - elif [ -f "${steamcmddir}/linux64/steamclient.so" ]; then - ln "${steamcmddir}/linux64/steamclient.so" "${steamclientsdk64}" - elif [ -f "${HOME}/.local/share/Steam/steamcmd/linux64/steamclient.so" ]; then - ln "${HOME}/.local/share/Steam/steamcmd/linux64/steamclient.so" "${steamclientsdk64}" - else - fn_print_fail_nl "Could not copy any steamclient.so 64bit for the gameserver" - fi - fn_fix_msg_end + for steamclientso in "${HOME}/.steam/steamcmd/linux64/steamclient.so" "${steamcmddir}/linux64/steamclient.so" "${HOME}/.local/share/Steam/steamcmd/linux64/steamclient.so"; do + if [ -f "${steamclientso}" ]; then + fixname="steamclient.so sdk64 hardlink" + fn_fix_msg_start + mkdir -p "${steamsdk64}" + ln "${steamclientso}" "${steamclientsdk64}" + fn_fix_msg_end + break + fi + done fi # Helps fix: [S_API FAIL] SteamAPI_Init() failed; unable to locate a running instance of Steam,or a local steamclient.so. @@ -96,21 +91,16 @@ fi # place new hardlink for the file to the disk if [ ! -f "${steamclientsdk32}" ]; then - fixname="steamclient.so sdk32 link" - fn_fix_msg_start - if [ ! -d "${steamsdk32}" ]; then - mkdir -p "${steamsdk32}" - fi - if [ -f "${HOME}/.steam/steamcmd/linux32/steamclient.so" ]; then - ln "${HOME}/.steam/steamcmd/linux32/steamclient.so" "${steamclientsdk32}" - elif [ -f "${steamcmddir}/linux32/steamclient.so" ]; then - ln "${steamcmddir}/linux32/steamclient.so" "${steamclientsdk32}" - elif [ -f "${HOME}/.local/share/Steam/steamcmd/linux32/steamclient.so" ]; then - ln "${HOME}/.local/share/Steam/steamcmd/linux32/steamclient.so" "${steamclientsdk32}" - else - fn_print_fail_nl "Could not copy any steamclient.so 32bit for the gameserver" - fi - fn_fix_msg_end + for steamclientso in "${HOME}/.steam/steamcmd/linux32/steamclient.so" "${steamcmddir}/linux32/steamclient.so" "${HOME}/.local/share/Steam/steamcmd/linux32/steamclient.so"; do + if [ -f "${steamclientso}" ]; then + fixname="steamclient.so sdk32 link" + fn_fix_msg_start + mkdir -p "${steamsdk32}" + ln "${steamclientso}" "${steamclientsdk32}" + fn_fix_msg_end + break + fi + done fi # Helps fix: WARNING: Failed to load 32-bit libtinfo.so.5 or libncurses.so.5. diff --git a/lgsm/modules/info_game.sh b/lgsm/modules/info_game.sh index 1c578a2f8e..2923f74a61 100755 --- a/lgsm/modules/info_game.sh +++ b/lgsm/modules/info_game.sh @@ -975,6 +975,27 @@ fn_info_game_bf1942() { serverpassword="${serverpassword:-"NOT SET"}" } +# Config Type: json +# Parameters: false +# Comment: none +# Example: "name": "SERVERNAME", +# Filetype: json +fn_info_game_bfe() { + if [ -f "${servercfgfullpath}" ]; then + fn_info_game_json "configip" ".bind // empty" + fn_info_game_json "discoveryport" ".discoveryPort // empty" + fn_info_game_json "maxplayers" ".maxPlayers // empty" + fn_info_game_json "port" ".gamePort // empty" + fn_info_game_json "servername" ".name // empty" + fi + configip="${configip:-"0.0.0.0"}" + discoveryport="${discoveryport:-"18452"}" + maxplayers="${maxplayers:-"64"}" + port="${port:-"18451"}" + queryport="${port}" + servername="${servername:-"NOT SET"}" +} + # Config Type: con # Parameters: true # Comment: # or // @@ -2470,6 +2491,8 @@ elif [ "${shortname}" == "av" ]; then fn_info_game_av elif [ "${shortname}" == "bf1942" ]; then fn_info_game_bf1942 +elif [ "${shortname}" == "bfe" ]; then + fn_info_game_bfe elif [ "${shortname}" == "bfv" ]; then fn_info_game_bfv elif [ "${shortname}" == "bo" ]; then diff --git a/lgsm/modules/info_messages.sh b/lgsm/modules/info_messages.sh index 267a1e100b..3ee6bd286c 100755 --- a/lgsm/modules/info_messages.sh +++ b/lgsm/modules/info_messages.sh @@ -736,7 +736,7 @@ fn_info_messages_ports_edit() { startparameterslocation="${red}UNKNOWN${default}" # engines/games that require editing in the config file. - local ports_edit_array=("ac" "arma3" "armar" "bo" "bt" "ct" "dst" "eco" "idtech2" "idtech3" "idtech3_ql" "jc2" "jc3" "lwjgl2" "mcb" "nec" "pc" "pc2" "prism3d" "pz" "qw" "refractor" "renderware" "rw" "rwr" "sb" "sdtd" "st" "stn" "ts3" "tw" "terraria" "unreal" "unreal2" "unreal3" "vints" "xnt" "wurm") + local ports_edit_array=("ac" "arma3" "armar" "bfe" "bo" "bt" "ct" "dst" "eco" "idtech2" "idtech3" "idtech3_ql" "jc2" "jc3" "lwjgl2" "mcb" "nec" "pc" "pc2" "prism3d" "pz" "qw" "refractor" "renderware" "rw" "rwr" "sb" "sdtd" "st" "stn" "ts3" "tw" "terraria" "unreal" "unreal2" "unreal3" "vints" "xnt" "wurm") for port_edit in "${ports_edit_array[@]}"; do if [ "${shortname}" == "ut3" ]; then startparameterslocation="${servercfgdir}/UTWeb.ini" @@ -765,6 +765,8 @@ fn_info_messages_ports() { portcommand="ss -tuplwn | grep AvorionServer" elif [ "${shortname}" == "bf1942" ]; then portcommand="ss -tuplwn | grep bf1942_lnxded" + elif [ "${shortname}" == "bfe" ]; then + portcommand="ss -tuplwn | grep MainThread" elif [ "${shortname}" == "bfv" ]; then portcommand="ss -tuplwn | grep bfv_linded" elif [ "${shortname}" == "ce" ]; then @@ -930,6 +932,15 @@ fn_info_messages_bf1942() { } | column -s $'\t' -t } +fn_info_messages_bfe() { + { + fn_port "header" + fn_port "Game" port udp + fn_port "Query" queryport tcp + fn_port "LAN Discovery" discoveryport udp + } | column -s $'\t' -t +} + fn_info_messages_bfv() { { fn_port "header" @@ -1904,6 +1915,8 @@ fn_info_messages_select_engine() { fn_info_messages_av elif [ "${shortname}" == "bf1942" ]; then fn_info_messages_bf1942 + elif [ "${shortname}" == "bfe" ]; then + fn_info_messages_bfe elif [ "${shortname}" == "bfv" ]; then fn_info_messages_bfv elif [ "${shortname}" == "bo" ]; then diff --git a/lgsm/modules/install_config.sh b/lgsm/modules/install_config.sh index 2cf561e210..88811a9baf 100755 --- a/lgsm/modules/install_config.sh +++ b/lgsm/modules/install_config.sh @@ -346,6 +346,11 @@ elif [ "${shortname}" == "bs" ]; then fn_default_config_remote fn_set_config_vars fn_list_config_locations +elif [ "${shortname}" == "bfe" ]; then + array_configs+=(config.json) + fn_default_config_remote + fn_set_config_vars + fn_list_config_locations elif [ "${shortname}" == "bb" ]; then array_configs+=(server.cfg) fn_default_config_remote diff --git a/lgsm/modules/install_server_files.sh b/lgsm/modules/install_server_files.sh index 3bee586a3e..1c76489092 100755 --- a/lgsm/modules/install_server_files.sh +++ b/lgsm/modules/install_server_files.sh @@ -285,6 +285,8 @@ elif [ "${shortname}" == "orar" ]; then update_openra.sh elif [ "${shortname}" == "vints" ]; then update_vints.sh +elif [ "${shortname}" == "bfe" ]; then + update_bfe.sh elif [ "${shortname}" == "bb" ]; then update_bb.sh elif [ "${shortname}" == "ut99" ]; then diff --git a/lgsm/modules/update_bfe.sh b/lgsm/modules/update_bfe.sh new file mode 100755 index 0000000000..9c2ac8c895 --- /dev/null +++ b/lgsm/modules/update_bfe.sh @@ -0,0 +1,256 @@ +#!/bin/bash +# LinuxGSM update_bfe.sh module +# Author: Daniel Gibbs +# Contributors: https://linuxgsm.com/contrib +# Website: https://linuxgsm.com +# Description: Handles updating of Battlefront Eternal servers. + +moduleselfname="$(basename "$(readlink -f "${BASH_SOURCE[0]}")")" + +fn_update_node_remote() { + # Gets the latest Node.js 24 build and the installed version. + nodeurl="https://nodejs.org/dist/latest-v24.x" + nodeshasums=$(curl -s "${nodeurl}/SHASUMS256.txt") + nodefilename=$(echo "${nodeshasums}" | grep -o "node-v[0-9.]*-linux-${nodearch}.tar.xz" | head -1) + nodeversion=$(echo "${nodefilename}" | cut -d '-' -f 2) + nodehash=$(echo "${nodeshasums}" | grep " ${nodefilename}$" | awk '{print $1}') + if [ -z "${nodefilename}" ] || [ -z "${nodehash}" ]; then + fn_print_failure_nl "Unable to get Node.js build" + fn_script_log_fail "Unable to get Node.js build" + core_exit.sh + fi + nodelocalversion="" + if [ -x "${serverfiles}/node/bin/node" ]; then + nodelocalversion=$("${serverfiles}/node/bin/node" --version 2> /dev/null) + fi +} + +fn_update_node_dl() { + # Installs the Node.js runtime the server runs on. + fn_fetch_file "${nodeurl}/${nodefilename}" "" "" "" "${tmpdir}" "${nodefilename}" "nochmodx" "norun" "forcedl" "${nodehash}" + rm -rf "${serverfiles:?}/node.new" + fn_dl_extract "${tmpdir}" "${nodefilename}" "${serverfiles}/node.new" "${nodefilename%.tar.xz}" + rm -rf "${serverfiles:?}/node" + mv "${serverfiles}/node.new" "${serverfiles}/node" + fn_clear_tmp +} + +fn_update_node() { + fn_update_node_remote + if [ "${nodelocalversion}" != "${nodeversion}" ]; then + fn_update_node_dl + fi +} + +fn_update_node_compare() { + fn_print_dots "Checking for update: nodejs.org" + fn_update_node_remote + if [ "${nodelocalversion}" != "${nodeversion}" ]; then + date '+%s' > "${lockdir:?}/update.lock" + fn_print_ok_nl "Checking for update: nodejs.org" + fn_print "\n" + fn_print_nl "${bold}${underline}Node.js update${default} available" + fn_print_nl "* Local version: ${red}${nodelocalversion:-none}${default}" + fn_print_nl "* Remote version: ${green}${nodeversion}${default}" + fn_print "\n" + fn_script_log_info "Node.js update available" + fn_script_log_info "Local version: ${nodelocalversion:-none}" + fn_script_log_info "Remote version: ${nodeversion}" + previousbuild="Node.js ${nodelocalversion:-none}" + localbuild="Node.js ${nodelocalversion:-none}" + remotebuild="Node.js ${nodeversion}" + if [ "${commandname}" == "UPDATE" ]; then + unset updateonstart + fn_update_apply fn_update_node_dl + localbuild="${remotebuild}" + alert="update" + elif [ "${commandname}" == "CHECK-UPDATE" ]; then + alert="check-update" + fi + alert.sh + else + fn_print_ok_nl "Checking for update: nodejs.org" + fn_print "\n" + fn_print_nl "${bold}${underline}No Node.js update${default} available" + fn_print_nl "* Local version: ${green}${nodelocalversion}${default}" + fn_print_nl "* Remote version: ${green}${nodeversion}${default}" + fn_print "\n" + fn_script_log_info "No Node.js update available" + fn_script_log_info "Local version: ${nodelocalversion}" + fn_script_log_info "Remote version: ${nodeversion}" + fi +} + +fn_update_prepare() { + # Prepares the game data from the owned game when the release's tools change. + datakey=$(jq -r '.files[] | select((.path | startswith("resources/tools/")) or (.path | startswith("resources/toolchain/python/"))) | "\(.path) \(.sha256)"' "${serverfiles}/bfe/bfe-tree.json" | LC_ALL=C sort) + datakey=$(printf '%s' "${datakey}" | sha256sum | cut -c 1-32) + if [ -f "${serverfiles}/bfe-data/.lgsm-data-key" ] && [ "$(cat "${serverfiles}/bfe-data/.lgsm-data-key")" == "${datakey}" ]; then + return + fi + if [ ! -d "${serverfiles}/GameData" ]; then + fn_print_failure_nl "Game data not found: ${serverfiles}/GameData" + fn_script_log_fail "Game data not found: ${serverfiles}/GameData" + echo -e "* The Steam account must own STAR WARS Battlefront (Classic, 2004)." + echo -e "* Run ./${selfname} validate to download it." + core_exit.sh + fi + preparelog="${lgsmlogdir}/${selfname}-prepare.log" + echo -e "preparing game data, this can take several minutes" + fn_script_log_info "Preparing game data ${datakey}" + rm -rf "${serverfiles:?}/bfe-data.new" + mkdir -p "${serverfiles}/bfe-data.new" + ( + cd "${serverfiles}/bfe/tools" || exit 1 + env -i PATH="${serverfiles}/bfe/toolchain/bin:/usr/local/bin:/usr/bin:/bin" HOME="${serverfiles}/bfe-data.new" LANG="C.UTF-8" BFE_GAME_DIR="${serverfiles}" BFE_CONTENT_DIR="${serverfiles}/bfe-data.new" KTX2_ENCODER="off" PYTHONUNBUFFERED="1" PYTHONDONTWRITEBYTECODE="1" PYTHONIOENCODING="utf-8" "${serverfiles}/bfe/toolchain/python/bin/python3" -u prepare.py --core-only --jobs "$(nproc)" > "${preparelog}" 2>&1 + ) + exitcode=$? + if [ "${exitcode}" -ne 0 ]; then + fn_print_failure_nl "Preparing game data" + fn_script_log_fail "Preparing game data, see ${preparelog}" + tail -n 20 "${preparelog}" + rm -rf "${serverfiles:?}/bfe-data.new" + core_exit.sh + fi + echo "${datakey}" > "${serverfiles}/bfe-data.new/.lgsm-data-key" + rm -rf "${serverfiles:?}/bfe-data" + mv "${serverfiles}/bfe-data.new" "${serverfiles}/bfe-data" + fn_print_ok_nl "Preparing game data" + fn_script_log_pass "Preparing game data" +} + +fn_update_dl() { + # Download and extract files to tmpdir. + fn_update_node + fn_fetch_file "${remotebuildurl}" "" "" "" "${tmpdir}" "${remotebuildfilename}" "nochmodx" "norun" "forcedl" "${remotebuildhash}" + rm -rf "${serverfiles:?}/bfe" + fn_dl_extract "${tmpdir}" "${remotebuildfilename}" "${serverfiles}/bfe" + fn_update_prepare + echo "${remotebuild}" > "${localbuildfile}" + fn_clear_tmp +} + +fn_update_localbuild() { + # Gets local build info. + fn_print_dots "Checking local build: ${remotelocation}" + if [ -f "${localbuildfile}" ]; then + localbuild="$(cat "${localbuildfile}")" + fi + if [ -z "${localbuild}" ]; then + fn_print_error "Checking local build: ${remotelocation}: missing local build info" + 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}" + fn_script_log_pass "Checking local build" + fi +} + +fn_update_remotebuild() { + # Gets remote build info. + apiurl="https://get.battlefronteternal.com/downloads/latest" + remotebuildresponse=$(curl -s "${apiurl}/SHA256SUMS") + remotebuildfilename=$(echo "${remotebuildresponse}" | grep -o "battlefront-eternal-server_[^ ]*_linux-${archivearch}\.tar\.xz" | head -1) + remotebuildhash=$(echo "${remotebuildresponse}" | grep " ${remotebuildfilename}$" | awk '{print $1}') + remotebuild=$(echo "${remotebuildfilename}" | cut -d '_' -f 2) + remotebuildurl="${apiurl}/${remotebuildfilename}" + if [ "${firstcommandname}" != "INSTALL" ]; then + fn_print_dots "Checking remote build: ${remotelocation}" + # Checks if remotebuild variable has been set. + if [ -z "${remotebuild}" ] || [ -z "${remotebuildhash}" ]; then + fn_print_fail "Checking remote build: ${remotelocation}" + fn_script_log_fail "Checking remote build" + core_exit.sh + else + fn_print_ok "Checking remote build: ${remotelocation}" + fn_script_log_pass "Checking remote build" + fi + else + # Checks if remotebuild variable has been set. + if [ -z "${remotebuild}" ] || [ -z "${remotebuildhash}" ]; then + fn_print_failure "Unable to get remote build" + fn_script_log_fail "Unable to get remote build" + core_exit.sh + fi + fi +} + +fn_update_compare() { + fn_print_dots "Checking for update: ${remotelocation}" + # Update has been found or force update. + 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}${remotebuild}${default}" + if [ -f "${rootdir}/.dev-debug" ]; then + 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 + fn_print "\n" + fn_script_log_info "Update available" + fn_script_log_info "Local build: ${localbuild}" + fn_script_log_info "Remote build: ${remotebuild}" + fn_script_log_info "${localbuild} > ${remotebuild}" + + if [ "${commandname}" == "UPDATE" ]; then + unset updateonstart + fn_update_apply fn_update_dl + alert="update" + elif [ "${commandname}" == "CHECK-UPDATE" ]; then + alert="check-update" + fi + alert.sh + else + fn_print_ok_nl "Checking for update: ${remotelocation}" + 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}" + fn_print "\n" + fn_script_log_info "No update available" + fn_script_log_info "Local build: ${localbuild}" + fn_script_log_info "Remote build: ${remotebuild}" + if [ -f "${rootdir}/.dev-debug" ]; then + 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 +} + +if [ "$(uname -m)" == "aarch64" ]; then + archivearch="arm64" + nodearch="arm64" +else + archivearch="amd64" + nodearch="x64" +fi + +localbuildfile="${datadir}/${selfname}-bfe-version" +# The location where the builds are checked and downloaded. +remotelocation="get.battlefronteternal.com" + +if [ "${firstcommandname}" == "INSTALL" ]; then + fn_update_remotebuild + fn_update_dl +else + fn_print_dots "Checking for update" + fn_print_dots "Checking for update: ${remotelocation}" + fn_script_log_info "Checking for update: ${remotelocation}" + fn_update_localbuild + fn_update_remotebuild + fn_update_compare + if [ "${localbuild}" == "${remotebuild}" ] && [ "${forceupdate}" != "1" ]; then + fn_update_node_compare + fi +fi From 0fb301a249b85a457d563fcab75459fd7c85ca57 Mon Sep 17 00:00:00 2001 From: Daniel Gibbs Date: Sun, 1 Nov 2026 00:23:12 +0000 Subject: [PATCH 145/164] fix(gamedig): stop npm waiting on a registry that does not answer (#5128) npm install now skips its audit request, which was the only thing it waited on with gamedig already installed. npm update also skips it and gives up after one 10 second attempt per request instead of npm's default 5 minutes with 2 retries. It runs on every monitor with its output hidden, so a silent registry stalled monitor with no sign why. Fixes #5127 --- lgsm/modules/check_gamedig.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lgsm/modules/check_gamedig.sh b/lgsm/modules/check_gamedig.sh index 72d3700fec..630834e874 100755 --- a/lgsm/modules/check_gamedig.sh +++ b/lgsm/modules/check_gamedig.sh @@ -13,11 +13,11 @@ if [ "$(command -v node)" ] && [ "$(command -v npm)" ] && [ "$(node -v | cut -d fn_script_log_info "Installing Gamedig" cd "${lgsmdir}" || exit curl -L -o package.json "https://raw.githubusercontent.com/${githubuser}/${githubrepo}/${githubbranch}/package.json" - npm install + npm install --no-audit elif [ "$(command -v node)" ] && [ "$(command -v npm)" ] && [ "$(node -v | cut -d 'v' -f 2 | cut -d '.' -f 1)" -ge 16 ]; then cd "${lgsmdir}" || exit curl -s -L -o package.json "https://raw.githubusercontent.com/${githubuser}/${githubrepo}/${githubbranch}/package.json" - npm update > /dev/null 2>&1 + npm update --no-audit --fetch-timeout=10000 --fetch-retries=0 > /dev/null 2>&1 else fn_script_log_info "Install Node.js and NPM to enable Gamedig" fi From 46069360e7cb16072e1c13ed4973b4bbc037c93a Mon Sep 17 00:00:00 2001 From: Daniel Gibbs Date: Sun, 1 Nov 2026 00:26:35 +0000 Subject: [PATCH 146/164] feat(fivemserver): add FiveM server (#5103) * feat(fivemserver): add FiveM server Adds FiveM (GTA V multiplayer, Cfx.re FXServer) as fivemserver. - update_fivem.sh installs and updates the "recommended" Linux build from the Cfx.re changelog API, and tracks the installed build in a data file for check-update and update. - Install fetches the base resources from citizenfx/cfx-server-data (a tarball of the default branch) once. Updates never touch resources. - FXServer always starts with +exec server.cfg, so the bundled txAdmin web panel never starts and LinuxGSM is the only thing managing the server. - licensekey in the LinuxGSM config is passed as +set sv_licenseKey. start and debug stop with a clear message if no key is set here or in server.cfg. - Details parse server.cfg, and querying uses gamedig (gta5f). * fix(fivemserver): only pass sv_licenseKey when licensekey is set With licensekey empty, +set sv_licenseKey overrode a key set in server.cfg and would take the first extra parameter as its value. The +set is now only added when licensekey is set. Also adds extraparams and the Matrix alert settings to the default config. * feat(fivemserver): set the license key in server.cfg only Drops the licensekey LinuxGSM setting. The key now lives only in server.cfg as sv_licenseKey, so it is no longer on the command line. The start check, install message and default config point to server.cfg. --- .../config-lgsm/fivemserver/_default.cfg | 205 ++++++++++++++++++ lgsm/data/almalinux-8.csv | 1 + lgsm/data/almalinux-9.csv | 1 + lgsm/data/centos-7.csv | 1 + lgsm/data/centos-8.csv | 1 + lgsm/data/centos-9.csv | 1 + lgsm/data/debian-10.csv | 1 + lgsm/data/debian-11.csv | 1 + lgsm/data/debian-12.csv | 1 + lgsm/data/debian-13.csv | 1 + lgsm/data/debian-9.csv | 1 + lgsm/data/gameicons/fivem-icon.png | Bin 0 -> 1455 bytes lgsm/data/rhel-7.csv | 1 + lgsm/data/rhel-8.csv | 1 + lgsm/data/rhel-9.csv | 1 + lgsm/data/rocky-8.csv | 1 + lgsm/data/rocky-9.csv | 1 + lgsm/data/serverlist.csv | 1 + lgsm/data/ubuntu-16.04.csv | 1 + lgsm/data/ubuntu-18.04.csv | 1 + lgsm/data/ubuntu-20.04.csv | 1 + lgsm/data/ubuntu-22.04.csv | 1 + lgsm/data/ubuntu-23.04.csv | 1 + lgsm/data/ubuntu-23.10.csv | 1 + lgsm/data/ubuntu-24.04.csv | 1 + lgsm/data/ubuntu-26.04.csv | 1 + lgsm/modules/check_config.sh | 10 + lgsm/modules/command_check_update.sh | 2 + lgsm/modules/command_install.sh | 2 + lgsm/modules/command_update.sh | 2 + lgsm/modules/core_getopt.sh | 4 +- lgsm/modules/core_modules.sh | 10 + lgsm/modules/info_game.sh | 20 ++ lgsm/modules/info_messages.sh | 14 +- lgsm/modules/install_config.sh | 5 + lgsm/modules/install_fivem_license.sh | 24 ++ lgsm/modules/install_server_files.sh | 2 + lgsm/modules/update_fivem.sh | 139 ++++++++++++ 38 files changed, 460 insertions(+), 3 deletions(-) create mode 100644 lgsm/config-default/config-lgsm/fivemserver/_default.cfg create mode 100644 lgsm/data/gameicons/fivem-icon.png create mode 100755 lgsm/modules/install_fivem_license.sh create mode 100755 lgsm/modules/update_fivem.sh diff --git a/lgsm/config-default/config-lgsm/fivemserver/_default.cfg b/lgsm/config-default/config-lgsm/fivemserver/_default.cfg new file mode 100644 index 0000000000..f48ccbd0a8 --- /dev/null +++ b/lgsm/config-default/config-lgsm/fivemserver/_default.cfg @@ -0,0 +1,205 @@ +################################## +######## Default Settings ######## +################################## +# DO NOT EDIT, ANY CHANGES WILL BE OVERWRITTEN! +# Copy settings from here and use them in either: +# common.cfg - applies settings to every instance. +# [instance].cfg - applies settings to a specific instance. + +#### Game Server Settings #### + +## Server Parameters | https://docs.linuxgsm.com/configuration/start-parameters#additional-parameters +## Game Server Docs | https://docs.fivem.net/docs/server-manual/setting-up-a-server-vanilla/ +# Ports, server name, max players and the license key (sv_licenseKey) are set in server.cfg. +startparameters="+exec ${servercfg}" + +## Extra Parameters | https://docs.linuxgsm.com/configuration/start-parameters#extra-parameters +# Added to the end of startparameters. +extraparams="" + +#### LinuxGSM Settings #### + +## LinuxGSM Stats +# Send useful stats to LinuxGSM developers. +# https://docs.linuxgsm.com/configuration/linuxgsm-stats +# (on|off) +stats="off" + +## Notification Alerts +# (on|off) + +# Display IP | https://docs.linuxgsm.com/alerts#display-ip +displayip="" + +# More info | https://docs.linuxgsm.com/alerts#more-info +postalert="off" + +# Alert on Start/Stop/Restart +statusalert="off" + +# Discord Alerts | https://docs.linuxgsm.com/alerts/discord +discordalert="off" +discordwebhook="webhook" + +# Email Alerts | https://docs.linuxgsm.com/alerts/email +emailalert="off" +email="email@example.com" +emailfrom="" + +# Gotify Alerts | https://docs.linuxgsm.com/alerts/gotify +gotifyalert="off" +gotifytoken="token" +gotifywebhook="webhook" + +# IFTTT Alerts | https://docs.linuxgsm.com/alerts/ifttt +iftttalert="off" +ifttttoken="accesstoken" +iftttevent="linuxgsm_alert" + +# ntfy Alerts | https://docs.linuxgsm.com/alerts/ntfy +ntfyalert="off" +ntfytopic="LinuxGSM" +ntfyserver="https://ntfy.sh" +ntfytoken="" +ntfyusername="" +ntfypassword="" +ntfypriority="" +ntfytags="" + +# Matrix Alerts | https://docs.linuxgsm.com/alerts/matrix +matrixalert="off" +matrixhomeserver="matrix.org" +matrixtoken="accesstoken" +matrixroom="" + +# Pushbullet Alerts | https://docs.linuxgsm.com/alerts/pushbullet +pushbulletalert="off" +pushbullettoken="accesstoken" +channeltag="" + +# Pushover Alerts | https://docs.linuxgsm.com/alerts/pushover +pushoveralert="off" +pushovertoken="accesstoken" +pushoveruserkey="userkey" + +# Rocket.Chat Alerts | https://docs.linuxgsm.com/alerts/rocket.chat +rocketchatalert="off" +rocketchatwebhook="webhook" + +# Slack Alerts | https://docs.linuxgsm.com/alerts/slack +slackalert="off" +slackwebhook="webhook" + +# Telegram Alerts | https://docs.linuxgsm.com/alerts/telegram +# You can add a custom cURL string eg proxy (useful in Russia) in "curlcustomstring". +# For example "--socks5 ipaddr:port" for socks5 proxy see more in "curl --help all". +telegramapi="api.telegram.org" +telegramalert="off" +telegramtoken="accesstoken" +telegramchatid="" +telegramthreadid="" +telegramsilentnotification="false" +curlcustomstring="" + +## Stop | https://docs.linuxgsm.com/commands/start-stop-restart +stoponlyifnoplayers="off" +stoponlyifnoplayersallcommands="on" + +## Player Warnings | https://docs.linuxgsm.com/features/player-warnings +# Minutes to warn players in-game before a stop, restart or update. 0 to disable. +# e.g. 15 warns at 15, 10, 5, 3 and 1 minutes. +warnplayerstimer="0" + +## Updating | https://docs.linuxgsm.com/commands/update +updateonstart="off" + +## Backup | https://docs.linuxgsm.com/commands/backup +maxbackups="4" +maxbackupdays="30" +stoponbackup="on" + +## Logging | https://docs.linuxgsm.com/features/logging +consolelogging="on" +logdays="7" + +## Monitor | https://docs.linuxgsm.com/commands/monitor +# Query delay time +querydelay="5" + +## ANSI Colors | https://docs.linuxgsm.com/features/ansi-colors +ansi="on" + +#### Advanced Settings #### + +## Message Display Time | https://docs.linuxgsm.com/features/message-display-time +sleeptime="0.5" + +## Stop Mode | https://docs.linuxgsm.com/features/stop-mode +# 1: tmux kill +# 2: CTRL+c +# 3: quit +# 4: quit 120s +# 5: stop +# 6: q +# 7: exit +# 8: 7 Days to Die +# 9: GoldSrc +# 10: Avorion +# 11: end +# 12: shutdown +# 13: soulmask +# 14: Running With Rifles +# 15: Rising World +# 16: Conan Exiles +stopmode="3" + +## Query mode +# 1: session only +# 2: gamedig (gsquery fallback) +# 3: gamedig +# 4: gsquery +# 5: tcp +querymode="3" +querytype="gta5f" + +## Console type +consoleverbose="yes" +consoleinteract="yes" + +## Game Server Details +# Do not edit +gamename="FiveM" +engine="cfx" +glibc="null" + +#### Directories #### +# Edit with care + +## Game Server Directories +systemdir="${serverfiles}" +executabledir="${serverfiles}" +executable="./run.sh" +servercfgdir="${systemdir}" +servercfg="server.cfg" +servercfgdefault="server.cfg" +servercfgfullpath="${servercfgdir}/${servercfg}" + +## Backup Directory +backupdir="${lgsmdir}/backup" + +## Logging Directories +[ -n "${LGSM_LOGDIR}" ] && logdir="${LGSM_LOGDIR}" || logdir="${rootdir}/log" +lgsmlogdir="${logdir}/script" +consolelogdir="${logdir}/console" +lgsmlog="${lgsmlogdir}/${selfname}-script.log" +consolelog="${consolelogdir}/${selfname}-console.log" +alertlog="${lgsmlogdir}/${selfname}-alert.log" +postdetailslog="${lgsmlogdir}/${selfname}-postdetails.log" + +## Logs Naming +lgsmlogdate="${lgsmlogdir}/${selfname}-script-$(date '+%Y-%m-%d-%H:%M:%S').log" +consolelogdate="${consolelogdir}/${selfname}-console-$(date '+%Y-%m-%d-%H:%M:%S').log" + +## Log Parameters +logtimestamp="off" +logtimestampformat="%Y-%m-%d %H:%M:%S" diff --git a/lgsm/data/almalinux-8.csv b/lgsm/data/almalinux-8.csv index 68d6923cb1..df94f531d3 100644 --- a/lgsm/data/almalinux-8.csv +++ b/lgsm/data/almalinux-8.csv @@ -50,6 +50,7 @@ em etl ets2,libatomic fctr +fivem fof gmod,ncurses-libs.i686 hcu diff --git a/lgsm/data/almalinux-9.csv b/lgsm/data/almalinux-9.csv index 58efd58b6d..a3cf265fa3 100644 --- a/lgsm/data/almalinux-9.csv +++ b/lgsm/data/almalinux-9.csv @@ -50,6 +50,7 @@ em etl ets2,libatomic fctr +fivem fof gmod,ncurses-libs.i686 hcu diff --git a/lgsm/data/centos-7.csv b/lgsm/data/centos-7.csv index 5ab23dd6ff..a08769763a 100644 --- a/lgsm/data/centos-7.csv +++ b/lgsm/data/centos-7.csv @@ -50,6 +50,7 @@ em etl ets2,libatomic fctr +fivem fof gmod,ncurses-libs.i686 hcu diff --git a/lgsm/data/centos-8.csv b/lgsm/data/centos-8.csv index 1dd0820b37..5c466bd2b8 100644 --- a/lgsm/data/centos-8.csv +++ b/lgsm/data/centos-8.csv @@ -50,6 +50,7 @@ em etl ets2,libatomic fctr +fivem fof gmod,ncurses-libs.i686 hcu diff --git a/lgsm/data/centos-9.csv b/lgsm/data/centos-9.csv index 85048bc5a9..cba4326bc3 100644 --- a/lgsm/data/centos-9.csv +++ b/lgsm/data/centos-9.csv @@ -50,6 +50,7 @@ em etl ets2,libatomic fctr +fivem fof gmod,ncurses-libs.i686 hcu diff --git a/lgsm/data/debian-10.csv b/lgsm/data/debian-10.csv index 5827871c09..e79ad4bf15 100644 --- a/lgsm/data/debian-10.csv +++ b/lgsm/data/debian-10.csv @@ -49,6 +49,7 @@ em etl ets2,libatomic1 fctr +fivem fof gmod,libtinfo5:i386 hcu diff --git a/lgsm/data/debian-11.csv b/lgsm/data/debian-11.csv index e7a43d7cfd..bfdbd0647d 100644 --- a/lgsm/data/debian-11.csv +++ b/lgsm/data/debian-11.csv @@ -50,6 +50,7 @@ em etl ets2,libatomic1 fctr +fivem fof gmod,libtinfo5:i386 hcu diff --git a/lgsm/data/debian-12.csv b/lgsm/data/debian-12.csv index 8bfd2d09e9..0bcf5e8d7a 100644 --- a/lgsm/data/debian-12.csv +++ b/lgsm/data/debian-12.csv @@ -50,6 +50,7 @@ em etl ets2,libatomic1 fctr +fivem fof gmod,libtinfo5:i386 hcu diff --git a/lgsm/data/debian-13.csv b/lgsm/data/debian-13.csv index bee026499c..e909a12669 100644 --- a/lgsm/data/debian-13.csv +++ b/lgsm/data/debian-13.csv @@ -50,6 +50,7 @@ em etl ets2,libatomic1 fctr +fivem fof gmod hcu diff --git a/lgsm/data/debian-9.csv b/lgsm/data/debian-9.csv index 78875ea9c4..088ec5a0fa 100644 --- a/lgsm/data/debian-9.csv +++ b/lgsm/data/debian-9.csv @@ -50,6 +50,7 @@ em etl ets2,libatomic1 fctr +fivem fof gmod,libtinfo5:i386 hcu diff --git a/lgsm/data/gameicons/fivem-icon.png b/lgsm/data/gameicons/fivem-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..db832a78ec10b53ebc8a83415dc7583ad5cddf14 GIT binary patch literal 1455 zcmZ{kc{mh!7{`Axxe1AJXSy7lW>D^=21AXEM8-OYTsy-wV`QZUnHbS?(<&H`+c9!^ZxTbZ;FevgRGRA6aYZh5ruRW z*8MvnAtKCMP=47?gG0HZ0r>GS0MwfR{3(>E9|4Gh12E?YfJGhvDv?Fa7%SmGEa0pI z5^V2SXP?3y8d6EE--n$dKKtT~yD2kIE(RSi4XgeI;3EP_Qc_b;x^!2tmAb41#@p}J?> zry`UtDxKu@&rgo?DH9@S_19!|N_^v(_77emElRHk^(9$fXb2Xv?BvETN?5Sba6#R)6Ga@QvXJObUUeEbAD_} z`uu8laoFc=9V&tat>2v1GF*5wEzcISg8&HF?6S8*A}1}6tk<#?*iqg%&>>Gp(9GpT zU?K_%n1HoFkc>jkl0Wo4o(k`4h|ybY3HPwsp2vYz?pc+LTxWZ_670)T;`-x8EsKoR zF17u2x|s*c_8ut9;&7}tz6JbzNZL;(|J>oM#bcDHbq#gH^lWD*RU=k`9$Tpc$}Jiw z!Y1SN9=c&UzRdN=)kOxQ&nd`TZ=VBQ#x90}D8vtAO%3Q-{qHFrB?yP)u+VEi&L-vJ z6K>av@6j*j31*~krHZz-#lQx!(G&`U!SQNZPU|)|fw51CB28%5Y}$Uis?`Ai?p$wV zK%EuBvr+Yu8w@r`TIJ=`_^`3Z53=Q{k{D~B0(~X%XYfa8uGvCG$+gczcShxxm+1GU zYubZ09h}BTeW6;K+aG#8@^il9|9Vjr;ChIY)~#GGsWNsec+`>k{{*Nhbl&hht^s(uIyyOh1nDd0Fhkz24kxT|!~%yzNS<8&Q*o zlH@y2k1u3l}eVMYcE4)cl{cLxgu7^0Q8PftUX?!!6rUDS7GTI<$#Vzqda(Hu8dLLnrS zlZn4qXyZ`+DUNe63Duiu9e2T)bmD8*)37f*?P$W*TKzjSYUy2lWpTN+_t~k8e1w>) z^cloS^Ho8v@1$qjERi4}J!Zq*m*?|&6BFy>{JeuGWc%Wc8*v*e57Wj+GynllXkB@2 zc}q&PuyAnht}earLvMXr?lEu3Qn*(Kw~I(Ft*wTI&xvkTvM?jo160oWd;HniGf1zGd}g&_>a*(V#0uWPb7Eivan~um?B5#%GkdlCk0;INZ{C!E;>K#3qp9;|hIFxz){zwQgH&ty$h@*~4>S~?=B`c< zp7cUYJgzQy-uBaz{7Ov2o8zn}FS5UmEhcKp6cBd<^-6nk_bEQwzk8ZFW`pyk48S^U XbXBRro10YOuK~c(&KX&K+ArZRW7&(= literal 0 HcmV?d00001 diff --git a/lgsm/data/rhel-7.csv b/lgsm/data/rhel-7.csv index 894b7856df..4da812078c 100644 --- a/lgsm/data/rhel-7.csv +++ b/lgsm/data/rhel-7.csv @@ -52,6 +52,7 @@ em etl ets2,libatomic fctr +fivem fof gmod,ncurses-libs.i686 hcu diff --git a/lgsm/data/rhel-8.csv b/lgsm/data/rhel-8.csv index 78293ca904..f1940f74ab 100644 --- a/lgsm/data/rhel-8.csv +++ b/lgsm/data/rhel-8.csv @@ -50,6 +50,7 @@ em etl ets2,libatomic fctr +fivem fof gmod,ncurses-libs.i686 hcu diff --git a/lgsm/data/rhel-9.csv b/lgsm/data/rhel-9.csv index 58efd58b6d..a3cf265fa3 100644 --- a/lgsm/data/rhel-9.csv +++ b/lgsm/data/rhel-9.csv @@ -50,6 +50,7 @@ em etl ets2,libatomic fctr +fivem fof gmod,ncurses-libs.i686 hcu diff --git a/lgsm/data/rocky-8.csv b/lgsm/data/rocky-8.csv index 78293ca904..f1940f74ab 100644 --- a/lgsm/data/rocky-8.csv +++ b/lgsm/data/rocky-8.csv @@ -50,6 +50,7 @@ em etl ets2,libatomic fctr +fivem fof gmod,ncurses-libs.i686 hcu diff --git a/lgsm/data/rocky-9.csv b/lgsm/data/rocky-9.csv index 58efd58b6d..a3cf265fa3 100644 --- a/lgsm/data/rocky-9.csv +++ b/lgsm/data/rocky-9.csv @@ -50,6 +50,7 @@ em etl ets2,libatomic fctr +fivem fof gmod,ncurses-libs.i686 hcu diff --git a/lgsm/data/serverlist.csv b/lgsm/data/serverlist.csv index 0e9167f8cf..295cc60a3f 100644 --- a/lgsm/data/serverlist.csv +++ b/lgsm/data/serverlist.csv @@ -49,6 +49,7 @@ em,emserver,Empires Mod,ubuntu-26.04 etl,etlserver,ET: Legacy,ubuntu-26.04 ets2,ets2server,Euro Truck Simulator 2,ubuntu-26.04 fctr,fctrserver,Factorio,ubuntu-26.04 +fivem,fivemserver,FiveM,ubuntu-26.04 fof,fofserver,Fistful of Frags,ubuntu-26.04 gmod,gmodserver,Garrys Mod,ubuntu-26.04 hcu,hcuserver,HYPERCHARGE: Unboxed,ubuntu-26.04 diff --git a/lgsm/data/ubuntu-16.04.csv b/lgsm/data/ubuntu-16.04.csv index 3171162a9a..d8e3e7690f 100644 --- a/lgsm/data/ubuntu-16.04.csv +++ b/lgsm/data/ubuntu-16.04.csv @@ -52,6 +52,7 @@ em etl ets2,libatomic1 fctr +fivem fof gmod,libtinfo5:i386 hcu diff --git a/lgsm/data/ubuntu-18.04.csv b/lgsm/data/ubuntu-18.04.csv index 5833b5dfe3..5b21882ab3 100644 --- a/lgsm/data/ubuntu-18.04.csv +++ b/lgsm/data/ubuntu-18.04.csv @@ -52,6 +52,7 @@ em etl ets2,libatomic1 fctr +fivem fof gmod,libtinfo5:i386 hcu diff --git a/lgsm/data/ubuntu-20.04.csv b/lgsm/data/ubuntu-20.04.csv index 3f597b719d..482d238912 100644 --- a/lgsm/data/ubuntu-20.04.csv +++ b/lgsm/data/ubuntu-20.04.csv @@ -50,6 +50,7 @@ em etl ets2,libatomic1 fctr +fivem fof gmod,libtinfo5:i386 hcu diff --git a/lgsm/data/ubuntu-22.04.csv b/lgsm/data/ubuntu-22.04.csv index 17551ecca0..ea611d7ee9 100644 --- a/lgsm/data/ubuntu-22.04.csv +++ b/lgsm/data/ubuntu-22.04.csv @@ -50,6 +50,7 @@ em etl ets2,libatomic1 fctr +fivem fof gmod,libtinfo5:i386 hcu diff --git a/lgsm/data/ubuntu-23.04.csv b/lgsm/data/ubuntu-23.04.csv index 5592f27edf..9d19c5031b 100644 --- a/lgsm/data/ubuntu-23.04.csv +++ b/lgsm/data/ubuntu-23.04.csv @@ -50,6 +50,7 @@ em etl ets2,libatomic1 fctr +fivem fof gmod,libtinfo5:i386 hcu diff --git a/lgsm/data/ubuntu-23.10.csv b/lgsm/data/ubuntu-23.10.csv index 5592f27edf..9d19c5031b 100644 --- a/lgsm/data/ubuntu-23.10.csv +++ b/lgsm/data/ubuntu-23.10.csv @@ -50,6 +50,7 @@ em etl ets2,libatomic1 fctr +fivem fof gmod,libtinfo5:i386 hcu diff --git a/lgsm/data/ubuntu-24.04.csv b/lgsm/data/ubuntu-24.04.csv index 724445f863..0c72910a2d 100644 --- a/lgsm/data/ubuntu-24.04.csv +++ b/lgsm/data/ubuntu-24.04.csv @@ -50,6 +50,7 @@ em etl ets2,libatomic1 fctr +fivem fof gmod hcu diff --git a/lgsm/data/ubuntu-26.04.csv b/lgsm/data/ubuntu-26.04.csv index d21b7304b3..8822d559d0 100644 --- a/lgsm/data/ubuntu-26.04.csv +++ b/lgsm/data/ubuntu-26.04.csv @@ -50,6 +50,7 @@ em etl ets2,libatomic1 fctr +fivem fof gmod hcu diff --git a/lgsm/modules/check_config.sh b/lgsm/modules/check_config.sh index 6907ab4752..05157e0169 100755 --- a/lgsm/modules/check_config.sh +++ b/lgsm/modules/check_config.sh @@ -49,3 +49,13 @@ elif [ "${shortname}" == "vh" ] && [ "${#serverpassword}" -le "4" ]; then fn_print_fail_nl "serverpassword is to short (min 5 chars)" fn_script_log_fail "serverpassword is to short (min 5 chars)" fi + +if [ "${shortname}" == "fivem" ] && ! grep -qE "^[[:space:]]*(set[[:space:]]+)?sv_licenseKey[[:space:]]+\"?[^\" ]" "${servercfgfullpath}" 2> /dev/null; then + fn_print_fail_nl "FiveM license key is not set" + echo -e "* Get a free key from ${italic}https://portal.cfx.re/servers/registration-keys${default}" + echo -e "* Set sv_licenseKey in ${servercfgfullpath}" + fn_script_log_fail "FiveM license key is not set" + if [ "${commandname}" == "START" ] || [ "${commandname}" == "DEBUG" ]; then + core_exit.sh + fi +fi diff --git a/lgsm/modules/command_check_update.sh b/lgsm/modules/command_check_update.sh index f4856aa6e7..97b6d0d97d 100755 --- a/lgsm/modules/command_check_update.sh +++ b/lgsm/modules/command_check_update.sh @@ -24,6 +24,8 @@ elif [ "${shortname}" == "pmc" ] || [ "${shortname}" == "vpmc" ] || [ "${shortna update_pmc.sh elif [ "${shortname}" == "fctr" ]; then update_fctr.sh +elif [ "${shortname}" == "fivem" ]; then + update_fivem.sh elif [ "${shortname}" == "hyt" ]; then update_hyt.sh elif [ "${shortname}" == "mta" ]; then diff --git a/lgsm/modules/command_install.sh b/lgsm/modules/command_install.sh index 8dc9a77df8..7918db4579 100755 --- a/lgsm/modules/command_install.sh +++ b/lgsm/modules/command_install.sh @@ -39,6 +39,8 @@ else install_gslt.sh elif [ "${shortname}" == "dst" ]; then install_dst_token.sh + elif [ "${shortname}" == "fivem" ]; then + install_fivem_license.sh elif [ "${shortname}" == "squad" ]; then install_squad_license.sh elif [ "${shortname}" == "ts3" ]; then diff --git a/lgsm/modules/command_update.sh b/lgsm/modules/command_update.sh index 2462408b98..e8d435eafb 100755 --- a/lgsm/modules/command_update.sh +++ b/lgsm/modules/command_update.sh @@ -65,6 +65,8 @@ elif [ "${shortname}" == "pmc" ] || [ "${shortname}" == "vpmc" ] || [ "${shortna update_pmc.sh elif [ "${shortname}" == "fctr" ]; then update_fctr.sh +elif [ "${shortname}" == "fivem" ]; then + update_fivem.sh elif [ "${shortname}" == "hyt" ]; then update_hyt.sh elif [ "${shortname}" == "mta" ]; then diff --git a/lgsm/modules/core_getopt.sh b/lgsm/modules/core_getopt.sh index df93c08326..ef9348c858 100755 --- a/lgsm/modules/core_getopt.sh +++ b/lgsm/modules/core_getopt.sh @@ -71,8 +71,8 @@ currentopt+=("${cmd_update_linuxgsm[@]}") if [ "${shortname}" == "jk2" ] || [ "${shortname}" == "jk3" ] || [ "${shortname}" == "etl" ] || [ "${engine}" != "idtech3" ]; then if [ "${querytype}" != "protocol-valve-won" ] && [ "${shortname}" != "bf1942" ] && [ "${shortname}" != "bfv" ] && [ "${engine}" != "idtech2" ] && [ "${engine}" != "iw2.0" ] && [ "${engine}" != "iw3.0" ] && [ "${engine}" != "quake" ] && [ "${shortname}" != "samp" ] && [ "${shortname}" != "ut2k4" ]; then currentopt+=("${cmd_update[@]}" "${cmd_check_update[@]}") - # force update for SteamCMD, Multi Theft Auto or Hytale only. - if [ "${appid}" ] || [ "${shortname}" == "mta" ] || [ "${shortname}" == "hyt" ]; then + # force update for SteamCMD, Multi Theft Auto, Hytale or FiveM only. + if [ "${appid}" ] || [ "${shortname}" == "mta" ] || [ "${shortname}" == "hyt" ] || [ "${shortname}" == "fivem" ]; then currentopt+=("${cmd_force_update[@]}") fi fi diff --git a/lgsm/modules/core_modules.sh b/lgsm/modules/core_modules.sh index a7bda742aa..b1d2da0142 100755 --- a/lgsm/modules/core_modules.sh +++ b/lgsm/modules/core_modules.sh @@ -186,6 +186,11 @@ command_workshop_update.sh() { fn_fetch_module } +install_fivem_license.sh() { + modulefile="${FUNCNAME[0]}" + fn_fetch_module +} + install_squad_license.sh() { modulefile="${FUNCNAME[0]}" fn_fetch_module @@ -732,6 +737,11 @@ update_fctr.sh() { fn_fetch_module } +update_fivem.sh() { + modulefile="${FUNCNAME[0]}" + fn_fetch_module +} + update_hyt.sh() { modulefile="${FUNCNAME[0]}" fn_fetch_module diff --git a/lgsm/modules/info_game.sh b/lgsm/modules/info_game.sh index 2923f74a61..3bfcf2634e 100755 --- a/lgsm/modules/info_game.sh +++ b/lgsm/modules/info_game.sh @@ -1340,6 +1340,24 @@ fn_info_game_etl() { serverpassword="${serverpassword:-"NOT SET"}" } +# Config Type: Custom (key value pairs) +# Comment: # +# Example: sv_hostname "SERVERNAME" +# Filetype: cfg +fn_info_game_fivem() { + if [ -f "${servercfgfullpath}" ]; then + servername="$(sed -n 's/^sv_hostname[[:space:]]\+"\?\([^"]*\)"\?.*/\1/p' "${servercfgfullpath}" | head -1 | tr -d '\r')" + maxplayers="$(sed -n 's/^sv_maxclients[[:space:]]\+\([0-9]*\).*/\1/p' "${servercfgfullpath}" | head -1)" + rconpassword="$(sed -n 's/^rcon_password[[:space:]]\+"\?\([^"]*\)"\?.*/\1/p' "${servercfgfullpath}" | head -1 | tr -d '\r')" + port="$(sed -n 's/^endpoint_add_udp[[:space:]]\+"\?[^:"]*:\([0-9]*\)"\?.*/\1/p' "${servercfgfullpath}" | head -1)" + fi + maxplayers="${maxplayers:-"0"}" + port="${port:-"0"}" + queryport="${port}" + rconpassword="${rconpassword:-"NOT SET"}" + servername="${servername:-"NOT SET"}" +} + # Config Type: json # Parameters: true # Comment: // or /* */ @@ -2535,6 +2553,8 @@ elif [ "${shortname}" == "etl" ]; then fn_info_game_etl elif [ "${shortname}" == "fctr" ]; then fn_info_game_fctr +elif [ "${shortname}" == "fivem" ]; then + fn_info_game_fivem elif [ "${shortname}" == "hw" ]; then fn_info_game_hw elif [ "${shortname}" == "hz" ]; then diff --git a/lgsm/modules/info_messages.sh b/lgsm/modules/info_messages.sh index 3ee6bd286c..635f9f673a 100755 --- a/lgsm/modules/info_messages.sh +++ b/lgsm/modules/info_messages.sh @@ -736,7 +736,7 @@ fn_info_messages_ports_edit() { startparameterslocation="${red}UNKNOWN${default}" # engines/games that require editing in the config file. - local ports_edit_array=("ac" "arma3" "armar" "bfe" "bo" "bt" "ct" "dst" "eco" "idtech2" "idtech3" "idtech3_ql" "jc2" "jc3" "lwjgl2" "mcb" "nec" "pc" "pc2" "prism3d" "pz" "qw" "refractor" "renderware" "rw" "rwr" "sb" "sdtd" "st" "stn" "ts3" "tw" "terraria" "unreal" "unreal2" "unreal3" "vints" "xnt" "wurm") + local ports_edit_array=("ac" "arma3" "armar" "bfe" "bo" "bt" "ct" "dst" "eco" "fivem" "idtech2" "idtech3" "idtech3_ql" "jc2" "jc3" "lwjgl2" "mcb" "nec" "pc" "pc2" "prism3d" "pz" "qw" "refractor" "renderware" "rw" "rwr" "sb" "sdtd" "st" "stn" "ts3" "tw" "terraria" "unreal" "unreal2" "unreal3" "vints" "xnt" "wurm") for port_edit in "${ports_edit_array[@]}"; do if [ "${shortname}" == "ut3" ]; then startparameterslocation="${servercfgdir}/UTWeb.ini" @@ -775,6 +775,8 @@ fn_info_messages_ports() { portcommand="ss -tuplwn | grep enfMain" elif [ "${shortname}" == "q4" ]; then portcommand="ss -tuplwn | grep q4ded.x86" + elif [ "${shortname}" == "fivem" ]; then + portcommand="ss -tuplwn | grep ld-musl" elif [ "${shortname}" == "rwr" ]; then portcommand="ss -tuplwn | grep rwr_server" elif [ "${shortname}" == "hyt" ] || [ "${shortname}" == "mc" ] || [ "${shortname}" == "nec" ] || [ "${shortname}" == "pmc" ] || [ "${shortname}" == "vpmc" ] || [ "${shortname}" == "wmc" ]; then @@ -1132,6 +1134,14 @@ fn_info_messages_etl() { } | column -s $'\t' -t } +fn_info_messages_fivem() { + { + fn_port "header" + fn_port "Game" port tcp + fn_port "Game" port udp + } | column -s $'\t' -t +} + fn_info_messages_fctr() { { fn_port "header" @@ -1961,6 +1971,8 @@ fn_info_messages_select_engine() { fn_info_messages_etl elif [ "${shortname}" == "fctr" ]; then fn_info_messages_fctr + elif [ "${shortname}" == "fivem" ]; then + fn_info_messages_fivem elif [ "${shortname}" == "hcu" ]; then fn_info_messages_hcu elif [ "${shortname}" == "hw" ]; then diff --git a/lgsm/modules/install_config.sh b/lgsm/modules/install_config.sh index 88811a9baf..4c3e34f124 100755 --- a/lgsm/modules/install_config.sh +++ b/lgsm/modules/install_config.sh @@ -503,6 +503,11 @@ elif [ "${shortname}" == "fctr" ]; then fn_default_config_remote fn_set_config_vars fn_list_config_locations +elif [ "${shortname}" == "fivem" ]; then + array_configs+=(server.cfg) + fn_default_config_remote + fn_set_config_vars + fn_list_config_locations elif [ "${shortname}" == "fof" ]; then array_configs+=(server.cfg) fn_default_config_remote diff --git a/lgsm/modules/install_fivem_license.sh b/lgsm/modules/install_fivem_license.sh new file mode 100755 index 0000000000..9fa9db26f9 --- /dev/null +++ b/lgsm/modules/install_fivem_license.sh @@ -0,0 +1,24 @@ +#!/bin/bash +# LinuxGSM install_fivem_license.sh module +# Author: Daniel Gibbs +# Contributors: https://linuxgsm.com/contrib +# Website: https://linuxgsm.com +# Description: Explains how to set the FiveM server license key. + +moduleselfname="$(basename "$(readlink -f "${BASH_SOURCE[0]}")")" + +echo -e "" +echo -e "${bold}${lightyellow}${gamename} License Key${default}" +fn_messages_separator +echo -e "A license key is required to run a ${gamename} server." +fn_script_log_info "A license key is required to run a ${gamename} server." + +echo -e "Get a free license key here:" +echo -e "${italic}https://portal.cfx.re/servers/registration-keys${default}" +fn_script_log_info "Get a free license key here:" +fn_script_log_info "https://portal.cfx.re/servers/registration-keys" +echo -e "" +fn_sleep_time_1 +echo -e "Set the license key with sv_licenseKey in ${servercfgfullpath}." +fn_script_log_info "Set the license key with sv_licenseKey in ${servercfgfullpath}." +echo -e "" diff --git a/lgsm/modules/install_server_files.sh b/lgsm/modules/install_server_files.sh index 1c76489092..03b7538862 100755 --- a/lgsm/modules/install_server_files.sh +++ b/lgsm/modules/install_server_files.sh @@ -273,6 +273,8 @@ elif [ "${shortname}" == "mta" ]; then elif [ "${shortname}" == "fctr" ]; then update_fctr.sh install_factorio_save.sh +elif [ "${shortname}" == "fivem" ]; then + update_fivem.sh elif [ "${shortname}" == "hyt" ]; then update_hyt.sh elif [ "${shortname}" == "jk2" ]; then diff --git a/lgsm/modules/update_fivem.sh b/lgsm/modules/update_fivem.sh new file mode 100755 index 0000000000..9557e3adee --- /dev/null +++ b/lgsm/modules/update_fivem.sh @@ -0,0 +1,139 @@ +#!/bin/bash +# LinuxGSM update_fivem.sh module +# Author: Daniel Gibbs +# Contributors: https://linuxgsm.com/contrib +# Website: https://linuxgsm.com +# Description: Handles updating of FiveM servers. + +moduleselfname="$(basename "$(readlink -f "${BASH_SOURCE[0]}")")" + +fn_update_resources() { + # Download and extract the cfx-server-data base resources. + fn_fetch_file "https://github.com/citizenfx/cfx-server-data/archive/refs/heads/master.tar.gz" "" "" "" "${tmpdir}" "cfx-server-data.tar.gz" "nochmodx" "norun" "force" "nohash" + fn_dl_extract "${tmpdir}" "cfx-server-data.tar.gz" "${serverfiles}" "cfx-server-data-master/resources" +} + +fn_update_dl() { + # Download and extract files to tmpdir. + fn_fetch_file "${remotebuildurl}" "" "" "" "${tmpdir}" "${remotebuildfilename}" "nochmodx" "norun" "force" "nohash" + rm -rf "${serverfiles:?}/alpine" + fn_dl_extract "${tmpdir}" "${remotebuildfilename}" "${serverfiles}" + if [ ! -d "${serverfiles}/resources" ]; then + fn_update_resources + fi + echo "${remotebuild}" > "${localbuildfile}" + fn_clear_tmp +} + +fn_update_localbuild() { + # Gets local build info. + fn_print_dots "Checking local build: ${remotelocation}" + if [ -f "${localbuildfile}" ]; then + localbuild="$(cat "${localbuildfile}")" + fi + if [ -z "${localbuild}" ]; then + fn_print_error "Checking local build: ${remotelocation}: missing local build info" + 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}" + fn_script_log_pass "Checking local build" + fi +} + +fn_update_remotebuild() { + # Gets remote build info. + apiurl="https://changelogs-live.fivem.net/api/changelog/versions/linux/server" + remotebuildresponse=$(curl -s "${apiurl}") + remotebuild=$(echo "${remotebuildresponse}" | jq -r '.recommended') + remotebuildurl=$(echo "${remotebuildresponse}" | jq -r '.recommended_download') + remotebuildfilename="fx.tar.xz" + if [ "${firstcommandname}" != "INSTALL" ]; then + fn_print_dots "Checking remote build: ${remotelocation}" + # Checks if remotebuild variable has been set. + if [ -z "${remotebuild}" ] || [ "${remotebuild}" == "null" ] || [ -z "${remotebuildurl}" ] || [ "${remotebuildurl}" == "null" ]; then + fn_print_fail "Checking remote build: ${remotelocation}" + fn_script_log_fail "Checking remote build" + core_exit.sh + else + fn_print_ok "Checking remote build: ${remotelocation}" + fn_script_log_pass "Checking remote build" + fi + else + # Checks if remotebuild variable has been set. + if [ -z "${remotebuild}" ] || [ "${remotebuild}" == "null" ] || [ -z "${remotebuildurl}" ] || [ "${remotebuildurl}" == "null" ]; then + fn_print_failure "Unable to get remote build" + fn_script_log_fail "Unable to get remote build" + core_exit.sh + fi + fi +} + +fn_update_compare() { + fn_print_dots "Checking for update: ${remotelocation}" + # Update has been found or force update. + 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}${remotebuild}${default}" + if [ -f "${rootdir}/.dev-debug" ]; then + 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 + fn_print "\n" + fn_script_log_info "Update available" + fn_script_log_info "Local build: ${localbuild}" + fn_script_log_info "Remote build: ${remotebuild}" + fn_script_log_info "${localbuild} > ${remotebuild}" + + if [ "${commandname}" == "UPDATE" ]; then + unset updateonstart + fn_update_apply fn_update_dl + alert="update" + elif [ "${commandname}" == "CHECK-UPDATE" ]; then + alert="check-update" + fi + alert.sh + else + fn_print_ok_nl "Checking for update: ${remotelocation}" + 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}" + fn_print "\n" + fn_script_log_info "No update available" + fn_script_log_info "Local build: ${localbuild}" + fn_script_log_info "Remote build: ${remotebuild}" + if [ -f "${rootdir}/.dev-debug" ]; then + 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 +} + +localbuildfile="${datadir}/${selfname}-fivem-version" +# The location where the builds are checked and downloaded. +remotelocation="runtime.fivem.net" + +if [ "${firstcommandname}" == "INSTALL" ]; then + fn_update_remotebuild + fn_update_dl +else + fn_print_dots "Checking for update" + fn_print_dots "Checking for update: ${remotelocation}" + fn_script_log_info "Checking for update: ${remotelocation}" + fn_update_localbuild + fn_update_remotebuild + fn_update_compare +fi From 1b66cf85dd703f0e82e5cf8be3c5ded78173369e Mon Sep 17 00:00:00 2001 From: Daniel Gibbs Date: Sun, 1 Nov 2026 01:43:22 +0000 Subject: [PATCH 147/164] fix(update): stop a second update running while one is in progress (#5095) Adds check_update_lock.sh, which stops a second update, force-update, validate or workshop-update from running while one is in progress. The lock is removed in core_exit.sh, and a lock left by a dead or reused PID is treated as stale. Also fixes the SteamCMD retry loop: a failing base app no longer retries forever without an error, and the SteamCMD log is cleared before each attempt so a successful retry is not reported as failed. Fixes #5094 --- lgsm/modules/check_update_lock.sh | 59 +++++++++++++++++++++++++ lgsm/modules/command_update.sh | 1 + lgsm/modules/command_validate.sh | 1 + lgsm/modules/command_workshop_update.sh | 1 + lgsm/modules/core_dl.sh | 55 +++++++++++------------ lgsm/modules/core_exit.sh | 4 ++ lgsm/modules/core_modules.sh | 5 +++ 7 files changed, 96 insertions(+), 30 deletions(-) create mode 100755 lgsm/modules/check_update_lock.sh diff --git a/lgsm/modules/check_update_lock.sh b/lgsm/modules/check_update_lock.sh new file mode 100755 index 0000000000..42e64e9e39 --- /dev/null +++ b/lgsm/modules/check_update_lock.sh @@ -0,0 +1,59 @@ +#!/bin/bash +# LinuxGSM check_update_lock.sh module +# Author: Daniel Gibbs +# Contributors: https://linuxgsm.com/contrib +# Website: https://linuxgsm.com +# Description: Stops an update or validate from running while another one is running. + +moduleselfname="$(basename "$(readlink -f "${BASH_SOURCE[0]}")")" + +updatinglock="${lockdir}/updating.lock" + +fn_update_lock_create() { + ( + set -o noclobber + echo "$$" > "${updatinglock}" + ) 2> /dev/null +} + +# Checks the PID in the lockfile is running and started before the lockfile was written. +fn_update_lock_running() { + local lockpid="${1}" + local lockage processage + if [ -z "${lockpid}" ] || ! kill -0 "${lockpid}" 2> /dev/null; then + return 1 + fi + lockage="$(($(date '+%s') - $(stat -c %Y "${updatinglock}" 2> /dev/null || echo 0)))" + processage="$(ps -o etimes= -p "${lockpid}" 2> /dev/null | tr -d ' ')" + [ -n "${processage}" ] && [ "$((processage + 2))" -ge "${lockage}" ] +} + +if ! fn_update_lock_create; then + updatelockpid="$(cat "${updatinglock}" 2> /dev/null)" + if [ -z "${updatelockpid}" ]; then + sleep 1 + updatelockpid="$(cat "${updatinglock}" 2> /dev/null)" + fi + if [ "${updatelockpid}" == "$$" ] && [ -n "${updatelocklevel}" ]; then + return + fi + if [ "${updatelockpid}" == "$$" ] || ! fn_update_lock_running "${updatelockpid}"; then + fn_script_log_warn "Checking update: Removing stale lockfile from PID ${updatelockpid:-unknown}" + rm -f "${updatinglock:?}" + fn_update_lock_create + fi +fi + +updatelockpid="$(cat "${updatinglock}" 2> /dev/null)" +if [ "${updatelockpid}" != "$$" ]; then + fn_print_dots "Checking update" + fn_print_checking_eol + fn_print_info "Checking update: Update is already running (PID ${updatelockpid})" + fn_print_info_eol_nl + fn_script_log_info "Checking update: Update is already running (PID ${updatelockpid})" + # shellcheck disable=SC2034 # Used by core_exit.sh. + exitcode=0 + unset exitbypass + core_exit.sh +fi +updatelocklevel="${BASH_SUBSHELL}" diff --git a/lgsm/modules/command_update.sh b/lgsm/modules/command_update.sh index e8d435eafb..2f6148cc7d 100755 --- a/lgsm/modules/command_update.sh +++ b/lgsm/modules/command_update.sh @@ -49,6 +49,7 @@ fn_update_apply() { fn_print_dots "" check.sh core_logs.sh +check_update_lock.sh # A postponed update is requested again if players are still online. rm -f "${lockdir:?}/${selfname}-update-request.lock" diff --git a/lgsm/modules/command_validate.sh b/lgsm/modules/command_validate.sh index 30c20e96ea..ff24c84688 100755 --- a/lgsm/modules/command_validate.sh +++ b/lgsm/modules/command_validate.sh @@ -30,6 +30,7 @@ fn_validate() { fn_print_dots "" check.sh core_logs.sh +check_update_lock.sh fn_print_dots "SteamCMD" diff --git a/lgsm/modules/command_workshop_update.sh b/lgsm/modules/command_workshop_update.sh index 479ff492fe..9d39185222 100755 --- a/lgsm/modules/command_workshop_update.sh +++ b/lgsm/modules/command_workshop_update.sh @@ -13,6 +13,7 @@ fn_firstcommand_set fn_print_dots "" check.sh core_logs.sh +check_update_lock.sh if [ -z "${workshopmods}" ] && [ ! -f "${datadir}/${selfname}-workshop.txt" ]; then fn_print_info_nl "No Workshop mods set. Add Workshop IDs to workshopmods in ${configdirserver}" diff --git a/lgsm/modules/core_dl.sh b/lgsm/modules/core_dl.sh index 02b458c105..418e8eefb7 100755 --- a/lgsm/modules/core_dl.sh +++ b/lgsm/modules/core_dl.sh @@ -75,14 +75,12 @@ fn_dl_steamcmd() { # To do error checking for SteamCMD the output of steamcmd will be saved to a log. steamcmdlog="${lgsmlogdir}/${selfname}-steamcmd.log" - # clear previous steamcmd log - if [ -f "${steamcmdlog}" ]; then - rm -f "${steamcmdlog:?}" - fi local invalidplatformworkaround="" counter=0 while [ "${counter}" -eq 0 ] || [ "${exitcode}" -ne 0 ]; do counter=$((counter + 1)) + # clear previous steamcmd log + rm -f "${steamcmdlog:?}" # Select SteamCMD parameters # If GoldSrc (appid 90) servers. GoldSrc (appid 90) require extra commands. if [ "${appid}" == "90" ]; then @@ -108,19 +106,18 @@ fn_dl_steamcmd() { fi "${unbuffercommand[@]}" "${steamcmdcommandarray[@]}" +@sSteamCmdForcePlatformType windows +force_install_dir "${supportdir}" +login "${steamuser}" "${steampass}" +app_update "${baseappid}" "${validateparam[@]}" +quit | fn_dl_steamcmd_output | tee -a "${lgsmlog}" "${steamcmdlog}" exitcode="${PIPESTATUS[0]}" - if [ "${exitcode}" -ne 0 ]; then - continue - fi fi - if [ -n "${branch}" ] && [ -n "${betapassword}" ]; then - "${unbuffercommand[@]}" "${steamcmdcommandarray[@]}" +@sSteamCmdForcePlatformType windows +force_install_dir "${serverfiles}" +login "${steamuser}" "${steampass}" +app_update "${appid}" -beta "${branch}" -betapassword "${betapassword}" "${validateparam[@]}" +quit | fn_dl_steamcmd_output | tee -a "${lgsmlog}" "${steamcmdlog}" - exitcode="${PIPESTATUS[0]}" - elif [ -n "${branch}" ]; then - "${unbuffercommand[@]}" "${steamcmdcommandarray[@]}" +@sSteamCmdForcePlatformType windows +force_install_dir "${serverfiles}" +login "${steamuser}" "${steampass}" +app_update "${appid}" -beta "${branch}" "${validateparam[@]}" +quit | fn_dl_steamcmd_output | tee -a "${lgsmlog}" "${steamcmdlog}" - exitcode="${PIPESTATUS[0]}" - else - "${unbuffercommand[@]}" "${steamcmdcommandarray[@]}" +@sSteamCmdForcePlatformType windows +force_install_dir "${serverfiles}" +login "${steamuser}" "${steampass}" +app_update "${appid}" "${validateparam[@]}" +quit | fn_dl_steamcmd_output | tee -a "${lgsmlog}" "${steamcmdlog}" - exitcode="${PIPESTATUS[0]}" + if [ -z "${baseappid}" ] || [ "${exitcode}" -eq 0 ]; then + if [ -n "${branch}" ] && [ -n "${betapassword}" ]; then + "${unbuffercommand[@]}" "${steamcmdcommandarray[@]}" +@sSteamCmdForcePlatformType windows +force_install_dir "${serverfiles}" +login "${steamuser}" "${steampass}" +app_update "${appid}" -beta "${branch}" -betapassword "${betapassword}" "${validateparam[@]}" +quit | fn_dl_steamcmd_output | tee -a "${lgsmlog}" "${steamcmdlog}" + exitcode="${PIPESTATUS[0]}" + elif [ -n "${branch}" ]; then + "${unbuffercommand[@]}" "${steamcmdcommandarray[@]}" +@sSteamCmdForcePlatformType windows +force_install_dir "${serverfiles}" +login "${steamuser}" "${steampass}" +app_update "${appid}" -beta "${branch}" "${validateparam[@]}" +quit | fn_dl_steamcmd_output | tee -a "${lgsmlog}" "${steamcmdlog}" + exitcode="${PIPESTATUS[0]}" + else + "${unbuffercommand[@]}" "${steamcmdcommandarray[@]}" +@sSteamCmdForcePlatformType windows +force_install_dir "${serverfiles}" +login "${steamuser}" "${steampass}" +app_update "${appid}" "${validateparam[@]}" +quit | fn_dl_steamcmd_output | tee -a "${lgsmlog}" "${steamcmdlog}" + exitcode="${PIPESTATUS[0]}" + fi fi # All other servers. else @@ -133,25 +130,23 @@ fn_dl_steamcmd() { fi "${unbuffercommand[@]}" "${steamcmdcommandarray[@]}" +force_install_dir "${supportdir}" +login "${steamuser}" "${steampass}" +app_update "${baseappid}" "${validateparam[@]}" +quit | fn_dl_steamcmd_output | tee -a "${lgsmlog}" "${steamcmdlog}" exitcode="${PIPESTATUS[0]}" - if [ "${exitcode}" -ne 0 ]; then - continue - fi fi - if [ -n "${branch}" ] && [ -n "${betapassword}" ]; then - "${unbuffercommand[@]}" "${steamcmdcommandarray[@]}" +force_install_dir "${serverfiles}" +login "${steamuser}" "${steampass}" +app_update "${appid}" -beta "${branch}" -betapassword "${betapassword}" "${validateparam[@]}" +quit | fn_dl_steamcmd_output | tee -a "${lgsmlog}" "${steamcmdlog}" - exitcode="${PIPESTATUS[0]}" - elif [ -n "${branch}" ]; then - "${unbuffercommand[@]}" "${steamcmdcommandarray[@]}" +force_install_dir "${serverfiles}" +login "${steamuser}" "${steampass}" +app_update "${appid}" -beta "${branch}" "${validateparam[@]}" +quit | fn_dl_steamcmd_output | tee -a "${lgsmlog}" "${steamcmdlog}" - exitcode="${PIPESTATUS[0]}" - else - "${unbuffercommand[@]}" "${steamcmdcommandarray[@]}" +force_install_dir "${serverfiles}" +login "${steamuser}" "${steampass}" +app_update "${appid}" "${validateparam[@]}" +quit | fn_dl_steamcmd_output | tee -a "${lgsmlog}" "${steamcmdlog}" - exitcode="${PIPESTATUS[0]}" + if [ -z "${baseappid}" ] || [ "${exitcode}" -eq 0 ]; then + if [ -n "${branch}" ] && [ -n "${betapassword}" ]; then + "${unbuffercommand[@]}" "${steamcmdcommandarray[@]}" +force_install_dir "${serverfiles}" +login "${steamuser}" "${steampass}" +app_update "${appid}" -beta "${branch}" -betapassword "${betapassword}" "${validateparam[@]}" +quit | fn_dl_steamcmd_output | tee -a "${lgsmlog}" "${steamcmdlog}" + exitcode="${PIPESTATUS[0]}" + elif [ -n "${branch}" ]; then + "${unbuffercommand[@]}" "${steamcmdcommandarray[@]}" +force_install_dir "${serverfiles}" +login "${steamuser}" "${steampass}" +app_update "${appid}" -beta "${branch}" "${validateparam[@]}" +quit | fn_dl_steamcmd_output | tee -a "${lgsmlog}" "${steamcmdlog}" + exitcode="${PIPESTATUS[0]}" + else + "${unbuffercommand[@]}" "${steamcmdcommandarray[@]}" +force_install_dir "${serverfiles}" +login "${steamuser}" "${steampass}" +app_update "${appid}" "${validateparam[@]}" +quit | fn_dl_steamcmd_output | tee -a "${lgsmlog}" "${steamcmdlog}" + exitcode="${PIPESTATUS[0]}" + fi fi fi # Error checking for SteamCMD. Some errors will loop to try again and some will just exit. - # Check also if we have more errors than retries to be sure that we do not loop to many times and error out. - if [ -n "$(grep -i "Error!" "${steamcmdlog}" | tail -1)" ] && [ "$(grep -ic "Error!" "${steamcmdlog}")" -ge "${counter}" ]; then + if grep -qi "Error!" "${steamcmdlog}"; then # Not enough space. if [ -n "$(grep "0x202" "${steamcmdlog}" | tail -1)" ]; then fn_print_failure_nl "${commandaction} ${selfname}: ${remotelocation}: Not enough disk space to download server files" diff --git a/lgsm/modules/core_exit.sh b/lgsm/modules/core_exit.sh index 274c847d7c..9e92a1a3c1 100755 --- a/lgsm/modules/core_exit.sh +++ b/lgsm/modules/core_exit.sh @@ -27,6 +27,10 @@ if [ "$(whoami)" == "root" ]; then find "${logdir}"/ -group root -prune -exec rm -rf {} + > /dev/null 2>&1 fi +if [ -z "${exitbypass}" ] && [ "${updatelocklevel}" == "${BASH_SUBSHELL}" ] && [ "$(cat "${lockdir}/updating.lock" 2> /dev/null)" == "$$" ]; then + rm -f "${lockdir:?}/updating.lock" +fi + if [ "${exitbypass}" ]; then unset exitbypass elif [ "${exitcode}" -ne 0 ]; then diff --git a/lgsm/modules/core_modules.sh b/lgsm/modules/core_modules.sh index b1d2da0142..520e3f4c24 100755 --- a/lgsm/modules/core_modules.sh +++ b/lgsm/modules/core_modules.sh @@ -278,6 +278,11 @@ check_tmuxception.sh() { fn_fetch_module } +check_update_lock.sh() { + modulefile="${FUNCNAME[0]}" + fn_fetch_module +} + check_version.sh() { modulefile="${FUNCNAME[0]}" fn_fetch_module From eeb6c9a7e5b8a136ca34b1d67b0299e0a1389528 Mon Sep 17 00:00:00 2001 From: Daniel Gibbs Date: Sun, 1 Nov 2026 11:03:37 +0000 Subject: [PATCH 148/164] fix(ct): keep Craftopia saves inside serverfiles (#5131) Craftopia joins its install folder and the relative savePath from ServerSetting.ini with no separator, so saves went to serverfilesDedicatedServerSave beside serverfiles. A new pre-start fix (fix_ct.sh) moves an existing stray save folder into serverfiles and sets savePath to the absolute path. If saves exist in both places it warns and changes nothing, and an absolute savePath set by the owner is left alone. Fixes #5130 --- lgsm/modules/core_modules.sh | 5 +++++ lgsm/modules/fix.sh | 2 +- lgsm/modules/fix_ct.sh | 37 ++++++++++++++++++++++++++++++++++++ 3 files changed, 43 insertions(+), 1 deletion(-) create mode 100755 lgsm/modules/fix_ct.sh diff --git a/lgsm/modules/core_modules.sh b/lgsm/modules/core_modules.sh index 520e3f4c24..ce10c0472b 100755 --- a/lgsm/modules/core_modules.sh +++ b/lgsm/modules/core_modules.sh @@ -433,6 +433,11 @@ fix_csgo.sh() { fn_fetch_module } +fix_ct.sh() { + modulefile="${FUNCNAME[0]}" + fn_fetch_module +} + fix_dst.sh() { modulefile="${FUNCNAME[0]}" fn_fetch_module diff --git a/lgsm/modules/fix.sh b/lgsm/modules/fix.sh index 9d6787314d..d17ef3f597 100755 --- a/lgsm/modules/fix.sh +++ b/lgsm/modules/fix.sh @@ -53,7 +53,7 @@ fn_apply_fix() { fi } -apply_pre_start_fix=(arma3 armar ark av bf1942 bfv bt bo csgo cmw cod cod2 coduo dst hw ins ios kf nd nmrih onset pvr ro rust rw samp sdtd sfc sm sof2 squad st tf2 terraria ts3 mcb mohaa mta unt vh wurm xnt zmr) +apply_pre_start_fix=(arma3 armar ark av bf1942 bfv bt bo csgo cmw cod cod2 coduo ct dst hw ins ios kf nd nmrih onset pvr ro rust rw samp sdtd sfc sm sof2 squad st tf2 terraria ts3 mcb mohaa mta unt vh wurm xnt zmr) apply_post_install_fix=(av kf kf2 nd ro ut2k4 ut ut3) # validate registered fixes for safe development diff --git a/lgsm/modules/fix_ct.sh b/lgsm/modules/fix_ct.sh new file mode 100755 index 0000000000..b5c816b434 --- /dev/null +++ b/lgsm/modules/fix_ct.sh @@ -0,0 +1,37 @@ +#!/bin/bash +# LinuxGSM fix_ct.sh module +# Author: Daniel Gibbs +# Contributors: https://linuxgsm.com/contrib +# Website: https://linuxgsm.com +# Description: Resolves issues with Craftopia. + +moduleselfname="$(basename "$(readlink -f "${BASH_SOURCE[0]}")")" + +if [ -f "${servercfgfullpath}" ]; then + savepath="$(sed -n 's/^savePath=//p' "${servercfgfullpath}" | tr -d '\r')" + if [ -n "${savepath}" ] && [ "${savepath:0:1}" != "/" ]; then + oldsavedir="${serverfiles}${savepath%/}" + newsavedir="${serverfiles}/${savepath%/}" + if [ -e "${oldsavedir}" ] && [ -e "${newsavedir}" ]; then + fn_print_warn_nl "Craftopia saves found in both ${oldsavedir} and ${newsavedir}" + fn_script_log_warn "Craftopia saves found in both ${oldsavedir} and ${newsavedir}" + echo -e "* Keep the one you want in ${newsavedir}, remove the other, then start again." + else + if [ -e "${oldsavedir}" ]; then + fixname="move saves to ${newsavedir}" + fn_fix_msg_start + mkdir -p "$(dirname "${newsavedir}")" + mv "${oldsavedir}" "${newsavedir}" + exitcode=$? + fn_fix_msg_end + fi + if [ ! -e "${oldsavedir}" ]; then + fixname="savePath ${serverfiles}/${savepath}" + fn_fix_msg_start + sed -i "s|^savePath=[^\r]*|savePath=${serverfiles}/${savepath}|" "${servercfgfullpath}" + exitcode=$? + fn_fix_msg_end + fi + fi + fi +fi From 41e09301099df1704a1bd002dc3ce157e56cd760 Mon Sep 17 00:00:00 2001 From: Daniel Gibbs Date: Sun, 1 Nov 2026 11:07:52 +0000 Subject: [PATCH 149/164] fix(backup): include game data kept outside rootdir (#5129) backup only archived rootdir, so game data kept under the home directory was left out whenever rootdir is not the home directory, as in the Docker images. backup now adds, when outside rootdir and not reached through a symlink in it: savedir and servercfgdir for any game, plus the data folders of Project Zomboid, Don't Starve Together, 7 Days to Die, Craftopia, SCP:SL and Barotrauma. Caches and logs are left out. The previous-backup exclusion is also matched by its path under rootdir, so a symlinked backup directory is not archived into the next backup, and the exclusion check no longer prints a spurious failure when backup stops a running server. Fixes #3300 --- lgsm/modules/command_backup.sh | 55 ++++++++++++++++++++++++++++++++-- 1 file changed, 52 insertions(+), 3 deletions(-) diff --git a/lgsm/modules/command_backup.sh b/lgsm/modules/command_backup.sh index 91c34fbd06..28dedb6984 100755 --- a/lgsm/modules/command_backup.sh +++ b/lgsm/modules/command_backup.sh @@ -135,8 +135,52 @@ fn_select_compression() { fi } +# Game data kept outside rootdir, such as worlds saved under the home directory. +fn_backup_extradirs() { + local candidates=() + local covered=() dir dirreal link coveredpath + backupextradirs=() + if [ "${shortname}" == "bt" ]; then + candidates+=("${XDG_DATA_HOME:-${HOME}/.local/share}/Daedalic Entertainment GmbH/Barotrauma") + elif [ "${shortname}" == "ct" ]; then + candidates+=("${serverfiles}DedicatedServerSave") + elif [ "${shortname}" == "dst" ]; then + candidates+=("${persistentstorageroot}") + elif [ "${shortname}" == "pz" ]; then + candidates+=("${HOME}/Zomboid") + elif [ "${shortname}" == "scpsl" ]; then + candidates+=("${HOME}/.config/SCP Secret Laboratory/config") + elif [ "${shortname}" == "sdtd" ]; then + candidates+=("${HOME}/.local/share/7DaysToDie/Saves") + fi + candidates+=("${savedir}" "${servercfgdir}") + covered+=("$(readlink -f "${rootdir}")") + while IFS= read -r link; do + covered+=("$(readlink -f "${link}")") + done < <(find "${rootdir}" -maxdepth 2 -type l 2> /dev/null) + for dir in "${candidates[@]}"; do + if [ -z "${dir}" ] || [ ! -d "${dir}" ]; then + continue + fi + dirreal="$(readlink -f "${dir}")" + for coveredpath in "${covered[@]}" "${backupextradirs[@]}"; do + if [[ "${dirreal}/" == "${coveredpath}/"* ]]; then + continue 2 + fi + done + backupextradirs+=("${dirreal}") + done +} + # Compressing files. fn_backup_compression() { + fn_backup_extradirs + backupextras=() + for extradir in "${backupextradirs[@]}"; do + echo -e "* Including ${extradir}" + fn_script_log_info "Including ${extradir}" + backupextras+=(-C / "${extradir#/}") + done fn_print_info "A total of ${rootdirduexbackup} will be compressed." fn_script_log_info "A total of ${rootdirduexbackup} will be compressed: ${backupdir}/${backupname}.${compressext}" @@ -144,16 +188,21 @@ fn_backup_compression() { fn_script_log_info "Backup ${rootdirduexbackup} ${backupname}.${compressext}, in progress" excludedir=$(fn_backup_relpath) - if [ ! -d "${excludedir}" ]; then + if [ ! -d "${rootdir}/${excludedir}" ]; then fn_print_fail_nl "Problem identifying the previous backup directory for exclusion." fn_script_log_fail "Problem identifying the previous backup directory for exclusion" core_exit.sh fi + backupexcludes=(--exclude "${excludedir}" --exclude "${lockdir}" --exclude "${tmpdir}") + if [[ "${backupdir}" == "${rootdir}/"* ]]; then + backupexcludes+=(--exclude "./${backupdir#"${rootdir}"/}") + fi + if [ -n "${compressflag}" ]; then - tar ${compressflag} -hcf "${backupdir}/${backupname}.${compressext}" -C "${rootdir}" --exclude "${excludedir}" --exclude "${lockdir}" --exclude "${tmpdir}" ./. + tar ${compressflag} -hcf "${backupdir}/${backupname}.${compressext}" "${backupexcludes[@]}" -C "${rootdir}" ./. "${backupextras[@]}" else - tar -hcf "${backupdir}/${backupname}.${compressext}" -C "${rootdir}" --exclude "${excludedir}" --exclude "${lockdir}" --exclude "${tmpdir}" ./. + tar -hcf "${backupdir}/${backupname}.${compressext}" "${backupexcludes[@]}" -C "${rootdir}" ./. "${backupextras[@]}" fi exitcode=$? From 05c883eec732a7729a9388dca45887134d8f356b Mon Sep 17 00:00:00 2001 From: Daniel Gibbs Date: Sun, 1 Nov 2026 13:03:46 +0000 Subject: [PATCH 150/164] feat(ci): fill assignee, outcome, type and milestone on closed issues (#5136) Closed issues are rarely given their sidebar fields: since 2024, 250 of 268 completed issues have no assignee, 258 no outcome label and 100 no milestone. Add a workflow that fills only missing values when an issue closes, after Release Issues completes (its GITHUB_TOKEN closes fire no issues events), and as a dry-run-by-default backfill: - assignee dgibbs64 - outcome label from the close reason (completed, duplicate) - issue type from the type: label - milestone from the merged closing PR, else the first release whose tag contains the merge commit; left unset when none does --- .../workflows/action-issue-close-fields.yml | 199 ++++++++++++++++++ 1 file changed, 199 insertions(+) create mode 100644 .github/workflows/action-issue-close-fields.yml diff --git a/.github/workflows/action-issue-close-fields.yml b/.github/workflows/action-issue-close-fields.yml new file mode 100644 index 0000000000..dfab412298 --- /dev/null +++ b/.github/workflows/action-issue-close-fields.yml @@ -0,0 +1,199 @@ +name: Issue Close Fields +on: + issues: + types: + - closed + workflow_run: + workflows: + - Release Issues + types: + - completed + # checkov:skip=CKV_GHA_7:Inputs only select which closed issues a backfill run touches; nothing is built. + workflow_dispatch: + inputs: + dry_run: + description: List the changes without writing them + required: true + default: "true" + type: choice + options: + - "true" + - "false" + closed_since: + description: Only issues closed on or after this date (YYYY-MM-DD, blank = all) + required: false + default: "" + type: string + limit: + description: Max issues to change (0 = no limit) + required: true + default: "200" + type: string + +permissions: + issues: write + pull-requests: read + contents: read + +concurrency: + group: issue-close-fields-${{ github.event.issue.number || github.run_id }} + +jobs: + issue-close-fields: + if: github.repository_owner == 'GameServerManagers' && (github.event_name != 'workflow_run' || github.event.workflow_run.conclusion == 'success') + runs-on: ubuntu-latest + steps: + - name: Fill assignee, outcome, type and milestone on closed issues + uses: actions/github-script@v9 + env: + DEFAULT_ASSIGNEE: dgibbs64 + DRY_RUN: ${{ inputs.dry_run || 'false' }} + CLOSED_SINCE: ${{ inputs.closed_since }} + LIMIT: ${{ inputs.limit || '0' }} + with: + script: | + const { owner, repo } = context.repo; + const dryRun = process.env.DRY_RUN === 'true'; + const limit = Number.parseInt(process.env.LIMIT || '0', 10) || 0; + const outcomeByReason = { + completed: 'outcome: issue resolved', + duplicate: 'outcome: duplicate', + }; + const issueTypeByLabel = { + 'type: bug': 'Bug', + 'type: feature': 'Feature', + 'type: game server request': 'Server Request', + 'type: docs': 'Task', + }; + + let milestoneByTitle = null; + let releases = null; + async function loadReleaseData() { + if (releases) return; + const milestones = await github.paginate(github.rest.issues.listMilestones, { owner, repo, state: 'all', per_page: 100 }); + milestoneByTitle = new Map(milestones.map((m) => [m.title, m])); + releases = (await github.paginate(github.rest.repos.listReleases, { owner, repo, per_page: 100 })) + .filter((r) => !r.draft && !r.prerelease && r.published_at) + .sort((a, b) => new Date(a.published_at) - new Date(b.published_at)); + } + + async function releaseMilestoneFor(sha, mergedAt) { + await loadReleaseData(); + for (const release of releases) { + if (new Date(release.published_at) < new Date(mergedAt)) continue; + const { data } = await github.rest.repos.compareCommits({ owner, repo, base: release.tag_name, head: sha, per_page: 1 }); + if (data.status !== 'behind' && data.status !== 'identical') continue; + const minor = release.tag_name.match(/^v(\d+)\.(\d+)\./); + return milestoneByTitle.get(release.tag_name) || (minor && milestoneByTitle.get(`v${minor[1]}.${minor[2]}.0`)) || null; + } + return null; + } + + async function milestoneFor(issueNumber) { + const data = await github.graphql( + `query($owner:String!,$repo:String!,$number:Int!){ + repository(owner:$owner,name:$repo){ + issue(number:$number){ + closedByPullRequestsReferences(first:10,includeClosedPrs:true){ + nodes { number merged mergedAt mergeCommit { oid } milestone { number title } } + } + } + } + }`, + { owner, repo, number: issueNumber } + ); + const prs = (data.repository?.issue?.closedByPullRequestsReferences?.nodes || []) + .filter((pr) => pr.merged && pr.mergeCommit?.oid) + .sort((a, b) => new Date(a.mergedAt) - new Date(b.mergedAt)); + if (prs.length === 0) return null; + const chosen = prs.find((pr) => pr.milestone); + if (chosen) return { number: chosen.milestone.number, title: chosen.milestone.title, source: `#${chosen.number}` }; + const released = await releaseMilestoneFor(prs[0].mergeCommit.oid, prs[0].mergedAt); + return released ? { number: released.number, title: released.title, source: `#${prs[0].number} release` } : null; + } + + async function planChanges(issue) { + const labels = (issue.labels || []).map((l) => (typeof l === 'string' ? l : l.name)); + const changes = {}; + if ((issue.assignees || []).length === 0) changes.assignee = process.env.DEFAULT_ASSIGNEE; + const outcome = outcomeByReason[issue.state_reason]; + if (outcome && !labels.some((l) => l.startsWith('outcome: '))) changes.label = outcome; + const typeLabel = labels.find((l) => issueTypeByLabel[l]); + if (!issue.type && typeLabel) changes.type = issueTypeByLabel[typeLabel]; + if (issue.state_reason === 'completed' && !issue.milestone) { + const milestone = await milestoneFor(issue.number); + if (milestone) changes.milestone = milestone; + } + return changes; + } + + async function applyChanges(issueNumber, changes) { + if (changes.assignee) { + await github.rest.issues.addAssignees({ owner, repo, issue_number: issueNumber, assignees: [changes.assignee] }); + } + if (changes.label) { + await github.rest.issues.addLabels({ owner, repo, issue_number: issueNumber, labels: [changes.label] }); + } + const update = {}; + if (changes.type) update.type = changes.type; + if (changes.milestone) update.milestone = changes.milestone.number; + if (Object.keys(update).length > 0) { + await github.rest.issues.update({ owner, repo, issue_number: issueNumber, ...update }); + } + } + + function describe(changes) { + const parts = []; + if (changes.assignee) parts.push(`assignee ${changes.assignee}`); + if (changes.label) parts.push(`label "${changes.label}"`); + if (changes.type) parts.push(`type ${changes.type}`); + if (changes.milestone) parts.push(`milestone ${changes.milestone.title} (from ${changes.milestone.source})`); + return parts.join(', '); + } + + let issues; + if (context.eventName === 'issues') { + issues = [context.payload.issue]; + } else { + const sinceInput = context.eventName === 'workflow_run' + ? new Date(Date.now() - 2 * 24 * 60 * 60 * 1000) + : (process.env.CLOSED_SINCE ? new Date(`${process.env.CLOSED_SINCE}T00:00:00Z`) : null); + const listParams = { owner, repo, state: 'closed', sort: 'updated', direction: 'desc', per_page: 100 }; + if (sinceInput) listParams.since = sinceInput.toISOString(); + issues = (await github.paginate(github.rest.issues.listForRepo, listParams)) + .filter((issue) => !issue.pull_request) + .filter((issue) => !sinceInput || new Date(issue.closed_at) >= sinceInput) + .sort((a, b) => new Date(b.closed_at) - new Date(a.closed_at)); + } + + const rows = []; + const failures = []; + let changed = 0; + for (const issue of issues) { + if (limit > 0 && changed >= limit) break; + try { + const changes = await planChanges(issue); + if (Object.keys(changes).length === 0) continue; + if (!dryRun) await applyChanges(issue.number, changes); + changed += 1; + rows.push([`#${issue.number}`, issue.state_reason || '', describe(changes)]); + core.info(`${dryRun ? 'Would set' : 'Set'} #${issue.number}: ${describe(changes)}`); + } catch (err) { + failures.push(`#${issue.number}: ${err.message}`); + core.warning(`#${issue.number}: ${err.message}`); + if (err.status === 403 || err.status === 429) { + core.warning('Rate limited, stopping. Re-run to continue: done issues are skipped.'); + break; + } + } + } + + await core.summary + .addHeading(`Issue close fields (${dryRun ? 'dry run' : 'applied'})`) + .addRaw(`Checked ${issues.length} closed issue(s), ${changed} needed changes.\n\n`) + .addTable([ + [{ data: 'Issue', header: true }, { data: 'Close reason', header: true }, { data: 'Changes', header: true }], + ...rows, + ]) + .addRaw(failures.length > 0 ? `\nFailures:\n\n${failures.map((f) => `- ${f}`).join('\n')}\n` : '') + .write(); From 68a78a6742525728d39ac2549ab9d3820cd44cad Mon Sep 17 00:00:00 2001 From: Daniel Gibbs Date: Sun, 1 Nov 2026 13:03:46 +0000 Subject: [PATCH 151/164] feat(ci): fill assignee, outcome, type and milestone on closed issues (#5136) Closed issues are rarely given their sidebar fields: since 2024, 250 of 268 completed issues have no assignee, 258 no outcome label and 100 no milestone. Add a workflow that fills only missing values when an issue closes, after Release Issues completes (its GITHUB_TOKEN closes fire no issues events), and as a dry-run-by-default backfill: - assignee dgibbs64 - outcome label from the close reason (completed, duplicate) - issue type from the type: label - milestone from the merged closing PR, else the first release whose tag contains the merge commit; left unset when none does --- .../workflows/action-issue-close-fields.yml | 199 ++++++++++++++++++ 1 file changed, 199 insertions(+) create mode 100644 .github/workflows/action-issue-close-fields.yml diff --git a/.github/workflows/action-issue-close-fields.yml b/.github/workflows/action-issue-close-fields.yml new file mode 100644 index 0000000000..dfab412298 --- /dev/null +++ b/.github/workflows/action-issue-close-fields.yml @@ -0,0 +1,199 @@ +name: Issue Close Fields +on: + issues: + types: + - closed + workflow_run: + workflows: + - Release Issues + types: + - completed + # checkov:skip=CKV_GHA_7:Inputs only select which closed issues a backfill run touches; nothing is built. + workflow_dispatch: + inputs: + dry_run: + description: List the changes without writing them + required: true + default: "true" + type: choice + options: + - "true" + - "false" + closed_since: + description: Only issues closed on or after this date (YYYY-MM-DD, blank = all) + required: false + default: "" + type: string + limit: + description: Max issues to change (0 = no limit) + required: true + default: "200" + type: string + +permissions: + issues: write + pull-requests: read + contents: read + +concurrency: + group: issue-close-fields-${{ github.event.issue.number || github.run_id }} + +jobs: + issue-close-fields: + if: github.repository_owner == 'GameServerManagers' && (github.event_name != 'workflow_run' || github.event.workflow_run.conclusion == 'success') + runs-on: ubuntu-latest + steps: + - name: Fill assignee, outcome, type and milestone on closed issues + uses: actions/github-script@v9 + env: + DEFAULT_ASSIGNEE: dgibbs64 + DRY_RUN: ${{ inputs.dry_run || 'false' }} + CLOSED_SINCE: ${{ inputs.closed_since }} + LIMIT: ${{ inputs.limit || '0' }} + with: + script: | + const { owner, repo } = context.repo; + const dryRun = process.env.DRY_RUN === 'true'; + const limit = Number.parseInt(process.env.LIMIT || '0', 10) || 0; + const outcomeByReason = { + completed: 'outcome: issue resolved', + duplicate: 'outcome: duplicate', + }; + const issueTypeByLabel = { + 'type: bug': 'Bug', + 'type: feature': 'Feature', + 'type: game server request': 'Server Request', + 'type: docs': 'Task', + }; + + let milestoneByTitle = null; + let releases = null; + async function loadReleaseData() { + if (releases) return; + const milestones = await github.paginate(github.rest.issues.listMilestones, { owner, repo, state: 'all', per_page: 100 }); + milestoneByTitle = new Map(milestones.map((m) => [m.title, m])); + releases = (await github.paginate(github.rest.repos.listReleases, { owner, repo, per_page: 100 })) + .filter((r) => !r.draft && !r.prerelease && r.published_at) + .sort((a, b) => new Date(a.published_at) - new Date(b.published_at)); + } + + async function releaseMilestoneFor(sha, mergedAt) { + await loadReleaseData(); + for (const release of releases) { + if (new Date(release.published_at) < new Date(mergedAt)) continue; + const { data } = await github.rest.repos.compareCommits({ owner, repo, base: release.tag_name, head: sha, per_page: 1 }); + if (data.status !== 'behind' && data.status !== 'identical') continue; + const minor = release.tag_name.match(/^v(\d+)\.(\d+)\./); + return milestoneByTitle.get(release.tag_name) || (minor && milestoneByTitle.get(`v${minor[1]}.${minor[2]}.0`)) || null; + } + return null; + } + + async function milestoneFor(issueNumber) { + const data = await github.graphql( + `query($owner:String!,$repo:String!,$number:Int!){ + repository(owner:$owner,name:$repo){ + issue(number:$number){ + closedByPullRequestsReferences(first:10,includeClosedPrs:true){ + nodes { number merged mergedAt mergeCommit { oid } milestone { number title } } + } + } + } + }`, + { owner, repo, number: issueNumber } + ); + const prs = (data.repository?.issue?.closedByPullRequestsReferences?.nodes || []) + .filter((pr) => pr.merged && pr.mergeCommit?.oid) + .sort((a, b) => new Date(a.mergedAt) - new Date(b.mergedAt)); + if (prs.length === 0) return null; + const chosen = prs.find((pr) => pr.milestone); + if (chosen) return { number: chosen.milestone.number, title: chosen.milestone.title, source: `#${chosen.number}` }; + const released = await releaseMilestoneFor(prs[0].mergeCommit.oid, prs[0].mergedAt); + return released ? { number: released.number, title: released.title, source: `#${prs[0].number} release` } : null; + } + + async function planChanges(issue) { + const labels = (issue.labels || []).map((l) => (typeof l === 'string' ? l : l.name)); + const changes = {}; + if ((issue.assignees || []).length === 0) changes.assignee = process.env.DEFAULT_ASSIGNEE; + const outcome = outcomeByReason[issue.state_reason]; + if (outcome && !labels.some((l) => l.startsWith('outcome: '))) changes.label = outcome; + const typeLabel = labels.find((l) => issueTypeByLabel[l]); + if (!issue.type && typeLabel) changes.type = issueTypeByLabel[typeLabel]; + if (issue.state_reason === 'completed' && !issue.milestone) { + const milestone = await milestoneFor(issue.number); + if (milestone) changes.milestone = milestone; + } + return changes; + } + + async function applyChanges(issueNumber, changes) { + if (changes.assignee) { + await github.rest.issues.addAssignees({ owner, repo, issue_number: issueNumber, assignees: [changes.assignee] }); + } + if (changes.label) { + await github.rest.issues.addLabels({ owner, repo, issue_number: issueNumber, labels: [changes.label] }); + } + const update = {}; + if (changes.type) update.type = changes.type; + if (changes.milestone) update.milestone = changes.milestone.number; + if (Object.keys(update).length > 0) { + await github.rest.issues.update({ owner, repo, issue_number: issueNumber, ...update }); + } + } + + function describe(changes) { + const parts = []; + if (changes.assignee) parts.push(`assignee ${changes.assignee}`); + if (changes.label) parts.push(`label "${changes.label}"`); + if (changes.type) parts.push(`type ${changes.type}`); + if (changes.milestone) parts.push(`milestone ${changes.milestone.title} (from ${changes.milestone.source})`); + return parts.join(', '); + } + + let issues; + if (context.eventName === 'issues') { + issues = [context.payload.issue]; + } else { + const sinceInput = context.eventName === 'workflow_run' + ? new Date(Date.now() - 2 * 24 * 60 * 60 * 1000) + : (process.env.CLOSED_SINCE ? new Date(`${process.env.CLOSED_SINCE}T00:00:00Z`) : null); + const listParams = { owner, repo, state: 'closed', sort: 'updated', direction: 'desc', per_page: 100 }; + if (sinceInput) listParams.since = sinceInput.toISOString(); + issues = (await github.paginate(github.rest.issues.listForRepo, listParams)) + .filter((issue) => !issue.pull_request) + .filter((issue) => !sinceInput || new Date(issue.closed_at) >= sinceInput) + .sort((a, b) => new Date(b.closed_at) - new Date(a.closed_at)); + } + + const rows = []; + const failures = []; + let changed = 0; + for (const issue of issues) { + if (limit > 0 && changed >= limit) break; + try { + const changes = await planChanges(issue); + if (Object.keys(changes).length === 0) continue; + if (!dryRun) await applyChanges(issue.number, changes); + changed += 1; + rows.push([`#${issue.number}`, issue.state_reason || '', describe(changes)]); + core.info(`${dryRun ? 'Would set' : 'Set'} #${issue.number}: ${describe(changes)}`); + } catch (err) { + failures.push(`#${issue.number}: ${err.message}`); + core.warning(`#${issue.number}: ${err.message}`); + if (err.status === 403 || err.status === 429) { + core.warning('Rate limited, stopping. Re-run to continue: done issues are skipped.'); + break; + } + } + } + + await core.summary + .addHeading(`Issue close fields (${dryRun ? 'dry run' : 'applied'})`) + .addRaw(`Checked ${issues.length} closed issue(s), ${changed} needed changes.\n\n`) + .addTable([ + [{ data: 'Issue', header: true }, { data: 'Close reason', header: true }, { data: 'Changes', header: true }], + ...rows, + ]) + .addRaw(failures.length > 0 ? `\nFailures:\n\n${failures.map((f) => `- ${f}`).join('\n')}\n` : '') + .write(); From a3e0960eca0905928395168bf37a2608f8f32a17 Mon Sep 17 00:00:00 2001 From: Daniel Gibbs Date: Sun, 1 Nov 2026 20:54:03 +0000 Subject: [PATCH 152/164] feat(ci): fail PR Body Check when a Fixes issue is not linked in Development (#5139) Closing keywords never create a Development link on pull requests into develop, so the link has to be added by hand and was often missed. The check now compares the issues named after Fixes, Closes or Resolves with the pull request's closingIssuesReferences and fails on any issue that is not linked. Related to and no-issue pull requests still only warn. --- .github/workflows/action-pr-body-check.yml | 39 ++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/.github/workflows/action-pr-body-check.yml b/.github/workflows/action-pr-body-check.yml index af5b8ddf3d..bb4475b015 100755 --- a/.github/workflows/action-pr-body-check.yml +++ b/.github/workflows/action-pr-body-check.yml @@ -11,6 +11,8 @@ on: permissions: contents: read + issues: read + pull-requests: read jobs: pr-body-check: @@ -39,6 +41,43 @@ jobs: core.warning('No closing keyword found. Add "Fixes #123" to link the issue, or "Related to #123" if this pull request does not fully resolve it.'); } + const repoName = `${context.repo.owner}/${context.repo.repo}`.toLowerCase(); + const closingRefs = [...body.matchAll(/\b(?:close[sd]?|fix(?:e[sd])?|resolve[sd]?):?\s+([\w.-]+\/[\w.-]+)?#(\d+)/gi)] + .filter((m) => !m[1] || m[1].toLowerCase() === repoName) + .map((m) => Number(m[2])); + const wanted = [...new Set(closingRefs)]; + if (wanted.length > 0) { + const vars = { owner: context.repo.owner, repo: context.repo.repo }; + const { repository } = await github.graphql( + `query($owner: String!, $repo: String!, $number: Int!) { + repository(owner: $owner, name: $repo) { + pullRequest(number: $number) { closingIssuesReferences(first: 50) { nodes { number } } } + } + }`, + { ...vars, number: context.payload.pull_request.number } + ); + const linked = new Set(repository.pullRequest.closingIssuesReferences.nodes.map((n) => n.number)); + const unlinked = []; + for (const number of wanted.filter((n) => !linked.has(n))) { + try { + const { repository: ref } = await github.graphql( + `query($owner: String!, $repo: String!, $number: Int!) { + repository(owner: $owner, name: $repo) { issueOrPullRequest(number: $number) { __typename } } + }`, + { ...vars, number } + ); + if (ref.issueOrPullRequest?.__typename === 'Issue') { + unlinked.push(`#${number}`); + } + } catch (error) { + core.warning(`Could not look up #${number}: ${error.message}`); + } + } + if (unlinked.length > 0) { + errors.push(`Not linked in Development: ${unlinked.join(', ')}. Closing keywords in pull requests to develop do not link issues. Select each issue in the Development section of this pull request's sidebar, then re-run this check.`); + } + } + if (errors.length > 0) { core.setFailed(errors.join('\n')); } From 7200565cf924f51ba1b379744ae9008c54d40ba5 Mon Sep 17 00:00:00 2001 From: Daniel Gibbs Date: Tue, 3 Nov 2026 20:47:42 +0000 Subject: [PATCH 153/164] fix(zmr): install the previous2021 Source SDK 2013 build (#5147) The public branch of Source SDK Base 2013 Dedicated Server (244310) is now the 2025 SDK update, which Zombie Master: Reborn b6.1 does not run on: the server falls back to LAN mode and never answers queries. Use the previous2021 branch (build 6982827), the engine ZMR was built for. --- lgsm/config-default/config-lgsm/zmrserver/_default.cfg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lgsm/config-default/config-lgsm/zmrserver/_default.cfg b/lgsm/config-default/config-lgsm/zmrserver/_default.cfg index 3d4e19851f..c9ad34904f 100644 --- a/lgsm/config-default/config-lgsm/zmrserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/zmrserver/_default.cfg @@ -150,7 +150,7 @@ sleeptime="0.5" appid="244310" # Source 2013 SDK steamcmdforcewindows="no" # SteamCMD Branch | https://docs.linuxgsm.com/steamcmd/branch -branch="" +branch="previous2021" betapassword="" # Master Server | https://docs.linuxgsm.com/steamcmd/steam-master-server steammaster="true" From 2eb63e48463c73ca6b03033ec31b03c808c568dd Mon Sep 17 00:00:00 2001 From: Daniel Gibbs Date: Tue, 3 Nov 2026 20:58:34 +0000 Subject: [PATCH 154/164] chore(install): rebuild hosted server archives with normalised ownership, permissions and names (#5146) Point install_server_files.sh at rebuilt copies of 18 archives on linuxgsm.download. Game content and versions are unchanged; the rebuilds only remove files. - Owner and group 0/0, numeric. Several archives were owned by uid 1000. - Directories 0755, files 0644, ELF executables and shebang scripts 0755. Twelve archives were 0777 throughout and the MoHAA archive had 0700 directories and a non-executable mohaa_lnxded. - Windows and macOS only files removed (exe, dll, bat, url, lnk, reg, sys, dylib, Thumbs.db), plus uninstaller leftovers and stray logs. - Client-only content removed: Quake 2 renderers, UT3 Direct3D shader caches, the MoHAA Windows client utilities, the iortcw pb directory, the UT2004 Windows GUI and macOS ucc. - Sorted entries, no ./ prefix, xz -9e. - Named --linux--linuxgsm-YYYYMMDD.tar.xz. This also fixes the cod local_filename, which named 1.5 instead of 1.5b. Repack the libncurses5 i386 library archive used by fix_bf1942 and fix_bfv with the libraries at 0644, as Ubuntu ships them. The library files are byte for byte the same. The original archives stay hosted, so older releases keep working. --- lgsm/modules/fix_bf1942.sh | 4 +- lgsm/modules/fix_bfv.sh | 4 +- lgsm/modules/install_server_files.sh | 108 +++++++++++++-------------- 3 files changed, 58 insertions(+), 58 deletions(-) diff --git a/lgsm/modules/fix_bf1942.sh b/lgsm/modules/fix_bf1942.sh index 918d81a5e4..bce71f39e2 100755 --- a/lgsm/modules/fix_bf1942.sh +++ b/lgsm/modules/fix_bf1942.sh @@ -14,8 +14,8 @@ if ldd "${executabledir}/bf1942_lnxded.static" 2>&1 | grep -qE "lib(ncurses|tinf # shellcheck disable=SC2034 # Used by fn_fix_msg_start_nl and fn_fix_msg_end. fixname="libncurses5 i386" fn_fix_msg_start_nl - fn_fetch_file "https://linuxgsm.download/libraries/libncurses5-i386-6.3-2ubuntu0.3.tar.xz" "" "" "" "${tmpdir}" "libncurses5-i386-6.3-2ubuntu0.3.tar.xz" "nochmodx" "norun" "noforce" "ee141cb3a843e4201786b6f188347666" - fn_dl_extract "${tmpdir}" "libncurses5-i386-6.3-2ubuntu0.3.tar.xz" "${serverfiles}" + fn_fetch_file "https://linuxgsm.download/libraries/libncurses5-i386-6.3-2ubuntu0.3-linuxgsm-20261102.tar.xz" "" "" "" "${tmpdir}" "libncurses5-i386-6.3-2ubuntu0.3-linuxgsm-20261102.tar.xz" "nochmodx" "norun" "noforce" "dd1cc98dd60420ea14345deb6a6beb8a" + fn_dl_extract "${tmpdir}" "libncurses5-i386-6.3-2ubuntu0.3-linuxgsm-20261102.tar.xz" "${serverfiles}" fn_clear_tmp fn_fix_msg_end fi diff --git a/lgsm/modules/fix_bfv.sh b/lgsm/modules/fix_bfv.sh index dbd10082e4..142d7062e1 100755 --- a/lgsm/modules/fix_bfv.sh +++ b/lgsm/modules/fix_bfv.sh @@ -14,8 +14,8 @@ if ldd "${executabledir}/bfv_linded.static" 2>&1 | grep -qE "lib(ncurses|tinfo)\ # shellcheck disable=SC2034 # Used by fn_fix_msg_start_nl and fn_fix_msg_end. fixname="libncurses5 i386" fn_fix_msg_start_nl - fn_fetch_file "https://linuxgsm.download/libraries/libncurses5-i386-6.3-2ubuntu0.3.tar.xz" "" "" "" "${tmpdir}" "libncurses5-i386-6.3-2ubuntu0.3.tar.xz" "nochmodx" "norun" "noforce" "ee141cb3a843e4201786b6f188347666" - fn_dl_extract "${tmpdir}" "libncurses5-i386-6.3-2ubuntu0.3.tar.xz" "${serverfiles}" + fn_fetch_file "https://linuxgsm.download/libraries/libncurses5-i386-6.3-2ubuntu0.3-linuxgsm-20261102.tar.xz" "" "" "" "${tmpdir}" "libncurses5-i386-6.3-2ubuntu0.3-linuxgsm-20261102.tar.xz" "nochmodx" "norun" "noforce" "dd1cc98dd60420ea14345deb6a6beb8a" + fn_dl_extract "${tmpdir}" "libncurses5-i386-6.3-2ubuntu0.3-linuxgsm-20261102.tar.xz" "${serverfiles}" fn_clear_tmp fn_fix_msg_end fi diff --git a/lgsm/modules/install_server_files.sh b/lgsm/modules/install_server_files.sh index 03b7538862..919ff98326 100755 --- a/lgsm/modules/install_server_files.sh +++ b/lgsm/modules/install_server_files.sh @@ -9,13 +9,13 @@ moduleselfname="$(basename "$(readlink -f "${BASH_SOURCE[0]}")")" fn_install_server_files() { if [ "${shortname}" == "ahl" ]; then - remote_fileurl="https://linuxgsm.download/ActionHalfLife/action_halflife-1.0.tar.xz" + remote_fileurl="https://linuxgsm.download/ActionHalfLife/ahl-1.0-linux-i386-linuxgsm-20261102.tar.xz" local_filedir="${tmpdir}" - local_filename="action_halflife-1.0.tar.xz" + local_filename="ahl-1.0-linux-i386-linuxgsm-20261102.tar.xz" chmodx="nochmodx" run="norun" force="noforce" - md5="61d7b79fd714888b6d65944fdaafa94a" + md5="4b502ed86fafd44b9b9dda99ee4cb44f" elif [ "${shortname}" == "bf1942" ]; then remote_fileurl="https://linuxgsm.download/BattleField1942/bf1942_lnxded-1.61-hacked-to-1.612.full-linuxgsm.tar.xz" local_filedir="${tmpdir}" @@ -34,21 +34,21 @@ fn_install_server_files() { md5="9a8117732b8abd99cc59f1f0fa92adfa" elif [ "${shortname}" == "cod" ]; then - remote_fileurl="https://linuxgsm.download/CallOfDuty/cod-lnxded-1.5b-full.tar.xz" + remote_fileurl="https://linuxgsm.download/CallOfDuty/cod-1.5b-linux-i386-linuxgsm-20261102.tar.xz" local_filedir="${tmpdir}" - local_filename="cod-lnxded-1.5-large.tar.xz" + local_filename="cod-1.5b-linux-i386-linuxgsm-20261102.tar.xz" chmodx="nochmodx" run="norun" force="noforce" - md5="ee0ad1ccbfa1fd27fde01a4a431a5c2f" + md5="a588df9db95f64ce5b5065fd94995bc1" elif [ "${shortname}" == "coduo" ]; then - remote_fileurl="https://linuxgsm.download/CallOfDutyUnitedOffensive/coduo-lnxded-1.51b-full.tar.xz" + remote_fileurl="https://linuxgsm.download/CallOfDutyUnitedOffensive/coduo-1.51b-linux-i386-linuxgsm-20261102.tar.xz" local_filedir="${tmpdir}" - local_filename="coduo-lnxded-1.51b-full.tar.xz" + local_filename="coduo-1.51b-linux-i386-linuxgsm-20261102.tar.xz" chmodx="nochmodx" run="norun" force="noforce" - md5="35cabccd67adcda44aaebc59405915b9" + md5="deb2f9a66c9f3c7a23099c31c98242d0" elif [ "${shortname}" == "cod2" ]; then remote_fileurl="https://linuxgsm.download/CallOfDuty2/cod2-lnxded-1.3-full.tar.xz" local_filedir="${tmpdir}" @@ -58,13 +58,13 @@ fn_install_server_files() { force="noforce" md5="b8c4c611f01627dd43348e78478a3d41" elif [ "${shortname}" == "cod4" ]; then - remote_fileurl="https://linuxgsm.download/CallOfDuty4/cod4x18_lnxded.tar.xz" + remote_fileurl="https://linuxgsm.download/CallOfDuty4/cod4x-21.2-linux-i386-linuxgsm-20261102.tar.xz" local_filedir="${tmpdir}" - local_filename="cod4x18_lnxded.tar.xz" + local_filename="cod4x-21.2-linux-i386-linuxgsm-20261102.tar.xz" chmodx="nochmodx" run="norun" force="noforce" - md5="d255b59b9756d7dbead67718208512ee" + md5="7c8d55d12e44f321f31ad1320567659a" elif [ "${shortname}" == "codwaw" ]; then remote_fileurl="https://linuxgsm.download/CallOfDutyWorldAtWar/codwaw-lnxded-1.7-full.tar.xz" local_filedir="${tmpdir}" @@ -74,45 +74,45 @@ fn_install_server_files() { force="noforce" md5="2c6be1bb66ea631b9b2e7ae6216c6680" elif [ "${shortname}" == "cswon" ]; then - remote_fileurl="https://linuxgsm.download/CounterStrikeWON2/hlds_l-3111e-cs15-won2-linuxgsm.tar.xz" + remote_fileurl="https://linuxgsm.download/CounterStrikeWON2/cswon-3111e-cs15-linux-i386-linuxgsm-20261102.tar.xz" local_filedir="${tmpdir}" - local_filename="hlds_l-3111e-cs15-won2-linuxgsm.tar.xz" + local_filename="cswon-3111e-cs15-linux-i386-linuxgsm-20261102.tar.xz" chmodx="nochmodx" run="norun" force="noforce" - md5="8109a66e2e906ff2c309e3a6b412132a" + md5="0be5f9f766e48b8bbd480dfa4a9d9aa0" elif [ "${shortname}" == "hlwon" ]; then - remote_fileurl="https://linuxgsm.download/HalfLifeWON2/hlds_l-3111e-won2-linuxgsm.tar.xz" + remote_fileurl="https://linuxgsm.download/HalfLifeWON2/hlwon-3111e-linux-i386-linuxgsm-20261102.tar.xz" local_filedir="${tmpdir}" - local_filename="hlds_l-3111e-won2-linuxgsm.tar.xz" + local_filename="hlwon-3111e-linux-i386-linuxgsm-20261102.tar.xz" chmodx="nochmodx" run="norun" force="noforce" - md5="83164405c744a5e424814e67eacf27fb" + md5="e64fda09d31f3acc977fb621b5ffd4fd" elif [ "${shortname}" == "mohaa" ]; then - remote_fileurl="https://linuxgsm.download/MedalofHonorAlliedAssault/moh_revival_v1.12_RC3.5.1.tar.xz" + remote_fileurl="https://linuxgsm.download/MedalofHonorAlliedAssault/mohaa-1.12-rc3.5.1-linux-i386-linuxgsm-20261102.tar.xz" local_filedir="${tmpdir}" - local_filename="moh_revival_v1.12_RC3.5.1.tar.xz" + local_filename="mohaa-1.12-rc3.5.1-linux-i386-linuxgsm-20261102.tar.xz" chmodx="nochmodx" run="norun" force="noforce" - md5="7c664538999252eeaf2b6d9949416480" + md5="bf66cbe1f4aefb221e17924e7bf9bdb4" elif [ "${shortname}" == "ns" ]; then - remote_fileurl="https://linuxgsm.download/NaturalSelection/ns_dedicated_server_v32.tar.xz" + remote_fileurl="https://linuxgsm.download/NaturalSelection/ns-3.2-linux-i386-linuxgsm-20261102.tar.xz" local_filedir="${tmpdir}" - local_filename="ns_dedicated_server_v32.tar.xz" + local_filename="ns-3.2-linux-i386-linuxgsm-20261102.tar.xz" chmodx="nochmodx" run="norun" force="noforce" - md5="23ec3cadd93d8bb1c475bad5b9cce370" + md5="a44d9769f9a035b98a4d57a7d7e1f81b" elif [ "${shortname}" == "q2" ]; then - remote_fileurl="https://linuxgsm.download/Quake2/quake2-3.20-glibc-i386-full-linux2.0.tar.xz" + remote_fileurl="https://linuxgsm.download/Quake2/q2-3.20-linux-i386-linuxgsm-20261102.tar.xz" local_filedir="${tmpdir}" - local_filename="quake2-3.20-glibc-i386-full-linux2.0.tar.xz" + local_filename="q2-3.20-linux-i386-linuxgsm-20261102.tar.xz" chmodx="nochmodx" run="norun" force="noforce" - md5="2908164a32d4808bb720f2161f6b0c82" + md5="f0abe39ed649765cd99b7e5e1c62b4f6" elif [ "${shortname}" == "q3" ]; then remote_fileurl="https://linuxgsm.download/Quake3/quake3-1.32c-x86-full-linux.tar.xz" local_filedir="${tmpdir}" @@ -138,21 +138,21 @@ fn_install_server_files() { force="noforce" md5="82055b7d973206c13a606db8ba288d03" elif [ "${shortname}" == "rtcw" ]; then - remote_fileurl="https://linuxgsm.download/ReturnToCastleWolfenstein/iortcw-1.51c-x86_64-server-linux-20190507.tar.xz" + remote_fileurl="https://linuxgsm.download/ReturnToCastleWolfenstein/rtcw-iortcw-1.51c-linux-amd64-linuxgsm-20261102.tar.xz" local_filedir="${tmpdir}" - local_filename="iortcw-1.51c-x86_64-server-linux-20190507.tar.xz" + local_filename="rtcw-iortcw-1.51c-linux-amd64-linuxgsm-20261102.tar.xz" chmodx="nochmodx" run="norun" force="noforce" - md5="df6ff664d37dd0d22787848bdb3cac5f" + md5="6bb410ac0faf9048c2ca8f918b068ed0" elif [ "${shortname}" == "sfc" ]; then - remote_fileurl="https://linuxgsm.download/SourceFortsClassic/SFClassic-1.0-RC7-fix.tar.xz" + remote_fileurl="https://linuxgsm.download/SourceFortsClassic/sfc-1.0-rc7-fix-linux-i386-linuxgsm-20261102.tar.xz" local_filedir="${tmpdir}" - local_filename="SFClassic-1.0-RC7-fix.tar.xz" + local_filename="sfc-1.0-rc7-fix-linux-i386-linuxgsm-20261102.tar.xz" chmodx="nochmodx" run="norun" force="noforce" - md5="70077137185700e28fe6bbb6021d12bc" + md5="a0e3980e944cd321c5f064d752a7431e" elif [ "${shortname}" == "sof2" ]; then remote_fileurl="https://linuxgsm.download/SoldierOfFortune2/sof2gold-1.03.tar.xz" local_filedir="${tmpdir}" @@ -162,53 +162,53 @@ fn_install_server_files() { force="noforce" md5="201e23bab04207d00ce813d001c483d9" elif [ "${shortname}" == "ts" ]; then - remote_fileurl="https://linuxgsm.download/TheSpecialists/ts-3-linux-final.tar.xz" + remote_fileurl="https://linuxgsm.download/TheSpecialists/ts-3.0-linux-i386-linuxgsm-20261102.tar.xz" local_filedir="${tmpdir}" - local_filename="ts-3-linux-final.tar.xz" + local_filename="ts-3.0-linux-i386-linuxgsm-20261102.tar.xz" chmodx="nochmodx" run="norun" force="noforce" - md5="3c66ecff6e3644f7ac88015732a0fb93" + md5="4ff0fdc126ec09c07d6a6f915cb9145f" elif [ "${shortname}" == "ut2k4" ]; then - remote_fileurl="https://linuxgsm.download/UnrealTournament2004/ut2004-server-3369-3-ultimate-linux.tar.xz" + remote_fileurl="https://linuxgsm.download/UnrealTournament2004/ut2k4-3369.3-linux-i386-linuxgsm-20261102.tar.xz" local_filedir="${tmpdir}" - local_filename="ut2004-server-3369-3-ultimate-linux.tar.xz" + local_filename="ut2k4-3369.3-linux-i386-linuxgsm-20261102.tar.xz" chmodx="nochmodx" run="norun" force="noforce" - md5="9fceaab68554749f4b45be66613b9a15" + md5="f0ce6b3d3c7831e1a45e2a436a6aaa3b" elif [ "${shortname}" == "ut99" ]; then - remote_fileurl="https://linuxgsm.download/UnrealTournament99/ut99-server-469b-ultimate-linux.tar.xz" + remote_fileurl="https://linuxgsm.download/UnrealTournament99/ut99-469b-linux-i386-linuxgsm-20261102.tar.xz" local_filedir="${tmpdir}" - local_filename="ut99-server-469b-ultimate-linux.tar.xz" + local_filename="ut99-469b-linux-i386-linuxgsm-20261102.tar.xz" chmodx="nochmodx" run="norun" force="noforce" - md5="dba3f1122a5e60ee45ece7422fcf78f5" + md5="ccb9b0907f2f926204c911c3041df743" elif [ "${shortname}" == "ut" ]; then - remote_fileurl="https://linuxgsm.download/UnrealTournament/UnrealTournament-Server-XAN-3525360-Linux.tar.xz" + remote_fileurl="https://linuxgsm.download/UnrealTournament/ut-xan-3525360-linux-amd64-linuxgsm-20261102.tar.xz" local_filedir="${tmpdir}" - local_filename="UnrealTournament-Server-XAN-3525360-Linux.tar.xz" + local_filename="ut-xan-3525360-linux-amd64-linuxgsm-20261102.tar.xz" chmodx="noexecute" run="norun" force="noforce" - md5="41dd92015713a78211eaccf503b72393" + md5="ffcb25dd03d82489e0cb3d6b9779e818" elif [ "${shortname}" == "ut3" ]; then - remote_fileurl="https://linuxgsm.download/UnrealTournament3/UT3-linux-server-2.1-openspy.tar.xz" + remote_fileurl="https://linuxgsm.download/UnrealTournament3/ut3-2.1-openspy-linux-i386-linuxgsm-20261102.tar.xz" local_filedir="${tmpdir}" - local_filename="UT3-linux-server-2.1-openspy.tar.xz" + local_filename="ut3-2.1-openspy-linux-i386-linuxgsm-20261102.tar.xz" chmodx="nochmodx" run="norun" force="noforce" - md5="f60b745613a8676666eb6a2450cbdc8e" + md5="a1ca829bd56d9a1abd17bf129e2bcb77" elif [ "${shortname}" == "vs" ]; then - remote_fileurl="https://linuxgsm.download/VampireSlayer/vs_l-6.0_full.tar.xz" + remote_fileurl="https://linuxgsm.download/VampireSlayer/vs-6.0-linux-i386-linuxgsm-20261102.tar.xz" local_filedir="${tmpdir}" - local_filename="vs_l-6.0_full.tar.xz" + local_filename="vs-6.0-linux-i386-linuxgsm-20261102.tar.xz" chmodx="nochmodx" run="norun" force="noforce" - md5="b322f79e0abd31847493c52acf802667" + md5="c1f908ab27772d8c6ca8ee731d32ddda" elif [ "${shortname}" == "wet" ]; then remote_fileurl="https://linuxgsm.download/WolfensteinEnemyTerritory/enemy-territory.260b.tar.xz" local_filedir="${tmpdir}" @@ -226,13 +226,13 @@ fn_install_server_files() { force="noforce" md5="93705e165550c97484678236749198a4" elif [ "${shortname}" == "zmr" ]; then - remote_fileurl="https://linuxgsm.download/ZombieMasterReborn/zombie_master_reborn_b6_1.tar.xz" + remote_fileurl="https://linuxgsm.download/ZombieMasterReborn/zmr-b6.1-linux-i386-linuxgsm-20261102.tar.xz" local_filedir="${tmpdir}" - local_filename="zombie_master_reborn_b6_1.tar.xz" + local_filename="zmr-b6.1-linux-i386-linuxgsm-20261102.tar.xz" chmodx="nochmodx" run="norun" force="noforce" - md5="0188ae86dbc9376f11ae3032dba2d665" + md5="f451da013ed386d3081dfcfc390c7723" else fn_print_fail_nl "Installing ${gamename} Server failed, missing default configuration" fn_script_log_fail "Installing ${gamename} Server failed, missing default configuration" From 5e10a815891e1fe8a4d2c6702c4858a17a9f6dce Mon Sep 17 00:00:00 2001 From: Daniel Gibbs Date: Tue, 3 Nov 2026 22:15:19 +0000 Subject: [PATCH 155/164] fix(logs): rotate the game log on start for all servers that set one (#5135) Game log rotation on start only ran for unreal2, so servers that write a single fixed game log (rust, ck, hw, ut3, cmw) overwrote the previous run's log on every start or restart. Rotate whenever the server config defines gamelogdate and the game log file exists. Servers without gamelogdate, or whose games write their own dated logs, are unchanged. Log cleanup only pruned game logs for unreal2 and source. Other servers now prune their rotated -game-*.log files older than logdays. The prune is limited to that name pattern at the top level of gamelogdir, since some servers set gamelogdir to a game directory (stn uses serverfiles). Fixes #4751 --- lgsm/modules/command_start.sh | 2 +- lgsm/modules/core_logs.sh | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/lgsm/modules/command_start.sh b/lgsm/modules/command_start.sh index 255bc29fbf..e8a3ec167b 100755 --- a/lgsm/modules/command_start.sh +++ b/lgsm/modules/command_start.sh @@ -102,7 +102,7 @@ fn_start_tmux() { # Log rotation. fn_script_log_info "Rotating log files" - if [ "${engine}" == "unreal2" ] && [ -f "${gamelog}" ]; then + if [ -n "${gamelogdate}" ] && [ -f "${gamelog}" ]; then mv "${gamelog}" "${gamelogdate}" fi if [ -f "${lgsmlog}" ]; then diff --git a/lgsm/modules/core_logs.sh b/lgsm/modules/core_logs.sh index 7b435b563b..6d8ed5a117 100755 --- a/lgsm/modules/core_logs.sh +++ b/lgsm/modules/core_logs.sh @@ -58,6 +58,11 @@ if [ "$(find "${lgsmlogdir}"/ -type f -mtime +"${logdays}" | wc -l)" -ne "0" ]; find "${gamelogdir}"/ -type f -mtime +"${logdays}" | tee >> "${lgsmlog}" gamecount=$(find "${gamelogdir}"/ -type f -mtime +"${logdays}" | wc -l) find "${gamelogdir}"/ -mtime +"${logdays}" -type f -exec rm -f {} \; + # Rotated game logfiles. + elif [ -n "${gamelogdate}" ] && [ -d "${gamelogdir}" ]; then + find "${gamelogdir}"/ -maxdepth 1 -type f -name "${selfname}-game-*.log" -mtime +"${logdays}" | tee >> "${lgsmlog}" + gamecount=$(find "${gamelogdir}"/ -maxdepth 1 -type f -name "${selfname}-game-*.log" -mtime +"${logdays}" | wc -l) + find "${gamelogdir}"/ -maxdepth 1 -type f -name "${selfname}-game-*.log" -mtime +"${logdays}" -exec rm -f {} \; fi # Console logfiles. if [ "${consolelog}" ]; then From 031da93d283dbdfcd750fab1287dc2add8f158c5 Mon Sep 17 00:00:00 2001 From: Daniel Gibbs Date: Tue, 3 Nov 2026 22:21:35 +0000 Subject: [PATCH 156/164] fix(core): stop download loop on slow connections (#5134) A 3 second connect timeout is too short for slow or high-latency links: DNS, TCP and TLS each need a round trip, so a 1 s RTT already fails. Raise it to 10 seconds in both the bootstrap and core_dl.sh fetchers. When a module download failed, fn_fetch_file called core_exit.sh, which is itself fetched on demand. If core_exit.sh was not yet downloaded, its fetch failed too and called core_exit.sh again, recursing forever between GitHub and Bitbucket. fn_fetch_trap had the same recursion, so CTRL+C could not break out. Exit directly when the file that failed is core_exit.sh itself. Fixes #4857 --- lgsm/modules/core_dl.sh | 8 +++++++- linuxgsm.sh | 2 +- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/lgsm/modules/core_dl.sh b/lgsm/modules/core_dl.sh index 418e8eefb7..92d79dfe50 100755 --- a/lgsm/modules/core_dl.sh +++ b/lgsm/modules/core_dl.sh @@ -372,6 +372,9 @@ fn_fetch_trap() { echo -en "downloading ${local_filename}" fn_print_removed_eol_nl fn_script_log_info "Downloading ${local_filename}...REMOVED" + if [ "${local_filename}" == "core_exit.sh" ]; then + exit 130 + fi core_exit.sh } @@ -486,7 +489,7 @@ fn_fetch_file() { fi # Trap will remove part downloaded files if canceled. trap fn_fetch_trap INT - curlcmd=(curl --connect-timeout 3 --fail -L -o "${local_filedir}/${local_filename}" --retry 2 -A "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.${randomint}.212 Safari/537.36") + curlcmd=(curl --connect-timeout 10 --fail -L -o "${local_filedir}/${local_filename}" --retry 2 -A "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.${randomint}.212 Safari/537.36") if [[ "${fileurl}" == https://* ]]; then curlcmd+=(--proto-redir "=https") fi @@ -527,6 +530,9 @@ fn_fetch_file() { fn_script_log_fail "Downloading ${local_filename}..." fn_script_log_fail "${fileurl}" fi + if [ "${local_filename}" == "core_exit.sh" ]; then + exit 1 + fi core_exit.sh else fn_print_error_eol_nl diff --git a/linuxgsm.sh b/linuxgsm.sh index 83f0ca5a88..cd4681203d 100755 --- a/linuxgsm.sh +++ b/linuxgsm.sh @@ -161,7 +161,7 @@ fn_bootstrap_fetch_file() { fi # Trap will remove part downloaded files if canceled. trap fn_bootstrap_fetch_trap INT - curlcmd=(curl --connect-timeout 3 --fail -L -o "${local_filedir}/${local_filename}" --retry 2 -A "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.${randomint}.212 Safari/537.36") + curlcmd=(curl --connect-timeout 10 --fail -L -o "${local_filedir}/${local_filename}" --retry 2 -A "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.${randomint}.212 Safari/537.36") # if is large file show progress, else be silent local exitcode="" From 97a46c20c615e6127a0aa5c75d83bbfc333e5a9a Mon Sep 17 00:00:00 2001 From: Daniel Gibbs Date: Tue, 3 Nov 2026 22:25:41 +0000 Subject: [PATCH 157/164] feat(punkbuster): ship the last PunkBuster release for every server that supports it (#5148) Rebuild the Battlefield 1942, Battlefield: Vietnam, Call of Duty 2, Call of Duty: World at War, Quake 3, Quake 4, Soldier of Fortune 2 and Wolfenstein: Enemy Territory archives so each has the same PunkBuster layout, using the last PunkBuster release for that game. World at War had no PunkBuster files before. Each pb folder now holds only pbsv.so, the client and agent libraries, the htm client update files, PB_EULA.txt, and pbns.dat where the game has one. The empty dll folder, PunkBuster runtime files and leftover logs, profiles and installers are removed. Every archive is repacked with root ownership. Directories, server binaries and shell scripts are 0755, and every other file, including the .so libraries, is 0644. The Quake 4 and Enemy Territory launcher scripts now change to their own directory instead of a fixed install path. The archives use a new naming format, --linux-i386-linuxgsm-.tar.xz. The old names were the upstream package names. Battlefield 1942 is still the 1.61 server patched to 1.612. The old archives stay on linuxgsm.download, so older releases keep installing. --- lgsm/modules/install_server_files.sh | 48 ++++++++++++++-------------- 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/lgsm/modules/install_server_files.sh b/lgsm/modules/install_server_files.sh index 919ff98326..562e31c53e 100755 --- a/lgsm/modules/install_server_files.sh +++ b/lgsm/modules/install_server_files.sh @@ -17,21 +17,21 @@ fn_install_server_files() { force="noforce" md5="4b502ed86fafd44b9b9dda99ee4cb44f" elif [ "${shortname}" == "bf1942" ]; then - remote_fileurl="https://linuxgsm.download/BattleField1942/bf1942_lnxded-1.61-hacked-to-1.612.full-linuxgsm.tar.xz" + remote_fileurl="https://linuxgsm.download/BattleField1942/bf1942-1.612-linux-i386-linuxgsm-20261101.tar.xz" local_filedir="${tmpdir}" - local_filename="bf1942_lnxded-1.61-hacked-to-1.612.full-linuxgsm.tar.xz" + local_filename="bf1942-1.612-linux-i386-linuxgsm-20261101.tar.xz" chmodx="nochmodx" run="norun" force="noforce" - md5="d58016b3c45f86a71bb56c39749ce941" + md5="0a3ae8721d3b14d81912b01fbfbd5cb2" elif [ "${shortname}" == "bfv" ]; then - remote_fileurl="https://linuxgsm.download/BattlefieldVietnam/bfv_linded-v1.21-20041207_patch-linuxgsm.tar.xz" + remote_fileurl="https://linuxgsm.download/BattlefieldVietnam/bfv-1.21-linux-i386-linuxgsm-20261101.tar.xz" local_filedir="${tmpdir}" - local_filename="bfv_linded-v1.21-20041207_patch-linuxgsm.tar.xz" + local_filename="bfv-1.21-linux-i386-linuxgsm-20261101.tar.xz" chmodx="nochmodx" run="norun" force="noforce" - md5="9a8117732b8abd99cc59f1f0fa92adfa" + md5="532bc18529c7cb86fb41c79ec61c5283" elif [ "${shortname}" == "cod" ]; then remote_fileurl="https://linuxgsm.download/CallOfDuty/cod-1.5b-linux-i386-linuxgsm-20261102.tar.xz" @@ -50,13 +50,13 @@ fn_install_server_files() { force="noforce" md5="deb2f9a66c9f3c7a23099c31c98242d0" elif [ "${shortname}" == "cod2" ]; then - remote_fileurl="https://linuxgsm.download/CallOfDuty2/cod2-lnxded-1.3-full.tar.xz" + remote_fileurl="https://linuxgsm.download/CallOfDuty2/cod2-1.3-linux-i386-linuxgsm-20261101.tar.xz" local_filedir="${tmpdir}" - local_filename="cod2-lnxded-1.3-full.tar.xz" + local_filename="cod2-1.3-linux-i386-linuxgsm-20261101.tar.xz" chmodx="nochmodx" run="norun" force="noforce" - md5="b8c4c611f01627dd43348e78478a3d41" + md5="e7dfaaf11f3f714c60e2ac1057476aa4" elif [ "${shortname}" == "cod4" ]; then remote_fileurl="https://linuxgsm.download/CallOfDuty4/cod4x-21.2-linux-i386-linuxgsm-20261102.tar.xz" local_filedir="${tmpdir}" @@ -66,13 +66,13 @@ fn_install_server_files() { force="noforce" md5="7c8d55d12e44f321f31ad1320567659a" elif [ "${shortname}" == "codwaw" ]; then - remote_fileurl="https://linuxgsm.download/CallOfDutyWorldAtWar/codwaw-lnxded-1.7-full.tar.xz" + remote_fileurl="https://linuxgsm.download/CallOfDutyWorldAtWar/codwaw-1.7-linux-i386-linuxgsm-20261101.tar.xz" local_filedir="${tmpdir}" - local_filename="codwaw-lnxded-1.7-full.tar.xz" + local_filename="codwaw-1.7-linux-i386-linuxgsm-20261101.tar.xz" chmodx="nochmodx" run="norun" force="noforce" - md5="2c6be1bb66ea631b9b2e7ae6216c6680" + md5="d7bdc6b2a671c3e07184e1a3262ec14c" elif [ "${shortname}" == "cswon" ]; then remote_fileurl="https://linuxgsm.download/CounterStrikeWON2/cswon-3111e-cs15-linux-i386-linuxgsm-20261102.tar.xz" local_filedir="${tmpdir}" @@ -114,21 +114,21 @@ fn_install_server_files() { force="noforce" md5="f0abe39ed649765cd99b7e5e1c62b4f6" elif [ "${shortname}" == "q3" ]; then - remote_fileurl="https://linuxgsm.download/Quake3/quake3-1.32c-x86-full-linux.tar.xz" + remote_fileurl="https://linuxgsm.download/Quake3/q3-1.32c-linux-i386-linuxgsm-20261101.tar.xz" local_filedir="${tmpdir}" - local_filename="quake3-1.32c-x86-full-linux.tar.xz" + local_filename="q3-1.32c-linux-i386-linuxgsm-20261101.tar.xz" chmodx="nochmodx" run="norun" force="noforce" - md5="b0e26d8919fe9313fb9d8ded2360f3db" + md5="e6c958f4e01845d06bd5b8f3835bafa0" elif [ "${shortname}" == "q4" ]; then - remote_fileurl="https://linuxgsm.download/Quake4/quake4-1.4.2-x86-linuxded.tar.xz" + remote_fileurl="https://linuxgsm.download/Quake4/q4-1.4.2-linux-i386-linuxgsm-20261101.tar.xz" local_filedir="${tmpdir}" - local_filename="quake4-1.4.2-x86-linuxded.tar.xz" + local_filename="q4-1.4.2-linux-i386-linuxgsm-20261101.tar.xz" chmodx="nochmodx" run="norun" force="noforce" - md5="afe30b44f23c8ae2ce6f0f464473d8ba" + md5="7aaa88fb0ba0c533fe23b7b993fd6530" elif [ "${shortname}" == "qw" ]; then remote_fileurl="https://linuxgsm.download/QuakeWorld/nquake.server.linux.190506.full.tar.xz" local_filedir="${tmpdir}" @@ -154,13 +154,13 @@ fn_install_server_files() { force="noforce" md5="a0e3980e944cd321c5f064d752a7431e" elif [ "${shortname}" == "sof2" ]; then - remote_fileurl="https://linuxgsm.download/SoldierOfFortune2/sof2gold-1.03.tar.xz" + remote_fileurl="https://linuxgsm.download/SoldierOfFortune2/sof2-1.03-linux-i386-linuxgsm-20261101.tar.xz" local_filedir="${tmpdir}" - local_filename="sof2gold-1.03.tar.xz" + local_filename="sof2-1.03-linux-i386-linuxgsm-20261101.tar.xz" chmodx="nochmodx" run="norun" force="noforce" - md5="201e23bab04207d00ce813d001c483d9" + md5="d8cd9ad624290a1de1c72e43aa35195e" elif [ "${shortname}" == "ts" ]; then remote_fileurl="https://linuxgsm.download/TheSpecialists/ts-3.0-linux-i386-linuxgsm-20261102.tar.xz" local_filedir="${tmpdir}" @@ -210,13 +210,13 @@ fn_install_server_files() { force="noforce" md5="c1f908ab27772d8c6ca8ee731d32ddda" elif [ "${shortname}" == "wet" ]; then - remote_fileurl="https://linuxgsm.download/WolfensteinEnemyTerritory/enemy-territory.260b.tar.xz" + remote_fileurl="https://linuxgsm.download/WolfensteinEnemyTerritory/wet-2.60b-linux-i386-linuxgsm-20261101.tar.xz" local_filedir="${tmpdir}" - local_filename="enemy-territory.260b.tar.xz" + local_filename="wet-2.60b-linux-i386-linuxgsm-20261101.tar.xz" chmodx="nochmodx" run="norun" force="noforce" - md5="581a333cc7eacda2f56d5a00fe11eafa" + md5="60b7483c22db98effc3622dbb9e5710f" elif [ "${shortname}" == "samp" ]; then remote_fileurl="https://files.samp-sc.com/samp037svr_R2-1.tar.gz" local_filedir="${tmpdir}" From b40200901f297a4773f4b960d54fc04d5f028abc Mon Sep 17 00:00:00 2001 From: Daniel Gibbs Date: Tue, 3 Nov 2026 22:30:37 +0000 Subject: [PATCH 158/164] fix(punkbuster): start PunkBuster on CoD2 and WaW with glibc 2.41 and newer (#5140) * fix(punkbuster): start PunkBuster on CoD2 and WaW with glibc 2.41 and newer The PunkBuster libraries have no PT_GNU_STACK header, so on i386 they need an executable stack. The Call of Duty 2 and World at War server binaries don't have one. Since glibc 2.41 the loader refuses to dlopen such a library into a process without an executable stack, so PunkBuster failed to start. Call of Duty 2 quietly reset sv_punkbuster to 0, and World at War logged "Unable to initialize punkbuster". Set GLIBC_TUNABLES=glibc.rtld.execstack=2 in fix_cod2.sh and a new fix_codwaw.sh, which restores the old behaviour for the server process. Older glibc versions ignore the setting. * fix(wet): add sv_punkbuster 0 to the default start parameters Every other Quake 3 engine server with PunkBuster has +set sv_punkbuster 0 in startparameters, so PunkBuster is turned on the same way everywhere. * fix(core): allow executable stack libraries for sfc, ts, vs and ut on glibc 2.41 and newer Glibc 2.41 and newer refuses to load a shared library that asks for an executable stack, so these servers exit at start with "cannot enable executable stack as shared object requires: Invalid argument". - sfc: sfclassic/bin/server.so and server_srv.so have an RWE GNU_STACK. - ts, vs: the GoldSrc mod libraries have no GNU_STACK header. - ut: four UE4 server libraries have an RWE GNU_STACK. Set glibc.rtld.execstack=2 in the pre-start fix for each, as for cod2 and codwaw. ts and vs get new fix modules. ut joins the pre-start fixes, and its chmod now only runs when the executable is not already executable. * fix(ut): remove the chmod from the Unreal Tournament fix The server binary is executable in both the original archive and the rebuilt one, so the chmod never had anything to do. It also printed a raw command instead of the usual fix messages. The fix now only sets the execstack tunable, so ut no longer needs to run it after install. --- .../config-lgsm/wetserver/_default.cfg | 2 +- lgsm/modules/core_modules.sh | 15 +++++++++++++++ lgsm/modules/fix.sh | 4 ++-- lgsm/modules/fix_cod2.sh | 1 + lgsm/modules/fix_codwaw.sh | 11 +++++++++++ lgsm/modules/fix_sfc.sh | 2 ++ lgsm/modules/fix_ts.sh | 11 +++++++++++ lgsm/modules/fix_ut.sh | 6 ++---- lgsm/modules/fix_vs.sh | 11 +++++++++++ 9 files changed, 56 insertions(+), 7 deletions(-) create mode 100755 lgsm/modules/fix_codwaw.sh create mode 100755 lgsm/modules/fix_ts.sh create mode 100755 lgsm/modules/fix_vs.sh diff --git a/lgsm/config-default/config-lgsm/wetserver/_default.cfg b/lgsm/config-default/config-lgsm/wetserver/_default.cfg index 715c723f04..f8f4c79e47 100644 --- a/lgsm/config-default/config-lgsm/wetserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/wetserver/_default.cfg @@ -9,7 +9,7 @@ #### Game Server Settings #### ## Server Parameters | https://docs.linuxgsm.com/configuration/start-parameters#additional-parameters -startparameters="+set net_strict 1 +set fs_homepath ${serverfiles} +exec ${servercfg}" +startparameters="+set sv_punkbuster 0 +set net_strict 1 +set fs_homepath ${serverfiles} +exec ${servercfg}" ## Extra Parameters | https://docs.linuxgsm.com/configuration/start-parameters#extra-parameters # Added to the end of startparameters. diff --git a/lgsm/modules/core_modules.sh b/lgsm/modules/core_modules.sh index ce10c0472b..4304fda3a8 100755 --- a/lgsm/modules/core_modules.sh +++ b/lgsm/modules/core_modules.sh @@ -428,6 +428,11 @@ fix_coduo.sh() { fn_fetch_module } +fix_codwaw.sh() { + modulefile="${FUNCNAME[0]}" + fn_fetch_module +} + fix_csgo.sh() { modulefile="${FUNCNAME[0]}" fn_fetch_module @@ -568,6 +573,11 @@ fix_tf2.sh() { fn_fetch_module } +fix_ts.sh() { + modulefile="${FUNCNAME[0]}" + fn_fetch_module +} + fix_ts3.sh() { modulefile="${FUNCNAME[0]}" fn_fetch_module @@ -598,6 +608,11 @@ fix_vh.sh() { fn_fetch_module } +fix_vs.sh() { + modulefile="${FUNCNAME[0]}" + fn_fetch_module +} + fix_wurm.sh() { modulefile="${FUNCNAME[0]}" fn_fetch_module diff --git a/lgsm/modules/fix.sh b/lgsm/modules/fix.sh index d17ef3f597..4d201dd5ed 100755 --- a/lgsm/modules/fix.sh +++ b/lgsm/modules/fix.sh @@ -53,8 +53,8 @@ fn_apply_fix() { fi } -apply_pre_start_fix=(arma3 armar ark av bf1942 bfv bt bo csgo cmw cod cod2 coduo ct dst hw ins ios kf nd nmrih onset pvr ro rust rw samp sdtd sfc sm sof2 squad st tf2 terraria ts3 mcb mohaa mta unt vh wurm xnt zmr) -apply_post_install_fix=(av kf kf2 nd ro ut2k4 ut ut3) +apply_pre_start_fix=(arma3 armar ark av bf1942 bfv bt bo csgo cmw cod cod2 coduo codwaw ct dst hw ins ios kf nd nmrih onset pvr ro rust rw samp sdtd sfc sm sof2 squad st tf2 terraria ts ts3 mcb mohaa mta unt ut vh vs wurm xnt zmr) +apply_post_install_fix=(av kf kf2 nd ro ut2k4 ut3) # validate registered fixes for safe development for fix in "${apply_pre_start_fix[@]}" "${apply_post_install_fix[@]}"; do diff --git a/lgsm/modules/fix_cod2.sh b/lgsm/modules/fix_cod2.sh index 6468dd206b..60d43d4db3 100755 --- a/lgsm/modules/fix_cod2.sh +++ b/lgsm/modules/fix_cod2.sh @@ -9,6 +9,7 @@ moduleselfname="$(basename "$(readlink -f "${BASH_SOURCE[0]}")")" export LD_LIBRARY_PATH="$LD_LIBRARY_PATH:${serverfiles}" +export GLIBC_TUNABLES="${GLIBC_TUNABLES:+${GLIBC_TUNABLES}:}glibc.rtld.execstack=2" if ldd "${executabledir}/cod2_lnxded" 2>&1 | grep -q "libstdc++\.so\.5 => not found"; then # shellcheck disable=SC2034 # Used by fn_fix_msg_start_nl and fn_fix_msg_end. diff --git a/lgsm/modules/fix_codwaw.sh b/lgsm/modules/fix_codwaw.sh new file mode 100755 index 0000000000..fa18ccb1fa --- /dev/null +++ b/lgsm/modules/fix_codwaw.sh @@ -0,0 +1,11 @@ +#!/bin/bash +# LinuxGSM fix_codwaw.sh module +# Author: Daniel Gibbs +# Contributors: https://linuxgsm.com/contrib +# Website: https://linuxgsm.com +# Description: Resolves issues with Call of Duty: World at War. + +# shellcheck disable=SC2034 # Used by the module loader. +moduleselfname="$(basename "$(readlink -f "${BASH_SOURCE[0]}")")" + +export GLIBC_TUNABLES="${GLIBC_TUNABLES:+${GLIBC_TUNABLES}:}glibc.rtld.execstack=2" diff --git a/lgsm/modules/fix_sfc.sh b/lgsm/modules/fix_sfc.sh index 70e5d04840..828ff95545 100755 --- a/lgsm/modules/fix_sfc.sh +++ b/lgsm/modules/fix_sfc.sh @@ -7,6 +7,8 @@ moduleselfname="$(basename "$(readlink -f "${BASH_SOURCE[0]}")")" +export GLIBC_TUNABLES="${GLIBC_TUNABLES:+${GLIBC_TUNABLES}:}glibc.rtld.execstack=2" + if [ ! -f "${serverfiles}/bin/datacache.so" ]; then ln -s "${serverfiles}/bin/datacache_srv.so" "${serverfiles}/bin/datacache.so" fi diff --git a/lgsm/modules/fix_ts.sh b/lgsm/modules/fix_ts.sh new file mode 100755 index 0000000000..b4a0519e89 --- /dev/null +++ b/lgsm/modules/fix_ts.sh @@ -0,0 +1,11 @@ +#!/bin/bash +# LinuxGSM fix_ts.sh module +# Author: Daniel Gibbs +# Contributors: https://linuxgsm.com/contrib +# Website: https://linuxgsm.com +# Description: Resolves issues with The Specialists. + +# shellcheck disable=SC2034 # Used by the module loader. +moduleselfname="$(basename "$(readlink -f "${BASH_SOURCE[0]}")")" + +export GLIBC_TUNABLES="${GLIBC_TUNABLES:+${GLIBC_TUNABLES}:}glibc.rtld.execstack=2" diff --git a/lgsm/modules/fix_ut.sh b/lgsm/modules/fix_ut.sh index 3da5c068c3..6771dfa687 100755 --- a/lgsm/modules/fix_ut.sh +++ b/lgsm/modules/fix_ut.sh @@ -5,9 +5,7 @@ # Website: https://linuxgsm.com # Description: Resolves issues with Unreal Tournament. +# shellcheck disable=SC2034 # Used by the module loader. moduleselfname="$(basename "$(readlink -f "${BASH_SOURCE[0]}")")" -#Set Binary Executable -echo -e "chmod +x ${executabledir}/${executable}" -chmod +x "${executabledir}/${executable}" -fn_sleep_time +export GLIBC_TUNABLES="${GLIBC_TUNABLES:+${GLIBC_TUNABLES}:}glibc.rtld.execstack=2" diff --git a/lgsm/modules/fix_vs.sh b/lgsm/modules/fix_vs.sh new file mode 100755 index 0000000000..03b3a3dfe4 --- /dev/null +++ b/lgsm/modules/fix_vs.sh @@ -0,0 +1,11 @@ +#!/bin/bash +# LinuxGSM fix_vs.sh module +# Author: Daniel Gibbs +# Contributors: https://linuxgsm.com/contrib +# Website: https://linuxgsm.com +# Description: Resolves issues with Vampire Slayer. + +# shellcheck disable=SC2034 # Used by the module loader. +moduleselfname="$(basename "$(readlink -f "${BASH_SOURCE[0]}")")" + +export GLIBC_TUNABLES="${GLIBC_TUNABLES:+${GLIBC_TUNABLES}:}glibc.rtld.execstack=2" From 8f1e3ed2135a0ceef534e55ebb45fa8fe45d128d Mon Sep 17 00:00:00 2001 From: Daniel Gibbs Date: Tue, 3 Nov 2026 22:44:45 +0000 Subject: [PATCH 159/164] fix(ut99): keep config and logs in serverfiles with -nohomedir (#5133) The OldUnreal 469 patch uses ~/.utpg as a per-user directory on Linux unless started with -nohomedir. Any ini the engine creates or saves (mutator configs such as ACE or map vote, User.ini) was written to ~/.utpg/System instead of serverfiles/System, and ucc.log and the per-match ngLog files went to ~/.utpg, where LinuxGSM never rotated them. Start UT99 with -nohomedir, as ut2k4 and ut3 already do. A new pre-start fix_ut99.sh moves any ini left in ~/.utpg/System into the System directory so existing servers keep their settings. Those files were the copies the server was reading, since 469 looks in the home directory first; a stock file they replace is kept as a numbered backup. Co-authored-by: dgibbs64 --- .../config-lgsm/ut99server/_default.cfg | 2 +- lgsm/modules/core_modules.sh | 5 +++++ lgsm/modules/fix.sh | 2 +- lgsm/modules/fix_ut99.sh | 18 ++++++++++++++++++ 4 files changed, 25 insertions(+), 2 deletions(-) create mode 100755 lgsm/modules/fix_ut99.sh diff --git a/lgsm/config-default/config-lgsm/ut99server/_default.cfg b/lgsm/config-default/config-lgsm/ut99server/_default.cfg index 0b9006faa9..69f25f857f 100644 --- a/lgsm/config-default/config-lgsm/ut99server/_default.cfg +++ b/lgsm/config-default/config-lgsm/ut99server/_default.cfg @@ -13,7 +13,7 @@ defaultmap="DM-Deck16][" ip="0.0.0.0" ## Server Parameters | https://docs.linuxgsm.com/configuration/start-parameters#additional-parameters -startparameters="server ${defaultmap}.unr ini=${servercfgfullpath}" +startparameters="server ${defaultmap}.unr ini=${servercfgfullpath} -nohomedir" ## Extra Parameters | https://docs.linuxgsm.com/configuration/start-parameters#extra-parameters # Added to the end of startparameters. diff --git a/lgsm/modules/core_modules.sh b/lgsm/modules/core_modules.sh index 4304fda3a8..482ed16849 100755 --- a/lgsm/modules/core_modules.sh +++ b/lgsm/modules/core_modules.sh @@ -603,6 +603,11 @@ fix_ut3.sh() { fn_fetch_module } +fix_ut99.sh() { + modulefile="${FUNCNAME[0]}" + fn_fetch_module +} + fix_vh.sh() { modulefile="${FUNCNAME[0]}" fn_fetch_module diff --git a/lgsm/modules/fix.sh b/lgsm/modules/fix.sh index 4d201dd5ed..b1910b1933 100755 --- a/lgsm/modules/fix.sh +++ b/lgsm/modules/fix.sh @@ -53,7 +53,7 @@ fn_apply_fix() { fi } -apply_pre_start_fix=(arma3 armar ark av bf1942 bfv bt bo csgo cmw cod cod2 coduo codwaw ct dst hw ins ios kf nd nmrih onset pvr ro rust rw samp sdtd sfc sm sof2 squad st tf2 terraria ts ts3 mcb mohaa mta unt ut vh vs wurm xnt zmr) +apply_pre_start_fix=(arma3 armar ark av bf1942 bfv bt bo csgo cmw cod cod2 coduo codwaw ct dst hw ins ios kf nd nmrih onset pvr ro rust rw samp sdtd sfc sm sof2 squad st tf2 terraria ts ts3 mcb mohaa mta unt ut ut99 vh vs wurm xnt zmr) apply_post_install_fix=(av kf kf2 nd ro ut2k4 ut3) # validate registered fixes for safe development diff --git a/lgsm/modules/fix_ut99.sh b/lgsm/modules/fix_ut99.sh new file mode 100755 index 0000000000..f12f6759d0 --- /dev/null +++ b/lgsm/modules/fix_ut99.sh @@ -0,0 +1,18 @@ +#!/bin/bash +# LinuxGSM fix_ut99.sh module +# Author: Daniel Gibbs +# Contributors: https://linuxgsm.com/contrib +# Website: https://linuxgsm.com +# Description: Resolves issues with Unreal Tournament 99. + +moduleselfname="$(basename "$(readlink -f "${BASH_SOURCE[0]}")")" + +if [[ "${startparameters}" == *"-nohomedir"* ]] && [ -d "${HOME}/.utpg/System" ]; then + while IFS= read -r -d '' homeini; do + fixname="move $(basename "${homeini}") from ${HOME}/.utpg/System to ${systemdir}" + fn_fix_msg_start + mv --backup=numbered "${homeini}" "${systemdir}/" + exitcode=$? + fn_fix_msg_end + done < <(find "${HOME}/.utpg/System" -maxdepth 1 -type f -name "*.ini" -print0) +fi From 70818f4639b06b8f046f71ccb21610f0451f0480 Mon Sep 17 00:00:00 2001 From: Daniel Gibbs Date: Tue, 3 Nov 2026 22:50:50 +0000 Subject: [PATCH 160/164] fix(deps): fetch distro dependency csv when run as root before install (#5132) fn_check_file only set checkflag when the script log already existed. Running install or auto-install as root before the game user had installed left checkflag empty, so check_deps.sh skipped fetching the distro dependency CSV and reported dependency checking as unavailable. Set checkflag regardless of the log state; only the log writes remain guarded. Fixes #3774 --- lgsm/modules/core_dl.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lgsm/modules/core_dl.sh b/lgsm/modules/core_dl.sh index 92d79dfe50..8e3dcfb638 100755 --- a/lgsm/modules/core_dl.sh +++ b/lgsm/modules/core_dl.sh @@ -412,17 +412,17 @@ fn_check_file() { if [ "${exitcode}" -ne 0 ]; then if [ ${counter} -ge 2 ]; then fn_print_fail_eol_nl + checkflag=1 if [ -f "${lgsmlog}" ]; then fn_script_log_fail "Checking ${remote_filename}" fn_script_log_fail "${fileurl}" - checkflag=1 fi else fn_print_error_eol_nl + checkflag=2 if [ -f "${lgsmlog}" ]; then fn_script_log_error "Checking ${remote_filename}" fn_script_log_error "${fileurl}" - checkflag=2 fi fi else @@ -432,9 +432,9 @@ fn_check_file() { fn_print_ok_eol echo -en "\033[2K\\r" fi + checkflag=0 if [ -f "${lgsmlog}" ]; then fn_script_log_pass "Checking ${remote_filename}" - checkflag=0 fi break fi From 98968df0fc0f5496f71be1bd754a2fef53027a81 Mon Sep 17 00:00:00 2001 From: Daniel Gibbs Date: Wed, 4 Nov 2026 20:27:32 +0000 Subject: [PATCH 161/164] feat(qwserver): install and update from qwserver-build releases (#5149) Install and update QuakeWorld from dated qwserver-build releases with SHA-256 verification and staged bundle validation. Preserve existing configuration and scripts, track installed releases, and enable update and check-update commands. Raise the MVDSV glibc requirement to 2.34. Fixes #5143 --- .../config-lgsm/qwserver/_default.cfg | 2 +- lgsm/modules/command_check_update.sh | 2 + lgsm/modules/command_update.sh | 2 + lgsm/modules/core_getopt.sh | 2 +- lgsm/modules/core_modules.sh | 5 + lgsm/modules/install_server_files.sh | 10 +- lgsm/modules/update_qw.sh | 162 ++++++++++++++++++ 7 files changed, 175 insertions(+), 10 deletions(-) create mode 100755 lgsm/modules/update_qw.sh diff --git a/lgsm/config-default/config-lgsm/qwserver/_default.cfg b/lgsm/config-default/config-lgsm/qwserver/_default.cfg index 481ff17911..8a95c21000 100644 --- a/lgsm/config-default/config-lgsm/qwserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/qwserver/_default.cfg @@ -164,7 +164,7 @@ consoleinteract="yes" # Do not edit gamename="QuakeWorld" engine="quake" -glibc="2.17" +glibc="2.34" #### Directories #### # Edit with care diff --git a/lgsm/modules/command_check_update.sh b/lgsm/modules/command_check_update.sh index 97b6d0d97d..78c04242ca 100755 --- a/lgsm/modules/command_check_update.sh +++ b/lgsm/modules/command_check_update.sh @@ -48,6 +48,8 @@ elif [ "${shortname}" == "ut99" ]; then update_ut99.sh elif [ "${shortname}" == "xnt" ]; then update_xnt.sh +elif [ "${shortname}" == "qw" ]; then + update_qw.sh elif [ "${shortname}" == "etl" ]; then update_etl.sh else diff --git a/lgsm/modules/command_update.sh b/lgsm/modules/command_update.sh index 2f6148cc7d..5d7b364ff3 100755 --- a/lgsm/modules/command_update.sh +++ b/lgsm/modules/command_update.sh @@ -90,6 +90,8 @@ elif [ "${shortname}" == "ut99" ]; then update_ut99.sh elif [ "${shortname}" == "xnt" ]; then update_xnt.sh +elif [ "${shortname}" == "qw" ]; then + update_qw.sh elif [ "${shortname}" == "etl" ]; then update_etl.sh else diff --git a/lgsm/modules/core_getopt.sh b/lgsm/modules/core_getopt.sh index ef9348c858..57cda74c75 100755 --- a/lgsm/modules/core_getopt.sh +++ b/lgsm/modules/core_getopt.sh @@ -69,7 +69,7 @@ currentopt+=("${cmd_update_linuxgsm[@]}") # Exclude noupdate games here. if [ "${shortname}" == "jk2" ] || [ "${shortname}" == "jk3" ] || [ "${shortname}" == "etl" ] || [ "${engine}" != "idtech3" ]; then - if [ "${querytype}" != "protocol-valve-won" ] && [ "${shortname}" != "bf1942" ] && [ "${shortname}" != "bfv" ] && [ "${engine}" != "idtech2" ] && [ "${engine}" != "iw2.0" ] && [ "${engine}" != "iw3.0" ] && [ "${engine}" != "quake" ] && [ "${shortname}" != "samp" ] && [ "${shortname}" != "ut2k4" ]; then + if [ "${querytype}" != "protocol-valve-won" ] && [ "${shortname}" != "bf1942" ] && [ "${shortname}" != "bfv" ] && [ "${engine}" != "idtech2" ] && [ "${engine}" != "iw2.0" ] && [ "${engine}" != "iw3.0" ] && { [ "${engine}" != "quake" ] || [ "${shortname}" == "qw" ]; } && [ "${shortname}" != "samp" ] && [ "${shortname}" != "ut2k4" ]; then currentopt+=("${cmd_update[@]}" "${cmd_check_update[@]}") # force update for SteamCMD, Multi Theft Auto, Hytale or FiveM only. if [ "${appid}" ] || [ "${shortname}" == "mta" ] || [ "${shortname}" == "hyt" ] || [ "${shortname}" == "fivem" ]; then diff --git a/lgsm/modules/core_modules.sh b/lgsm/modules/core_modules.sh index 482ed16849..7edc7c2f54 100755 --- a/lgsm/modules/core_modules.sh +++ b/lgsm/modules/core_modules.sh @@ -812,6 +812,11 @@ update_pmc.sh() { fn_fetch_module } +update_qw.sh() { + modulefile="${FUNCNAME[0]}" + fn_fetch_module +} + update_steamcmd.sh() { modulefile="${FUNCNAME[0]}" fn_fetch_module diff --git a/lgsm/modules/install_server_files.sh b/lgsm/modules/install_server_files.sh index 562e31c53e..34290d9bd5 100755 --- a/lgsm/modules/install_server_files.sh +++ b/lgsm/modules/install_server_files.sh @@ -129,14 +129,6 @@ fn_install_server_files() { run="norun" force="noforce" md5="7aaa88fb0ba0c533fe23b7b993fd6530" - elif [ "${shortname}" == "qw" ]; then - remote_fileurl="https://linuxgsm.download/QuakeWorld/nquake.server.linux.190506.full.tar.xz" - local_filedir="${tmpdir}" - local_filename="nquake.server.linux.190506.full.tar.xz" - chmodx="nochmodx" - run="norun" - force="noforce" - md5="82055b7d973206c13a606db8ba288d03" elif [ "${shortname}" == "rtcw" ]; then remote_fileurl="https://linuxgsm.download/ReturnToCastleWolfenstein/rtcw-iortcw-1.51c-linux-amd64-linuxgsm-20261102.tar.xz" local_filedir="${tmpdir}" @@ -296,6 +288,8 @@ elif [ "${shortname}" == "ut99" ]; then update_ut99.sh elif [ "${shortname}" == "xnt" ]; then update_xnt.sh +elif [ "${shortname}" == "qw" ]; then + update_qw.sh elif [ "${shortname}" == "etl" ]; then update_etl.sh elif [ -z "${appid}" ] || [ "${shortname}" == "ahl" ] || [ "${shortname}" == "q4" ] || [ "${shortname}" == "ns" ] || [ "${shortname}" == "sfc" ] || [ "${shortname}" == "ts" ] || [ "${shortname}" == "vs" ] || [ "${shortname}" == "zmr" ]; then diff --git a/lgsm/modules/update_qw.sh b/lgsm/modules/update_qw.sh new file mode 100755 index 0000000000..adcbfdc917 --- /dev/null +++ b/lgsm/modules/update_qw.sh @@ -0,0 +1,162 @@ +#!/bin/bash +# LinuxGSM update_qw.sh module +# Author: Daniel Gibbs +# Contributors: https://linuxgsm.com/contrib +# Website: https://linuxgsm.com +# Description: Handles updating of QuakeWorld servers. + +moduleselfname="$(basename "$(readlink -f "${BASH_SOURCE[0]}")")" + +fn_update_fail() { + fn_print_fail_nl "${1}" + fn_script_log_fail "${1}" + exitcode=1 + core_exit.sh +} + +fn_update_dl() { + # Verify and stage the complete bundle before changing serverfiles. + fn_fetch_file "${remotebuildurl}" "" "" "" "${tmpdir}" "${remotebuildfilename}" "nochmodx" "norun" "forcedl" "${remotebuildhash}" + local stagedir configfile relativefile + stagedir=$(mktemp -d "${tmpdir}/qw-update.XXXXXXXX") || fn_update_fail "Unable to create QuakeWorld staging directory" + fn_dl_extract "${tmpdir}" "${remotebuildfilename}" "${stagedir}" + if [ ! -x "${stagedir}/mvdsv" ] || [ ! -f "${stagedir}/ktx/qwprogs.so" ] || [ ! -f "${stagedir}/ktx/server.cfg" ]; then + fn_update_fail "Invalid QuakeWorld bundle layout" + fi + + # Keep existing configs, map lists and local scripts, including config symlinks. + # New default configs are still installed. Never remove files from serverfiles. + while IFS= read -r -d '' configfile; do + relativefile="${configfile#"${stagedir}/"}" + case "${relativefile,,}" in + *.cfg | *.conf | *.ini | *.txt | *.sh) ;; + *) + if [ "${serverfiles}/${relativefile}" != "${servercfgfullpath}" ]; then + continue + fi + ;; + esac + if [ -e "${serverfiles}/${relativefile}" ] || [ -L "${serverfiles}/${relativefile}" ]; then + rm -f "${configfile}" || fn_update_fail "Unable to preserve QuakeWorld config: ${relativefile}" + fi + done < <(find "${stagedir}" \( -type f -o -type l \) -print0) + + cp -a "${stagedir}/." "${serverfiles}/" || fn_update_fail "Unable to copy QuakeWorld update" + echo "${remotebuild}" > "${serverfiles}/build.txt" || fn_update_fail "Unable to save QuakeWorld build" + fn_clear_tmp +} + +fn_update_localbuild() { + # Gets local build info. + fn_print_dots "Checking local build: ${remotelocation}" + # Legacy installations without build.txt are updated once. + localbuild=$(head -n 1 "${serverfiles}/build.txt" 2> /dev/null) + if [ -z "${localbuild}" ]; then + fn_print_error "Checking local build: ${remotelocation}: missing local build info" + 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}" + fn_script_log_pass "Checking local build" + fi +} + +fn_update_remotebuild() { + # Use the dated release, not the mutable release tagged "latest". + apiurl="https://api.github.com/repos/GameServerManagers/qwserver-build/releases/latest" + fn_print_dots "Checking remote build: ${remotelocation}" + remotebuildresponse=$(curl -fsSL --connect-timeout 10 --max-time 60 "${apiurl}") || fn_update_fail "Unable to get QuakeWorld release" + remotebuild=$(echo "${remotebuildresponse}" | jq -er '.tag_name | select(test("^build-[0-9]{8}$"))') || fn_update_fail "Invalid QuakeWorld release tag" + remotebuildfilename="nquake.server.linux.${remotebuild#build-}.full.tar.xz" + remotebuildurl=$(echo "${remotebuildresponse}" | jq -er --arg name "${remotebuildfilename}" '[.assets[] | select(.name == $name)] | select(length == 1) | .[0].browser_download_url | select(type == "string" and startswith("https://"))') || fn_update_fail "Missing QuakeWorld release archive" + local checksumurl checksums + checksumurl=$(echo "${remotebuildresponse}" | jq -er '[.assets[] | select(.name == "SHA256SUMS")] | select(length == 1) | .[0].browser_download_url | select(type == "string" and startswith("https://"))') || fn_update_fail "Missing QuakeWorld checksums" + checksums=$(curl -fsSL --connect-timeout 10 --max-time 60 "${checksumurl}") || fn_update_fail "Unable to get QuakeWorld checksums" + remotebuildhash=$(echo "${checksums}" | awk -v filename="${remotebuildfilename}" 'NF == 2 && $2 == filename {print $1}') + if [[ ! "${remotebuildhash}" =~ ^[a-f0-9]{64}$ ]]; then + fn_update_fail "Missing or invalid QuakeWorld archive checksum" + fi + fn_print_ok "Checking remote build: ${remotelocation}" + fn_script_log_pass "Checking remote build" +} + +fn_update_compare() { + fn_print_dots "Checking for update: ${remotelocation}" + # Update has been found or force update. + 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}${remotebuild}${default}" + if [ -n "${branch}" ]; then + fn_print_nl "* Branch: ${branch}" + fi + if [ -f "${rootdir}/.dev-debug" ]; then + 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 + fn_print "\n" + fn_script_log_info "Update available" + fn_script_log_info "Local build: ${localbuild}" + fn_script_log_info "Remote build: ${remotebuild}" + if [ -n "${branch}" ]; then + fn_script_log_info "Branch: ${branch}" + fi + fn_script_log_info "${localbuild} > ${remotebuild}" + + if [ "${commandname}" == "UPDATE" ]; then + unset updateonstart + fn_update_apply fn_update_dl + unset exitbypass + alert="update" + elif [ "${commandname}" == "CHECK-UPDATE" ]; then + alert="check-update" + fi + alert.sh + else + fn_print_ok_nl "Checking for update: ${remotelocation}" + 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 + fn_print_nl "* Branch: ${branch}" + fi + fn_print "\n" + fn_script_log_info "No update available" + fn_script_log_info "Local build: ${localbuild}" + fn_script_log_info "Remote build: ${remotebuild}" + if [ -n "${branch}" ]; then + fn_script_log_info "Branch: ${branch}" + fi + if [ -f "${rootdir}/.dev-debug" ]; then + 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 +} + +# The location where the builds are checked and downloaded. +remotelocation="github.com" + +if [ "${firstcommandname}" == "INSTALL" ]; then + fn_update_remotebuild + fn_update_dl +else + fn_print_dots "Checking for update" + fn_print_dots "Checking for update: ${remotelocation}" + fn_script_log_info "Checking for update: ${remotelocation}" + fn_update_localbuild + fn_update_remotebuild + fn_update_compare +fi From c5efe90fedf23fa9903866e9068bc83739e37a8b Mon Sep 17 00:00:00 2001 From: Daniel Gibbs Date: Wed, 4 Nov 2026 20:41:49 +0000 Subject: [PATCH 162/164] fix(ahl): run Action Half-Life on ReHLDS to stop the startup segfault (#5150) --- .../config-lgsm/ahlserver/_default.cfg | 2 +- lgsm/modules/command_start.sh | 3 ++ lgsm/modules/core_modules.sh | 5 ++++ lgsm/modules/fix.sh | 2 +- lgsm/modules/fix_ahl.sh | 29 +++++++++++++++++++ 5 files changed, 39 insertions(+), 2 deletions(-) create mode 100755 lgsm/modules/fix_ahl.sh diff --git a/lgsm/config-default/config-lgsm/ahlserver/_default.cfg b/lgsm/config-default/config-lgsm/ahlserver/_default.cfg index 8fe39e1107..9766bcd1af 100644 --- a/lgsm/config-default/config-lgsm/ahlserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/ahlserver/_default.cfg @@ -150,7 +150,7 @@ appid="90" steamcmdforcewindows="no" appidmod="cstrike" # SteamCMD Branch | https://docs.linuxgsm.com/steamcmd/branch -branch="" +branch="steam_legacy" betapassword="" # Master Server | https://docs.linuxgsm.com/steamcmd/steam-master-server steammaster="true" diff --git a/lgsm/modules/command_start.sh b/lgsm/modules/command_start.sh index e8a3ec167b..86bdf1c4e3 100755 --- a/lgsm/modules/command_start.sh +++ b/lgsm/modules/command_start.sh @@ -280,6 +280,9 @@ if [ "${updateonstart}" == "yes" ] || [ "${updateonstart}" == "1" ] || [ "${upda fn_print_warn_nl "Update failed, starting ${servername} anyway" fn_script_log_warn "Update failed, starting ${servername} anyway" fi + if [ "${shortname}" == "ahl" ]; then + fix_ahl.sh + fi fi fn_print_dots "${servername}" diff --git a/lgsm/modules/core_modules.sh b/lgsm/modules/core_modules.sh index 7edc7c2f54..cbe4aa4af8 100755 --- a/lgsm/modules/core_modules.sh +++ b/lgsm/modules/core_modules.sh @@ -368,6 +368,11 @@ fix.sh() { fn_fetch_module } +fix_ahl.sh() { + modulefile="${FUNCNAME[0]}" + fn_fetch_module +} + fix_ark.sh() { modulefile="${FUNCNAME[0]}" fn_fetch_module diff --git a/lgsm/modules/fix.sh b/lgsm/modules/fix.sh index b1910b1933..9165ea0736 100755 --- a/lgsm/modules/fix.sh +++ b/lgsm/modules/fix.sh @@ -53,7 +53,7 @@ fn_apply_fix() { fi } -apply_pre_start_fix=(arma3 armar ark av bf1942 bfv bt bo csgo cmw cod cod2 coduo codwaw ct dst hw ins ios kf nd nmrih onset pvr ro rust rw samp sdtd sfc sm sof2 squad st tf2 terraria ts ts3 mcb mohaa mta unt ut ut99 vh vs wurm xnt zmr) +apply_pre_start_fix=(ahl arma3 armar ark av bf1942 bfv bt bo csgo cmw cod cod2 coduo codwaw ct dst hw ins ios kf nd nmrih onset pvr ro rust rw samp sdtd sfc sm sof2 squad st tf2 terraria ts ts3 mcb mohaa mta unt ut ut99 vh vs wurm xnt zmr) apply_post_install_fix=(av kf kf2 nd ro ut2k4 ut3) # validate registered fixes for safe development diff --git a/lgsm/modules/fix_ahl.sh b/lgsm/modules/fix_ahl.sh new file mode 100755 index 0000000000..a547d64a25 --- /dev/null +++ b/lgsm/modules/fix_ahl.sh @@ -0,0 +1,29 @@ +#!/bin/bash +# LinuxGSM fix_ahl.sh module +# Author: Daniel Gibbs +# Contributors: https://linuxgsm.com/contrib +# Website: https://linuxgsm.com +# Description: Resolves issues with Action Half-Life. + +# shellcheck disable=SC2034 # Used by the module loader. +moduleselfname="$(basename "$(readlink -f "${BASH_SOURCE[0]}")")" + +export GLIBC_TUNABLES="${GLIBC_TUNABLES:+${GLIBC_TUNABLES}:}glibc.rtld.execstack=2" + +rehldsversion="3.15.0.896" +rehldsfile="rehlds-bin-${rehldsversion}.zip" + +if ! grep -qs '"BetaKey"[[:space:]]*"steam_legacy"' "${serverfiles}/steamapps/appmanifest_90.acf"; then + fn_print_warn_nl "ReHLDS requires the steam_legacy branch: run ./${selfname} force-update" + fn_script_log_warn "ReHLDS requires the steam_legacy branch: run ./${selfname} force-update" +elif [ "$(md5sum "${serverfiles}/engine_i486.so" 2> /dev/null | awk '{print $1}')" != "a3aa351c97922f17b8290dce3f5b9bf0" ]; then + # shellcheck disable=SC2034 # Used by fn_fix_msg_start_nl and fn_fix_msg_end. + fixname="ReHLDS ${rehldsversion}" + fn_fix_msg_start_nl + fn_fetch_file "https://github.com/rehlds/ReHLDS/releases/download/${rehldsversion}/${rehldsfile}" "" "" "" "${tmpdir}" "${rehldsfile}" "nochmodx" "norun" "noforce" "87b8dd8bce18ccc2295069f7382bb4d3" + fn_dl_extract "${tmpdir}" "${rehldsfile}" "${tmpdir}/rehlds" + cp -a "${tmpdir}/rehlds/bin/linux32/." "${serverfiles}/" + chmod +x "${serverfiles}/hlds_linux" "${serverfiles}/hltv" + fn_clear_tmp + fn_fix_msg_end +fi From 75d3159c3efd4add4dfb916a846d59e1bb7c980b Mon Sep 17 00:00:00 2001 From: Daniel Gibbs Date: Wed, 4 Nov 2026 21:24:18 +0000 Subject: [PATCH 163/164] fix(won2): restore startup and queries on modern glibc (#5151) Select the generic i386 glibc copy path for hlwon and cswon so the legacy engine does not corrupt its startup command buffer and skip map loading. Use corrected server archives that restore the original client DLLs needed for the engine's client CRC check. Existing archive files are unchanged. Fixes #5142 --- lgsm/modules/core_modules.sh | 10 ++++++++++ lgsm/modules/fix.sh | 2 +- lgsm/modules/fix_cswon.sh | 11 +++++++++++ lgsm/modules/fix_hlwon.sh | 11 +++++++++++ lgsm/modules/install_server_files.sh | 12 ++++++------ 5 files changed, 39 insertions(+), 7 deletions(-) create mode 100755 lgsm/modules/fix_cswon.sh create mode 100755 lgsm/modules/fix_hlwon.sh diff --git a/lgsm/modules/core_modules.sh b/lgsm/modules/core_modules.sh index cbe4aa4af8..2dd80f8a4d 100755 --- a/lgsm/modules/core_modules.sh +++ b/lgsm/modules/core_modules.sh @@ -443,6 +443,11 @@ fix_csgo.sh() { fn_fetch_module } +fix_cswon.sh() { + modulefile="${FUNCNAME[0]}" + fn_fetch_module +} + fix_ct.sh() { modulefile="${FUNCNAME[0]}" fn_fetch_module @@ -453,6 +458,11 @@ fix_dst.sh() { fn_fetch_module } +fix_hlwon.sh() { + modulefile="${FUNCNAME[0]}" + fn_fetch_module +} + fix_hw.sh() { modulefile="${FUNCNAME[0]}" fn_fetch_module diff --git a/lgsm/modules/fix.sh b/lgsm/modules/fix.sh index 9165ea0736..ea74c7228f 100755 --- a/lgsm/modules/fix.sh +++ b/lgsm/modules/fix.sh @@ -53,7 +53,7 @@ fn_apply_fix() { fi } -apply_pre_start_fix=(ahl arma3 armar ark av bf1942 bfv bt bo csgo cmw cod cod2 coduo codwaw ct dst hw ins ios kf nd nmrih onset pvr ro rust rw samp sdtd sfc sm sof2 squad st tf2 terraria ts ts3 mcb mohaa mta unt ut ut99 vh vs wurm xnt zmr) +apply_pre_start_fix=(ahl arma3 armar ark av bf1942 bfv bt bo csgo cmw cod cod2 coduo codwaw cswon ct dst hlwon hw ins ios kf nd nmrih onset pvr ro rust rw samp sdtd sfc sm sof2 squad st tf2 terraria ts ts3 mcb mohaa mta unt ut ut99 vh vs wurm xnt zmr) apply_post_install_fix=(av kf kf2 nd ro ut2k4 ut3) # validate registered fixes for safe development diff --git a/lgsm/modules/fix_cswon.sh b/lgsm/modules/fix_cswon.sh new file mode 100755 index 0000000000..2ba4bafff9 --- /dev/null +++ b/lgsm/modules/fix_cswon.sh @@ -0,0 +1,11 @@ +#!/bin/bash +# LinuxGSM fix_cswon.sh module +# Author: Daniel Gibbs +# Contributors: https://linuxgsm.com/contrib +# Website: https://linuxgsm.com +# Description: Resolves issues with Counter-Strike WON2. + +# shellcheck disable=SC2034 # Used by the module loader. +moduleselfname="$(basename "$(readlink -f "${BASH_SOURCE[0]}")")" + +export GLIBC_TUNABLES="${GLIBC_TUNABLES:+${GLIBC_TUNABLES}:}glibc.cpu.hwcaps=-Fast_Unaligned_Load,-SSSE3" diff --git a/lgsm/modules/fix_hlwon.sh b/lgsm/modules/fix_hlwon.sh new file mode 100755 index 0000000000..5f8a0c47db --- /dev/null +++ b/lgsm/modules/fix_hlwon.sh @@ -0,0 +1,11 @@ +#!/bin/bash +# LinuxGSM fix_hlwon.sh module +# Author: Daniel Gibbs +# Contributors: https://linuxgsm.com/contrib +# Website: https://linuxgsm.com +# Description: Resolves issues with Half-Life WON2. + +# shellcheck disable=SC2034 # Used by the module loader. +moduleselfname="$(basename "$(readlink -f "${BASH_SOURCE[0]}")")" + +export GLIBC_TUNABLES="${GLIBC_TUNABLES:+${GLIBC_TUNABLES}:}glibc.cpu.hwcaps=-Fast_Unaligned_Load,-SSSE3" diff --git a/lgsm/modules/install_server_files.sh b/lgsm/modules/install_server_files.sh index 34290d9bd5..966268e48d 100755 --- a/lgsm/modules/install_server_files.sh +++ b/lgsm/modules/install_server_files.sh @@ -74,21 +74,21 @@ fn_install_server_files() { force="noforce" md5="d7bdc6b2a671c3e07184e1a3262ec14c" elif [ "${shortname}" == "cswon" ]; then - remote_fileurl="https://linuxgsm.download/CounterStrikeWON2/cswon-3111e-cs15-linux-i386-linuxgsm-20261102.tar.xz" + remote_fileurl="https://linuxgsm.download/CounterStrikeWON2/cswon-3111e-cs15-linux-i386-linuxgsm-20261104.tar.xz" local_filedir="${tmpdir}" - local_filename="cswon-3111e-cs15-linux-i386-linuxgsm-20261102.tar.xz" + local_filename="cswon-3111e-cs15-linux-i386-linuxgsm-20261104.tar.xz" chmodx="nochmodx" run="norun" force="noforce" - md5="0be5f9f766e48b8bbd480dfa4a9d9aa0" + md5="97f91d5a3b70ddff0fc9b2fd4ea1cfd6" elif [ "${shortname}" == "hlwon" ]; then - remote_fileurl="https://linuxgsm.download/HalfLifeWON2/hlwon-3111e-linux-i386-linuxgsm-20261102.tar.xz" + remote_fileurl="https://linuxgsm.download/HalfLifeWON2/hlwon-3111e-linux-i386-linuxgsm-20261104.tar.xz" local_filedir="${tmpdir}" - local_filename="hlwon-3111e-linux-i386-linuxgsm-20261102.tar.xz" + local_filename="hlwon-3111e-linux-i386-linuxgsm-20261104.tar.xz" chmodx="nochmodx" run="norun" force="noforce" - md5="e64fda09d31f3acc977fb621b5ffd4fd" + md5="d4a57dc07648853138a700cacc84aef2" elif [ "${shortname}" == "mohaa" ]; then remote_fileurl="https://linuxgsm.download/MedalofHonorAlliedAssault/mohaa-1.12-rc3.5.1-linux-i386-linuxgsm-20261102.tar.xz" local_filedir="${tmpdir}" From 3c16604d2fdf6063096f76542f3afab99f563303 Mon Sep 17 00:00:00 2001 From: Daniel Gibbs Date: Wed, 4 Nov 2026 21:50:01 +0000 Subject: [PATCH 164/164] Release v26.5.0 --- lgsm/modules/core_modules.sh | 2 +- linuxgsm.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lgsm/modules/core_modules.sh b/lgsm/modules/core_modules.sh index 2dd80f8a4d..47add40e40 100755 --- a/lgsm/modules/core_modules.sh +++ b/lgsm/modules/core_modules.sh @@ -8,7 +8,7 @@ moduleselfname="$(basename "$(readlink -f "${BASH_SOURCE[0]}")")" -modulesversion="v26.4.0" +modulesversion="v26.5.0" # Core diff --git a/linuxgsm.sh b/linuxgsm.sh index cd4681203d..cbf7f50a9c 100755 --- a/linuxgsm.sh +++ b/linuxgsm.sh @@ -24,7 +24,7 @@ if [ -f ".dev-debug" ]; then set -x fi -version="v26.4.0" +version="v26.5.0" shortname="core" gameservername="core" commandname="CORE"