From 4ff437ec0bae761d3c77b7f034ccf681c0ed08a0 Mon Sep 17 00:00:00 2001 From: Celio Lozatto Date: Wed, 2 Sep 2026 10:01:53 -0300 Subject: [PATCH 1/6] feat: add CI workflow for automated Windows and Linux build pipelines --- .github/workflows/build.yml | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 394c16b7..cfce8d46 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -167,18 +167,15 @@ jobs: - name: GPG Import run: | - echo "${{ secrets.PUB_ASC }}" > "${{ secrets.PUB_ASC_FILE }}" - echo "${{ secrets.KEY_ASC }}" > "${{ secrets.KEY_ASC_FILE }}" - # Import the public key - gpg --batch --yes --import "${{ secrets.PUB_ASC_FILE }}" + gpg --batch --yes --import <(echo "${{ secrets.PUB_ASC }}") if [[ $? -ne 0 ]]; then echo "Error: Failed to import the public key" exit 1 fi # Import the private key - gpg --batch --yes --import "${{ secrets.KEY_ASC_FILE }}" + gpg --batch --yes --import <(echo "${{ secrets.KEY_ASC }}") if [[ $? -ne 0 ]]; then echo "Error: Failed to import the private key" exit 2 @@ -281,10 +278,8 @@ jobs: run: | # new runner, niw signs - echo "${{ secrets.PUB_ASC }}" > "${{ secrets.PUB_ASC_FILE }}" - echo "${{ secrets.KEY_ASC }}" > "${{ secrets.KEY_ASC_FILE }}" - gpg --batch --yes --import "${{ secrets.PUB_ASC_FILE }}" - gpg --batch --yes --import "${{ secrets.KEY_ASC_FILE }}" + gpg --batch --yes --import <(echo "${{ secrets.PUB_ASC }}") + gpg --batch --yes --import <(echo "${{ secrets.KEY_ASC }}") GPG_LINUX_FINGERPRINT=$(gpg --list-keys --with-colons | grep '^fpr' | head -n 1 | cut -d: -f10) echo "$GPG_LINUX_FINGERPRINT:6:" | gpg --batch --import-ownertrust echo "GPG_LINUX_FINGERPRINT=$GPG_LINUX_FINGERPRINT" >> $GITHUB_ENV From 3b7a637e9ebaadf8d6692a7912ff3fb5502268e3 Mon Sep 17 00:00:00 2001 From: Celio Lozatto Date: Wed, 2 Sep 2026 12:59:32 -0300 Subject: [PATCH 2/6] ci: add GitHub Actions workflow for building and packaging Windows and Linux binaries --- .github/workflows/build.yml | 43 +++++++++++++++++++++---------------- 1 file changed, 24 insertions(+), 19 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index cfce8d46..8f7b0e19 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -166,6 +166,7 @@ jobs: fetch-depth: 0 - name: GPG Import + if: github.event_name != 'pull_request' && secrets.PUB_ASC != '' run: | # Import the public key gpg --batch --yes --import <(echo "${{ secrets.PUB_ASC }}") @@ -203,7 +204,6 @@ jobs: #export for global use echo "GPG_LINUX_FINGERPRINT=$GPG_LINUX_FINGERPRINT" >> $GITHUB_ENV shell: bash - if: github.event_name != 'pull_request' - name: Build run: | @@ -277,26 +277,31 @@ jobs: startsWith(github.ref, 'refs/tags/') run: | + # Pack final archive + 7z a -tzip reapi-bin-${{ needs.linux.outputs.app-version }}.zip addons/ + # new runner, niw signs - gpg --batch --yes --import <(echo "${{ secrets.PUB_ASC }}") - gpg --batch --yes --import <(echo "${{ secrets.KEY_ASC }}") - GPG_LINUX_FINGERPRINT=$(gpg --list-keys --with-colons | grep '^fpr' | head -n 1 | cut -d: -f10) - echo "$GPG_LINUX_FINGERPRINT:6:" | gpg --batch --import-ownertrust - echo "GPG_LINUX_FINGERPRINT=$GPG_LINUX_FINGERPRINT" >> $GITHUB_ENV + if [ -n "${{ secrets.PUB_ASC }}" ]; then + gpg --batch --yes --import <(echo "${{ secrets.PUB_ASC }}") + gpg --batch --yes --import <(echo "${{ secrets.KEY_ASC }}") + GPG_LINUX_FINGERPRINT=$(gpg --list-keys --with-colons | grep '^fpr' | head -n 1 | cut -d: -f10) + echo "$GPG_LINUX_FINGERPRINT:6:" | gpg --batch --import-ownertrust + echo "GPG_LINUX_FINGERPRINT=$GPG_LINUX_FINGERPRINT" >> $GITHUB_ENV + + sign_file() { + local file=$1 + gpg --batch --yes --detach-sign --armor -u "$GPG_LINUX_FINGERPRINT" "$file" + if [ $? -ne 0 ]; then + echo "Error: Failed to sign $file" + exit 2 + fi + echo "$file signed successfully." + } - sign_file() { - local file=$1 - gpg --batch --yes --detach-sign --armor -u "$GPG_LINUX_FINGERPRINT" "$file" - if [ $? -ne 0 ]; then - echo "Error: Failed to sign $file" - exit 2 - fi - echo "$file signed successfully." - } - - # Pack and sign final archive - 7z a -tzip reapi-bin-${{ needs.linux.outputs.app-version }}.zip addons/ - sign_file "reapi-bin-${{ needs.linux.outputs.app-version }}.zip" + sign_file "reapi-bin-${{ needs.linux.outputs.app-version }}.zip" + else + echo "GPG keys not provided, skipping signature." + fi - name: Publish artifacts uses: softprops/action-gh-release@v2 From bd26a87e5d2328c329521e65e228e0080e717f10 Mon Sep 17 00:00:00 2001 From: Celio Lozatto Date: Wed, 2 Sep 2026 13:04:55 -0300 Subject: [PATCH 3/6] feat: add GitHub Actions workflow for building and signing Windows and Linux binaries --- .github/workflows/build.yml | 74 +++++++++++++++++++------------------ 1 file changed, 39 insertions(+), 35 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 8f7b0e19..8e2329a2 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -166,43 +166,47 @@ jobs: fetch-depth: 0 - name: GPG Import - if: github.event_name != 'pull_request' && secrets.PUB_ASC != '' + if: github.event_name != 'pull_request' run: | - # Import the public key - gpg --batch --yes --import <(echo "${{ secrets.PUB_ASC }}") - if [[ $? -ne 0 ]]; then - echo "Error: Failed to import the public key" - exit 1 - fi - - # Import the private key - gpg --batch --yes --import <(echo "${{ secrets.KEY_ASC }}") - if [[ $? -ne 0 ]]; then - echo "Error: Failed to import the private key" - exit 2 - fi - - # Extract the fingerprint of the imported public key - GPG_LINUX_FINGERPRINT=$(gpg --list-keys --with-colons | grep '^fpr' | head -n 1 | cut -d: -f10) - - # Check if the fingerprint was extracted - if [[ -z "$GPG_LINUX_FINGERPRINT" ]]; then - echo "Error: Failed to extract the fingerprint of the key" - exit 3 - fi - - # Set the trust level for the key - echo "$GPG_LINUX_FINGERPRINT:6:" | gpg --batch --import-ownertrust - if [ $? -ne 0 ]; then - echo "Error: Failed to set trust for the key $GPG_LINUX_FINGERPRINT" - exit 4 - fi - - echo "Key $GPG_LINUX_FINGERPRINT successfully imported and trusted" - gpg --list-keys + if [ -n "${{ secrets.PUB_ASC }}" ]; then + # Import the public key + gpg --batch --yes --import <(echo "${{ secrets.PUB_ASC }}") + if [[ $? -ne 0 ]]; then + echo "Error: Failed to import the public key" + exit 1 + fi + + # Import the private key + gpg --batch --yes --import <(echo "${{ secrets.KEY_ASC }}") + if [[ $? -ne 0 ]]; then + echo "Error: Failed to import the private key" + exit 2 + fi + + # Extract the fingerprint of the imported public key + GPG_LINUX_FINGERPRINT=$(gpg --list-keys --with-colons | grep '^fpr' | head -n 1 | cut -d: -f10) + + # Check if the fingerprint was extracted + if [[ -z "$GPG_LINUX_FINGERPRINT" ]]; then + echo "Error: Failed to extract the fingerprint of the key" + exit 3 + fi + + # Set the trust level for the key + echo "$GPG_LINUX_FINGERPRINT:6:" | gpg --batch --import-ownertrust + if [ $? -ne 0 ]; then + echo "Error: Failed to set trust for the key $GPG_LINUX_FINGERPRINT" + exit 4 + fi + + echo "Key $GPG_LINUX_FINGERPRINT successfully imported and trusted" + gpg --list-keys - #export for global use - echo "GPG_LINUX_FINGERPRINT=$GPG_LINUX_FINGERPRINT" >> $GITHUB_ENV + #export for global use + echo "GPG_LINUX_FINGERPRINT=$GPG_LINUX_FINGERPRINT" >> $GITHUB_ENV + else + echo "GPG keys not provided, skipping signature." + fi shell: bash - name: Build From a12e4df8971bc355ea860f92acf4fbdb40344de0 Mon Sep 17 00:00:00 2001 From: Celio Lozatto Date: Wed, 2 Sep 2026 13:19:53 -0300 Subject: [PATCH 4/6] ci: add GitHub Actions workflow for cross-platform build and release automation --- .github/workflows/build.yml | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 8e2329a2..eea79dda 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -126,10 +126,14 @@ jobs: # https://github.com/actions/runner-images/blob/main/images/windows/Windows2025-Readme.md run: | $pfxBase64 = "${{ secrets.KEY_PFX_B64 }}" - [IO.File]::WriteAllBytes("${{ github.workspace }}\signing-cert.pfx", [Convert]::FromBase64String($pfxBase64)) - certutil -f -p "${{ secrets.KEY_PFX_PASS }}" -importPFX "${{ github.workspace }}\signing-cert.pfx" - & 'C:\Program Files (x86)\Windows Kits\10\bin\10.0.26100.0\x86\signtool.exe' sign /a /f "${{ github.workspace }}\signing-cert.pfx" /p $env:KEY_PFX_PASS /d "ReAPI - AMX Mod X module, using API regamedll & rehlds" /du "https://rehlds.dev/" /tr "http://timestamp.digicert.com" /td sha256 /fd sha256 /v ${{ github.workspace }}\publish\addons\amxmodx\modules\reapi_amxx.dll - Remove-Item -Recurse -Force "${{ github.workspace }}\signing-cert.pfx" + if (-not [string]::IsNullOrWhiteSpace($pfxBase64)) { + [IO.File]::WriteAllBytes("${{ github.workspace }}\signing-cert.pfx", [Convert]::FromBase64String($pfxBase64)) + certutil -f -p "${{ secrets.KEY_PFX_PASS }}" -importPFX "${{ github.workspace }}\signing-cert.pfx" + & 'C:\Program Files (x86)\Windows Kits\10\bin\10.0.26100.0\x86\signtool.exe' sign /a /f "${{ github.workspace }}\signing-cert.pfx" /p $env:KEY_PFX_PASS /d "ReAPI - AMX Mod X module, using API regamedll & rehlds" /du "https://rehlds.dev/" /tr "http://timestamp.digicert.com" /td sha256 /fd sha256 /v ${{ github.workspace }}\publish\addons\amxmodx\modules\reapi_amxx.dll + Remove-Item -Recurse -Force "${{ github.workspace }}\signing-cert.pfx" + } else { + Write-Host "PFX certificate not provided, skipping signature." + } shell: "pwsh" - name: Deploy artifacts From f5ca9ec3019dd3c20fe63d5ae2f4d80d487c4c63 Mon Sep 17 00:00:00 2001 From: Celio Lozatto Date: Wed, 2 Sep 2026 13:52:51 -0300 Subject: [PATCH 5/6] feat: Add HUD message queue natives --- .../scripting/include/reapi_gamedll.inc | 57 ++++++++++++++++++ reapi/src/natives/natives_misc.cpp | 60 +++++++++++++++++++ 2 files changed, 117 insertions(+) diff --git a/reapi/extra/amxmodx/scripting/include/reapi_gamedll.inc b/reapi/extra/amxmodx/scripting/include/reapi_gamedll.inc index 9dc9d8c9..ac128dad 100644 --- a/reapi/extra/amxmodx/scripting/include/reapi_gamedll.inc +++ b/reapi/extra/amxmodx/scripting/include/reapi_gamedll.inc @@ -881,6 +881,63 @@ native rg_send_bartime2(const index, const duration, const Float:startPercent, c */ native rg_send_audio(const index, const sample[], const pitch = PITCH_NORM); +/** +* Sends a HUD message using the new queue system without formatting. +* +* @param index Client index, use 0 to display to all players +* @param message Message to send +* @param red Red color component +* @param green Green color component +* @param blue Blue color component +* @param x X position +* @param y Y position +* @param effects Effects +* @param fxtime FX Time +* @param holdtime Hold time +* @param fadeintime Fade in time +* @param fadeouttime Fade out time +* @param channel Channel +* +* @noreturn +*/ +native rg_send_hudmessage(const index, const message[], const red = 200, const green = 100, const blue = 0, const Float:x = -1.0, const Float:y = 0.35, const effects = 0, const Float:fxtime = 6.0, const Float:holdtime = 12.0, const Float:fadeintime = 0.1, const Float:fadeouttime = 0.2, const channel = 0); + +stock Float:__rg_hud_params[10]; +stock __rg_hud_colors[4]; + +/** +* Simulates the old set_hudmessage by saving parameters to globals. +*/ +stock rg_set_hudmessage(red=200, green=100, blue=0, Float:x=-1.0, Float:y=0.35, effects=0, Float:fxtime=6.0, Float:holdtime=12.0, Float:fadeintime=0.1, Float:fadeouttime=0.2, channel=0) { + __rg_hud_colors[0] = red; + __rg_hud_colors[1] = green; + __rg_hud_colors[2] = blue; + __rg_hud_colors[3] = channel; + + __rg_hud_params[0] = x; + __rg_hud_params[1] = y; + __rg_hud_params[2] = float(effects); + __rg_hud_params[3] = fxtime; + __rg_hud_params[4] = holdtime; + __rg_hud_params[5] = fadeintime; + __rg_hud_params[6] = fadeouttime; +} + +/** +* Simulates the old show_hudmessage, automatically formatting the text and pushing to the queue. +*/ +stock rg_show_hudmessage(const index, const message[], any:...) { + new buffer[512]; + vformat(buffer, charsmax(buffer), message, 3); + + rg_send_hudmessage(index, buffer, + __rg_hud_colors[0], __rg_hud_colors[1], __rg_hud_colors[2], + __rg_hud_params[0], __rg_hud_params[1], + floatround(__rg_hud_params[2]), // effects + __rg_hud_params[3], __rg_hud_params[4], __rg_hud_params[5], __rg_hud_params[6], + __rg_hud_colors[3]); +} + /** * Sets a parameter of the member CSPlayerItem::m_ItemInfo * diff --git a/reapi/src/natives/natives_misc.cpp b/reapi/src/natives/natives_misc.cpp index 4e813bea..460497ea 100644 --- a/reapi/src/natives/natives_misc.cpp +++ b/reapi/src/natives/natives_misc.cpp @@ -2138,6 +2138,65 @@ enum ItemInfo_e ItemInfo_iWeight }; +/** +* Sends a HUD message using the new queue system +* +* @param index Client index, use 0 to display to all players +* @param message Message to send +* @param red Red color component +* @param green Green color component +* @param blue Blue color component +* @param x X position +* @param y Y position +* @param effects Effects +* @param fxtime FX Time +* @param holdtime Hold time +* @param fadeintime Fade in time +* @param fadeouttime Fade out time +* @param channel Channel +* +* @noreturn +*/ +cell AMX_NATIVE_CALL rg_send_hudmessage(AMX *amx, cell *params) +{ + enum args_e { arg_count, arg_index, arg_message, arg_red, arg_green, arg_blue, arg_x, arg_y, arg_effects, arg_fxtime, arg_holdtime, arg_fadeintime, arg_fadeouttime, arg_channel }; + + if (!g_ReGameApi) + return FALSE; + + int nIndex = params[arg_index]; + if (nIndex < 0 || nIndex > gpGlobals->maxClients) { + AMXX_LogError(amx, AMX_ERR_NATIVE, "Invalid player %d", nIndex); + return FALSE; + } + + char message[512]; + const char *szMessage = getAmxString(amx, params[arg_message], message); + + hudtextparms_t textparms; + textparms.r1 = params[arg_red]; + textparms.g1 = params[arg_green]; + textparms.b1 = params[arg_blue]; + textparms.a1 = 0; + + textparms.r2 = 255; + textparms.g2 = 255; + textparms.b2 = 250; + textparms.a2 = 0; + + textparms.x = amx_ctof(params[arg_x]); + textparms.y = amx_ctof(params[arg_y]); + textparms.effect = params[arg_effects]; + textparms.fxTime = amx_ctof(params[arg_fxtime]); + textparms.holdTime = amx_ctof(params[arg_holdtime]); + textparms.fadeinTime = amx_ctof(params[arg_fadeintime]); + textparms.fadeoutTime = amx_ctof(params[arg_fadeouttime]); + textparms.channel = params[arg_channel]; + + g_ReGameApi->QueueHudMessage(nIndex, textparms, szMessage); + return TRUE; +} + /** * Sets a parameter of the member CSPlayerItem::m_ItemInfo * @@ -3547,6 +3606,7 @@ AMX_NATIVE_INFO Misc_Natives_RG[] = { "rg_send_bartime", rg_send_bartime }, { "rg_send_bartime2", rg_send_bartime2 }, { "rg_send_audio", rg_send_audio }, + { "rg_send_hudmessage", rg_send_hudmessage }, { "rg_set_iteminfo", rg_set_iteminfo }, { "rg_get_iteminfo", rg_get_iteminfo }, From 9cd226106fe964684411860f1bdf3814aac90743 Mon Sep 17 00:00:00 2001 From: Celio Lozatto Date: Wed, 2 Sep 2026 14:00:45 -0300 Subject: [PATCH 6/6] fix: compilation errors missing amx_ctof and QueueHudMessage in ReAPI headers --- reapi/include/cssdk/dlls/regamedll_api.h | 1 + reapi/src/natives/natives_misc.cpp | 12 ++++++------ 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/reapi/include/cssdk/dlls/regamedll_api.h b/reapi/include/cssdk/dlls/regamedll_api.h index 8222d68b..82583f92 100644 --- a/reapi/include/cssdk/dlls/regamedll_api.h +++ b/reapi/include/cssdk/dlls/regamedll_api.h @@ -858,6 +858,7 @@ class IReGameApi { virtual struct AmmoInfoStruct *GetAmmoInfoEx(const char *ammoName) = 0; virtual bool BGetICSEntity(const char *pchVersion) const = 0; virtual bool BGetIGameRules(const char *pchVersion) const = 0; + virtual void QueueHudMessage(int client, const struct hudtextparms_s &textparms, const char *pMessage) = 0; }; #define VRE_GAMEDLL_API_VERSION "VRE_GAMEDLL_API_VERSION001" diff --git a/reapi/src/natives/natives_misc.cpp b/reapi/src/natives/natives_misc.cpp index 460497ea..f94148b8 100644 --- a/reapi/src/natives/natives_misc.cpp +++ b/reapi/src/natives/natives_misc.cpp @@ -2184,13 +2184,13 @@ cell AMX_NATIVE_CALL rg_send_hudmessage(AMX *amx, cell *params) textparms.b2 = 250; textparms.a2 = 0; - textparms.x = amx_ctof(params[arg_x]); - textparms.y = amx_ctof(params[arg_y]); + textparms.x = *(float *)¶ms[arg_x]; + textparms.y = *(float *)¶ms[arg_y]; textparms.effect = params[arg_effects]; - textparms.fxTime = amx_ctof(params[arg_fxtime]); - textparms.holdTime = amx_ctof(params[arg_holdtime]); - textparms.fadeinTime = amx_ctof(params[arg_fadeintime]); - textparms.fadeoutTime = amx_ctof(params[arg_fadeouttime]); + textparms.fxTime = *(float *)¶ms[arg_fxtime]; + textparms.holdTime = *(float *)¶ms[arg_holdtime]; + textparms.fadeinTime = *(float *)¶ms[arg_fadeintime]; + textparms.fadeoutTime = *(float *)¶ms[arg_fadeouttime]; textparms.channel = params[arg_channel]; g_ReGameApi->QueueHudMessage(nIndex, textparms, szMessage);