From bb7a98df26e0f5b4902883da21b589e6de5f0bc9 Mon Sep 17 00:00:00 2001 From: Timi007 Date: Tue, 26 Dec 2023 15:38:56 +0100 Subject: [PATCH 1/6] Use HEMTT v1 build system (#104) * Use HEMTT v1 * Remove obsolete tools * Download HEMTT from GitHub * Use new HEMTT in CI/CD * Fix HEMTT build errors * Fix padding macro warning * Fix path and env vars * Do not archive when running CD and add build CI test * Formatting * Use maintained upload release asset action * Fix helper script commands --- .editorconfig | 2 + .github/workflows/arma.yml | 14 +- .github/workflows/release.yml | 51 +- .gitignore | 2 +- .hemtt/hooks/post_release/01_rename_zip.rhai | 14 + .hemtt/project.toml | 35 + .vscode/tasks.json | 11 +- addons/armory/ui/RscAttributes.hpp | 102 +- .../functions/fnc_getModuleDestination.sqf | 2 +- build.bat | 2 +- build_release.bat | 2 +- hemtt.toml | 44 - .../cba/addons/main/script_macros_common.hpp | 32 +- sqfc.json | 15 - tools/build.py | 104 -- tools/compile_sqf.py | 55 - tools/make.cfg | 96 -- tools/make.py | 1515 ----------------- tools/setup.bat | 30 +- 19 files changed, 171 insertions(+), 1957 deletions(-) create mode 100644 .hemtt/hooks/post_release/01_rename_zip.rhai create mode 100644 .hemtt/project.toml delete mode 100644 hemtt.toml delete mode 100644 sqfc.json delete mode 100644 tools/build.py delete mode 100644 tools/compile_sqf.py delete mode 100644 tools/make.cfg delete mode 100644 tools/make.py diff --git a/.editorconfig b/.editorconfig index 0deca3d..a5ee115 100644 --- a/.editorconfig +++ b/.editorconfig @@ -11,3 +11,5 @@ trim_trailing_whitespace = true [*.md] trim_trailing_whitespace = false +[*.yml] +indent_size = 2 diff --git a/.github/workflows/arma.yml b/.github/workflows/arma.yml index 55e030f..293c2d3 100644 --- a/.github/workflows/arma.yml +++ b/.github/workflows/arma.yml @@ -11,8 +11,20 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout the source code - uses: actions/checkout@master + uses: actions/checkout@v4 - name: Validate SQF run: python3 tools/sqf_validator.py - name: Validate Config run: python3 tools/config_style_checker.py + - name: Check for BOM + uses: arma-actions/bom-check@v1 + + build: + runs-on: ubuntu-latest + steps: + - name: Checkout the source code + uses: actions/checkout@v4 + - name: Setup HEMTT + uses: arma-actions/hemtt@v1 + - name: Run HEMTT build + run: hemtt build diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index f1b11a5..a4b7386 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -12,45 +12,36 @@ jobs: if: github.repository == 'Metis-Team/mts_enhanced' && ! contains(github.event.head_commit.message, '[ci skip]') runs-on: windows-latest outputs: - NAME: ${{ env.NAME }} MOD_NAME: ${{ env.MOD_NAME }} - MOD_NAME_LOWER: ${{ env.MOD_NAME_LOWER }} - MAIN_PREFIX: ${{ env.MAIN_PREFIX }} VERSION: ${{ env.VERSION }} VERSION_SHORT: ${{ env.VERSION_SHORT }} SHA_SHORT: ${{ env.SHA_SHORT }} steps: - name: Checkout the source code - uses: actions/checkout@v2 + uses: actions/checkout@v4 + + - name: Setup HEMTT + uses: arma-actions/hemtt@v1 - name: Setup Tools run: | C:\msys64\usr\bin\wget.exe ${{ secrets.FTP_SERVER }}/arma_tools.zip --user ${{ secrets.FTP_USERNAME }} --password ${{ secrets.FTP_PASSWORD }} -q Expand-Archive arma_tools.zip -DestinationPath ci - echo "Check HEMTT: $(Test-Path .\\ci\\hemtt.exe)" echo "Check Binarize: $(Test-Path .\\ci\\binarize\\binarize_x64.exe)" - echo "Check ArmaScriptCompiler: $(Test-Path .\\ci\\ArmaScriptCompiler.exe)" - .\ci\hemtt.exe --version + hemtt --version echo "Install Binarize dependencies" cp .\ci\binarize\X3DAudio1_7.dll,.\ci\binarize\XAPOFX1_5.dll C:\Windows\System32\ echo "::group::Set Binarize registry path" New-Item "HKCU:\\Software\\Bohemia Interactive\\binarize" -Force | New-ItemProperty -Name path -Value "${{ github.workspace }}\ci\binarize" echo "::endgroup::" echo "Set env variables" - echo "NAME=$(.\\ci\\hemtt.exe var name)" >> $env:GITHUB_ENV - echo "MOD_NAME=$(.\\ci\\hemtt.exe var modname)" >> $env:GITHUB_ENV - echo "MOD_NAME_LOWER=$((.\\ci\\hemtt.exe var modname).toLower())" >> $env:GITHUB_ENV - echo "MAIN_PREFIX=$(.\\ci\\hemtt.exe var mainprefix)" >> $env:GITHUB_ENV - echo "VERSION=$(.\\ci\\hemtt.exe var version)" >> $env:GITHUB_ENV - echo "VERSION_SHORT=$(($(.\\ci\\hemtt.exe var version) | Select-String -Pattern '^\d+\.\d+\.\d+').Matches.Value)" >> $env:GITHUB_ENV + echo "MOD_NAME=Metis_Enhanced" >> $env:GITHUB_ENV + $version = Select-String -Path "addons\\main\\script_version.hpp" -Pattern '#define (MAJOR|MINOR|PATCHLVL|BUILD) (\d+)' | ForEach-Object { $_.Matches.Groups[2].Value } | Join-String -Separator "." + $version_short = (Select-String -InputObject $version -Pattern '^\d+\.\d+\.\d+').Matches.Value + echo "VERSION=$version" >> $env:GITHUB_ENV + echo "VERSION_SHORT=$version_short" >> $env:GITHUB_ENV echo "SHA_SHORT=$(git rev-parse --short HEAD)" >> $env:GITHUB_ENV - - name: Setup P-Drive for ArmaScriptCompiler - run: | - echo "Creating P: and linking ${{ env.MAIN_PREFIX }}\mts_enhanced\addons" - subst p: include - New-Item -ItemType Junction -Path "p:${{ env.MAIN_PREFIX }}\mts_enhanced\addons" -Target "addons" - - name: Test Binarize run: | echo "::group::Run Binarize without arguments (look for missing DLLs)" @@ -60,16 +51,19 @@ jobs: - name: Build (HEMTT) run: | - echo "${{ env.NAME }} v${{ env.VERSION_SHORT }} (${{ env.VERSION }}; ${{ env.SHA_SHORT }})" - .\ci\hemtt.exe build --release --ci --time + echo "${{ env.MOD_NAME }} v${{ env.VERSION }} (${{ env.SHA_SHORT }})" + hemtt release --no-archive env: BIOUTPUT: 1 # output binarize log + - name: Rename build folder + run: mv .hemttout/release .hemttout/@${{ env.MOD_NAME }} + - name: Upload Artifact - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v3 with: name: ${{ env.MOD_NAME }} - path: releases/${{ env.VERSION }}/* # Upload folder to avoid double-zip artifacts + path: .hemttout/@* retention-days: 1 publish-release: @@ -78,14 +72,16 @@ jobs: runs-on: ubuntu-latest steps: - name: Download Artifacts - uses: actions/download-artifact@v2 + uses: actions/download-artifact@v3 + - name: Prepare Archives run: | mv ${{ needs.build.outputs.MOD_NAME }}/* . echo "::group::Archive build" zip -r ${{ needs.build.outputs.MOD_NAME }}_${{ needs.build.outputs.VERSION_SHORT }}.zip @${{ needs.build.outputs.MOD_NAME }} echo "::endgroup::" - - name: Prepare GitHub + + - name: Prepare GitHub Release id: release_drafter uses: release-drafter/release-drafter@v5 with: @@ -94,8 +90,9 @@ jobs: version: ${{ needs.build.outputs.VERSION }} env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - name: Upload to GitHub - uses: actions/upload-release-asset@v1 + + - name: Upload mod archive to GitHub Release + uses: shogo82148/actions-upload-release-asset@v1.7.2 with: upload_url: ${{ steps.release_drafter.outputs.upload_url }} asset_path: ./${{ needs.build.outputs.MOD_NAME }}_${{ needs.build.outputs.VERSION_SHORT }}.zip diff --git a/.gitignore b/.gitignore index 64dca67..5f6f8a1 100644 --- a/.gitignore +++ b/.gitignore @@ -14,5 +14,5 @@ hemtt hemtt.exe releases/* keys/* -.hemtt/local +.hemttout/ #### diff --git a/.hemtt/hooks/post_release/01_rename_zip.rhai b/.hemtt/hooks/post_release/01_rename_zip.rhai new file mode 100644 index 0000000..3385fbf --- /dev/null +++ b/.hemtt/hooks/post_release/01_rename_zip.rhai @@ -0,0 +1,14 @@ +let releases = HEMTT_RFS.join("releases"); + +let src = releases.join(HEMTT.project().prefix() + "-" + HEMTT.project().version().to_string() + ".zip"); + +if (src.exists()) { + let dst = releases.join(HEMTT.project().name() + "_" + HEMTT.project().version().to_string_short() + ".zip"); + + print("Moving archive to " + dst); + if (!src.move(dst)) { + fatal("Failed to rename " + src + " to " + dst); + } +} else { + warn("Cannot rename archive. File " + src + " does not exist!"); +} diff --git a/.hemtt/project.toml b/.hemtt/project.toml new file mode 100644 index 0000000..821caf1 --- /dev/null +++ b/.hemtt/project.toml @@ -0,0 +1,35 @@ +name = "Metis_Enhanced" +mainprefix = "z" +prefix = "mts" +author = "Bix, PhILoX, Timi007" + +[files] +include = [ + "mod.cpp", + "README.md", + "LICENSE", + "mts_enhanced_picture.paa", + "mts_enhanced_logo_small.paa", + "mts_enhanced_logo_over_small.paa", + "meta.cpp" +] + +[signing] +authority = "mts_enhanced" + +[version] +git_hash = 0 + +[asc] +enabled = true +exclude = [ + "/initsettings.sqf", + "/initkeybinds.sqf", + "/xeh_prep.sqf", +] + +[hemtt.config] +preset = "Hemtt" + +[hemtt.release] +folder = "Metis_Enhanced" diff --git a/.vscode/tasks.json b/.vscode/tasks.json index 629df82..bef2126 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -5,7 +5,7 @@ "label": "Build Debug", "detail": "Build Arma addon with HEMTT in debug mode.", "type": "process", - "command": "hemtt.exe", + "command": "hemtt", "args": ["build"], "group": "build", "presentation": { @@ -18,13 +18,8 @@ "label": "Build Release", "detail": "Build Arma addon with HEMTT for release.", "type": "process", - "command": "hemtt.exe", - "args": [ - "build", - "--release", - "--time", - "-f" - ], + "command": "hemtt", + "args": ["release"], "group": "build" } ] diff --git a/addons/armory/ui/RscAttributes.hpp b/addons/armory/ui/RscAttributes.hpp index 6f9d1bc..4c10d60 100644 --- a/addons/armory/ui/RscAttributes.hpp +++ b/addons/armory/ui/RscAttributes.hpp @@ -46,7 +46,7 @@ class GVAR(dialog) { y = "SafeZoneY + (180 / 1080) * SafeZoneH"; w = "(30 / 1920) * SafeZoneW"; h = "(30 / 1080) * SafeZoneH"; - onCheckedChanged = QUOTE([ARR_2(QQGVAR(updateArsenal), [ARR_2(ctrlText IDC_TEXT_TITLE, (cbChecked (_this select 0)))])] call CBA_fnc_globalEvent); + onCheckedChanged = QUOTE([ARR_2(QQGVAR(updateArsenal),[ARR_2(ctrlText IDC_TEXT_TITLE,(cbChecked (_this select 0)))])] call CBA_fnc_globalEvent); }; class Text_Title : Text { idc = IDC_TEXT_TITLE; @@ -112,7 +112,7 @@ class GVAR(dialog) { y = "SafeZoneY + (310 / 1080) * SafeZoneH"; w = "(150 / 1920) * SafeZoneW"; h = "(30 / 1080) * SafeZoneH"; - onButtonClick = QUOTE([ARR_2(ctrlText IDC_TEXT_TITLE, ctrlText (_this select 0))] call LINKFUNC(equipLoadout)); + onButtonClick = QUOTE([ARR_2(ctrlText IDC_TEXT_TITLE,ctrlText (_this select 0))] call LINKFUNC(equipLoadout)); }; class Button_Loadout_2 : Button { idc = IDC_LOADOUT_2; @@ -120,7 +120,7 @@ class GVAR(dialog) { y = "SafeZoneY + (350 / 1080) * SafeZoneH"; w = "(150 / 1920) * SafeZoneW"; h = "(30 / 1080) * SafeZoneH"; - onButtonClick = QUOTE([ARR_2(ctrlText IDC_TEXT_TITLE, ctrlText (_this select 0))] call LINKFUNC(equipLoadout)); + onButtonClick = QUOTE([ARR_2(ctrlText IDC_TEXT_TITLE,ctrlText (_this select 0))] call LINKFUNC(equipLoadout)); }; class Button_Loadout_3 : Button { idc = IDC_LOADOUT_3; @@ -128,7 +128,7 @@ class GVAR(dialog) { y = "SafeZoneY + (390 / 1080) * SafeZoneH"; w = "(150 / 1920) * SafeZoneW"; h = "(30 / 1080) * SafeZoneH"; - onButtonClick = QUOTE([ARR_2(ctrlText IDC_TEXT_TITLE, ctrlText (_this select 0))] call LINKFUNC(equipLoadout)); + onButtonClick = QUOTE([ARR_2(ctrlText IDC_TEXT_TITLE,ctrlText (_this select 0))] call LINKFUNC(equipLoadout)); }; class Button_Loadout_4 : Button { idc = IDC_LOADOUT_4; @@ -136,7 +136,7 @@ class GVAR(dialog) { y = "SafeZoneY + (430 / 1080) * SafeZoneH"; w = "(150 / 1920) * SafeZoneW"; h = "(30 / 1080) * SafeZoneH"; - onButtonClick = QUOTE([ARR_2(ctrlText IDC_TEXT_TITLE, ctrlText (_this select 0))] call LINKFUNC(equipLoadout)); + onButtonClick = QUOTE([ARR_2(ctrlText IDC_TEXT_TITLE,ctrlText (_this select 0))] call LINKFUNC(equipLoadout)); }; class Button_Loadout_5 : Button { idc = IDC_LOADOUT_5; @@ -144,7 +144,7 @@ class GVAR(dialog) { y = "SafeZoneY + (470 / 1080) * SafeZoneH"; w = "(150 / 1920) * SafeZoneW"; h = "(30 / 1080) * SafeZoneH"; - onButtonClick = QUOTE([ARR_2(ctrlText IDC_TEXT_TITLE, ctrlText (_this select 0))] call LINKFUNC(equipLoadout)); + onButtonClick = QUOTE([ARR_2(ctrlText IDC_TEXT_TITLE,ctrlText (_this select 0))] call LINKFUNC(equipLoadout)); }; class Button_Loadout_6 : Button { idc = IDC_LOADOUT_6; @@ -152,7 +152,7 @@ class GVAR(dialog) { y = "SafeZoneY + (510 / 1080) * SafeZoneH"; w = "(150 / 1920) * SafeZoneW"; h = "(30 / 1080) * SafeZoneH"; - onButtonClick = QUOTE([ARR_2(ctrlText IDC_TEXT_TITLE, ctrlText (_this select 0))] call LINKFUNC(equipLoadout)); + onButtonClick = QUOTE([ARR_2(ctrlText IDC_TEXT_TITLE,ctrlText (_this select 0))] call LINKFUNC(equipLoadout)); }; class Button_Loadout_7 : Button { idc = IDC_LOADOUT_7; @@ -160,7 +160,7 @@ class GVAR(dialog) { y = "SafeZoneY + (550 / 1080) * SafeZoneH"; w = "(150 / 1920) * SafeZoneW"; h = "(30 / 1080) * SafeZoneH"; - onButtonClick = QUOTE([ARR_2(ctrlText IDC_TEXT_TITLE, ctrlText (_this select 0))] call LINKFUNC(equipLoadout)); + onButtonClick = QUOTE([ARR_2(ctrlText IDC_TEXT_TITLE,ctrlText (_this select 0))] call LINKFUNC(equipLoadout)); }; class Button_Loadout_8 : Button { idc = IDC_LOADOUT_8; @@ -168,7 +168,7 @@ class GVAR(dialog) { y = "SafeZoneY + (590 / 1080) * SafeZoneH"; w = "(150 / 1920) * SafeZoneW"; h = "(30 / 1080) * SafeZoneH"; - onButtonClick = QUOTE([ARR_2(ctrlText IDC_TEXT_TITLE, ctrlText (_this select 0))] call LINKFUNC(equipLoadout)); + onButtonClick = QUOTE([ARR_2(ctrlText IDC_TEXT_TITLE,ctrlText (_this select 0))] call LINKFUNC(equipLoadout)); }; class Button_Loadout_9 : Button { idc = IDC_LOADOUT_9; @@ -176,7 +176,7 @@ class GVAR(dialog) { y = "SafeZoneY + (630 / 1080) * SafeZoneH"; w = "(150 / 1920) * SafeZoneW"; h = "(30 / 1080) * SafeZoneH"; - onButtonClick = QUOTE([ARR_2(ctrlText IDC_TEXT_TITLE, ctrlText (_this select 0))] call LINKFUNC(equipLoadout)); + onButtonClick = QUOTE([ARR_2(ctrlText IDC_TEXT_TITLE,ctrlText (_this select 0))] call LINKFUNC(equipLoadout)); }; class Button_Loadout_10 : Button { idc = IDC_LOADOUT_10; @@ -184,7 +184,7 @@ class GVAR(dialog) { y = "SafeZoneY + (670 / 1080) * SafeZoneH"; w = "(150 / 1920) * SafeZoneW"; h = "(30 / 1080) * SafeZoneH"; - onButtonClick = QUOTE([ARR_2(ctrlText IDC_TEXT_TITLE, ctrlText (_this select 0))] call LINKFUNC(equipLoadout)); + onButtonClick = QUOTE([ARR_2(ctrlText IDC_TEXT_TITLE,ctrlText (_this select 0))] call LINKFUNC(equipLoadout)); }; class Button_Loadout_11 : Button { idc = IDC_LOADOUT_11; @@ -192,7 +192,7 @@ class GVAR(dialog) { y = "SafeZoneY + (710 / 1080) * SafeZoneH"; w = "(150 / 1920) * SafeZoneW"; h = "(30 / 1080) * SafeZoneH"; - onButtonClick = QUOTE([ARR_2(ctrlText IDC_TEXT_TITLE, ctrlText (_this select 0))] call LINKFUNC(equipLoadout)); + onButtonClick = QUOTE([ARR_2(ctrlText IDC_TEXT_TITLE,ctrlText (_this select 0))] call LINKFUNC(equipLoadout)); }; class Button_Loadout_12 : Button { idc = IDC_LOADOUT_12; @@ -200,7 +200,7 @@ class GVAR(dialog) { y = "SafeZoneY + (750 / 1080) * SafeZoneH"; w = "(150 / 1920) * SafeZoneW"; h = "(30 / 1080) * SafeZoneH"; - onButtonClick = QUOTE([ARR_2(ctrlText IDC_TEXT_TITLE, ctrlText (_this select 0))] call LINKFUNC(equipLoadout)); + onButtonClick = QUOTE([ARR_2(ctrlText IDC_TEXT_TITLE,ctrlText (_this select 0))] call LINKFUNC(equipLoadout)); }; // Body loadout configure buttons ---------------------------------------- class Button_Loadout_Edit_1 : Button_Image { @@ -209,7 +209,7 @@ class GVAR(dialog) { y = "SafeZoneY + (310 / 1080) * SafeZoneH"; w = "(30 / 1920) * SafeZoneW"; h = "(30 / 1080) * SafeZoneH"; - onButtonClick = QUOTE([ARR_2(IDC_LOADOUT_1, LOADOUT)] call LINKFUNC(setEditArea)); + onButtonClick = QUOTE([ARR_2(IDC_LOADOUT_1,LOADOUT)] call LINKFUNC(setEditArea)); onMouseEnter = QUOTE(((ctrlParent (_this select 0)) displayCtrl IDC_BACKGROUND_EDIT_LOADOUT_1) ctrlSetBackgroundColor [ARR_4(0,0,0,1)]); onMouseExit = QUOTE(((ctrlParent (_this select 0)) displayCtrl IDC_BACKGROUND_EDIT_LOADOUT_1) ctrlSetBackgroundColor [ARR_4(0,0,0,0.5)]); }; @@ -219,7 +219,7 @@ class GVAR(dialog) { y = "SafeZoneY + (350 / 1080) * SafeZoneH"; w = "(30 / 1920) * SafeZoneW"; h = "(30 / 1080) * SafeZoneH"; - onButtonClick = QUOTE([ARR_2(IDC_LOADOUT_2, LOADOUT)] call LINKFUNC(setEditArea)); + onButtonClick = QUOTE([ARR_2(IDC_LOADOUT_2,LOADOUT)] call LINKFUNC(setEditArea)); onMouseEnter = QUOTE(((ctrlParent (_this select 0)) displayCtrl IDC_BACKGROUND_EDIT_LOADOUT_2) ctrlSetBackgroundColor [ARR_4(0,0,0,1)]); onMouseExit = QUOTE(((ctrlParent (_this select 0)) displayCtrl IDC_BACKGROUND_EDIT_LOADOUT_2) ctrlSetBackgroundColor [ARR_4(0,0,0,0.5)]); }; @@ -229,7 +229,7 @@ class GVAR(dialog) { y = "SafeZoneY + (390 / 1080) * SafeZoneH"; w = "(30 / 1920) * SafeZoneW"; h = "(30 / 1080) * SafeZoneH"; - onButtonClick = QUOTE([ARR_2(IDC_LOADOUT_3, LOADOUT)] call LINKFUNC(setEditArea)); + onButtonClick = QUOTE([ARR_2(IDC_LOADOUT_3,LOADOUT)] call LINKFUNC(setEditArea)); onMouseEnter = QUOTE(((ctrlParent (_this select 0)) displayCtrl IDC_BACKGROUND_EDIT_LOADOUT_3) ctrlSetBackgroundColor [ARR_4(0,0,0,1)]); onMouseExit = QUOTE(((ctrlParent (_this select 0)) displayCtrl IDC_BACKGROUND_EDIT_LOADOUT_3) ctrlSetBackgroundColor [ARR_4(0,0,0,0.5)]); }; @@ -239,7 +239,7 @@ class GVAR(dialog) { y = "SafeZoneY + (430 / 1080) * SafeZoneH"; w = "(30 / 1920) * SafeZoneW"; h = "(30 / 1080) * SafeZoneH"; - onButtonClick = QUOTE([ARR_2(IDC_LOADOUT_4, LOADOUT)] call LINKFUNC(setEditArea)); + onButtonClick = QUOTE([ARR_2(IDC_LOADOUT_4,LOADOUT)] call LINKFUNC(setEditArea)); onMouseEnter = QUOTE(((ctrlParent (_this select 0)) displayCtrl IDC_BACKGROUND_EDIT_LOADOUT_4) ctrlSetBackgroundColor [ARR_4(0,0,0,1)]); onMouseExit = QUOTE(((ctrlParent (_this select 0)) displayCtrl IDC_BACKGROUND_EDIT_LOADOUT_4) ctrlSetBackgroundColor [ARR_4(0,0,0,0.5)]); }; @@ -249,7 +249,7 @@ class GVAR(dialog) { y = "SafeZoneY + (470 / 1080) * SafeZoneH"; w = "(30 / 1920) * SafeZoneW"; h = "(30 / 1080) * SafeZoneH"; - onButtonClick = QUOTE([ARR_2(IDC_LOADOUT_5, LOADOUT)] call LINKFUNC(setEditArea)); + onButtonClick = QUOTE([ARR_2(IDC_LOADOUT_5,LOADOUT)] call LINKFUNC(setEditArea)); onMouseEnter = QUOTE(((ctrlParent (_this select 0)) displayCtrl IDC_BACKGROUND_EDIT_LOADOUT_5) ctrlSetBackgroundColor [ARR_4(0,0,0,1)]); onMouseExit = QUOTE(((ctrlParent (_this select 0)) displayCtrl IDC_BACKGROUND_EDIT_LOADOUT_5) ctrlSetBackgroundColor [ARR_4(0,0,0,0.5)]); }; @@ -259,7 +259,7 @@ class GVAR(dialog) { y = "SafeZoneY + (510 / 1080) * SafeZoneH"; w = "(30 / 1920) * SafeZoneW"; h = "(30 / 1080) * SafeZoneH"; - onButtonClick = QUOTE([ARR_2(IDC_LOADOUT_6, LOADOUT)] call LINKFUNC(setEditArea)); + onButtonClick = QUOTE([ARR_2(IDC_LOADOUT_6,LOADOUT)] call LINKFUNC(setEditArea)); onMouseEnter = QUOTE(((ctrlParent (_this select 0)) displayCtrl IDC_BACKGROUND_EDIT_LOADOUT_6) ctrlSetBackgroundColor [ARR_4(0,0,0,1)]); onMouseExit = QUOTE(((ctrlParent (_this select 0)) displayCtrl IDC_BACKGROUND_EDIT_LOADOUT_6) ctrlSetBackgroundColor [ARR_4(0,0,0,0.5)]); }; @@ -269,7 +269,7 @@ class GVAR(dialog) { y = "SafeZoneY + (550 / 1080) * SafeZoneH"; w = "(30 / 1920) * SafeZoneW"; h = "(30 / 1080) * SafeZoneH"; - onButtonClick = QUOTE([ARR_2(IDC_LOADOUT_7, LOADOUT)] call LINKFUNC(setEditArea)); + onButtonClick = QUOTE([ARR_2(IDC_LOADOUT_7,LOADOUT)] call LINKFUNC(setEditArea)); onMouseEnter = QUOTE(((ctrlParent (_this select 0)) displayCtrl IDC_BACKGROUND_EDIT_LOADOUT_7) ctrlSetBackgroundColor [ARR_4(0,0,0,1)]); onMouseExit = QUOTE(((ctrlParent (_this select 0)) displayCtrl IDC_BACKGROUND_EDIT_LOADOUT_7) ctrlSetBackgroundColor [ARR_4(0,0,0,0.5)]); }; @@ -279,7 +279,7 @@ class GVAR(dialog) { y = "SafeZoneY + (590 / 1080) * SafeZoneH"; w = "(30 / 1920) * SafeZoneW"; h = "(30 / 1080) * SafeZoneH"; - onButtonClick = QUOTE([ARR_2(IDC_LOADOUT_8, LOADOUT)] call LINKFUNC(setEditArea)); + onButtonClick = QUOTE([ARR_2(IDC_LOADOUT_8,LOADOUT)] call LINKFUNC(setEditArea)); onMouseEnter = QUOTE(((ctrlParent (_this select 0)) displayCtrl IDC_BACKGROUND_EDIT_LOADOUT_8) ctrlSetBackgroundColor [ARR_4(0,0,0,1)]); onMouseExit = QUOTE(((ctrlParent (_this select 0)) displayCtrl IDC_BACKGROUND_EDIT_LOADOUT_8) ctrlSetBackgroundColor [ARR_4(0,0,0,0.5)]); }; @@ -289,7 +289,7 @@ class GVAR(dialog) { y = "SafeZoneY + (630 / 1080) * SafeZoneH"; w = "(30 / 1920) * SafeZoneW"; h = "(30 / 1080) * SafeZoneH"; - onButtonClick = QUOTE([ARR_2(IDC_LOADOUT_9, LOADOUT)] call LINKFUNC(setEditArea)); + onButtonClick = QUOTE([ARR_2(IDC_LOADOUT_9,LOADOUT)] call LINKFUNC(setEditArea)); onMouseEnter = QUOTE(((ctrlParent (_this select 0)) displayCtrl IDC_BACKGROUND_EDIT_LOADOUT_9) ctrlSetBackgroundColor [ARR_4(0,0,0,1)]); onMouseExit = QUOTE(((ctrlParent (_this select 0)) displayCtrl IDC_BACKGROUND_EDIT_LOADOUT_9) ctrlSetBackgroundColor [ARR_4(0,0,0,0.5)]); }; @@ -299,7 +299,7 @@ class GVAR(dialog) { y = "SafeZoneY + (670 / 1080) * SafeZoneH"; w = "(30 / 1920) * SafeZoneW"; h = "(30 / 1080) * SafeZoneH"; - onButtonClick = QUOTE([ARR_2(IDC_LOADOUT_10, LOADOUT)] call LINKFUNC(setEditArea)); + onButtonClick = QUOTE([ARR_2(IDC_LOADOUT_10,LOADOUT)] call LINKFUNC(setEditArea)); onMouseEnter = QUOTE(((ctrlParent (_this select 0)) displayCtrl IDC_BACKGROUND_EDIT_LOADOUT_10) ctrlSetBackgroundColor [ARR_4(0,0,0,1)]); onMouseExit = QUOTE(((ctrlParent (_this select 0)) displayCtrl IDC_BACKGROUND_EDIT_LOADOUT_10) ctrlSetBackgroundColor [ARR_4(0,0,0,0.5)]); }; @@ -309,7 +309,7 @@ class GVAR(dialog) { y = "SafeZoneY + (710 / 1080) * SafeZoneH"; w = "(30 / 1920) * SafeZoneW"; h = "(30 / 1080) * SafeZoneH"; - onButtonClick = QUOTE([ARR_2(IDC_LOADOUT_11, LOADOUT)] call LINKFUNC(setEditArea)); + onButtonClick = QUOTE([ARR_2(IDC_LOADOUT_11,LOADOUT)] call LINKFUNC(setEditArea)); onMouseEnter = QUOTE(((ctrlParent (_this select 0)) displayCtrl IDC_BACKGROUND_EDIT_LOADOUT_11) ctrlSetBackgroundColor [ARR_4(0,0,0,1)]); onMouseExit = QUOTE(((ctrlParent (_this select 0)) displayCtrl IDC_BACKGROUND_EDIT_LOADOUT_11) ctrlSetBackgroundColor [ARR_4(0,0,0,0.5)]); }; @@ -319,7 +319,7 @@ class GVAR(dialog) { y = "SafeZoneY + (750 / 1080) * SafeZoneH"; w = "(30 / 1920) * SafeZoneW"; h = "(30 / 1080) * SafeZoneH"; - onButtonClick = QUOTE([ARR_2(IDC_LOADOUT_12, LOADOUT)] call LINKFUNC(setEditArea)); + onButtonClick = QUOTE([ARR_2(IDC_LOADOUT_12,LOADOUT)] call LINKFUNC(setEditArea)); onMouseEnter = QUOTE(((ctrlParent (_this select 0)) displayCtrl IDC_BACKGROUND_EDIT_LOADOUT_12) ctrlSetBackgroundColor [ARR_4(0,0,0,1)]); onMouseExit = QUOTE(((ctrlParent (_this select 0)) displayCtrl IDC_BACKGROUND_EDIT_LOADOUT_12) ctrlSetBackgroundColor [ARR_4(0,0,0,0.5)]); }; @@ -330,7 +330,7 @@ class GVAR(dialog) { y = "SafeZoneY + (310 / 1080) * SafeZoneH"; w = "(150 / 1920) * SafeZoneW"; h = "(30 / 1080) * SafeZoneH"; - onButtonClick = QUOTE([ARR_2(ctrlText IDC_TEXT_TITLE, ctrlText (_this select 0))] call LINKFUNC(equipBackpack)); + onButtonClick = QUOTE([ARR_2(ctrlText IDC_TEXT_TITLE,ctrlText (_this select 0))] call LINKFUNC(equipBackpack)); }; class Button_Backpack_2 : Button { idc = IDC_BACKPACK_2; @@ -338,7 +338,7 @@ class GVAR(dialog) { y = "SafeZoneY + (350 / 1080) * SafeZoneH"; w = "(150 / 1920) * SafeZoneW"; h = "(30 / 1080) * SafeZoneH"; - onButtonClick = QUOTE([ARR_2(ctrlText IDC_TEXT_TITLE, ctrlText (_this select 0))] call LINKFUNC(equipBackpack)); + onButtonClick = QUOTE([ARR_2(ctrlText IDC_TEXT_TITLE,ctrlText (_this select 0))] call LINKFUNC(equipBackpack)); }; class Button_Backpack_3 : Button { idc = IDC_BACKPACK_3; @@ -346,7 +346,7 @@ class GVAR(dialog) { y = "SafeZoneY + (390 / 1080) * SafeZoneH"; w = "(150 / 1920) * SafeZoneW"; h = "(30 / 1080) * SafeZoneH"; - onButtonClick = QUOTE([ARR_2(ctrlText IDC_TEXT_TITLE, ctrlText (_this select 0))] call LINKFUNC(equipBackpack)); + onButtonClick = QUOTE([ARR_2(ctrlText IDC_TEXT_TITLE,ctrlText (_this select 0))] call LINKFUNC(equipBackpack)); }; class Button_Backpack_4 : Button { idc = IDC_BACKPACK_4; @@ -354,7 +354,7 @@ class GVAR(dialog) { y = "SafeZoneY + (430 / 1080) * SafeZoneH"; w = "(150 / 1920) * SafeZoneW"; h = "(30 / 1080) * SafeZoneH"; - onButtonClick = QUOTE([ARR_2(ctrlText IDC_TEXT_TITLE, ctrlText (_this select 0))] call LINKFUNC(equipBackpack)); + onButtonClick = QUOTE([ARR_2(ctrlText IDC_TEXT_TITLE,ctrlText (_this select 0))] call LINKFUNC(equipBackpack)); }; class Button_Backpack_5 : Button { idc = IDC_BACKPACK_5; @@ -362,7 +362,7 @@ class GVAR(dialog) { y = "SafeZoneY + (470 / 1080) * SafeZoneH"; w = "(150 / 1920) * SafeZoneW"; h = "(30 / 1080) * SafeZoneH"; - onButtonClick = QUOTE([ARR_2(ctrlText IDC_TEXT_TITLE, ctrlText (_this select 0))] call LINKFUNC(equipBackpack)); + onButtonClick = QUOTE([ARR_2(ctrlText IDC_TEXT_TITLE,ctrlText (_this select 0))] call LINKFUNC(equipBackpack)); }; class Button_Backpack_6 : Button { idc = IDC_BACKPACK_6; @@ -370,7 +370,7 @@ class GVAR(dialog) { y = "SafeZoneY + (510 / 1080) * SafeZoneH"; w = "(150 / 1920) * SafeZoneW"; h = "(30 / 1080) * SafeZoneH"; - onButtonClick = QUOTE([ARR_2(ctrlText IDC_TEXT_TITLE, ctrlText (_this select 0))] call LINKFUNC(equipBackpack)); + onButtonClick = QUOTE([ARR_2(ctrlText IDC_TEXT_TITLE,ctrlText (_this select 0))] call LINKFUNC(equipBackpack)); }; class Button_Backpack_7 : Button { idc = IDC_BACKPACK_7; @@ -378,7 +378,7 @@ class GVAR(dialog) { y = "SafeZoneY + (550 / 1080) * SafeZoneH"; w = "(150 / 1920) * SafeZoneW"; h = "(30 / 1080) * SafeZoneH"; - onButtonClick = QUOTE([ARR_2(ctrlText IDC_TEXT_TITLE, ctrlText (_this select 0))] call LINKFUNC(equipBackpack)); + onButtonClick = QUOTE([ARR_2(ctrlText IDC_TEXT_TITLE,ctrlText (_this select 0))] call LINKFUNC(equipBackpack)); }; class Button_Backpack_8 : Button { idc = IDC_BACKPACK_8; @@ -386,7 +386,7 @@ class GVAR(dialog) { y = "SafeZoneY + (590 / 1080) * SafeZoneH"; w = "(150 / 1920) * SafeZoneW"; h = "(30 / 1080) * SafeZoneH"; - onButtonClick = QUOTE([ARR_2(ctrlText IDC_TEXT_TITLE, ctrlText (_this select 0))] call LINKFUNC(equipBackpack)); + onButtonClick = QUOTE([ARR_2(ctrlText IDC_TEXT_TITLE,ctrlText (_this select 0))] call LINKFUNC(equipBackpack)); }; class Button_Backpack_9 : Button { idc = IDC_BACKPACK_9; @@ -394,7 +394,7 @@ class GVAR(dialog) { y = "SafeZoneY + (630 / 1080) * SafeZoneH"; w = "(150 / 1920) * SafeZoneW"; h = "(30 / 1080) * SafeZoneH"; - onButtonClick = QUOTE([ARR_2(ctrlText IDC_TEXT_TITLE, ctrlText (_this select 0))] call LINKFUNC(equipBackpack)); + onButtonClick = QUOTE([ARR_2(ctrlText IDC_TEXT_TITLE,ctrlText (_this select 0))] call LINKFUNC(equipBackpack)); }; class Button_Backpack_10 : Button { idc = IDC_BACKPACK_10; @@ -402,7 +402,7 @@ class GVAR(dialog) { y = "SafeZoneY + (670 / 1080) * SafeZoneH"; w = "(150 / 1920) * SafeZoneW"; h = "(30 / 1080) * SafeZoneH"; - onButtonClick = QUOTE([ARR_2(ctrlText IDC_TEXT_TITLE, ctrlText (_this select 0))] call LINKFUNC(equipBackpack)); + onButtonClick = QUOTE([ARR_2(ctrlText IDC_TEXT_TITLE,ctrlText (_this select 0))] call LINKFUNC(equipBackpack)); }; class Button_Backpack_11 : Button { idc = IDC_BACKPACK_11; @@ -410,7 +410,7 @@ class GVAR(dialog) { y = "SafeZoneY + (710 / 1080) * SafeZoneH"; w = "(150 / 1920) * SafeZoneW"; h = "(30 / 1080) * SafeZoneH"; - onButtonClick = QUOTE([ARR_2(ctrlText IDC_TEXT_TITLE, ctrlText (_this select 0))] call LINKFUNC(equipBackpack)); + onButtonClick = QUOTE([ARR_2(ctrlText IDC_TEXT_TITLE,ctrlText (_this select 0))] call LINKFUNC(equipBackpack)); }; class Button_Backpack_12 : Button { idc = IDC_BACKPACK_12; @@ -418,7 +418,7 @@ class GVAR(dialog) { y = "SafeZoneY + (750 / 1080) * SafeZoneH"; w = "(150 / 1920) * SafeZoneW"; h = "(30 / 1080) * SafeZoneH"; - onButtonClick = QUOTE([ARR_2(ctrlText IDC_TEXT_TITLE, ctrlText (_this select 0))] call LINKFUNC(equipBackpack)); + onButtonClick = QUOTE([ARR_2(ctrlText IDC_TEXT_TITLE,ctrlText (_this select 0))] call LINKFUNC(equipBackpack)); }; // Body backpacks configure buttons ---------------------------------------- class Button_Backpack_Edit_1 : Button_Image { @@ -427,7 +427,7 @@ class GVAR(dialog) { y = "SafeZoneY + (310 / 1080) * SafeZoneH"; w = "(30 / 1920) * SafeZoneW"; h = "(30 / 1080) * SafeZoneH"; - onButtonClick = QUOTE([ARR_2(IDC_BACKPACK_1, BACKPACK)] call LINKFUNC(setEditArea)); + onButtonClick = QUOTE([ARR_2(IDC_BACKPACK_1,BACKPACK)] call LINKFUNC(setEditArea)); onMouseEnter = QUOTE(((ctrlParent (_this select 0)) displayCtrl IDC_BACKGROUND_EDIT_BACKPACK_1) ctrlSetBackgroundColor [ARR_4(0,0,0,1)]); onMouseExit = QUOTE(((ctrlParent (_this select 0)) displayCtrl IDC_BACKGROUND_EDIT_BACKPACK_1) ctrlSetBackgroundColor [ARR_4(0,0,0,0.5)]); }; @@ -437,7 +437,7 @@ class GVAR(dialog) { y = "SafeZoneY + (350 / 1080) * SafeZoneH"; w = "(30 / 1920) * SafeZoneW"; h = "(30 / 1080) * SafeZoneH"; - onButtonClick = QUOTE([ARR_2(IDC_BACKPACK_2, BACKPACK)] call LINKFUNC(setEditArea)); + onButtonClick = QUOTE([ARR_2(IDC_BACKPACK_2,BACKPACK)] call LINKFUNC(setEditArea)); onMouseEnter = QUOTE(((ctrlParent (_this select 0)) displayCtrl IDC_BACKGROUND_EDIT_BACKPACK_2) ctrlSetBackgroundColor [ARR_4(0,0,0,1)]); onMouseExit = QUOTE(((ctrlParent (_this select 0)) displayCtrl IDC_BACKGROUND_EDIT_BACKPACK_2) ctrlSetBackgroundColor [ARR_4(0,0,0,0.5)]); }; @@ -447,7 +447,7 @@ class GVAR(dialog) { y = "SafeZoneY + (390 / 1080) * SafeZoneH"; w = "(30 / 1920) * SafeZoneW"; h = "(30 / 1080) * SafeZoneH"; - onButtonClick = QUOTE([ARR_2(IDC_BACKPACK_3, BACKPACK)] call LINKFUNC(setEditArea)); + onButtonClick = QUOTE([ARR_2(IDC_BACKPACK_3,BACKPACK)] call LINKFUNC(setEditArea)); onMouseEnter = QUOTE(((ctrlParent (_this select 0)) displayCtrl IDC_BACKGROUND_EDIT_BACKPACK_3) ctrlSetBackgroundColor [ARR_4(0,0,0,1)]); onMouseExit = QUOTE(((ctrlParent (_this select 0)) displayCtrl IDC_BACKGROUND_EDIT_BACKPACK_3) ctrlSetBackgroundColor [ARR_4(0,0,0,0.5)]); }; @@ -457,7 +457,7 @@ class GVAR(dialog) { y = "SafeZoneY + (430 / 1080) * SafeZoneH"; w = "(30 / 1920) * SafeZoneW"; h = "(30 / 1080) * SafeZoneH"; - onButtonClick = QUOTE([ARR_2(IDC_BACKPACK_4, BACKPACK)] call LINKFUNC(setEditArea)); + onButtonClick = QUOTE([ARR_2(IDC_BACKPACK_4,BACKPACK)] call LINKFUNC(setEditArea)); onMouseEnter = QUOTE(((ctrlParent (_this select 0)) displayCtrl IDC_BACKGROUND_EDIT_BACKPACK_4) ctrlSetBackgroundColor [ARR_4(0,0,0,1)]); onMouseExit = QUOTE(((ctrlParent (_this select 0)) displayCtrl IDC_BACKGROUND_EDIT_BACKPACK_4) ctrlSetBackgroundColor [ARR_4(0,0,0,0.5)]); }; @@ -467,7 +467,7 @@ class GVAR(dialog) { y = "SafeZoneY + (470 / 1080) * SafeZoneH"; w = "(30 / 1920) * SafeZoneW"; h = "(30 / 1080) * SafeZoneH"; - onButtonClick = QUOTE([ARR_2(IDC_BACKPACK_5, BACKPACK)] call LINKFUNC(setEditArea)); + onButtonClick = QUOTE([ARR_2(IDC_BACKPACK_5,BACKPACK)] call LINKFUNC(setEditArea)); onMouseEnter = QUOTE(((ctrlParent (_this select 0)) displayCtrl IDC_BACKGROUND_EDIT_BACKPACK_5) ctrlSetBackgroundColor [ARR_4(0,0,0,1)]); onMouseExit = QUOTE(((ctrlParent (_this select 0)) displayCtrl IDC_BACKGROUND_EDIT_BACKPACK_5) ctrlSetBackgroundColor [ARR_4(0,0,0,0.5)]); }; @@ -477,7 +477,7 @@ class GVAR(dialog) { y = "SafeZoneY + (510 / 1080) * SafeZoneH"; w = "(30 / 1920) * SafeZoneW"; h = "(30 / 1080) * SafeZoneH"; - onButtonClick = QUOTE([ARR_2(IDC_BACKPACK_6, BACKPACK)] call LINKFUNC(setEditArea)); + onButtonClick = QUOTE([ARR_2(IDC_BACKPACK_6,BACKPACK)] call LINKFUNC(setEditArea)); onMouseEnter = QUOTE(((ctrlParent (_this select 0)) displayCtrl IDC_BACKGROUND_EDIT_BACKPACK_6) ctrlSetBackgroundColor [ARR_4(0,0,0,1)]); onMouseExit = QUOTE(((ctrlParent (_this select 0)) displayCtrl IDC_BACKGROUND_EDIT_BACKPACK_6) ctrlSetBackgroundColor [ARR_4(0,0,0,0.5)]); }; @@ -487,7 +487,7 @@ class GVAR(dialog) { y = "SafeZoneY + (550 / 1080) * SafeZoneH"; w = "(30 / 1920) * SafeZoneW"; h = "(30 / 1080) * SafeZoneH"; - onButtonClick = QUOTE([ARR_2(IDC_BACKPACK_7, BACKPACK)] call LINKFUNC(setEditArea)); + onButtonClick = QUOTE([ARR_2(IDC_BACKPACK_7,BACKPACK)] call LINKFUNC(setEditArea)); onMouseEnter = QUOTE(((ctrlParent (_this select 0)) displayCtrl IDC_BACKGROUND_EDIT_BACKPACK_7) ctrlSetBackgroundColor [ARR_4(0,0,0,1)]); onMouseExit = QUOTE(((ctrlParent (_this select 0)) displayCtrl IDC_BACKGROUND_EDIT_BACKPACK_7) ctrlSetBackgroundColor [ARR_4(0,0,0,0.5)]); }; @@ -497,7 +497,7 @@ class GVAR(dialog) { y = "SafeZoneY + (590 / 1080) * SafeZoneH"; w = "(30 / 1920) * SafeZoneW"; h = "(30 / 1080) * SafeZoneH"; - onButtonClick = QUOTE([ARR_2(IDC_BACKPACK_8, BACKPACK)] call LINKFUNC(setEditArea)); + onButtonClick = QUOTE([ARR_2(IDC_BACKPACK_8,BACKPACK)] call LINKFUNC(setEditArea)); onMouseEnter = QUOTE(((ctrlParent (_this select 0)) displayCtrl IDC_BACKGROUND_EDIT_BACKPACK_8) ctrlSetBackgroundColor [ARR_4(0,0,0,1)]); onMouseExit = QUOTE(((ctrlParent (_this select 0)) displayCtrl IDC_BACKGROUND_EDIT_BACKPACK_8) ctrlSetBackgroundColor [ARR_4(0,0,0,0.5)]); }; @@ -507,7 +507,7 @@ class GVAR(dialog) { y = "SafeZoneY + (630 / 1080) * SafeZoneH"; w = "(30 / 1920) * SafeZoneW"; h = "(30 / 1080) * SafeZoneH"; - onButtonClick = QUOTE([ARR_2(IDC_BACKPACK_9, BACKPACK)] call LINKFUNC(setEditArea)); + onButtonClick = QUOTE([ARR_2(IDC_BACKPACK_9,BACKPACK)] call LINKFUNC(setEditArea)); onMouseEnter = QUOTE(((ctrlParent (_this select 0)) displayCtrl IDC_BACKGROUND_EDIT_BACKPACK_9) ctrlSetBackgroundColor [ARR_4(0,0,0,1)]); onMouseExit = QUOTE(((ctrlParent (_this select 0)) displayCtrl IDC_BACKGROUND_EDIT_BACKPACK_9) ctrlSetBackgroundColor [ARR_4(0,0,0,0.5)]); }; @@ -517,7 +517,7 @@ class GVAR(dialog) { y = "SafeZoneY + (670 / 1080) * SafeZoneH"; w = "(30 / 1920) * SafeZoneW"; h = "(30 / 1080) * SafeZoneH"; - onButtonClick = QUOTE([ARR_2(IDC_BACKPACK_10, BACKPACK)] call LINKFUNC(setEditArea)); + onButtonClick = QUOTE([ARR_2(IDC_BACKPACK_10,BACKPACK)] call LINKFUNC(setEditArea)); onMouseEnter = QUOTE(((ctrlParent (_this select 0)) displayCtrl IDC_BACKGROUND_EDIT_BACKPACK_10) ctrlSetBackgroundColor [ARR_4(0,0,0,1)]); onMouseExit = QUOTE(((ctrlParent (_this select 0)) displayCtrl IDC_BACKGROUND_EDIT_BACKPACK_10) ctrlSetBackgroundColor [ARR_4(0,0,0,0.5)]); }; @@ -527,7 +527,7 @@ class GVAR(dialog) { y = "SafeZoneY + (710 / 1080) * SafeZoneH"; w = "(30 / 1920) * SafeZoneW"; h = "(30 / 1080) * SafeZoneH"; - onButtonClick = QUOTE([ARR_2(IDC_BACKPACK_11, BACKPACK)] call LINKFUNC(setEditArea)); + onButtonClick = QUOTE([ARR_2(IDC_BACKPACK_11,BACKPACK)] call LINKFUNC(setEditArea)); onMouseEnter = QUOTE(((ctrlParent (_this select 0)) displayCtrl IDC_BACKGROUND_EDIT_BACKPACK_11) ctrlSetBackgroundColor [ARR_4(0,0,0,1)]); onMouseExit = QUOTE(((ctrlParent (_this select 0)) displayCtrl IDC_BACKGROUND_EDIT_BACKPACK_11) ctrlSetBackgroundColor [ARR_4(0,0,0,0.5)]); }; @@ -537,7 +537,7 @@ class GVAR(dialog) { y = "SafeZoneY + (750 / 1080) * SafeZoneH"; w = "(30 / 1920) * SafeZoneW"; h = "(30 / 1080) * SafeZoneH"; - onButtonClick = QUOTE([ARR_2(IDC_BACKPACK_12, BACKPACK)] call LINKFUNC(setEditArea)); + onButtonClick = QUOTE([ARR_2(IDC_BACKPACK_12,BACKPACK)] call LINKFUNC(setEditArea)); onMouseEnter = QUOTE(((ctrlParent (_this select 0)) displayCtrl IDC_BACKGROUND_EDIT_BACKPACK_12) ctrlSetBackgroundColor [ARR_4(0,0,0,1)]); onMouseExit = QUOTE(((ctrlParent (_this select 0)) displayCtrl IDC_BACKGROUND_EDIT_BACKPACK_12) ctrlSetBackgroundColor [ARR_4(0,0,0,0.5)]); }; @@ -566,7 +566,7 @@ class GVAR(dialog) { y = "SafeZoneY + (800 / 1080) * SafeZoneH"; w = "(30 / 1920) * SafeZoneW"; h = "(30 / 1080) * SafeZoneH"; - onButtonClick = QUOTE([ARR_2(((ctrlParent (_this select 0)) displayCtrl IDC_BUTTON_SAVE_EQUIPMENT), true)] call LINKFUNC(saveEquipment)); + onButtonClick = QUOTE([ARR_2(((ctrlParent (_this select 0)) displayCtrl IDC_BUTTON_SAVE_EQUIPMENT),true)] call LINKFUNC(saveEquipment)); onMouseEnter = QUOTE(((ctrlParent (_this select 0)) displayCtrl IDC_BACKGROUND_DELETE_EQUIPMENT) ctrlSetBackgroundColor [ARR_4(0,0,0,1)]); onMouseExit = QUOTE(((ctrlParent (_this select 0)) displayCtrl IDC_BACKGROUND_DELETE_EQUIPMENT) ctrlSetBackgroundColor [ARR_4(0,0,0,0.5)]); }; @@ -599,7 +599,7 @@ class GVAR(dialog) { y = "SafeZoneY + (965 / 1080) * SafeZoneH"; w = "(150 / 1920) * SafeZoneW"; h = "(30 / 1080) * SafeZoneH"; - onButtonClick = QUOTE([ARR_2(QQGVAR(updateEditors),[ARR_2(ctrlText IDC_TEXT_TITLE, ctrlText IDC_EDITBOX_EDITORS)])] call CBA_fnc_serverEvent); + onButtonClick = QUOTE([ARR_2(QQGVAR(updateEditors),[ARR_2(ctrlText IDC_TEXT_TITLE,ctrlText IDC_EDITBOX_EDITORS)])] call CBA_fnc_serverEvent); }; }; class controlsBackground { diff --git a/addons/zeus/functions/fnc_getModuleDestination.sqf b/addons/zeus/functions/fnc_getModuleDestination.sqf index 2f34f4c..2f41b7a 100644 --- a/addons/zeus/functions/fnc_getModuleDestination.sqf +++ b/addons/zeus/functions/fnc_getModuleDestination.sqf @@ -142,7 +142,7 @@ GVAR(moduleDestination_mapDrawEH) = [((findDisplay ZEUS_DISPLAY) displayCtrl ZEU (_this select 0) params ["_startPosASL", "_code", "_text", "_icon", "_color", "_angle", "_drawLine", "_drawIconAtStart", "_beforeDrawingCode"]; if (isNull findDisplay ZEUS_DISPLAY || {!isNull findDisplay PAUSE_MENU_DISPLAY}) then { - TRACE_3("null-exit",isNull findDisplay ZEUS_DISPLAY,isNull findDisplay PAUSE_MENU_DISPLAY); + TRACE_2("null-exit",(isNull findDisplay ZEUS_DISPLAY),(isNull findDisplay PAUSE_MENU_DISPLAY)); GVAR(moduleDestination_running) = false; [false, _startPosASL, [0,0,0], false, false, false, _args] call _code; }; diff --git a/build.bat b/build.bat index 3392b5b..34e67d1 100644 --- a/build.bat +++ b/build.bat @@ -1,3 +1,3 @@ @echo off -hemtt.exe build +hemtt build pause diff --git a/build_release.bat b/build_release.bat index 0b14c1d..8a19ec6 100644 --- a/build_release.bat +++ b/build_release.bat @@ -1,3 +1,3 @@ @echo off -hemtt.exe build --release --time -f +hemtt release pause diff --git a/hemtt.toml b/hemtt.toml deleted file mode 100644 index 499fd7e..0000000 --- a/hemtt.toml +++ /dev/null @@ -1,44 +0,0 @@ -name = "Metis Enhanced" -prefix = "mts" -author = "Bix, PhILoX, Timi007" -files = [ - "*.dll", - "*.so", - "mod.cpp", - "README.md", - "LICENSE", - "mts_enhanced_logo_over_small.paa", - "mts_enhanced_logo_small.paa", - "mts_enhanced_picture.paa", - "meta.cpp" -] - -modname = "Metis_Enhanced" -key_name = "mts_enhanced_{{version}}" -authority = "mts_enhanced_{{version}}-{{git \"id 8\"}}" - -prebuild = ["!compile_sqf"] -postbuild = ["!compile_sqf_cleanup"] -releasebuild = [ - "@zip Metis_Enhanced_{{semver.major}}.{{semver.minor}}.{{semver.patch}}" -] - -[header_exts] -version = "{{git \"id 8\"}}" - -# SQF Compilation -[scripts.compile_sqf] -steps_windows = [ - "echo Compile SQF", - "python tools/compile_sqf.py cleanup build" -] -only_release = true -show_output = true - -[scripts.compile_sqf_cleanup] -steps_windows = [ - "echo Compile SQF Cleanup", - "python tools/compile_sqf.py cleanup" -] -only_release = true -show_output = true diff --git a/include/x/cba/addons/main/script_macros_common.hpp b/include/x/cba/addons/main/script_macros_common.hpp index be13021..7d930c6 100644 --- a/include/x/cba/addons/main/script_macros_common.hpp +++ b/include/x/cba/addons/main/script_macros_common.hpp @@ -15,7 +15,7 @@ - Provide a solid structure that can be dynamic and easy editable (Which sometimes means we cannot adhere to Aim #1 ;-) An example is the path that is built from defines. Some available in this file, others in mods and addons. - Follows Standard: + Follows Standard: Object variables: PREFIX_COMPONENT Main-object variables: PREFIX_main Paths: MAINPREFIX\PREFIX\SUBPREFIX\COMPONENT\SCRIPTNAME.sqf @@ -29,6 +29,10 @@ and include your mod's script_macros.hpp In your scripts you can then include the addon's component.hpp with relative path) + use in subcomponents (subconfigs) + define SUBCOMPONENT and include parent component's script_component.hpp + currently only supported by SUBADDON, additional macros may be added in the future + TODO: - Try only to use 1 string type " vs ' - Evaluate double functions, and simplification @@ -54,6 +58,10 @@ #define ADDON DOUBLES(PREFIX,COMPONENT) #define MAIN_ADDON DOUBLES(PREFIX,main) +#ifdef SUBCOMPONENT + #define SUBADDON DOUBLES(ADDON,SUBCOMPONENT) +#endif + /* ------------------------------------------- Macro: VERSION_CONFIG Define CBA Versioning System config entries. @@ -857,15 +865,10 @@ Macro: ISNILS() #define COMPILE_SCRIPT(var1) compileScript ['PATHTO_SYS(PREFIX,COMPONENT_F,var1)'] -#define VERSIONING_SYS(var1) class CfgSettings \ -{ \ - class CBA \ - { \ - class Versioning \ - { \ - class var1 \ - { \ - }; \ +#define VERSIONING_SYS(var1) class CfgSettings { \ + class CBA { \ + class Versioning { \ + class var1 {}; \ }; \ }; \ }; @@ -1032,12 +1035,9 @@ Macro: PATHTO_FNC() #define QQEFUNC(var1,var2) QUOTE(QEFUNC(var1,var2)) #ifndef PRELOAD_ADDONS - #define PRELOAD_ADDONS class CfgAddons \ -{ \ - class PreloadAddons \ - { \ - class ADDON \ - { \ + #define PRELOAD_ADDONS class CfgAddons { \ + class PreloadAddons { \ + class ADDON { \ list[]={ QUOTE(ADDON) }; \ }; \ }; \ diff --git a/sqfc.json b/sqfc.json deleted file mode 100644 index b5f1b7d..0000000 --- a/sqfc.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "inputDirs": [ - "P:/z/mts_enhanced/addons/" - ], - "includePaths": [ - "P:/" - ], - "excludeList": [ - "\\initsettings.sqf", - "\\initkeybinds.sqf", - "\\xeh_prep.sqf" - ], - "outputDir": "P:/", - "workerThreads": 12 -} diff --git a/tools/build.py b/tools/build.py deleted file mode 100644 index 667851f..0000000 --- a/tools/build.py +++ /dev/null @@ -1,104 +0,0 @@ -#!/usr/bin/env python3 - -import os -import sys -import subprocess - -######## GLOBALS ######### -MAINPREFIX = "z" -PREFIX = "mts_" -########################## - -def tryHemttBuild(projectpath): - hemttExe = os.path.join(projectpath, "hemtt.exe") - if os.path.isfile(hemttExe): - os.chdir(projectpath) - ret = subprocess.call([hemttExe, "pack"], stderr=subprocess.STDOUT) - print("Using hemtt: {}".format(ret)) - return True - else: - print("hemtt not installed.") - return False - -def mod_time(path): - if not os.path.isdir(path): - return os.path.getmtime(path) - maxi = os.path.getmtime(path) - for p in os.listdir(path): - maxi = max(mod_time(os.path.join(path, p)), maxi) - return maxi - - -def check_for_changes(addonspath, module): - if not os.path.exists(os.path.join(addonspath, "{}{}.pbo".format(PREFIX,module))): - return True - return mod_time(os.path.join(addonspath, module)) > mod_time(os.path.join(addonspath, "{}{}.pbo".format(PREFIX,module))) - -def check_for_obsolete_pbos(addonspath, file): - module = file[len(PREFIX):-4] - if not os.path.exists(os.path.join(addonspath, module)): - return True - return False - -def main(): - print(""" - #################### - # MTS Debug Build # - #################### -""") - - scriptpath = os.path.realpath(__file__) - projectpath = os.path.dirname(os.path.dirname(scriptpath)) - addonspath = os.path.join(projectpath, "addons") - - if (tryHemttBuild(projectpath)): return - - os.chdir(addonspath) - - made = 0 - failed = 0 - skipped = 0 - removed = 0 - - for file in os.listdir(addonspath): - if os.path.isfile(file): - if check_for_obsolete_pbos(addonspath, file): - removed += 1 - print(" Removing obsolete file => " + file) - os.remove(file) - print("") - - for p in os.listdir(addonspath): - path = os.path.join(addonspath, p) - if not os.path.isdir(path): - continue - if p[0] == ".": - continue - if not check_for_changes(addonspath, p): - skipped += 1 - print(" Skipping {}.".format(p)) - continue - - print("# Making {} ...".format(p)) - - try: - subprocess.check_output([ - "makepbo", - "-NUP", - "-@={}\\{}\\addons\\{}".format(MAINPREFIX,PREFIX.rstrip("_"),p), - p, - "{}{}.pbo".format(PREFIX,p) - ], stderr=subprocess.STDOUT) - except: - failed += 1 - print(" Failed to make {}.".format(p)) - else: - made += 1 - print(" Successfully made {}.".format(p)) - - print("\n# Done.") - print(" Made {}, skipped {}, removed {}, failed to make {}.".format(made, skipped, removed, failed)) - - -if __name__ == "__main__": - sys.exit(main()) diff --git a/tools/compile_sqf.py b/tools/compile_sqf.py deleted file mode 100644 index 75b21e8..0000000 --- a/tools/compile_sqf.py +++ /dev/null @@ -1,55 +0,0 @@ -#!/usr/bin/env python3 - -import os -import sys -import subprocess - -# Handle script being called from either base or /tools folder (e.g. hemmt will run from base) -addon_base_path = os.getcwd() -if os.path.basename(addon_base_path) == "tools": - addon_base_path = os.path.dirname(addon_base_path) - - -def cleanup(): - count = 0 - for root, _dirs, files in os.walk(os.path.join(addon_base_path, "addons")): - for file in files: - if file.endswith(".sqfc"): - os.remove(os.path.join(root, file)) - count += 1 - print("cleaned [{} sqfc files]".format(count)) - - -def build(verbose = False): - compiler_exe = os.path.join(addon_base_path, "ArmaScriptCompiler.exe") - if not os.path.isfile(compiler_exe): - print("ArmaScriptCompiler.exe not found in base addon folder, trying ci folder") - compiler_exe = os.path.join(addon_base_path, "ci", "ArmaScriptCompiler.exe") - if not os.path.isfile(compiler_exe): - print("Warning: ArmaScriptCompiler.exe not found - skipping compiling") - return 1 - print("ArmaScriptCompiler.exe found - starting compiling") - if verbose: - print("\n") - ret = subprocess.call([compiler_exe], cwd=addon_base_path) - print("\n") - else: - ret = subprocess.call([compiler_exe], cwd=addon_base_path, stdout=subprocess.DEVNULL) - print("compiled [ret {}]".format(ret)) - return 0 - - -def main(argv): - ret = 0 - - # print("compile_sqf.py [Base: {}]".format(addon_base_path)) - if ("cleanup" in argv) or (len(argv) < 2): - cleanup() - if ("build" in argv) or (len(argv) < 2): - ret = build("verbose" in argv) - - return ret - - -if __name__ == "__main__": - sys.exit(main(sys.argv)) diff --git a/tools/make.cfg b/tools/make.cfg deleted file mode 100644 index 6357a05..0000000 --- a/tools/make.cfg +++ /dev/null @@ -1,96 +0,0 @@ -# EXAMPLE MAKE.CFG FILE -# Please see the comments for each option. Most options can be left -# off for sane defaults. - -################################################################# -# Default make target -################################################################# -[DEFAULT] - -# Project name (with @ symbol) -# This is used for naming the release files. -# Default: Current folder name -project = @Metis_Enhanced - -# Path to project secret key for signing -# Make sure this isn't in your public repository! -# Default: \private_keys\mts_3.0.0.biprivatekey -# key = P:\private_keys\mts_3.0.0.biprivatekey - -# Path to where private keys are automatically created if the command-line parameter "key" is used -# Make sure this isn't in your public repository! -# Default: \private_keys -# private_key_path = P:\private_keys - -# If set to True, the make system will attempt to autodetect addons in the -# current folder by looking for directories with 'config.cpp' in them. -# Default: True -# module_autodetect = True - -# List of directories to ignore when autodetecting addons. -# Default: release -# ignore = release, my_unfinished_module - -# If autodetect is set to False, only folders whose names are in this list -# will be built as modules. -# Default: None -# modules = my_module, my_supporting_module - -# This is the folder hierarchy that will be used as prefix inside the PBO. -# Default: None -prefix = z\mts_enhanced\addons - -# Set the location where the addon source folders (i.e. P:\z\ace\addons) -# Default: \\addons -module_root = P:\z\mts_enhanced\addons - -# Set the location where the optional addon source folders (i.e. P:\z\ace\optionals) -# Default: \\optionals -optionals_root = P:\z\mts_enhanced\optionals - - -# If the command-line variable test, the addons built will be copied to the following folder. -# Default: %USERPROFILE%\documents\Arma 3\ -# test_dir = %USERPROFILE%\documents\Arma 3\ - - -# Directory where the built addon will be saved. -# Default: release -release_dir = P:\z\mts_enhanced\release - - -# This string will be prefixed to all build PBO file names. -# Default: None -pbo_name_prefix = mts_ - -# This string will be prefixed to release archive. -# Default: None -zipPrefix = Metis_Enhanced - -# Which build tool will be used? Options: pboproject, addonbuilder -# Default: addonbuilder -build_tool = pboproject - -# Which name should be used for the key? -# Default: None -key_name = mts_enhanced_ - -################################################################## -# Alternate build target using a different key -################################################################### -# [DifferentKey] -# key = C:\Keys\different.biprivatekey - -################################################################## -# Alternate build target ignoring some modules when detecting -################################################################### -# [IgnoreSome] -# key = C:\Keys\different.biprivatekey -# ignore = release, my_server_module, my_private_module - -################################################################## -# Alternate build target with fixed build list -################################################################### -# [Fixed] -# module_autodetect = False -# modules = my_module, my_other_module diff --git a/tools/make.py b/tools/make.py deleted file mode 100644 index 5a20a92..0000000 --- a/tools/make.py +++ /dev/null @@ -1,1515 +0,0 @@ -#!/usr/bin/env python3 -# vim: set fileencoding=utf-8 : - -# make.py -# An Arma 3 addon build system - -############################################################################### - -# The MIT License (MIT) - -# Copyright (c) 2013-2014 Ryan Schultz - -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: - -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. - -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# 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. - -############################################################################### - -__version__ = "0.91" - -import sys - -if sys.version_info[0] == 2: - print("Python 3 is required.") - sys.exit(1) - -import os -import os.path -import shutil -import platform -import glob -import subprocess -import hashlib -import configparser -import json -import traceback -import time -import timeit -import re -from tempfile import mkstemp - -if sys.platform == "win32": - import winreg - -######## GLOBALS ######### -project = "@Metis_Enhanced" -project_version = "1.0.0" -arma3tools_path = "" -work_drive = "" -module_root = "" -make_root = "" -release_dir = "" -module_root_parent = "" -optionals_root = "" -key_name = "mts_enhanced_" -key = "" -dssignfile = "" -prefix = "mts" -pbo_name_prefix = "mts_" -signature_blacklist = [] -importantFiles = ["mod.cpp", "LICENSE", "mts_team_logo_small.paa"] -versionFiles = ["mod.cpp"] - -ciBuild = False # Used for CI builds - -############################################################################### -# http://akiscode.com/articles/sha-1directoryhash.shtml -# Copyright (c) 2009 Stephen Akiki -# MIT License (Means you can do whatever you want with this) -# See http://www.opensource.org/licenses/mit-license.php -# Error Codes: -# -1 -> Directory does not exist -# -2 -> General error (see stack traceback) -def get_directory_hash(directory): - directory_hash = hashlib.sha1() - if not os.path.exists (directory): - return -1 - - try: - for root, dirs, files in os.walk(directory): - for names in files: - path = os.path.join(root, names) - try: - f = open(path, 'rb') - except: - # You can't open the file for some reason - f.close() - continue - - while 1: - # Read file in as little chunks - buf = f.read(4096) - if not buf: break - new = hashlib.sha1(buf) - directory_hash.update(new.digest()) - f.close() - - except: - # Print the stack traceback - traceback.print_exc() - return -2 - - retVal = directory_hash.hexdigest() - #print_yellow("Hash Value for {} is {}".format(directory,retVal)) - return directory_hash.hexdigest() - -def Fract_Sec(s): - temp = float() - temp = float(s) / (60*60*24) - d = int(temp) - temp = (temp - d) * 24 - h = int(temp) - temp = (temp - h) * 60 - m = int(temp) - temp = (temp - m) * 60 - sec = temp - return d,h,m,sec - #endef Fract_Sec - -# Copyright (c) André Burgaud -# http://www.burgaud.com/bring-colors-to-the-windows-console-with-python/ -if sys.platform == "win32": - from ctypes import windll, Structure, c_short, c_ushort, byref - - SHORT = c_short - WORD = c_ushort - - class COORD(Structure): - """struct in wincon.h.""" - _fields_ = [ - ("X", SHORT), - ("Y", SHORT)] - - class SMALL_RECT(Structure): - """struct in wincon.h.""" - _fields_ = [ - ("Left", SHORT), - ("Top", SHORT), - ("Right", SHORT), - ("Bottom", SHORT)] - - class CONSOLE_SCREEN_BUFFER_INFO(Structure): - """struct in wincon.h.""" - _fields_ = [ - ("dwSize", COORD), - ("dwCursorPosition", COORD), - ("wAttributes", WORD), - ("srWindow", SMALL_RECT), - ("dwMaximumWindowSize", COORD)] - - # winbase.h - STD_INPUT_HANDLE = -10 - STD_OUTPUT_HANDLE = -11 - STD_ERROR_HANDLE = -12 - - # wincon.h - FOREGROUND_BLACK = 0x0000 - FOREGROUND_BLUE = 0x0001 - FOREGROUND_GREEN = 0x0002 - FOREGROUND_CYAN = 0x0003 - FOREGROUND_RED = 0x0004 - FOREGROUND_MAGENTA = 0x0005 - FOREGROUND_YELLOW = 0x0006 - FOREGROUND_GREY = 0x0007 - FOREGROUND_INTENSITY = 0x0008 # foreground color is intensified. - - BACKGROUND_BLACK = 0x0000 - BACKGROUND_BLUE = 0x0010 - BACKGROUND_GREEN = 0x0020 - BACKGROUND_CYAN = 0x0030 - BACKGROUND_RED = 0x0040 - BACKGROUND_MAGENTA = 0x0050 - BACKGROUND_YELLOW = 0x0060 - BACKGROUND_GREY = 0x0070 - BACKGROUND_INTENSITY = 0x0080 # background color is intensified. - - stdout_handle = windll.kernel32.GetStdHandle(STD_OUTPUT_HANDLE) - SetConsoleTextAttribute = windll.kernel32.SetConsoleTextAttribute - GetConsoleScreenBufferInfo = windll.kernel32.GetConsoleScreenBufferInfo - - def get_text_attr(): - """Returns the character attributes (colors) of the console screen - buffer.""" - csbi = CONSOLE_SCREEN_BUFFER_INFO() - GetConsoleScreenBufferInfo(stdout_handle, byref(csbi)) - return csbi.wAttributes - - def set_text_attr(color): - """Sets the character attributes (colors) of the console screen - buffer. Color is a combination of foreground and background color, - foreground and background intensity.""" - SetConsoleTextAttribute(stdout_handle, color) -############################################################################### - -def find_bi_tools(work_drive): - """Find BI tools.""" - - reg = winreg.ConnectRegistry(None, winreg.HKEY_CURRENT_USER) - try: - k = winreg.OpenKey(reg, r"Software\bohemia interactive\arma 3 tools") - arma3tools_path = winreg.QueryValueEx(k, "path")[0] - winreg.CloseKey(k) - except: - raise Exception("BadTools","Arma 3 Tools are not installed correctly or the P: drive needs to be created.") - - addonbuilder_path = os.path.join(arma3tools_path, "AddonBuilder", "AddonBuilder.exe") - dssignfile_path = os.path.join(arma3tools_path, "DSSignFile", "DSSignFile.exe") - dscreatekey_path = os.path.join(arma3tools_path, "DSSignFile", "DSCreateKey.exe") - cfgconvert_path = os.path.join(arma3tools_path, "CfgConvert", "CfgConvert.exe") - - if os.path.isfile(addonbuilder_path) and os.path.isfile(dssignfile_path) and os.path.isfile(dscreatekey_path) and os.path.isfile(cfgconvert_path): - return [addonbuilder_path, dssignfile_path, dscreatekey_path, cfgconvert_path] - else: - raise Exception("BadTools","Arma 3 Tools are not installed correctly or the P: drive needs to be created.") - -def mikero_windows_registry(path, access=winreg.KEY_READ): - try: - return winreg.OpenKey(winreg.HKEY_CURRENT_USER, r"Software\Mikero\{}".format(path), access=access) - except FileNotFoundError: - try: - return winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, r"Software\Mikero\{}".format(path), access=access) - except FileNotFoundError: - try: - return winreg.OpenKey(winreg.HKEY_CURRENT_USER, r"Software\Wow6432Node\Mikero\{}".format(path), access=access) - except FileNotFoundError: - return winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, r"Software\Wow6432Node\Mikero\{}".format(path), access=access) - -def find_depbo_tools(): - """Use registry entries to find DePBO-based tools.""" - requiredToolPaths = {"pboProject": None, "rapify": None, "MakePbo": None} - failed = False - - for tool in requiredToolPaths: - try: - k = mikero_windows_registry(tool) - path = winreg.QueryValueEx(k, "exe")[0] - except FileNotFoundError: - print_error("Could not find {}".format(tool)) - failed = True - else: - #Strip any quotations from the path due to a MikeRo tool bug which leaves a trailing space in some of its registry paths. - requiredToolPaths[tool] = path.strip('"') - print_green("Found {}.".format(tool)) - finally: - winreg.CloseKey(k) - - if failed: - raise Exception("BadDePBO", "DePBO tools not installed correctly") - - return requiredToolPaths - -def pboproject_settings(): - """Use registry entries to configure needed pboproject settings.""" - value_exclude = "thumbs.db,*.txt,*.h,*.dep,*.cpp,*.bak,*.png,*.log,*.pew,source,*.tga" - - try: - k = mikero_windows_registry(r"pboProject\Settings", access=winreg.KEY_SET_VALUE) - winreg.SetValueEx(k, "m_exclude", 0, winreg.REG_SZ, value_exclude) - winreg.SetValueEx(k, "m_exclude2", 0, winreg.REG_SZ, value_exclude) - except: - raise Exception("BadDePBO", "pboProject not installed correctly, make sure to run it at least once") - - -def color(color): - """Set the color. Works on Win32 and normal terminals.""" - if sys.platform == "win32": - if color == "green": - set_text_attr(FOREGROUND_GREEN | get_text_attr() & 0x0070 | FOREGROUND_INTENSITY) - elif color == "yellow": - set_text_attr(FOREGROUND_YELLOW | get_text_attr() & 0x0070 | FOREGROUND_INTENSITY) - elif color == "red": - set_text_attr(FOREGROUND_RED | get_text_attr() & 0x0070 | FOREGROUND_INTENSITY) - elif color == "blue": - set_text_attr(FOREGROUND_BLUE | get_text_attr() & 0x0070 | FOREGROUND_INTENSITY) - elif color == "reset": - set_text_attr(FOREGROUND_GREY | get_text_attr() & 0x0070) - elif color == "grey": - set_text_attr(FOREGROUND_GREY | get_text_attr() & 0x0070) - else : - if color == "green": - sys.stdout.write('\033[92m') - elif color == "red": - sys.stdout.write('\033[91m') - elif color == "blue": - sys.stdout.write('\033[94m') - elif color == "reset": - sys.stdout.write('\033[0m') - -def print_error(msg): - color("red") - print("ERROR: {}".format(msg)) - color("reset") - global printedErrors - printedErrors += 1 - -def print_green(msg): - color("green") - print(msg) - color("reset") - -def print_blue(msg): - color("blue") - print(msg) - color("reset") - -def print_yellow(msg): - color("yellow") - print(msg) - color("reset") - - -def copy_important_files(source_dir,destination_dir): - originalDir = os.getcwd() - - # Copy importantFiles - try: - print_blue("\nSearching for important files in {}".format(source_dir)) - print("Source_dir: {}".format(source_dir)) - print("Destination_dir: {}".format(destination_dir)) - - for file in importantFiles: - filePath = os.path.join(module_root_parent, file) - if os.path.exists(filePath): - print_green("Copying file => {}".format(filePath)) - shutil.copy(os.path.join(source_dir,filePath), destination_dir) - else: - missingFiles.append("{}".format(filePath)) - print_error("Failed copying file => {}".format(filePath)) - except: - print_error("COPYING IMPORTANT FILES.") - raise - - # Copy all extensions - try: - os.chdir(os.path.join(source_dir)) - print_blue("\nSearching for DLLs in {}".format(os.getcwd())) - filenames = glob.glob("*.dll") + glob.glob("*.so") - - if not filenames: - print ("Empty SET") - - for dll in filenames: - print_green("Copying dll => {}".format(os.path.join(source_dir,dll))) - if os.path.isfile(dll): - shutil.copyfile(os.path.join(source_dir,dll),os.path.join(destination_dir,dll)) - except: - print_error("COPYING DLL FILES.") - raise - finally: - os.chdir(originalDir) - - - -def copy_optionals_for_building(mod,pbos): - src_directories = os.listdir(optionals_root) - current_dir = os.getcwd() - - print_blue("\nChecking optionals folder...") - try: - #special server.pbo processing - files = glob.glob(os.path.join(release_dir, project, "optionals", "*.pbo")) - for file in files: - file_name = os.path.basename(file) - #print ("Adding the following file: {}".format(file_name)) - pbos.append(file_name) - pbo_path = os.path.join(release_dir, project, "optionals", file_name) - sigFile_name = file_name +"."+ key_name + ".bisign" - sig_path = os.path.join(release_dir, project, "optionals", sigFile_name) - if (os.path.isfile(pbo_path)): - print("Moving {} for processing.".format(pbo_path)) - shutil.move(pbo_path, os.path.join(release_dir, project, "addons", file_name)) - - if (os.path.isfile(sig_path)): - #print("Moving {} for processing.".format(sig_path)) - shutil.move(sig_path, os.path.join(release_dir, project, "addons", sigFile_name)) - - except: - print_error("Error in moving") - raise - finally: - os.chdir(current_dir) - - try: - for dir_name in src_directories: - mod.append(dir_name) - #userconfig requires special handling since it is not a PBO source folder. - #CfgConvert fails to build server.pbo if userconfig is not found in P:\ - if (dir_name == "userconfig"): - if (os.path.exists(os.path.join(release_dir, project, "optionals", dir_name))): - shutil.rmtree(os.path.join(release_dir, project, "optionals", dir_name), True) - shutil.copytree(os.path.join(optionals_root,dir_name), os.path.join(release_dir, project, "optionals", dir_name)) - destination = os.path.join(work_drive,dir_name) - else: - destination = os.path.join(module_root,dir_name) - - print("Temporarily copying {} => {} for building.".format(os.path.join(optionals_root,dir_name),destination)) - if (os.path.exists(destination)): - shutil.rmtree(destination, True) - shutil.copytree(os.path.join(optionals_root,dir_name), destination) - except: - print_error("Copy Optionals Failed") - raise - finally: - os.chdir(current_dir) - - -def cleanup_optionals(mod): - print("") - try: - for dir_name in mod: - #userconfig requires special handling since it is not a PBO source folder. - if (dir_name == "userconfig"): - destination = os.path.join(work_drive,dir_name) - else: - destination = os.path.join(module_root,dir_name) - - print("Cleaning {}".format(destination)) - - try: - file_name = "{}{}.pbo".format(pbo_name_prefix,dir_name) - folder= "@{}{}".format(pbo_name_prefix,dir_name) - src_file_path = os.path.join(release_dir, project, "addons", file_name) - dst_file_path = os.path.join(release_dir, project, "optionals",folder,"addons",file_name) - - sigFile_name = "{}.{}.bisign".format(file_name,key_name) - src_sig_path = os.path.join(release_dir, project, "addons", sigFile_name) - dst_sig_path = os.path.join(release_dir, project, "optionals",folder,"addons", sigFile_name) - - - if (os.path.isfile(src_file_path)): - if (os.path.isfile(dst_file_path)): - # print("Cleanuping up old file {}".format(dst_file_path)) - os.remove(dst_file_path); - #print("Preserving {}".format(file_name)) - os.renames(src_file_path,dst_file_path) - if (os.path.isfile(src_sig_path)): - if (os.path.isfile(dst_sig_path)): - # print("Cleanuping up old file {}".format(dst_sig_path)) - os.remove(dst_sig_path); - #print("Preserving {}".format(sigFile_name)) - os.renames(src_sig_path,dst_sig_path) - except FileExistsError: - print_error("{} already exists".format(file_name)) - continue - shutil.rmtree(destination) - - except FileNotFoundError: - print_yellow("{} file not found".format(file_name)) - - except: - print_error("Cleaning Optionals Failed") - raise - - -def purge(dir, pattern, friendlyPattern="files"): - print_green("Deleting {} files from directory: {}".format(friendlyPattern,dir)) - if os.path.exists(dir): - for f in os.listdir(dir): - if re.search(pattern, f): - os.remove(os.path.join(dir, f)) - - -def build_signature_file(file_name): - global key - global dssignfile - global signature_blacklist - ret = 0 - baseFile = os.path.basename(file_name) - #print_yellow("Sig_fileName: {}".format(baseFile)) - if not (baseFile in signature_blacklist): - print("Signing with {}.".format(key)) - ret = subprocess.call([dssignfile, key, file_name]) - if ret == 0: - return True - else: - return False - - -def check_for_obsolete_pbos(addonspath, file): - module = file[len(pbo_name_prefix):-4] - if not os.path.exists(os.path.join(addonspath, module)): - return True - return False - - -def backup_config(module): - #backup original $PBOPREFIX$ - global work_drive - global prefix - - try: - configpath = os.path.join(work_drive, prefix, module, "$PBOPREFIX$") - if os.path.isfile(configpath): - shutil.copyfile(configpath, os.path.join(work_drive, prefix, module, "$PBOPREFIX$.backup")) - else: - print_error("$PBOPREFIX$ Does not exist for module: {}.".format(module)) - - except: - print_error("Error creating backup of $PBOPREFIX$ for module {}.".format(module)) - - return True - -def addon_restore(modulePath): - #restore original $PBOPREFIX$ - try: - if os.path.isfile(os.path.join(modulePath, "$PBOPREFIX$.backup")): - if os.path.isfile(os.path.join(modulePath, "$PBOPREFIX$")): - os.remove(os.path.join(modulePath, "$PBOPREFIX$")) - os.rename(os.path.join(modulePath, "$PBOPREFIX$.backup"), os.path.join(modulePath, "$PBOPREFIX$")) - except: - print_yellow("Some error occurred. Check your addon folder {} for integrity".format(modulePath)) - - return True - - -def get_project_version(version_increments=[]): - global project_version - versionStamp = project_version - #do the magic based on https://github.com/acemod/ACE3/issues/806#issuecomment-95639048 - - try: - scriptModPath = os.path.join(module_root, "main\script_version.hpp") - - if os.path.isfile(scriptModPath): - f = open(scriptModPath, "r") - hpptext = f.read() - f.close() - - if hpptext: - majorText = re.search(r"#define MAJOR (.*\b)", hpptext).group(1) - minorText = re.search(r"#define MINOR (.*\b)", hpptext).group(1) - patchText = re.search(r"#define PATCHLVL (.*\b)", hpptext).group(1) - buildText = re.search(r"#define BUILD (.*\b)", hpptext).group(1) - - # Increment version (reset all below except build) - if version_increments != []: - if "major" in version_increments: - majorText = int(majorText) + 1 - minorText = 0 - patchText = 0 - elif "minor" in version_increments: - minorText = int(minorText) + 1 - patchText = 0 - elif "patch" in version_increments: - patchText = int(patchText) + 1 - - # Always increment build - if "build" in version_increments: - buildText = int(buildText) + 1 - - print_green("Incrementing version to {}.{}.{}.{}".format(majorText,minorText,patchText,buildText)) - with open(scriptModPath, "w", newline="\n") as file: - file.writelines([ - "#define MAJOR {}\n".format(majorText), - "#define MINOR {}\n".format(minorText), - "#define PATCHLVL {}\n".format(patchText), - "#define BUILD {}\n".format(buildText) - ]) - - if majorText: - versionStamp = "{}.{}.{}.{}".format(majorText,minorText,patchText,buildText) - - else: - print_error("A Critical file seems to be missing or inaccessible: {}".format(scriptModPath)) - raise FileNotFoundError("File Not Found: {}".format(scriptModPath)) - - except Exception as e: - print_error("Get_project_version error: {}".format(e)) - print_error("Check the integrity of the file: {}".format(scriptModPath)) - versionStamp = project_version - print_error("Resetting to the default version stamp: {}".format(versionStamp)) - input("Press Enter to continue...") - print("Resuming build...") - - print_yellow("{} VERSION set to {}".format(project.lstrip("@").upper(),versionStamp)) - project_version = versionStamp - return project_version - - -def replace_file(filePath, oldSubstring, newSubstring): - global work_drive - fh, absPath = mkstemp(None, None, work_drive + "temp") - os.close(fh) - with open(absPath, "w", encoding="utf-8") as newFile: - with open(filePath, encoding="utf-8") as oldFile: - for line in oldFile: - newFile.write(line.replace(oldSubstring, newSubstring)) - - newFile.close() - os.remove(filePath) - shutil.move(absPath, filePath) - - -def set_version_in_files(): - newVersion = project_version # MAJOR.MINOR.PATCH.BUILD - newVersionArr = newVersion.split(".") - newVersionShort = ".".join((newVersionArr[0],newVersionArr[1],newVersionArr[2])) # MAJOR.MINOR.PATCH - - # Regex patterns - pattern = re.compile(r"([\d]+\.[\d]+\.[\d]+\.[\d]+)") # MAJOR.MINOR.PATCH.BUILD - patternShort = re.compile(r"([\d]+\.[\d]+\.[\d]+)") # MAJOR.MINOR.PATCH - - # Change versions in files containing version - for i in versionFiles: - filePath = os.path.join(module_root_parent, i) - - try: - # Save the file contents to a variable if the file exists - if os.path.isfile(filePath): - f = open(filePath, "r+", encoding="utf-8") - fileText = f.read() - f.close() - - if fileText: - # Version string files - # Search and save version stamp - versionsFound = re.findall(pattern, fileText) + re.findall(patternShort, fileText) - # Filter out sub-versions of other versions - versionsFound = [j for i, j in enumerate(versionsFound) if all(j not in k for k in versionsFound[i + 1:])] - - # Replace version stamp if any of the new version parts is higher than the one found - for versionFound in versionsFound: - if versionFound: - # Use the same version length as the one found - newVersionUsed = "" # In case undefined - if versionFound.count(".") == newVersion.count("."): - newVersionUsed = newVersion - if versionFound.count(".") == newVersionShort.count("."): - newVersionUsed = newVersionShort - - # Print change and modify the file if changed - if newVersionUsed and versionFound != newVersionUsed: - print_green("Changing version {} => {} in {}".format(versionFound, newVersionUsed, filePath)) - replace_file(filePath, versionFound, newVersionUsed) - except WindowsError as e: - # Temporary file is still "in use" by Python, pass this exception - pass - except Exception as e: - print_error("set_version_in_files error: {}".format(e)) - raise - - return True - - -def stash_version_files_for_building(): - try: - for file in versionFiles: - filePath = os.path.join(module_root_parent, file) - if os.path.exists(filePath): - # Take only file name for stash location if in subfolder (otherwise it gets removed when removing folders from release dir) - if "\\" in file: - count = file.count("\\") - file = file.split("\\", count)[-1] - stashPath = os.path.join(release_dir, file) - print("Temporarily stashing {} => {}.bak for version update".format(filePath, stashPath)) - shutil.copy(filePath, "{}.bak".format(stashPath)) - else: - print_error("Failed temporarily stashing {} for version update".format(filePath)) - missingFiles.append("{}".format(filePath)) - except: - print_error("Stashing version files failed") - raise - - # Set version - set_version_in_files() - return True - - -def restore_version_files(): - try: - print_blue("\nRestoring version files...") - - for file in versionFiles: - filePath = os.path.join(module_root_parent, file) - # Take only file name for stash path if in subfolder (otherwise it gets removed when removing folders from release dir) - if "\\" in file: - count = file.count("\\") - file = file.split("\\", count)[-1] - stashPath = os.path.join(release_dir, file) - if os.path.exists(filePath): - print("Restoring {}".format(filePath)) - shutil.move("{}.bak".format(stashPath), filePath) - except: - print_error("Restoring version files failed") - raise - return True - - -def get_private_keyname(commitID,module="main"): - global key_name - global project_version - - keyName = str("{prefix}{version}-{commit_id}".format(prefix=key_name,version=project_version,commit_id=commitID)) - return keyName - - -def get_commit_ID(): - # Get latest commit ID - global make_root - curDir = os.getcwd() - commit_id = "" - - try: - # Verify if Git repository - gitpath = os.path.join(os.path.dirname(make_root), ".git") - assert os.path.exists(gitpath) - - # Try to get commit ID through Git client - os.chdir(make_root) - commit_id = subprocess.check_output(["git", "rev-parse", "HEAD"]) - commit_id = str(commit_id, "utf-8")[:8] - except FileNotFoundError: - # Try to get commit ID from git files (subprocess failed - eg. no Git client) - head_path = os.path.join(gitpath, "HEAD") - if os.path.exists(head_path): - with open(head_path, "r") as head_file: - branch_path = head_file.readline().split(": ") - - # Commit ID is written in HEAD file directly when in detached state - if len(branch_path) == 1: - commit_id = branch_path[0] - else: - branch_path = branch_path[-1].strip() - ref_path = os.path.join(gitpath, branch_path) - if os.path.exists(ref_path): - with open(ref_path, "r") as ref_file: - commit_id = ref_file.readline() - - if commit_id != "": - commit_id = commit_id.strip()[:8] - else: - raise - except: - # All other exceptions (eg. AssertionException) - if commit_id == "": - raise - finally: - pass - if commit_id == "": - print_error("Failed to determine commit ID - folder is not a Git repository.") - commit_id = "NOGIT" - os.chdir(curDir) - - print_yellow("COMMIT ID set to {}".format(commit_id)) - return commit_id - - -def version_stamp_pboprefix(module,commitID): - ### Update pboPrefix with the correct version stamp. Use commit_id as the build number. - #This function will not handle any $PBOPREFIX$ backup or cleanup. - global work_drive - global prefix - - configpath = os.path.join(work_drive, prefix, module, "$PBOPREFIX$") - - try: - f = open(configpath, "r") - configtext = f.read() - f.close() - - if configtext: - if re.search(r"version=(.*?)$", configtext, re.DOTALL): - if configtext: - configtext = re.sub(r"version=(.*?)$", "version={}\n".format(commitID), configtext, flags=re.DOTALL) - f = open(configpath, "w") - f.write(configtext) - f.close() - else: - os.remove(os.path.join(work_drive, prefix, module, "$PBOPREFIX$")) - os.rename(os.path.join(work_drive, prefix, module, "$PBOPREFIX$.backup"), os.path.join(work_drive, prefix, module, "$PBOPREFIX$")) - else: - if configtext: - #append version info - f = open(configpath, "a") - f.write("\nversion = {}".format(commitID)) - f.close() - else: - os.remove(os.path.join(work_drive, prefix, module, "$PBOPREFIX$")) - os.rename(os.path.join(work_drive, prefix, module, "$PBOPREFIX$.backup"), os.path.join(work_drive, prefix, module, "$PBOPREFIX$")) - except Exception as e: - print_error("Failed to include build number: {}".format(e)) - return False - - return True - - -############################################################################### - - -def main(argv): - """Build an Arma addon suite in a directory from rules in a make.cfg file.""" - print_blue("\nmake.py for Arma, modified for Metis v{}".format(__version__)) - - global project_version - global arma3tools_path - global work_drive - global module_root - global make_root - global release_dir - global module_root_parent - global optionals_root - global key_name - global key - global dssignfile - global prefix - global pbo_name_prefix - global ciBuild - global missingFiles - global failedBuilds - global printedErrors - - printedErrors = 0 - - if sys.platform != "win32": - print_error("Non-Windows platform (Cygwin?). Please re-run from cmd.") - sys.exit(1) - - reg = winreg.ConnectRegistry(None, winreg.HKEY_CURRENT_USER) - try: - k = winreg.OpenKey(reg, r"Software\bohemia interactive\arma 3 tools") - arma3tools_path = winreg.QueryValueEx(k, "path")[0] - winreg.CloseKey(k) - except: - raise Exception("BadTools","Arma 3 Tools are not installed correctly or the P: drive needs to be created.") - - # Default behaviors - test = False # Copy to Arma 3 directory? - arg_modules = False # Only build modules on command line? - use_pboproject = True # Default to pboProject build tool - make_target = "DEFAULT" # Which section in make.cfg to use for the build - new_key = True # Make a new key and use it to sign? - quiet = False # Suppress output from build tool? - - # Parse arguments - if "help" in argv or "-h" in argv or "--help" in argv: - print (""" -make.py [help] [test] [force] [key ] [target ] [release ] - [module name] [module name] [...] -test -- Copy result to Arma 3. -release -- Make archive with . -force -- Ignore cache and build all. -target -- Use rules in make.cfg under heading [] rather than - default [Make] -key -- Use key in working directory with to sign. If it does not - exist, create key. -quiet -- Suppress command line output from build tool. -If module names are specified, only those modules will be built. -Examples: - make.py force test - Build all modules (ignoring cache) and copy the mod folder to the Arma 3 - directory. - make.py mymodule_gun - Only build the module named 'mymodule_gun'. - make.py force key MyNewKey release 1.0 - Build all modules (ignoring cache), sign them with NewKey, and pack them - into a zip file for release with version 1.0. -If a file called $NOBIN$ is found in the module directory, that module will not be binarized. -See the make.cfg file for additional build options. -""") - sys.exit(0) - - if "force" in argv: - argv.remove("force") - force_build = True - else: - force_build = False - - if "test" in argv: - test = True - argv.remove("test") - - if "release" in argv: - make_release_zip = True - argv.remove("release") - else: - make_release_zip = False - - if "target" in argv: - make_target = argv[argv.index("target") + 1] - argv.remove("target") - argv.remove(make_target) - force_build = True - - if "key" in argv: - new_key = True - key_name = argv[argv.index("key") + 1] - argv.remove("key") - argv.remove(key_name) - - if "quiet" in argv: - quiet = True - argv.remove("quiet") - - if "version" in argv: - argv.remove("version") - version_update = True - else: - version_update = False - - version_increments = [] - if "increment_build" in argv: - argv.remove("increment_build") - version_increments.append("build") - if "increment_patch" in argv: - argv.remove("increment_patch") - version_increments.append("patch") - if "increment_minor" in argv: - argv.remove("increment_minor") - version_increments.append("minor") - if "increment_major" in argv: - argv.remove("increment_major") - version_increments.append("major") - - if "ci" in argv: - argv.remove("ci") - ciBuild = True - - # Get the directory the make script is in. - make_root = os.path.dirname(os.path.realpath(__file__)) - make_root_parent = os.path.abspath(os.path.join(os.getcwd(), os.pardir)) - os.chdir(make_root) - - - - cfg = configparser.ConfigParser(); - try: - cfg.read(os.path.join(make_root, "make.cfg")) - - # Project name (with @ symbol) - project = cfg.get(make_target, "project", fallback="@"+os.path.basename(os.getcwd())) - - # BI Tools work drive on Windows - work_drive = cfg.get(make_target, "work_drive", fallback="P:\\") - - # Private key path - key = cfg.get(make_target, "key", fallback=None) - - # Private key creation directory - private_key_path = cfg.get(make_target, "private_key_path", fallback=os.path.join(work_drive, "private_keys")) - - # Project prefix (folder path) - prefix = cfg.get(make_target, "prefix", fallback="") - - # Release archive prefix - zipPrefix = cfg.get(make_target, "zipPrefix", fallback=project.lstrip("@").lower()) - - # Should we autodetect modules on a complete build? - module_autodetect = cfg.getboolean(make_target, "module_autodetect", fallback=True) - - # Manual list of modules to build for a complete build - modules = cfg.get(make_target, "modules", fallback=None) - # Parse it out - if modules: - modules = [x.strip() for x in modules.split(',')] - else: - modules = [] - - # List of directories to ignore when detecting - ignore = [x.strip() for x in cfg.get(make_target, "ignore", fallback="release").split(',')] - - # Which build tool should we use? - build_tool = cfg.get(make_target, "build_tool", fallback="addonbuilder").lower() - - # Release/build directory, relative to script dir - release_dir = cfg.get(make_target, "release_dir", fallback="release") - - #Directory to copy the final built PBO's for a test run. - test_dir = cfg.get(make_target, "test_dir", fallback=os.path.join(os.environ["USERPROFILE"],r"documents\Arma 3")) - - # Project PBO file prefix (files are renamed to prefix_name.pbo) - pbo_name_prefix = cfg.get(make_target, "pbo_name_prefix", fallback=None) - - # Project module Root - module_root_parent = os.path.abspath(os.path.join(os.path.join(work_drive, prefix), os.pardir)) - module_root = cfg.get(make_target, "module_root", fallback=os.path.join(make_root_parent, "addons")) - optionals_root = os.path.join(module_root_parent, "optionals") - extensions_root = os.path.join(module_root_parent, "extensions") - - if (os.path.isdir(module_root)): - os.chdir(module_root) - else: - print_error ("Directory {} does not exist.".format(module_root)) - sys.exit(1) - - commit_id = get_commit_ID() - get_project_version(version_increments) - key_name = versionStamp = get_private_keyname(commit_id) - print_green ("module_root: {}".format(module_root)) - - if (os.path.isdir(optionals_root)): - print_green ("optionals_root: {}".format(optionals_root)) - else: - print("optionals_root does not exist: {}".format(optionals_root)) - - print_green ("release_dir: {}".format(release_dir)) - - except: - raise - print_error("Could not parse make.cfg.") - sys.exit(1) - - # See if we have been given specific modules to build from command line. - if len(argv) > 1 and not make_release_zip: - arg_modules = True - modules = [a for a in argv[1:] if a[0] != "-"] - - # Find the tools we need. - try: - tools = find_bi_tools(work_drive) - addonbuilder = tools[0] - dssignfile = tools[1] - dscreatekey = tools[2] - cfgconvert = tools[3] - - except: - print_error("Arma 3 Tools are not installed correctly or the P: drive has not been created.") - sys.exit(1) - - if build_tool == "pboproject": - try: - depbo_tools = find_depbo_tools() - - pboproject = depbo_tools["pboProject"] - rapifyTool = depbo_tools["rapify"] - makepboTool = depbo_tools["MakePbo"] - - pboproject_settings() - except: - raise - print_error("Could not find dePBO tools. Download the needed tools from: https://dev.withsix.com/projects/mikero-pbodll/files") - sys.exit(1) - - # Try to open and deserialize build cache file. - try: - cache = {} - with open(os.path.join(make_root, "make.cache"), 'r') as f: - cache_raw = f.read() - - cache = json.loads(cache_raw) - - except: - print ("No cache found.") - cache = {} - - # Check the build version (from main) with cached version - forces a full rebuild when version changes - cacheVersion = "None"; - if 'cacheVersion' in cache: - cacheVersion = cache['cacheVersion'] - - if (project_version != cacheVersion): - cache = {} - print("Reseting Cache {0} to New Version {1}".format(cacheVersion, project_version)) - cache['cacheVersion'] = project_version - - if not os.path.isdir(os.path.join(release_dir, project, "addons")): - try: - os.makedirs(os.path.join(release_dir, project, "addons")) - except: - print_error("Cannot create release directory") - raise - - if not os.path.isdir(os.path.join(release_dir, project, "keys")): - try: - os.makedirs(os.path.join(release_dir, project, "keys")) - except: - print_error("Cannot create release directory") - raise - - failedBuilds = [] - missingFiles = [] - - # Update version stamp in all files that contain it - # Update version only for release if full update not requested (backup and restore files) - print_blue("\nChecking for obsolete version numbers...") - if not version_update: - stash_version_files_for_building() - else: - # Set version - set_version_in_files(); - print("Version in files has been changed, make sure you commit and push the updates!") - - try: - # Temporarily copy optionals_root for building. They will be removed later. - if (os.path.isdir(optionals_root)): - optionals_modules = [] - optional_files = [] - copy_optionals_for_building(optionals_modules,optional_files) - - # Get list of subdirs in make root. - dirs = next(os.walk(module_root))[1] - - # Autodetect what directories to build. - if module_autodetect and not arg_modules: - modules = [] - for path in dirs: - # Any dir that has a config.cpp in its root is an addon to build. - config_path = os.path.join(path, 'config.cpp') - if os.path.isfile(config_path) and not path in ignore: - modules.append(path) - - # Make the key specified from command line if necessary. - if new_key: - if not os.path.isfile(os.path.join(private_key_path, key_name + ".biprivatekey")): - print_yellow("\nRequested key does not exist.") - try: - os.makedirs(private_key_path) - except: - pass - curDir = os.getcwd() - os.chdir(private_key_path) - ret = subprocess.call([dscreatekey, key_name]) # Created in make_root - os.chdir(curDir) - if ret == 0: - print_green("Created: {}".format(os.path.join(private_key_path, key_name + ".biprivatekey"))) - print("Removing any old signature keys...") - purge(os.path.join(module_root, release_dir, project, "addons"), "^.*\.bisign$","*.bisign") - purge(os.path.join(module_root, release_dir, project, "optionals"), "^.*\.bisign$","*.bisign") - purge(os.path.join(module_root, release_dir, project, "keys"), "^.*\.bikey$","*.bikey") - else: - print_error("Failed to create key!") - - - - else: - print_green("\nNOTE: Using key {}".format(os.path.join(private_key_path, key_name + ".biprivatekey"))) - - try: - print("Copying public key to release directory.") - - try: - os.makedirs(os.path.join(module_root, release_dir, project, "keys")) - except: - pass - - # Use biKeyNameAbrev to attempt to minimize problems from this BI Bug REFERENCE: http://feedback.arma3.com/view.php?id=22133 - biKeyNameAbrev = key_name.split("-")[0] - shutil.copyfile(os.path.join(private_key_path, key_name + ".bikey"), os.path.join(module_root, release_dir, project, "keys", "{}.bikey".format(biKeyNameAbrev))) - - except: - print_error("Could not copy key to release directory.") - raise - - key = os.path.join(private_key_path, "{}.biprivatekey".format(key_name)) - - # Remove any obsolete files. - print_blue("\nChecking for obsolete files...") - obsolete_check_path = os.path.join(module_root, release_dir, project,"addons") - for file in os.listdir(obsolete_check_path): - if (file.endswith(".pbo") and os.path.isfile(os.path.join(obsolete_check_path,file))): - if check_for_obsolete_pbos(module_root, file): - fileName = os.path.splitext(file)[0] - print_yellow("Removing obsolete pbo => {}".format(file)) - purge(obsolete_check_path, "{}\..".format(fileName), "{}.*".format(fileName)) - - obsolete_check_path = os.path.join(module_root, release_dir, project) - for file in os.listdir(obsolete_check_path): - if (file.endswith(".dll") and os.path.isfile(os.path.join(obsolete_check_path,file))): - if not os.path.exists(os.path.join(module_root_parent, file)): - print_yellow("Removing obsolete dll => {}".format(file)) - try: - os.remove(os.path.join(obsolete_check_path,file)) - except: - print_error("\nFailed to delete {}".format(os.path.join(obsolete_check_path,file))) - pass - - # For each module, prep files and then build. - print_blue("\nBuilding...") - for module in modules: - print_green("\nMaking {}".format(module + "-"*max(1, (60-len(module))))) - missing = False - sigMissing = False - - # Cache check - if module in cache: - old_sha = cache[module] - else: - old_sha = "" - - # Hash the module - new_sha = get_directory_hash(os.path.join(module_root, module)) - - # Is the pbo or sig file missing? - missing = not os.path.isfile(os.path.join(release_dir, project, "addons", "{}{}.pbo".format(pbo_name_prefix,module))) - sigFile = "{}{}.pbo.{}.bisign".format(pbo_name_prefix,module,key_name) - sigMissing = not os.path.isfile(os.path.join(release_dir, project, "addons", sigFile)) - - if missing: - print_yellow("Missing PBO file {}{}.pbo. Building...".format(pbo_name_prefix,module)) - - # Check if it needs rebuilt - # print ("Hash:", new_sha) - if old_sha == new_sha and not missing: - if not force_build: - print("Module has not changed.") - if sigMissing: - if key: - print("Missing Signature key {}".format(sigFile)) - build_signature_file(os.path.join(module_root, release_dir, project, "addons", "{}{}.pbo".format(pbo_name_prefix,module))) - # Skip everything else - continue - - # Only do this if the project isn't stored directly on the work drive. - # Split the path at the drive name and see if they are on the same drive (usually P:) - if os.path.splitdrive(module_root)[0] != os.path.splitdrive(work_drive)[0]: - try: - # Remove old work drive version (ignore errors) - shutil.rmtree(os.path.join(work_drive, prefix, module), True) - - # Copy module to the work drive - shutil.copytree(module, os.path.join(work_drive, prefix, module)) - - except: - raise - print_error("Could not copy module to work drive. Does the module exist?") - input("Press Enter to continue...") - print("Resuming build...") - continue - #else: - #print("WARNING: Module is stored on work drive ({}).".format(work_drive)) - - try: - # Remove the old pbo, key, and log - old = os.path.join(module_root, release_dir, project, "addons", "{}{}".format(pbo_name_prefix,module)) + "*" - files = glob.glob(old) - for f in files: - os.remove(f) - - if pbo_name_prefix: - old = os.path.join(module_root, release_dir, project, "addons", "{}{}".format(pbo_name_prefix,module)) + "*" - files = glob.glob(old) - for f in files: - os.remove(f) - except: - raise - print_error("Could not copy module to work drive. Does the module exist?") - input("Press Enter to continue...") - print("Resuming build...") - continue - - # Build the module into a pbo - print_blue("Building: {}".format(os.path.join(work_drive, prefix, module))) - print_blue("Destination: {}".format(os.path.join(module_root, release_dir, project, "addons"))) - - # Make destination folder (if needed) - try: - os.makedirs(os.path.join(module_root, release_dir, project, "addons")) - except: - pass - - - # Run build tool - build_successful = False - if build_tool == "pboproject": - try: - nobinFilePath = os.path.join(work_drive, prefix, module, "$NOBIN$") - backup_config(module) - - version_stamp_pboprefix(module,commit_id) - - if os.path.isfile(nobinFilePath): - print_green("$NOBIN$ Found. Proceeding with non-binarizing!") - cmd = [makepboTool, "-P","-A","-X=*.backup", os.path.join(work_drive, prefix, module),os.path.join(module_root, release_dir, project,"addons")] - - else: - cmd = [pboproject, "-B", "-P", os.path.join(work_drive, prefix, module), "+Engine=Arma3", "-S", "+Noisy", "+Clean", "-Warnings", "+Mod="+os.path.join(module_root, release_dir, project), "-Key"] - - color("grey") - if quiet: - devnull = open(os.devnull, 'w') - ret = subprocess.call(cmd, stdout=devnull) - devnull.close() - else: - ret = subprocess.call(cmd) - color("reset") - - if ret == 0: - print_green("pboProject return code == {}".format(str(ret))) - # Prettyprefix rename the PBO if requested. - if pbo_name_prefix: - try: - os.rename(os.path.join(module_root, release_dir, project, "addons", "{}.pbo".format(module)), os.path.join(module_root, release_dir, project, "addons", "{}{}.pbo".format(pbo_name_prefix,module))) - except: - raise - print_error("Could not rename built PBO with prefix.") - # Sign result - if (key and not "{}{}.pbo".format(pbo_name_prefix,module) in signature_blacklist): - print("Signing with {}.".format(key)) - if pbo_name_prefix: - ret = subprocess.call([dssignfile, key, os.path.join(module_root, release_dir, project, "addons", "{}{}.pbo".format(pbo_name_prefix,module))]) - else: - ret = subprocess.call([dssignfile, key, os.path.join(module_root, release_dir, project, "addons", "{}.pbo".format(module))]) - - if ret == 0: - build_successful = True - else: - build_successful = True - - if not build_successful: - print_error("pboProject return code == {}".format(str(ret))) - print_error("Module not successfully built/signed. Check your {}temp\{}_packing.log for more info.".format(work_drive,module)) - print ("Resuming build...") - failedBuilds.append("{}".format(module)) - continue - - # Back to the root - os.chdir(module_root) - - except: - raise - print_error("Could not run Addon Builder.") - input("Press Enter to continue...") - print ("Resuming build...") - continue - finally: - addon_restore(os.path.join(work_drive, prefix, module)) - - elif build_tool== "addonbuilder": - # Detect $NOBIN$ and do not binarize if found. - if os.path.isfile(os.path.join(work_drive, prefix, module, "$NOBIN$")): - do_binarize = False - print("$NOBIN$ file found in module, packing only.") - else: - do_binarize = True - try: - # Call AddonBuilder - os.chdir("P:\\") - - cmd = [addonbuilder, os.path.join(work_drive, prefix, module), os.path.join(make_root, release_dir, project, "addons"), "-clear", "-project="+work_drive] - if not do_binarize: - cmd.append("-packonly") - - if quiet: - previousDirectory = os.getcwd() - os.chdir(arma3tools_path) - devnull = open(os.devnull, 'w') - ret = subprocess.call(cmd, stdout=devnull) - devnull.close() - os.chdir(previousDirectory) - else: - previousDirectory = os.getcwd() - os.chdir(arma3tools_path) - print_error("Current directory - {}".format(os.getcwd())) - ret = subprocess.call(cmd) - os.chdir(previousDirectory) - print_error("Current directory - {}".format(os.getcwd())) - color("reset") - print_green("completed") - # Prettyprefix rename the PBO if requested. - if pbo_name_prefix: - try: - os.rename(os.path.join(make_root, release_dir, project, "addons", "{}.pbo".format(module)), os.path.join(make_root, release_dir, project, "addons", "{}{}.pbo".format(pbo_name_prefix,module))) - except: - raise - print_error("Could not rename built PBO with prefix.") - - if ret == 0: - # Sign result - - #print_yellow("Sig_fileName: ace_{}.pbo".format(module)) - if (key and not "{}{}.pbo".format(pbo_name_prefix,module) in signature_blacklist) : - print("Signing with {}.".format(key)) - if pbo_name_prefix: - ret = subprocess.call([dssignfile, key, os.path.join(make_root, release_dir, project, "addons","{}{}.pbo".format(pbo_name_prefix,module))]) - else: - ret = subprocess.call([dssignfile, key, os.path.join(make_root, release_dir, project, "addons", "{}.pbo".format(module))]) - - if ret == 0: - build_successful = True - else: - build_successful = True - - if not build_successful: - print_error("Module not successfully built. Check your {}temp\{}_packing.log for more info.".format(work_drive,module)) - - # Back to the root - os.chdir(make_root) - - except: - raise - print_error("Could not run Addon Builder.") - input("Press Enter to continue...") - print ("Resuming build...") - continue - - else: - print_error("Unknown build_tool {}!".format(build_tool)) - - # Update the hash for a successfully built module - if build_successful: - cache[module] = new_sha - - except Exception as e: - print_yellow("Cancel or some error detected: {}".format(e)) - - - finally: - copy_important_files(module_root_parent,os.path.join(release_dir, project)) - if (os.path.isdir(optionals_root)): - cleanup_optionals(optionals_modules) - if not version_update: - restore_version_files() - - # Done building all modules! - - # Write out the cache state - cache_out = json.dumps(cache) - with open(os.path.join(make_root, "make.cache"), 'w') as f: - f.write(cache_out) - - # Delete the pboproject temp files if building a release. - if make_release_zip and build_tool == "pboproject": - try: - shutil.rmtree(os.path.join(release_dir, project, "temp"), True) - except: - print_error("ERROR: Could not delete pboProject temp files.") - - # Make release - if make_release_zip: - release_name = "{}_{}".format(zipPrefix, project_version.rsplit(".", 1)[0]) - - try: - # Delete all log files - for root, dirs, files in os.walk(os.path.join(release_dir, project, "addons")): - for currentFile in files: - if currentFile.lower().endswith("log"): - os.remove(os.path.join(root, currentFile)) - - # Remove all zip files from release folder to prevent zipping the zip - for file in os.listdir(release_dir): - if file.endswith(".zip"): - os.remove(os.path.join(release_dir, file)) - - # Create a zip with the contents of release folder in it - print_blue("\nMaking release: {}.zip ...".format(release_name)) - print("Packing...") - release_zip = shutil.make_archive("{}".format(release_name), "zip", release_dir) - - # Move release zip to release folder - shutil.copy(release_zip, release_dir) - os.remove(release_zip) - except: - raise - print_error("Could not make release.") - - # Copy to Arma 3 folder for testing - if test: - print_blue("\nCopying to Arma 3.") - - if sys.platform == "win32": - reg = winreg.ConnectRegistry(None, winreg.HKEY_LOCAL_MACHINE) - try: - k = winreg.OpenKey(reg, r"SOFTWARE\Wow6432Node\Bohemia Interactive\Arma 3") - a3_path = winreg.EnumValue(k, 1)[1] - winreg.CloseKey(k) - except: - print_error("Could not find Arma 3's directory in the registry.") - else: - a3_path = cygwin_a3path - - print_yellow("Path from the registry => {}".format(a3_path)) - a3_path = test_dir - - print_yellow("Copying build files to {}".format(a3_path)) - - if os.path.exists(a3_path): - try: - shutil.rmtree(os.path.join(a3_path, project), True) - shutil.copytree(os.path.join(module_root, release_dir, project), os.path.join(a3_path, project)) - except: - print_error("Could not copy files. Is Arma 3 running?") - - tracedErrors = len(failedBuilds) + len(missingFiles) - if printedErrors > 0: # printedErrors includes tracedErrors - printedOnlyErrors = printedErrors - tracedErrors - print() - print_error("Failed with {} errors.".format(printedErrors)) - if len(failedBuilds) > 0: - for failedBuild in failedBuilds: - print("- {} build failed!".format(failedBuild)) - if len(missingFiles) > 0: - for missingFile in missingFiles: - print("- {} not found!".format(missingFile)) - if printedOnlyErrors > 0: - print_yellow("- {} untraced error(s)!".format(printedOnlyErrors)) - else: - print_green("\nCompleted with 0 errors.") - - -if __name__ == "__main__": - start_time = timeit.default_timer() - main(sys.argv) - d,h,m,s = Fract_Sec(timeit.default_timer() - start_time) - print("\nTotal Program time elapsed: {0:2}h {1:2}m {2:4.5f}s".format(h,m,s)) - - if ciBuild: - if len(failedBuilds) > 0: - sys.exit(1) - else: - sys.exit(0) - - input("Press Enter to continue...") diff --git a/tools/setup.bat b/tools/setup.bat index 3323a12..8d7245a 100644 --- a/tools/setup.bat +++ b/tools/setup.bat @@ -1,28 +1,16 @@ ;@Findstr -bv ;@F "%~f0" | powershell -Command - & pause & goto:eof -# Unzip backwards compatibility (Windows 8) -Add-Type -AssemblyName System.IO.Compression.FileSystem -function Unzip { - param([string]$zipfile, [string]$outpath) - - [System.IO.Compression.ZipFile]::ExtractToDirectory($zipfile, $outpath) -} - +Write-Output "=> Downloading ..." [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 -$client = New-Object Net.WebClient - -Write-Output "=> Downloading tools ..." -$client.DownloadFile("http://dev.idi-systems.com/tools/acre2_tools_user.zip", "acre2_tools_user.zip") -$client.dispose() -Write-Output "=> Cleaning old ..." -Remove-Item "..\hemtt.exe" -ErrorAction Ignore -Remove-Item "..\ArmaScriptCompiler.exe" -ErrorAction Ignore +$url = "https://github.com/BrettMayson/HEMTT/releases/latest/download/windows-x64.zip" +(New-Object Net.WebClient).DownloadFile($url, "hemtt.zip"); Write-Output "$url => hemtt.zip" -Write-Output "=> Extracting ..." -Unzip "acre2_tools_user.zip" "..\." -Remove-Item "acre2_tools_user.zip" +Write-Output "`n=> Extracting ..." +Expand-Archive -Path "hemtt.zip" -DestinationPath "..\." -Force; Write-Output "hemtt.zip" +Remove-Item "hemtt.zip" -Remove-Item "..\hemtt" -ErrorAction Ignore +Write-Output "`n=> Verifying ..." +Start-Process -FilePath ..\hemtt.exe -ArgumentList --version -NoNewWindow -Wait -Write-Output "=> Tools successfully installed to project!" +Write-Output "`nTools successfully installed to project!" From 8ec07c84f02bcbd49dd9361067e5c9843795a592 Mon Sep 17 00:00:00 2001 From: Timi007 Date: Sat, 30 Dec 2023 16:01:36 +0100 Subject: [PATCH 2/6] Fix scripts which allow enabling filepatching (#105) * Add script to create links to the addons needed for file patching * Fix VSCode task --- .gitignore | 8 +- .hemtt/project.toml | 7 ++ .vscode/settings.json | 10 +++ .vscode/tasks.json | 2 +- build.bat | 2 +- tools/setup.py | 119 ------------------------------ tools/setup_filepatching_links.py | 94 +++++++++++++++++++++++ 7 files changed, 117 insertions(+), 125 deletions(-) delete mode 100644 tools/setup.py create mode 100644 tools/setup_filepatching_links.py diff --git a/.gitignore b/.gitignore index 5f6f8a1..9e7860c 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,3 @@ -release/* *.cache *.pbo texHeaders.bin @@ -9,10 +8,11 @@ Thumbs.db *.sqfc *.exe -## Added by HEMTT +#### HEMTT hemtt hemtt.exe -releases/* -keys/* +release/ +releases/ +keys/ .hemttout/ #### diff --git a/.hemtt/project.toml b/.hemtt/project.toml index 821caf1..e7005d4 100644 --- a/.hemtt/project.toml +++ b/.hemtt/project.toml @@ -33,3 +33,10 @@ preset = "Hemtt" [hemtt.release] folder = "Metis_Enhanced" + +[hemtt.launch.default] +workshop = [ + "450814997", # CBA_A3's Workshop ID + "463939057", # ACE3's Workshop ID + "1779063631", # ZEN's Workshop ID +] diff --git a/.vscode/settings.json b/.vscode/settings.json index ce71ff4..51491a0 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -19,6 +19,16 @@ "*.rpt": "log", "init*.hpp": "sqf", }, + "search.exclude": { + ".hemttout/dev": true, + ".hemttout/build": true, + ".hemttout/release": true, + }, + "explorer.autoRevealExclude": { + ".hemttout/dev": true, + ".hemttout/build": true, + ".hemttout/release": true, + }, "sqf.enableACE3": true, "sqf.enableCBA": true, } diff --git a/.vscode/tasks.json b/.vscode/tasks.json index bef2126..dd4a1e4 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -6,7 +6,7 @@ "detail": "Build Arma addon with HEMTT in debug mode.", "type": "process", "command": "hemtt", - "args": ["build"], + "args": ["dev"], "group": "build", "presentation": { "close": true, diff --git a/build.bat b/build.bat index 34e67d1..d82070d 100644 --- a/build.bat +++ b/build.bat @@ -1,3 +1,3 @@ @echo off -hemtt build +hemtt dev pause diff --git a/tools/setup.py b/tools/setup.py deleted file mode 100644 index 3d92ea2..0000000 --- a/tools/setup.py +++ /dev/null @@ -1,119 +0,0 @@ -#!/usr/bin/env python3 - -######################## -# Metis Setup Script # -######################## - -import os -import sys -import shutil -import platform -import subprocess -import winreg - -######## GLOBALS ######### -MAINDIR = "z" -PROJECTDIR = "mts_enhanced" -CBA = "P:\\x\\cba" -########################## - -def main(): - FULLDIR = "{}\\{}".format(MAINDIR,PROJECTDIR) - print(""" - ####################################### - # Metis Development Environment Setup # - ####################################### - - This script will create your Metis dev environment for you. - - Before you run this, you should already have: - - The Arma 3 Tools installed properly via Steam - - A properly set up P-drive - - If you have not done those things yet, please abort this script in the next step and do so first. - - This script will create two hard links on your system, both pointing to your Metis project folder: - [Arma 3 installation directory]\\{} => Metis project folder - P:\\{} => Metis project folder - - It will also copy the required CBA includes to {}, if you do not have the CBA source code already.""".format(FULLDIR,FULLDIR,CBA)) - print("\n") - - try: - reg = winreg.ConnectRegistry(None, winreg.HKEY_LOCAL_MACHINE) - key = winreg.OpenKey(reg, - r"SOFTWARE\Wow6432Node\bohemia interactive\arma 3") - armapath = winreg.EnumValue(key,1)[1] - except: - print("Failed to determine Arma 3 Path.") - return 1 - - if not os.path.exists("P:\\"): - print("No P-drive detected.") - return 2 - - scriptpath = os.path.realpath(__file__) - projectpath = os.path.dirname(os.path.dirname(scriptpath)) - - print("# Detected Paths:") - print(" Arma Path: {}".format(armapath)) - print(" Project Path: {}".format(projectpath)) - - repl = input("\nAre these correct? (y/n): ") - if repl.lower() != "y": - return 3 - - print("\n# Creating links ...") - - if os.path.exists("P:\\{}\\{}".format(MAINDIR,PROJECTDIR)): - print("Link on P: already exists. Please finish the setup manually.") - return 4 - - if os.path.exists(os.path.join(armapath, MAINDIR, PROJECTDIR)): - print("Link in Arma directory already exists. Please finish the setup manually.") - return 5 - - try: - if not os.path.exists("P:\\{}".format(MAINDIR)): - os.makedirs("P:\\{}".format(MAINDIR)) - if not os.path.exists(os.path.join(armapath, MAINDIR)): - os.makedirs(os.path.join(armapath, MAINDIR)) - - subprocess.call(["cmd", "/c", "mklink", "/J", "P:\\{}\\{}".format(MAINDIR,PROJECTDIR), projectpath]) - subprocess.call(["cmd", "/c", "mklink", "/J", os.path.join(armapath, MAINDIR, PROJECTDIR), projectpath]) - except: - raise - print("Something went wrong during the link creation. Please finish the setup manually.") - return 6 - - print("# Links created successfully.") - - - print("\n# Copying required CBA includes ...") - - if os.path.exists(CBA): - print("{} already exists, skipping.".format(CBA)) - return -1 - - try: - shutil.copytree(os.path.join(projectpath, "include", "x", "cba"), CBA) - except: - raise - print("Something went wrong while copying CBA includes. Please copy include\\x\\cba to {} manually.".format(CBA)) - return 7 - - print("# CBA includes copied successfully to {}.".format(CBA)) - - return 0 - - -if __name__ == "__main__": - exitcode = main() - - if exitcode > 0: - print("\nSomething went wrong during the setup. Make sure you run this script as administrator. If these issues persist, please follow the instructions on the Metis wiki to perform the setup manually.") - else: - print("\nSetup successfully completed.") - - input("\nPress enter to exit ...") - sys.exit(exitcode) diff --git a/tools/setup_filepatching_links.py b/tools/setup_filepatching_links.py new file mode 100644 index 0000000..fcab641 --- /dev/null +++ b/tools/setup_filepatching_links.py @@ -0,0 +1,94 @@ +#!/usr/bin/env python3 + +######################## +# Metis Setup Script # +######################## + +import os +import sys +import winreg +import _winapi + +######## GLOBALS ######### +MAINDIR = "z" +PROJECTDIR = "mts_enhanced" +########################## + +def main(): + FULLDIR = f"{MAINDIR}\\{PROJECTDIR}" + print(f""" + ####################################### + # Metis Development Environment Setup # + ####################################### + + This script will create your Metis dev environment for you. + + Before you run this, you should already have: + - The Arma 3 Tools installed properly via Steam + - A properly set up P-drive + + If you have not done those things yet, please abort this script in the next step and do so first. + + This script will create two hard links on your system, both pointing to your Metis project folder: + [Arma 3 installation directory]\\{FULLDIR} => Metis project HEMTT dev build folder + P:\\{FULLDIR} => Metis project HEMTT dev build folder""") + print("\n") + + try: + reg = winreg.ConnectRegistry(None, winreg.HKEY_LOCAL_MACHINE) + key = winreg.OpenKey(reg, r"SOFTWARE\Wow6432Node\bohemia interactive\arma 3") + armapath = winreg.EnumValue(key,1)[1] + except: + print("Failed to determine Arma 3 Path.") + return 2 + + if not os.path.exists("P:\\"): + print("No P-drive detected.") + return 3 + + scriptpath = os.path.realpath(__file__) + projectpath = os.path.dirname(os.path.dirname(scriptpath)) + devpath = os.path.join(projectpath, '.hemttout', 'dev') + + print("# Detected Paths:") + print(f" Arma path: {armapath}") + print(f" Project path: {projectpath}") + print(f" HEMTT dev build path: {devpath}") + + repl = input("\nAre these correct? (y/n): ") + if repl.lower() != "y": + return 4 + + print("\n# Creating links ...") + try: + os.makedirs(devpath, exist_ok=True) + + if not os.path.exists(os.path.join("P:", MAINDIR, PROJECTDIR)): + os.makedirs(os.path.join("P:", MAINDIR), exist_ok=True) + _winapi.CreateJunction(devpath, os.path.join("P:", MAINDIR, PROJECTDIR)) + else: + print("Link on P: already exists. Skipping it.") + + if not os.path.exists(os.path.join(armapath, MAINDIR, PROJECTDIR)): + os.makedirs(os.path.join(armapath, MAINDIR), exist_ok=True) + _winapi.CreateJunction(devpath, os.path.join(armapath, MAINDIR, PROJECTDIR)) + else: + print("Link in Arma directory already exists. Skipping it.") + except: + print("Something went wrong during the link creation. Please finish the setup manually.") + raise + + print("# Links created successfully.") + + return 0 + + +if __name__ == "__main__": + exitcode = main() + + if exitcode > 0: + print("\nSomething went wrong during the setup. If these issues persist, please follow the instructions on the Metis wiki to perform the setup manually.") + else: + print("\nSetup successfully completed.") + + sys.exit(exitcode) From a0b10438fe5b3339f832eb5efb0b3ea649eff160 Mon Sep 17 00:00:00 2001 From: Timi007 Date: Sun, 31 Dec 2023 16:48:04 +0100 Subject: [PATCH 3/6] Do not require P-drive on setup links and delete links before creation (#106) * Do not require P-drive on setup links * Delete links before creating them again --- tools/setup_filepatching_links.py | 35 ++++++++++++++++++------------- 1 file changed, 20 insertions(+), 15 deletions(-) diff --git a/tools/setup_filepatching_links.py b/tools/setup_filepatching_links.py index fcab641..62fa2a7 100644 --- a/tools/setup_filepatching_links.py +++ b/tools/setup_filepatching_links.py @@ -24,8 +24,8 @@ def main(): This script will create your Metis dev environment for you. Before you run this, you should already have: - - The Arma 3 Tools installed properly via Steam - - A properly set up P-drive + - The Arma 3 Tools installed properly via Steam (optional) + - A properly set up P-drive (optional) If you have not done those things yet, please abort this script in the next step and do so first. @@ -42,10 +42,6 @@ def main(): print("Failed to determine Arma 3 Path.") return 2 - if not os.path.exists("P:\\"): - print("No P-drive detected.") - return 3 - scriptpath = os.path.realpath(__file__) projectpath = os.path.dirname(os.path.dirname(scriptpath)) devpath = os.path.join(projectpath, '.hemttout', 'dev') @@ -63,17 +59,26 @@ def main(): try: os.makedirs(devpath, exist_ok=True) - if not os.path.exists(os.path.join("P:", MAINDIR, PROJECTDIR)): - os.makedirs(os.path.join("P:", MAINDIR), exist_ok=True) - _winapi.CreateJunction(devpath, os.path.join("P:", MAINDIR, PROJECTDIR)) - else: - print("Link on P: already exists. Skipping it.") + if os.path.exists("P:\\"): + link = os.path.join("P:", MAINDIR, PROJECTDIR) + if os.path.exists(link): + os.unlink(link) + print("Previous link on P: deleted.") - if not os.path.exists(os.path.join(armapath, MAINDIR, PROJECTDIR)): - os.makedirs(os.path.join(armapath, MAINDIR), exist_ok=True) - _winapi.CreateJunction(devpath, os.path.join(armapath, MAINDIR, PROJECTDIR)) + os.makedirs(os.path.dirname(link), exist_ok=True) + _winapi.CreateJunction(devpath, link) + print("Link on P: created.") else: - print("Link in Arma directory already exists. Skipping it.") + print("No P-drive detected. Skipping it.") + + link = os.path.join(armapath, MAINDIR, PROJECTDIR) + if os.path.exists(link): + os.unlink(link) + print("Previous link in Arma directory deleted.") + + os.makedirs(os.path.dirname(link), exist_ok=True) + _winapi.CreateJunction(devpath, link) + print("Link in Arma directory created.") except: print("Something went wrong during the link creation. Please finish the setup manually.") raise From c609a4e6e8935d9d90786948ba57d420858d0dd0 Mon Sep 17 00:00:00 2001 From: Timi007 Date: Sat, 13 Jan 2024 17:39:48 +0100 Subject: [PATCH 4/6] Fix unconscious state not updating when zeus is in remote controlled unit (#107) * Fix unconscious state not updating when zeus is in remote controlled unit * Add eventhandler for players only --- addons/zeus/XEH_postInit.sqf | 2 +- addons/zeus/functions/fnc_addACEUnconsciousIconDrawEH.sqf | 3 ++- addons/zeus/functions/fnc_drawACEUnconsciousIcon.sqf | 5 ++++- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/addons/zeus/XEH_postInit.sqf b/addons/zeus/XEH_postInit.sqf index c15f33a..7350d5d 100644 --- a/addons/zeus/XEH_postInit.sqf +++ b/addons/zeus/XEH_postInit.sqf @@ -27,7 +27,7 @@ TRACE_1("3DEN Comments", GVAR(3DENComments_data)); GVAR(ACEIcon_drawEHAdded) = false; -ACE_player addEventHandler ["killed", { +player addEventHandler ["killed", { params ["_unit"]; [QGVAR(killed), [_unit, false]] call CBA_fnc_globalEvent; }]; diff --git a/addons/zeus/functions/fnc_addACEUnconsciousIconDrawEH.sqf b/addons/zeus/functions/fnc_addACEUnconsciousIconDrawEH.sqf index 2d75688..bc0db73 100644 --- a/addons/zeus/functions/fnc_addACEUnconsciousIconDrawEH.sqf +++ b/addons/zeus/functions/fnc_addACEUnconsciousIconDrawEH.sqf @@ -21,7 +21,8 @@ params ["_display"]; CHECK(!GVAR(enableACEUnconsciousIcon)); -private _curatorModule = getAssignedCuratorLogic ACE_player; +// This needs to be player because we want the zeus unit not a unit that zeus currently controls (ace_player). +private _curatorModule = getAssignedCuratorLogic player; // Only do this if zeus display is opened for the first time if (isNil {(_curatorModule getVariable QGVAR(unconsciousPlayers))}) then { diff --git a/addons/zeus/functions/fnc_drawACEUnconsciousIcon.sqf b/addons/zeus/functions/fnc_drawACEUnconsciousIcon.sqf index 978f9b2..3c4f9cd 100644 --- a/addons/zeus/functions/fnc_drawACEUnconsciousIcon.sqf +++ b/addons/zeus/functions/fnc_drawACEUnconsciousIcon.sqf @@ -18,11 +18,14 @@ */ params [["_unit", objnull, [objnull]], ["_isUnconscious", false, [false]]]; +TRACE_1("params",_this); CHECK(isNull _unit || !isPlayer _unit); -private _curatorModule = getAssignedCuratorLogic ACE_player; +// This needs to be player because we want the zeus unit not a unit that zeus currently controls (ace_player). +private _curatorModule = getAssignedCuratorLogic player; private _unconsciousPlayers = _curatorModule getVariable [QGVAR(unconsciousPlayers), []]; +TRACE_3("Unconscious players",player,_curatorModule,_unconsciousPlayers); if (_isUnconscious) then { _unconsciousPlayers pushbackUnique _unit; From ba45b7ade29ae6979d148fd6ca85afa0056f59e8 Mon Sep 17 00:00:00 2001 From: Timi007 Date: Sat, 13 Jan 2024 18:11:01 +0100 Subject: [PATCH 5/6] Add line connecting unconscious icon and unit (#108) --- .../functions/fnc_add3DENCommentsDrawEH.sqf | 2 +- .../fnc_addACEUnconsciousIconDrawEH.sqf | 19 ++++++++++++++----- 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/addons/zeus/functions/fnc_add3DENCommentsDrawEH.sqf b/addons/zeus/functions/fnc_add3DENCommentsDrawEH.sqf index c203b98..395dc33 100644 --- a/addons/zeus/functions/fnc_add3DENCommentsDrawEH.sqf +++ b/addons/zeus/functions/fnc_add3DENCommentsDrawEH.sqf @@ -64,7 +64,7 @@ if (!GVAR(3DENComments_drawEHAdded)) then { [_posAGL select 0, _posAGL select 1, 0], _color ]; - } + }; } count _3denComments; }, [GVAR(3DENComments_data)]] call CBA_fnc_addBISEventHandler; }; diff --git a/addons/zeus/functions/fnc_addACEUnconsciousIconDrawEH.sqf b/addons/zeus/functions/fnc_addACEUnconsciousIconDrawEH.sqf index bc0db73..cd6c092 100644 --- a/addons/zeus/functions/fnc_addACEUnconsciousIconDrawEH.sqf +++ b/addons/zeus/functions/fnc_addACEUnconsciousIconDrawEH.sqf @@ -55,25 +55,34 @@ if (!GVAR(ACEIcon_drawEHAdded)) then { private _unconsciousPlayers = _curatorModule getVariable [QGVAR(unconsciousPlayers), []]; { - private _pos = ASLToAGL (getPosASLVisual _x); - private _camPos = ASLToAGL (getPosASLVisual curatorCamera); - private _d = _pos distance _camPos; + private _unitPosAGL = _x modelToWorldVisual (_x selectionPosition "pelvis"); // Model center position + private _camPosAGL = ASLToAGL (getPosASLVisual curatorCamera); + private _d = _unitPosAGL distance _camPosAGL; private _scale = linearConversion [300, 730, _d, 1.5, 0, true]; // 300m => 1.5, 730m => 0 if (_scale < 0.01) then { continue; }; + private _color = [0.9, 0, 0, 1]; + private _iconPosAGL = [_unitPosAGL select 0, _unitPosAGL select 1, (_unitPosAGL select 2) + 2]; + drawIcon3D [ "z\ace\addons\zeus\ui\Icon_Module_Zeus_Unconscious_ca.paa", - [0.9, 0, 0, 1], - [_pos select 0, _pos select 1, (_pos select 2) + 2], + _color, + _iconPosAGL, _scale, // Width _scale, // Height 0, // Angle "", // Text 1 // Shadow ]; + + drawLine3D [ + [_iconPosAGL select 0, _iconPosAGL select 1, (_iconPosAGL select 2) - 0.02], // Hide line start behind icon + _unitPosAGL, + _color + ]; } count _unconsciousPlayers; }, [_curatorModule]] call CBA_fnc_addBISEventHandler; }; From 0e80cb04d2d20b9dc7ae87d9ee2fd70d2ec8b51f Mon Sep 17 00:00:00 2001 From: Timi007 Date: Sat, 13 Jan 2024 18:13:56 +0100 Subject: [PATCH 6/6] Bump to 1.6.3 --- README.md | 2 +- addons/main/script_version.hpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 8953411..3de480a 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@

- Metis Enhanced Version + Metis Enhanced Version Metis Enhanced Downloads diff --git a/addons/main/script_version.hpp b/addons/main/script_version.hpp index 6e47e37..1911232 100644 --- a/addons/main/script_version.hpp +++ b/addons/main/script_version.hpp @@ -1,4 +1,4 @@ #define MAJOR 1 #define MINOR 6 -#define PATCHLVL 2 -#define BUILD 230926 +#define PATCHLVL 3 +#define BUILD 240113