mirror of
				https://github.com/vcmi/vcmi.git
				synced 2025-10-31 00:07:39 +02:00 
			
		
		
		
	Merge branch 'develop' into handlersAbstraction
# Conflicts: # CI/linux/before_install.sh # CI/mac/before_install.sh # CI/mxe/before_install.sh # lib/CModHandler.cpp # lib/mapObjects/CObjectClassesHandler.cpp # lib/mapObjects/CObjectClassesHandler.h # lib/mapObjects/CommonConstructors.cpp # server/CGameHandler.cpp # test/CMakeLists.txt # test/spells/effects/TeleportTest.cpp
This commit is contained in:
		
							
								
								
									
										118
									
								
								.github/workflows/github.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										118
									
								
								.github/workflows/github.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,118 @@ | ||||
| name: CMake | ||||
|  | ||||
| on: [ push ] | ||||
|  | ||||
| env: | ||||
|   # Customize the CMake build type here (Release, Debug, RelWithDebInfo, etc.) | ||||
|   BUILD_TYPE: Release | ||||
|  | ||||
| jobs: | ||||
|   build: | ||||
|     strategy: | ||||
|       matrix: | ||||
|         include: | ||||
|           - platform: linux | ||||
|             os: ubuntu-20.04 | ||||
|             cc: clang-10 | ||||
|             cxx: clang++-10 | ||||
|             test: 0 | ||||
|           - platform: linux | ||||
|             os: ubuntu-20.04 | ||||
|             cc: gcc-9 | ||||
|             cxx: g++-9 | ||||
|             test: 0 | ||||
|           - platform: mac | ||||
|             os: macos-latest | ||||
|             test: 0 | ||||
|             pack: 1 | ||||
|             extension: dmg | ||||
|           - platform: mxe | ||||
|             os: ubuntu-20.04 | ||||
|             mxe: i686-w64-mingw32.shared | ||||
|             test: 0 | ||||
|             pack: 1 | ||||
|             extension: exe | ||||
|              | ||||
|     runs-on: ${{ matrix.os }} | ||||
|  | ||||
|     steps: | ||||
|     - uses: actions/checkout@v2 | ||||
|       with: | ||||
|         submodules: recursive | ||||
|  | ||||
|     - name: Dependencies | ||||
|       run: source ${{github.workspace}}/CI/${{matrix.platform}}/before_install.sh | ||||
|       env: | ||||
|         MXE_TARGET: ${{ matrix.mxe }} | ||||
|          | ||||
|     - name: Git branch name | ||||
|       id: git-branch-name | ||||
|       uses: EthanSK/git-branch-name-action@v1 | ||||
|  | ||||
|     - name: Build Number | ||||
|       run: | | ||||
|         source ${{github.workspace}}/CI/get_package_name.sh | ||||
|         echo VCMI_PACKAGE_FILE_NAME="$VCMI_PACKAGE_FILE_NAME" >> $GITHUB_ENV | ||||
|         echo VCMI_PACKAGE_NAME_SUFFIX="$VCMI_PACKAGE_NAME_SUFFIX" >> $GITHUB_ENV | ||||
|       env: | ||||
|         PULL_REQUEST: ${{ github.event.pull_request.number }} | ||||
|  | ||||
|     - name: Configure CMake | ||||
|       run: | | ||||
|         mkdir ${{github.workspace}}/build | ||||
|         cd ${{github.workspace}}/build | ||||
|         cmake -G Ninja .. -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} \ | ||||
|             -DENABLE_TEST=${{matrix.test}} \ | ||||
|             -DPACKAGE_NAME_SUFFIX:STRING="$VCMI_PACKAGE_NAME_SUFFIX" \ | ||||
|             -DPACKAGE_FILE_NAME:STRING="$VCMI_PACKAGE_FILE_NAME" | ||||
|       env: | ||||
|         CC: ${{ matrix.cc }} | ||||
|         CXX: ${{ matrix.cxx }} | ||||
|  | ||||
|     - name: Build | ||||
|       run: | | ||||
|         cd ${{github.workspace}}/build | ||||
|         ninja | ||||
|  | ||||
|     - name: Test | ||||
|       if: ${{ matrix.test == 1 }} | ||||
|       run: | | ||||
|         cd ${{github.workspace}}/build | ||||
|         ctest -C Release -V | ||||
|    | ||||
|     - name: Pack | ||||
|       id: cpack | ||||
|       if: ${{ matrix.pack == 1 }} | ||||
|       run: | | ||||
|         cd ${{github.workspace}}/build | ||||
|         cpack | ||||
|          | ||||
|     - name: Additional logs | ||||
|       if: ${{ failure() && steps.cpack.outcome == 'failure' && matrix.platform == 'mxe' }} | ||||
|       run: | | ||||
|         cat ${{github.workspace}}/build/_CPack_Packages/win32/NSIS/project.nsi | ||||
|         cat ${{github.workspace}}/build/_CPack_Packages/win32/NSIS/NSISOutput.log | ||||
|          | ||||
|     - name: Artifacts | ||||
|       if: ${{ matrix.pack == 1 }} | ||||
|       uses: actions/upload-artifact@v2 | ||||
|       with: | ||||
|         name: ${{ env.VCMI_PACKAGE_FILE_NAME }} - ${{ matrix.platform }} | ||||
|         path: ${{github.workspace}}/build/${{ env.VCMI_PACKAGE_FILE_NAME }}.${{ matrix.extension }} | ||||
|    | ||||
|     - name: Upload build | ||||
|       if: ${{ matrix.pack == 1 && github.ref == 'refs/heads/develop' }} | ||||
|       run: | | ||||
|         cd ${{github.workspace}}/build | ||||
|         source ${{github.workspace}}/CI/upload_package.sh | ||||
|       env: | ||||
|         DEPLOY_RSA: ${{ secrets.DEPLOY_RSA }} | ||||
|         PACKAGE_EXTENSION: ${{ matrix.extension }} | ||||
|          | ||||
|     - uses: act10ns/slack@v1 | ||||
|       with: | ||||
|         status: ${{ job.status }} | ||||
|         channel: '#notifications' | ||||
|       env: | ||||
|         SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }} | ||||
|       if: always() | ||||
| @@ -1166,12 +1166,12 @@ void VCAI::pickBestArtifacts(const CGHeroInstance * h, const CGHeroInstance * ot | ||||
|  | ||||
| 			for(auto location : allArtifacts) | ||||
| 			{ | ||||
| 				if(location.slot == ArtifactPosition::MACH4 || location.slot == ArtifactPosition::SPELLBOOK) | ||||
| 					continue; // don't attempt to move catapult and spellbook | ||||
|  | ||||
| 				if(location.relatedObj() == target && location.slot < ArtifactPosition::AFTER_LAST) | ||||
| 					continue; //don't reequip artifact we already wear | ||||
|  | ||||
| 				if(location.slot == ArtifactPosition::MACH4) // don't attempt to move catapult | ||||
| 					continue; | ||||
|  | ||||
| 				auto s = location.getSlot(); | ||||
| 				if(!s || s->locked) //we can't move locks | ||||
| 					continue; | ||||
|   | ||||
							
								
								
									
										973
									
								
								CI/NSIS.template.in
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										973
									
								
								CI/NSIS.template.in
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,973 @@ | ||||
| ; CPack install script designed for a nmake build | ||||
|  | ||||
| ;-------------------------------- | ||||
| ; You must define these values | ||||
|  | ||||
|   !define VERSION "@CPACK_PACKAGE_VERSION@" | ||||
|   !define PATCH  "@CPACK_PACKAGE_VERSION_PATCH@" | ||||
|   !define INST_DIR "@CPACK_TEMPORARY_DIRECTORY@" | ||||
|  | ||||
| ;-------------------------------- | ||||
| ;Variables | ||||
|  | ||||
|   Var MUI_TEMP | ||||
|   Var STARTMENU_FOLDER | ||||
|   Var SV_ALLUSERS | ||||
|   Var START_MENU | ||||
|   Var DO_NOT_ADD_TO_PATH | ||||
|   Var ADD_TO_PATH_ALL_USERS | ||||
|   Var ADD_TO_PATH_CURRENT_USER | ||||
|   Var INSTALL_DESKTOP | ||||
|   Var IS_DEFAULT_INSTALLDIR | ||||
| ;-------------------------------- | ||||
| ;Include Modern UI | ||||
|  | ||||
|   Unicode True | ||||
|   !include "MUI.nsh" | ||||
|  | ||||
|   ;Default installation folder | ||||
|   InstallDir "@CPACK_NSIS_INSTALL_ROOT@\@CPACK_PACKAGE_INSTALL_DIRECTORY@" | ||||
|  | ||||
| ;-------------------------------- | ||||
| ;General | ||||
|  | ||||
|   ;Name and file | ||||
|   Name "@CPACK_NSIS_PACKAGE_NAME@" | ||||
|   OutFile "@CPACK_TOPLEVEL_DIRECTORY@/@CPACK_OUTPUT_FILE_NAME@" | ||||
|  | ||||
|   ;Set compression | ||||
|   SetCompressor @CPACK_NSIS_COMPRESSOR@ | ||||
|  | ||||
|   ;Require administrator access | ||||
|   RequestExecutionLevel admin | ||||
|  | ||||
| @CPACK_NSIS_DEFINES@ | ||||
|  | ||||
|   !include Sections.nsh | ||||
|  | ||||
| ;--- Component support macros: --- | ||||
| ; The code for the add/remove functionality is from: | ||||
| ;   http://nsis.sourceforge.net/Add/Remove_Functionality | ||||
| ; It has been modified slightly and extended to provide | ||||
| ; inter-component dependencies. | ||||
| Var AR_SecFlags | ||||
| Var AR_RegFlags | ||||
| @CPACK_NSIS_SECTION_SELECTED_VARS@ | ||||
|  | ||||
| ; Loads the "selected" flag for the section named SecName into the | ||||
| ; variable VarName. | ||||
| !macro LoadSectionSelectedIntoVar SecName VarName | ||||
|  SectionGetFlags ${${SecName}} $${VarName} | ||||
|  IntOp $${VarName} $${VarName} & ${SF_SELECTED}  ;Turn off all other bits | ||||
| !macroend | ||||
|  | ||||
| ; Loads the value of a variable... can we get around this? | ||||
| !macro LoadVar VarName | ||||
|   IntOp $R0 0 + $${VarName} | ||||
| !macroend | ||||
|  | ||||
| ; Sets the value of a variable | ||||
| !macro StoreVar VarName IntValue | ||||
|   IntOp $${VarName} 0 + ${IntValue} | ||||
| !macroend | ||||
|  | ||||
| !macro InitSection SecName | ||||
|   ;  This macro reads component installed flag from the registry and | ||||
|   ;changes checked state of the section on the components page. | ||||
|   ;Input: section index constant name specified in Section command. | ||||
|  | ||||
|   ClearErrors | ||||
|   ;Reading component status from registry | ||||
|   ReadRegDWORD $AR_RegFlags HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@\Components\${SecName}" "Installed" | ||||
|   IfErrors "default_${SecName}" | ||||
|     ;Status will stay default if registry value not found | ||||
|     ;(component was never installed) | ||||
|   IntOp $AR_RegFlags $AR_RegFlags & ${SF_SELECTED} ;Turn off all other bits | ||||
|   SectionGetFlags ${${SecName}} $AR_SecFlags  ;Reading default section flags | ||||
|   IntOp $AR_SecFlags $AR_SecFlags & 0xFFFE  ;Turn lowest (enabled) bit off | ||||
|   IntOp $AR_SecFlags $AR_RegFlags | $AR_SecFlags      ;Change lowest bit | ||||
|  | ||||
|   ; Note whether this component was installed before | ||||
|   !insertmacro StoreVar ${SecName}_was_installed $AR_RegFlags | ||||
|   IntOp $R0 $AR_RegFlags & $AR_RegFlags | ||||
|  | ||||
|   ;Writing modified flags | ||||
|   SectionSetFlags ${${SecName}} $AR_SecFlags | ||||
|  | ||||
|  "default_${SecName}:" | ||||
|  !insertmacro LoadSectionSelectedIntoVar ${SecName} ${SecName}_selected | ||||
| !macroend | ||||
|  | ||||
| !macro FinishSection SecName | ||||
|   ;  This macro reads section flag set by user and removes the section | ||||
|   ;if it is not selected. | ||||
|   ;Then it writes component installed flag to registry | ||||
|   ;Input: section index constant name specified in Section command. | ||||
|  | ||||
|   SectionGetFlags ${${SecName}} $AR_SecFlags  ;Reading section flags | ||||
|   ;Checking lowest bit: | ||||
|   IntOp $AR_SecFlags $AR_SecFlags & ${SF_SELECTED} | ||||
|   IntCmp $AR_SecFlags 1 "leave_${SecName}" | ||||
|     ;Section is not selected: | ||||
|     ;Calling Section uninstall macro and writing zero installed flag | ||||
|     !insertmacro "Remove_${${SecName}}" | ||||
|     WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@\Components\${SecName}" \ | ||||
|   "Installed" 0 | ||||
|     Goto "exit_${SecName}" | ||||
|  | ||||
|  "leave_${SecName}:" | ||||
|     ;Section is selected: | ||||
|     WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@\Components\${SecName}" \ | ||||
|   "Installed" 1 | ||||
|  | ||||
|  "exit_${SecName}:" | ||||
| !macroend | ||||
|  | ||||
| !macro RemoveSection_CPack SecName | ||||
|   ;  This macro is used to call section's Remove_... macro | ||||
|   ;from the uninstaller. | ||||
|   ;Input: section index constant name specified in Section command. | ||||
|  | ||||
|   !insertmacro "Remove_${${SecName}}" | ||||
| !macroend | ||||
|  | ||||
| ; Determine whether the selection of SecName changed | ||||
| !macro MaybeSelectionChanged SecName | ||||
|   !insertmacro LoadVar ${SecName}_selected | ||||
|   SectionGetFlags ${${SecName}} $R1 | ||||
|   IntOp $R1 $R1 & ${SF_SELECTED} ;Turn off all other bits | ||||
|  | ||||
|   ; See if the status has changed: | ||||
|   IntCmp $R0 $R1 "${SecName}_unchanged" | ||||
|   !insertmacro LoadSectionSelectedIntoVar ${SecName} ${SecName}_selected | ||||
|  | ||||
|   IntCmp $R1 ${SF_SELECTED} "${SecName}_was_selected" | ||||
|   !insertmacro "Deselect_required_by_${SecName}" | ||||
|   goto "${SecName}_unchanged" | ||||
|  | ||||
|   "${SecName}_was_selected:" | ||||
|   !insertmacro "Select_${SecName}_depends" | ||||
|  | ||||
|   "${SecName}_unchanged:" | ||||
| !macroend | ||||
| ;--- End of Add/Remove macros --- | ||||
|  | ||||
| ;-------------------------------- | ||||
| ;Interface Settings | ||||
|  | ||||
|   !define MUI_HEADERIMAGE | ||||
|   !define MUI_ABORTWARNING | ||||
|  | ||||
| ;---------------------------------------- | ||||
| ; based upon a script of "Written by KiCHiK 2003-01-18 05:57:02" | ||||
| ;---------------------------------------- | ||||
| !verbose 3 | ||||
| !include "WinMessages.NSH" | ||||
| !verbose 4 | ||||
| ;==================================================== | ||||
| ; get_NT_environment | ||||
| ;     Returns: the selected environment | ||||
| ;     Output : head of the stack | ||||
| ;==================================================== | ||||
| !macro select_NT_profile UN | ||||
| Function ${UN}select_NT_profile | ||||
|    StrCmp $ADD_TO_PATH_ALL_USERS "1" 0 environment_single | ||||
|       DetailPrint "Selected environment for all users" | ||||
|       Push "all" | ||||
|       Return | ||||
|    environment_single: | ||||
|       DetailPrint "Selected environment for current user only." | ||||
|       Push "current" | ||||
|       Return | ||||
| FunctionEnd | ||||
| !macroend | ||||
| !insertmacro select_NT_profile "" | ||||
| !insertmacro select_NT_profile "un." | ||||
| ;---------------------------------------------------- | ||||
| !define NT_current_env 'HKCU "Environment"' | ||||
| !define NT_all_env     'HKLM "SYSTEM\CurrentControlSet\Control\Session Manager\Environment"' | ||||
|  | ||||
| !ifndef WriteEnvStr_RegKey | ||||
|   !ifdef ALL_USERS | ||||
|     !define WriteEnvStr_RegKey \ | ||||
|        'HKLM "SYSTEM\CurrentControlSet\Control\Session Manager\Environment"' | ||||
|   !else | ||||
|     !define WriteEnvStr_RegKey 'HKCU "Environment"' | ||||
|   !endif | ||||
| !endif | ||||
|  | ||||
| ; AddToPath - Adds the given dir to the search path. | ||||
| ;        Input - head of the stack | ||||
| ;        Note - Win9x systems requires reboot | ||||
|  | ||||
| Function AddToPath | ||||
|   Exch $0 | ||||
|   Push $1 | ||||
|   Push $2 | ||||
|   Push $3 | ||||
|  | ||||
|   # don't add if the path doesn't exist | ||||
|   IfFileExists "$0\*.*" "" AddToPath_done | ||||
|  | ||||
|   ReadEnvStr $1 PATH | ||||
|   ; if the path is too long for a NSIS variable NSIS will return a 0 | ||||
|   ; length string.  If we find that, then warn and skip any path | ||||
|   ; modification as it will trash the existing path. | ||||
|   StrLen $2 $1 | ||||
|   IntCmp $2 0 CheckPathLength_ShowPathWarning CheckPathLength_Done CheckPathLength_Done | ||||
|     CheckPathLength_ShowPathWarning: | ||||
|     Messagebox MB_OK|MB_ICONEXCLAMATION "Warning! PATH too long installer unable to modify PATH!" | ||||
|     Goto AddToPath_done | ||||
|   CheckPathLength_Done: | ||||
|   Push "$1;" | ||||
|   Push "$0;" | ||||
|   Call StrStr | ||||
|   Pop $2 | ||||
|   StrCmp $2 "" "" AddToPath_done | ||||
|   Push "$1;" | ||||
|   Push "$0\;" | ||||
|   Call StrStr | ||||
|   Pop $2 | ||||
|   StrCmp $2 "" "" AddToPath_done | ||||
|   GetFullPathName /SHORT $3 $0 | ||||
|   Push "$1;" | ||||
|   Push "$3;" | ||||
|   Call StrStr | ||||
|   Pop $2 | ||||
|   StrCmp $2 "" "" AddToPath_done | ||||
|   Push "$1;" | ||||
|   Push "$3\;" | ||||
|   Call StrStr | ||||
|   Pop $2 | ||||
|   StrCmp $2 "" "" AddToPath_done | ||||
|  | ||||
|   Call IsNT | ||||
|   Pop $1 | ||||
|   StrCmp $1 1 AddToPath_NT | ||||
|     ; Not on NT | ||||
|     StrCpy $1 $WINDIR 2 | ||||
|     FileOpen $1 "$1\autoexec.bat" a | ||||
|     FileSeek $1 -1 END | ||||
|     FileReadByte $1 $2 | ||||
|     IntCmp $2 26 0 +2 +2 # DOS EOF | ||||
|       FileSeek $1 -1 END # write over EOF | ||||
|     FileWrite $1 "$\r$\nSET PATH=%PATH%;$3$\r$\n" | ||||
|     FileClose $1 | ||||
|     SetRebootFlag true | ||||
|     Goto AddToPath_done | ||||
|  | ||||
|   AddToPath_NT: | ||||
|     StrCmp $ADD_TO_PATH_ALL_USERS "1" ReadAllKey | ||||
|       ReadRegStr $1 ${NT_current_env} "PATH" | ||||
|       Goto DoTrim | ||||
|     ReadAllKey: | ||||
|       ReadRegStr $1 ${NT_all_env} "PATH" | ||||
|     DoTrim: | ||||
|     StrCmp $1 "" AddToPath_NTdoIt | ||||
|       Push $1 | ||||
|       Call Trim | ||||
|       Pop $1 | ||||
|       StrCpy $0 "$1;$0" | ||||
|     AddToPath_NTdoIt: | ||||
|       StrCmp $ADD_TO_PATH_ALL_USERS "1" WriteAllKey | ||||
|         WriteRegExpandStr ${NT_current_env} "PATH" $0 | ||||
|         Goto DoSend | ||||
|       WriteAllKey: | ||||
|         WriteRegExpandStr ${NT_all_env} "PATH" $0 | ||||
|       DoSend: | ||||
|       SendMessage ${HWND_BROADCAST} ${WM_WININICHANGE} 0 "STR:Environment" /TIMEOUT=5000 | ||||
|  | ||||
|   AddToPath_done: | ||||
|     Pop $3 | ||||
|     Pop $2 | ||||
|     Pop $1 | ||||
|     Pop $0 | ||||
| FunctionEnd | ||||
|  | ||||
|  | ||||
| ; RemoveFromPath - Remove a given dir from the path | ||||
| ;     Input: head of the stack | ||||
|  | ||||
| Function un.RemoveFromPath | ||||
|   Exch $0 | ||||
|   Push $1 | ||||
|   Push $2 | ||||
|   Push $3 | ||||
|   Push $4 | ||||
|   Push $5 | ||||
|   Push $6 | ||||
|  | ||||
|   IntFmt $6 "%c" 26 # DOS EOF | ||||
|  | ||||
|   Call un.IsNT | ||||
|   Pop $1 | ||||
|   StrCmp $1 1 unRemoveFromPath_NT | ||||
|     ; Not on NT | ||||
|     StrCpy $1 $WINDIR 2 | ||||
|     FileOpen $1 "$1\autoexec.bat" r | ||||
|     GetTempFileName $4 | ||||
|     FileOpen $2 $4 w | ||||
|     GetFullPathName /SHORT $0 $0 | ||||
|     StrCpy $0 "SET PATH=%PATH%;$0" | ||||
|     Goto unRemoveFromPath_dosLoop | ||||
|  | ||||
|     unRemoveFromPath_dosLoop: | ||||
|       FileRead $1 $3 | ||||
|       StrCpy $5 $3 1 -1 # read last char | ||||
|       StrCmp $5 $6 0 +2 # if DOS EOF | ||||
|         StrCpy $3 $3 -1 # remove DOS EOF so we can compare | ||||
|       StrCmp $3 "$0$\r$\n" unRemoveFromPath_dosLoopRemoveLine | ||||
|       StrCmp $3 "$0$\n" unRemoveFromPath_dosLoopRemoveLine | ||||
|       StrCmp $3 "$0" unRemoveFromPath_dosLoopRemoveLine | ||||
|       StrCmp $3 "" unRemoveFromPath_dosLoopEnd | ||||
|       FileWrite $2 $3 | ||||
|       Goto unRemoveFromPath_dosLoop | ||||
|       unRemoveFromPath_dosLoopRemoveLine: | ||||
|         SetRebootFlag true | ||||
|         Goto unRemoveFromPath_dosLoop | ||||
|  | ||||
|     unRemoveFromPath_dosLoopEnd: | ||||
|       FileClose $2 | ||||
|       FileClose $1 | ||||
|       StrCpy $1 $WINDIR 2 | ||||
|       Delete "$1\autoexec.bat" | ||||
|       CopyFiles /SILENT $4 "$1\autoexec.bat" | ||||
|       Delete $4 | ||||
|       Goto unRemoveFromPath_done | ||||
|  | ||||
|   unRemoveFromPath_NT: | ||||
|     StrCmp $ADD_TO_PATH_ALL_USERS "1" unReadAllKey | ||||
|       ReadRegStr $1 ${NT_current_env} "PATH" | ||||
|       Goto unDoTrim | ||||
|     unReadAllKey: | ||||
|       ReadRegStr $1 ${NT_all_env} "PATH" | ||||
|     unDoTrim: | ||||
|     StrCpy $5 $1 1 -1 # copy last char | ||||
|     StrCmp $5 ";" +2 # if last char != ; | ||||
|       StrCpy $1 "$1;" # append ; | ||||
|     Push $1 | ||||
|     Push "$0;" | ||||
|     Call un.StrStr ; Find `$0;` in $1 | ||||
|     Pop $2 ; pos of our dir | ||||
|     StrCmp $2 "" unRemoveFromPath_done | ||||
|       ; else, it is in path | ||||
|       # $0 - path to add | ||||
|       # $1 - path var | ||||
|       StrLen $3 "$0;" | ||||
|       StrLen $4 $2 | ||||
|       StrCpy $5 $1 -$4 # $5 is now the part before the path to remove | ||||
|       StrCpy $6 $2 "" $3 # $6 is now the part after the path to remove | ||||
|       StrCpy $3 $5$6 | ||||
|  | ||||
|       StrCpy $5 $3 1 -1 # copy last char | ||||
|       StrCmp $5 ";" 0 +2 # if last char == ; | ||||
|         StrCpy $3 $3 -1 # remove last char | ||||
|  | ||||
|       StrCmp $ADD_TO_PATH_ALL_USERS "1" unWriteAllKey | ||||
|         WriteRegExpandStr ${NT_current_env} "PATH" $3 | ||||
|         Goto unDoSend | ||||
|       unWriteAllKey: | ||||
|         WriteRegExpandStr ${NT_all_env} "PATH" $3 | ||||
|       unDoSend: | ||||
|       SendMessage ${HWND_BROADCAST} ${WM_WININICHANGE} 0 "STR:Environment" /TIMEOUT=5000 | ||||
|  | ||||
|   unRemoveFromPath_done: | ||||
|     Pop $6 | ||||
|     Pop $5 | ||||
|     Pop $4 | ||||
|     Pop $3 | ||||
|     Pop $2 | ||||
|     Pop $1 | ||||
|     Pop $0 | ||||
| FunctionEnd | ||||
|  | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| ; Uninstall sutff | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
|  | ||||
| ########################################### | ||||
| #            Utility Functions            # | ||||
| ########################################### | ||||
|  | ||||
| ;==================================================== | ||||
| ; IsNT - Returns 1 if the current system is NT, 0 | ||||
| ;        otherwise. | ||||
| ;     Output: head of the stack | ||||
| ;==================================================== | ||||
| ; IsNT | ||||
| ; no input | ||||
| ; output, top of the stack = 1 if NT or 0 if not | ||||
| ; | ||||
| ; Usage: | ||||
| ;   Call IsNT | ||||
| ;   Pop $R0 | ||||
| ;  ($R0 at this point is 1 or 0) | ||||
|  | ||||
| !macro IsNT un | ||||
| Function ${un}IsNT | ||||
|   Push $0 | ||||
|   ReadRegStr $0 HKLM "SOFTWARE\Microsoft\Windows NT\CurrentVersion" CurrentVersion | ||||
|   StrCmp $0 "" 0 IsNT_yes | ||||
|   ; we are not NT. | ||||
|   Pop $0 | ||||
|   Push 0 | ||||
|   Return | ||||
|  | ||||
|   IsNT_yes: | ||||
|     ; NT!!! | ||||
|     Pop $0 | ||||
|     Push 1 | ||||
| FunctionEnd | ||||
| !macroend | ||||
| !insertmacro IsNT "" | ||||
| !insertmacro IsNT "un." | ||||
|  | ||||
| ; StrStr | ||||
| ; input, top of stack = string to search for | ||||
| ;        top of stack-1 = string to search in | ||||
| ; output, top of stack (replaces with the portion of the string remaining) | ||||
| ; modifies no other variables. | ||||
| ; | ||||
| ; Usage: | ||||
| ;   Push "this is a long ass string" | ||||
| ;   Push "ass" | ||||
| ;   Call StrStr | ||||
| ;   Pop $R0 | ||||
| ;  ($R0 at this point is "ass string") | ||||
|  | ||||
| !macro StrStr un | ||||
| Function ${un}StrStr | ||||
| Exch $R1 ; st=haystack,old$R1, $R1=needle | ||||
|   Exch    ; st=old$R1,haystack | ||||
|   Exch $R2 ; st=old$R1,old$R2, $R2=haystack | ||||
|   Push $R3 | ||||
|   Push $R4 | ||||
|   Push $R5 | ||||
|   StrLen $R3 $R1 | ||||
|   StrCpy $R4 0 | ||||
|   ; $R1=needle | ||||
|   ; $R2=haystack | ||||
|   ; $R3=len(needle) | ||||
|   ; $R4=cnt | ||||
|   ; $R5=tmp | ||||
|   loop: | ||||
|     StrCpy $R5 $R2 $R3 $R4 | ||||
|     StrCmp $R5 $R1 done | ||||
|     StrCmp $R5 "" done | ||||
|     IntOp $R4 $R4 + 1 | ||||
|     Goto loop | ||||
| done: | ||||
|   StrCpy $R1 $R2 "" $R4 | ||||
|   Pop $R5 | ||||
|   Pop $R4 | ||||
|   Pop $R3 | ||||
|   Pop $R2 | ||||
|   Exch $R1 | ||||
| FunctionEnd | ||||
| !macroend | ||||
| !insertmacro StrStr "" | ||||
| !insertmacro StrStr "un." | ||||
|  | ||||
| Function Trim ; Added by Pelaca | ||||
| 	Exch $R1 | ||||
| 	Push $R2 | ||||
| Loop: | ||||
| 	StrCpy $R2 "$R1" 1 -1 | ||||
| 	StrCmp "$R2" " " RTrim | ||||
| 	StrCmp "$R2" "$\n" RTrim | ||||
| 	StrCmp "$R2" "$\r" RTrim | ||||
| 	StrCmp "$R2" ";" RTrim | ||||
| 	GoTo Done | ||||
| RTrim: | ||||
| 	StrCpy $R1 "$R1" -1 | ||||
| 	Goto Loop | ||||
| Done: | ||||
| 	Pop $R2 | ||||
| 	Exch $R1 | ||||
| FunctionEnd | ||||
|  | ||||
| Function ConditionalAddToRegisty | ||||
|   Pop $0 | ||||
|   Pop $1 | ||||
|   StrCmp "$0" "" ConditionalAddToRegisty_EmptyString | ||||
|     WriteRegStr SHCTX "Software\Microsoft\Windows\CurrentVersion\Uninstall\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@" \ | ||||
|     "$1" "$0" | ||||
|     ;MessageBox MB_OK "Set Registry: '$1' to '$0'" | ||||
|     DetailPrint "Set install registry entry: '$1' to '$0'" | ||||
|   ConditionalAddToRegisty_EmptyString: | ||||
| FunctionEnd | ||||
|  | ||||
| ;-------------------------------- | ||||
|  | ||||
| !ifdef CPACK_USES_DOWNLOAD | ||||
| Function DownloadFile | ||||
|     IfFileExists $INSTDIR\* +2 | ||||
|     CreateDirectory $INSTDIR | ||||
|     Pop $0 | ||||
|  | ||||
|     ; Skip if already downloaded | ||||
|     IfFileExists $INSTDIR\$0 0 +2 | ||||
|     Return | ||||
|  | ||||
|     StrCpy $1 "@CPACK_DOWNLOAD_SITE@" | ||||
|  | ||||
|   try_again: | ||||
|     NSISdl::download "$1/$0" "$INSTDIR\$0" | ||||
|  | ||||
|     Pop $1 | ||||
|     StrCmp $1 "success" success | ||||
|     StrCmp $1 "Cancelled" cancel | ||||
|     MessageBox MB_OK "Download failed: $1" | ||||
|   cancel: | ||||
|     Return | ||||
|   success: | ||||
| FunctionEnd | ||||
| !endif | ||||
|  | ||||
| ;-------------------------------- | ||||
| ; Installation types | ||||
| @CPACK_NSIS_INSTALLATION_TYPES@ | ||||
|  | ||||
| ;-------------------------------- | ||||
| ; Component sections | ||||
| @CPACK_NSIS_COMPONENT_SECTIONS@ | ||||
|  | ||||
| ;-------------------------------- | ||||
| ; Define some macro setting for the gui | ||||
| @CPACK_NSIS_INSTALLER_MUI_ICON_CODE@ | ||||
| @CPACK_NSIS_INSTALLER_ICON_CODE@ | ||||
| @CPACK_NSIS_INSTALLER_MUI_WELCOMEFINISH_CODE@ | ||||
| @CPACK_NSIS_INSTALLER_MUI_UNWELCOMEFINISH_CODE@ | ||||
| @CPACK_NSIS_INSTALLER_MUI_COMPONENTS_DESC@ | ||||
| @CPACK_NSIS_INSTALLER_MUI_FINISHPAGE_RUN_CODE@ | ||||
|  | ||||
| ;-------------------------------- | ||||
| ;Pages | ||||
|   !insertmacro MUI_PAGE_WELCOME | ||||
|  | ||||
|   !insertmacro MUI_PAGE_LICENSE "@CPACK_RESOURCE_FILE_LICENSE@" | ||||
|   Page custom InstallOptionsPage | ||||
|   !insertmacro MUI_PAGE_DIRECTORY | ||||
|  | ||||
|   ;Start Menu Folder Page Configuration | ||||
|   !define MUI_STARTMENUPAGE_REGISTRY_ROOT "SHCTX" | ||||
|   !define MUI_STARTMENUPAGE_REGISTRY_KEY "Software\@CPACK_PACKAGE_VENDOR@\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@" | ||||
|   !define MUI_STARTMENUPAGE_REGISTRY_VALUENAME "Start Menu Folder" | ||||
|   !insertmacro MUI_PAGE_STARTMENU Application $STARTMENU_FOLDER | ||||
|  | ||||
|   @CPACK_NSIS_PAGE_COMPONENTS@ | ||||
|  | ||||
|   !insertmacro MUI_PAGE_INSTFILES | ||||
|   !insertmacro MUI_PAGE_FINISH | ||||
|  | ||||
|   !insertmacro MUI_UNPAGE_CONFIRM | ||||
|   !insertmacro MUI_UNPAGE_INSTFILES | ||||
|  | ||||
| ;-------------------------------- | ||||
| ;Languages | ||||
|  | ||||
|   !insertmacro MUI_LANGUAGE "English" ;first language is the default language | ||||
|   !insertmacro MUI_LANGUAGE "Albanian" | ||||
|   !insertmacro MUI_LANGUAGE "Arabic" | ||||
|   !insertmacro MUI_LANGUAGE "Basque" | ||||
|   !insertmacro MUI_LANGUAGE "Belarusian" | ||||
|   !insertmacro MUI_LANGUAGE "Bosnian" | ||||
|   !insertmacro MUI_LANGUAGE "Breton" | ||||
|   !insertmacro MUI_LANGUAGE "Bulgarian" | ||||
|   !insertmacro MUI_LANGUAGE "Croatian" | ||||
|   !insertmacro MUI_LANGUAGE "Czech" | ||||
|   !insertmacro MUI_LANGUAGE "Danish" | ||||
|   !insertmacro MUI_LANGUAGE "Dutch" | ||||
|   !insertmacro MUI_LANGUAGE "Estonian" | ||||
|   !insertmacro MUI_LANGUAGE "Farsi" | ||||
|   !insertmacro MUI_LANGUAGE "Finnish" | ||||
|   !insertmacro MUI_LANGUAGE "French" | ||||
|   !insertmacro MUI_LANGUAGE "German" | ||||
|   !insertmacro MUI_LANGUAGE "Greek" | ||||
|   !insertmacro MUI_LANGUAGE "Hebrew" | ||||
|   !insertmacro MUI_LANGUAGE "Hungarian" | ||||
|   !insertmacro MUI_LANGUAGE "Icelandic" | ||||
|   !insertmacro MUI_LANGUAGE "Indonesian" | ||||
|   !insertmacro MUI_LANGUAGE "Irish" | ||||
|   !insertmacro MUI_LANGUAGE "Italian" | ||||
|   !insertmacro MUI_LANGUAGE "Japanese" | ||||
|   !insertmacro MUI_LANGUAGE "Korean" | ||||
|   !insertmacro MUI_LANGUAGE "Kurdish" | ||||
|   !insertmacro MUI_LANGUAGE "Latvian" | ||||
|   !insertmacro MUI_LANGUAGE "Lithuanian" | ||||
|   !insertmacro MUI_LANGUAGE "Luxembourgish" | ||||
|   !insertmacro MUI_LANGUAGE "Macedonian" | ||||
|   !insertmacro MUI_LANGUAGE "Malay" | ||||
|   !insertmacro MUI_LANGUAGE "Mongolian" | ||||
|   !insertmacro MUI_LANGUAGE "Norwegian" | ||||
|   !insertmacro MUI_LANGUAGE "Polish" | ||||
|   !insertmacro MUI_LANGUAGE "Portuguese" | ||||
|   !insertmacro MUI_LANGUAGE "PortugueseBR" | ||||
|   !insertmacro MUI_LANGUAGE "Romanian" | ||||
|   !insertmacro MUI_LANGUAGE "Russian" | ||||
|   !insertmacro MUI_LANGUAGE "Serbian" | ||||
|   !insertmacro MUI_LANGUAGE "SerbianLatin" | ||||
|   !insertmacro MUI_LANGUAGE "SimpChinese" | ||||
|   !insertmacro MUI_LANGUAGE "Slovak" | ||||
|   !insertmacro MUI_LANGUAGE "Slovenian" | ||||
|   !insertmacro MUI_LANGUAGE "Spanish" | ||||
|   !insertmacro MUI_LANGUAGE "Swedish" | ||||
|   !insertmacro MUI_LANGUAGE "Thai" | ||||
|   !insertmacro MUI_LANGUAGE "TradChinese" | ||||
|   !insertmacro MUI_LANGUAGE "Turkish" | ||||
|   !insertmacro MUI_LANGUAGE "Ukrainian" | ||||
|   !insertmacro MUI_LANGUAGE "Welsh" | ||||
|  | ||||
|  | ||||
| ;-------------------------------- | ||||
| ;Reserve Files | ||||
|  | ||||
|   ;These files should be inserted before other files in the data block | ||||
|   ;Keep these lines before any File command | ||||
|   ;Only for solid compression (by default, solid compression is enabled for BZIP2 and LZMA) | ||||
|  | ||||
|   ReserveFile "NSIS.InstallOptions.ini" | ||||
|   !insertmacro MUI_RESERVEFILE_INSTALLOPTIONS | ||||
|  | ||||
| ;-------------------------------- | ||||
| ;Installer Sections | ||||
|  | ||||
| Section "-Core installation" | ||||
|   ;Use the entire tree produced by the INSTALL target.  Keep the | ||||
|   ;list of directories here in sync with the RMDir commands below. | ||||
|   SetOutPath "$INSTDIR" | ||||
|   @CPACK_NSIS_EXTRA_PREINSTALL_COMMANDS@ | ||||
|   @CPACK_NSIS_FULL_INSTALL@ | ||||
|  | ||||
|   ;Store installation folder | ||||
|   WriteRegStr SHCTX "Software\@CPACK_PACKAGE_VENDOR@\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@" "" $INSTDIR | ||||
|  | ||||
|   ;Create uninstaller | ||||
|   WriteUninstaller "$INSTDIR\Uninstall.exe" | ||||
|   Push "DisplayName" | ||||
|   Push "@CPACK_NSIS_DISPLAY_NAME@" | ||||
|   Call ConditionalAddToRegisty | ||||
|   Push "DisplayVersion" | ||||
|   Push "@CPACK_PACKAGE_VERSION@" | ||||
|   Call ConditionalAddToRegisty | ||||
|   Push "Publisher" | ||||
|   Push "@CPACK_PACKAGE_VENDOR@" | ||||
|   Call ConditionalAddToRegisty | ||||
|   Push "UninstallString" | ||||
|   Push "$INSTDIR\Uninstall.exe" | ||||
|   Call ConditionalAddToRegisty | ||||
|   Push "NoRepair" | ||||
|   Push "1" | ||||
|   Call ConditionalAddToRegisty | ||||
|  | ||||
|   !ifdef CPACK_NSIS_ADD_REMOVE | ||||
|   ;Create add/remove functionality | ||||
|   Push "ModifyPath" | ||||
|   Push "$INSTDIR\AddRemove.exe" | ||||
|   Call ConditionalAddToRegisty | ||||
|   !else | ||||
|   Push "NoModify" | ||||
|   Push "1" | ||||
|   Call ConditionalAddToRegisty | ||||
|   !endif | ||||
|  | ||||
|   ; Optional registration | ||||
|   Push "DisplayIcon" | ||||
|   Push "$INSTDIR\@CPACK_NSIS_INSTALLED_ICON_NAME@" | ||||
|   Call ConditionalAddToRegisty | ||||
|   Push "HelpLink" | ||||
|   Push "@CPACK_NSIS_HELP_LINK@" | ||||
|   Call ConditionalAddToRegisty | ||||
|   Push "URLInfoAbout" | ||||
|   Push "@CPACK_NSIS_URL_INFO_ABOUT@" | ||||
|   Call ConditionalAddToRegisty | ||||
|   Push "Contact" | ||||
|   Push "@CPACK_NSIS_CONTACT@" | ||||
|   Call ConditionalAddToRegisty | ||||
|   !insertmacro MUI_INSTALLOPTIONS_READ $INSTALL_DESKTOP "NSIS.InstallOptions.ini" "Field 5" "State" | ||||
|   !insertmacro MUI_STARTMENU_WRITE_BEGIN Application | ||||
|  | ||||
|   ;Create shortcuts | ||||
|   CreateDirectory "$SMPROGRAMS\$STARTMENU_FOLDER" | ||||
| @CPACK_NSIS_CREATE_ICONS@ | ||||
| @CPACK_NSIS_CREATE_ICONS_EXTRA@ | ||||
|   CreateShortCut "$SMPROGRAMS\$STARTMENU_FOLDER\Uninstall.lnk" "$INSTDIR\Uninstall.exe" | ||||
|  | ||||
|   ;Read a value from an InstallOptions INI file | ||||
|   !insertmacro MUI_INSTALLOPTIONS_READ $DO_NOT_ADD_TO_PATH "NSIS.InstallOptions.ini" "Field 2" "State" | ||||
|   !insertmacro MUI_INSTALLOPTIONS_READ $ADD_TO_PATH_ALL_USERS "NSIS.InstallOptions.ini" "Field 3" "State" | ||||
|   !insertmacro MUI_INSTALLOPTIONS_READ $ADD_TO_PATH_CURRENT_USER "NSIS.InstallOptions.ini" "Field 4" "State" | ||||
|  | ||||
|   ; Write special uninstall registry entries | ||||
|   Push "StartMenu" | ||||
|   Push "$STARTMENU_FOLDER" | ||||
|   Call ConditionalAddToRegisty | ||||
|   Push "DoNotAddToPath" | ||||
|   Push "$DO_NOT_ADD_TO_PATH" | ||||
|   Call ConditionalAddToRegisty | ||||
|   Push "AddToPathAllUsers" | ||||
|   Push "$ADD_TO_PATH_ALL_USERS" | ||||
|   Call ConditionalAddToRegisty | ||||
|   Push "AddToPathCurrentUser" | ||||
|   Push "$ADD_TO_PATH_CURRENT_USER" | ||||
|   Call ConditionalAddToRegisty | ||||
|   Push "InstallToDesktop" | ||||
|   Push "$INSTALL_DESKTOP" | ||||
|   Call ConditionalAddToRegisty | ||||
|  | ||||
|   !insertmacro MUI_STARTMENU_WRITE_END | ||||
|  | ||||
| @CPACK_NSIS_EXTRA_INSTALL_COMMANDS@ | ||||
|  | ||||
| SectionEnd | ||||
|  | ||||
| Section "-Add to path" | ||||
|   Push $INSTDIR\bin | ||||
|   StrCmp "@CPACK_NSIS_MODIFY_PATH@" "ON" 0 doNotAddToPath | ||||
|   StrCmp $DO_NOT_ADD_TO_PATH "1" doNotAddToPath 0 | ||||
|     Call AddToPath | ||||
|   doNotAddToPath: | ||||
| SectionEnd | ||||
|  | ||||
| ;-------------------------------- | ||||
| ; Create custom pages | ||||
| Function InstallOptionsPage | ||||
|   !insertmacro MUI_HEADER_TEXT "Install Options" "Choose options for installing @CPACK_NSIS_PACKAGE_NAME@" | ||||
|   !insertmacro MUI_INSTALLOPTIONS_DISPLAY "NSIS.InstallOptions.ini" | ||||
|  | ||||
| FunctionEnd | ||||
|  | ||||
| ;-------------------------------- | ||||
| ; determine admin versus local install | ||||
| Function un.onInit | ||||
|  | ||||
|   ClearErrors | ||||
|   UserInfo::GetName | ||||
|   IfErrors noLM | ||||
|   Pop $0 | ||||
|   UserInfo::GetAccountType | ||||
|   Pop $1 | ||||
|   StrCmp $1 "Admin" 0 +3 | ||||
|     SetShellVarContext all | ||||
|     ;MessageBox MB_OK 'User "$0" is in the Admin group' | ||||
|     Goto done | ||||
|   StrCmp $1 "Power" 0 +3 | ||||
|     SetShellVarContext all | ||||
|     ;MessageBox MB_OK 'User "$0" is in the Power Users group' | ||||
|     Goto done | ||||
|  | ||||
|   noLM: | ||||
|     ;Get installation folder from registry if available | ||||
|  | ||||
|   done: | ||||
|  | ||||
| FunctionEnd | ||||
|  | ||||
| ;--- Add/Remove callback functions: --- | ||||
| !macro SectionList MacroName | ||||
|   ;This macro used to perform operation on multiple sections. | ||||
|   ;List all of your components in following manner here. | ||||
| @CPACK_NSIS_COMPONENT_SECTION_LIST@ | ||||
| !macroend | ||||
|  | ||||
| Section -FinishComponents | ||||
|   ;Removes unselected components and writes component status to registry | ||||
|   !insertmacro SectionList "FinishSection" | ||||
|  | ||||
| !ifdef CPACK_NSIS_ADD_REMOVE | ||||
|   ; Get the name of the installer executable | ||||
|   System::Call 'kernel32::GetModuleFileNameA(i 0, t .R0, i 1024) i r1' | ||||
|   StrCpy $R3 $R0 | ||||
|  | ||||
|   ; Strip off the last 13 characters, to see if we have AddRemove.exe | ||||
|   StrLen $R1 $R0 | ||||
|   IntOp $R1 $R0 - 13 | ||||
|   StrCpy $R2 $R0 13 $R1 | ||||
|   StrCmp $R2 "AddRemove.exe" addremove_installed | ||||
|  | ||||
|   ; We're not running AddRemove.exe, so install it | ||||
|   CopyFiles $R3 $INSTDIR\AddRemove.exe | ||||
|  | ||||
|   addremove_installed: | ||||
| !endif | ||||
| SectionEnd | ||||
| ;--- End of Add/Remove callback functions --- | ||||
|  | ||||
| ;-------------------------------- | ||||
| ; Component dependencies | ||||
| Function .onSelChange | ||||
|   !insertmacro SectionList MaybeSelectionChanged | ||||
| FunctionEnd | ||||
|  | ||||
| ;-------------------------------- | ||||
| ;Uninstaller Section | ||||
|  | ||||
| Section "Uninstall" | ||||
|   ReadRegStr $START_MENU SHCTX \ | ||||
|    "Software\Microsoft\Windows\CurrentVersion\Uninstall\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@" "StartMenu" | ||||
|   ;MessageBox MB_OK "Start menu is in: $START_MENU" | ||||
|   ReadRegStr $DO_NOT_ADD_TO_PATH SHCTX \ | ||||
|     "Software\Microsoft\Windows\CurrentVersion\Uninstall\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@" "DoNotAddToPath" | ||||
|   ReadRegStr $ADD_TO_PATH_ALL_USERS SHCTX \ | ||||
|     "Software\Microsoft\Windows\CurrentVersion\Uninstall\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@" "AddToPathAllUsers" | ||||
|   ReadRegStr $ADD_TO_PATH_CURRENT_USER SHCTX \ | ||||
|     "Software\Microsoft\Windows\CurrentVersion\Uninstall\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@" "AddToPathCurrentUser" | ||||
|   ;MessageBox MB_OK "Add to path: $DO_NOT_ADD_TO_PATH all users: $ADD_TO_PATH_ALL_USERS" | ||||
|   ReadRegStr $INSTALL_DESKTOP SHCTX \ | ||||
|     "Software\Microsoft\Windows\CurrentVersion\Uninstall\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@" "InstallToDesktop" | ||||
|   ;MessageBox MB_OK "Install to desktop: $INSTALL_DESKTOP " | ||||
|  | ||||
| @CPACK_NSIS_EXTRA_UNINSTALL_COMMANDS@ | ||||
|  | ||||
|   ;Remove files we installed. | ||||
|   ;Keep the list of directories here in sync with the File commands above. | ||||
| @CPACK_NSIS_DELETE_FILES@ | ||||
| @CPACK_NSIS_DELETE_DIRECTORIES@ | ||||
|  | ||||
| !ifdef CPACK_NSIS_ADD_REMOVE | ||||
|   ;Remove the add/remove program | ||||
|   Delete "$INSTDIR\AddRemove.exe" | ||||
| !endif | ||||
|  | ||||
|   ;Remove the uninstaller itself. | ||||
|   Delete "$INSTDIR\Uninstall.exe" | ||||
|   DeleteRegKey SHCTX "Software\Microsoft\Windows\CurrentVersion\Uninstall\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@" | ||||
|  | ||||
|   ;Remove the installation directory if it is empty. | ||||
|   RMDir "$INSTDIR" | ||||
|  | ||||
|   ; Remove the registry entries. | ||||
|   DeleteRegKey SHCTX "Software\@CPACK_PACKAGE_VENDOR@\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@" | ||||
|  | ||||
|   ; Removes all optional components | ||||
|   !insertmacro SectionList "RemoveSection_CPack" | ||||
|  | ||||
|   !insertmacro MUI_STARTMENU_GETFOLDER Application $MUI_TEMP | ||||
|  | ||||
|   Delete "$SMPROGRAMS\$MUI_TEMP\Uninstall.lnk" | ||||
| @CPACK_NSIS_DELETE_ICONS@ | ||||
| @CPACK_NSIS_DELETE_ICONS_EXTRA@ | ||||
|  | ||||
|   ;Delete empty start menu parent diretories | ||||
|   StrCpy $MUI_TEMP "$SMPROGRAMS\$MUI_TEMP" | ||||
|  | ||||
|   startMenuDeleteLoop: | ||||
|     ClearErrors | ||||
|     RMDir $MUI_TEMP | ||||
|     GetFullPathName $MUI_TEMP "$MUI_TEMP\.." | ||||
|  | ||||
|     IfErrors startMenuDeleteLoopDone | ||||
|  | ||||
|     StrCmp "$MUI_TEMP" "$SMPROGRAMS" startMenuDeleteLoopDone startMenuDeleteLoop | ||||
|   startMenuDeleteLoopDone: | ||||
|  | ||||
|   ; If the user changed the shortcut, then untinstall may not work. This should | ||||
|   ; try to fix it. | ||||
|   StrCpy $MUI_TEMP "$START_MENU" | ||||
|   Delete "$SMPROGRAMS\$MUI_TEMP\Uninstall.lnk" | ||||
| @CPACK_NSIS_DELETE_ICONS_EXTRA@ | ||||
|  | ||||
|   ;Delete empty start menu parent diretories | ||||
|   StrCpy $MUI_TEMP "$SMPROGRAMS\$MUI_TEMP" | ||||
|  | ||||
|   secondStartMenuDeleteLoop: | ||||
|     ClearErrors | ||||
|     RMDir $MUI_TEMP | ||||
|     GetFullPathName $MUI_TEMP "$MUI_TEMP\.." | ||||
|  | ||||
|     IfErrors secondStartMenuDeleteLoopDone | ||||
|  | ||||
|     StrCmp "$MUI_TEMP" "$SMPROGRAMS" secondStartMenuDeleteLoopDone secondStartMenuDeleteLoop | ||||
|   secondStartMenuDeleteLoopDone: | ||||
|  | ||||
|   DeleteRegKey /ifempty SHCTX "Software\@CPACK_PACKAGE_VENDOR@\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@" | ||||
|  | ||||
|   Push $INSTDIR\bin | ||||
|   StrCmp $DO_NOT_ADD_TO_PATH_ "1" doNotRemoveFromPath 0 | ||||
|     Call un.RemoveFromPath | ||||
|   doNotRemoveFromPath: | ||||
| SectionEnd | ||||
|  | ||||
| ;-------------------------------- | ||||
| ; determine admin versus local install | ||||
| ; Is install for "AllUsers" or "JustMe"? | ||||
| ; Default to "JustMe" - set to "AllUsers" if admin or on Win9x | ||||
| ; This function is used for the very first "custom page" of the installer. | ||||
| ; This custom page does not show up visibly, but it executes prior to the | ||||
| ; first visible page and sets up $INSTDIR properly... | ||||
| ; Choose different default installation folder based on SV_ALLUSERS... | ||||
| ; "Program Files" for AllUsers, "My Documents" for JustMe... | ||||
|  | ||||
| Function .onInit | ||||
|   StrCmp "@CPACK_NSIS_ENABLE_UNINSTALL_BEFORE_INSTALL@" "ON" 0 inst | ||||
|  | ||||
|   ReadRegStr $0 HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@" "UninstallString" | ||||
|   StrCmp $0 "" inst | ||||
|  | ||||
|   MessageBox MB_YESNOCANCEL|MB_ICONEXCLAMATION \ | ||||
|   "@CPACK_NSIS_PACKAGE_NAME@ is already installed. $\n$\nDo you want to uninstall the old version before installing the new one?" \ | ||||
|   /SD IDYES IDYES uninst IDNO inst | ||||
|   Abort | ||||
|  | ||||
| ;Run the uninstaller | ||||
| uninst: | ||||
|   ClearErrors | ||||
|   StrLen $2 "\Uninstall.exe" | ||||
|   StrCpy $3 $0 -$2 # remove "\Uninstall.exe" from UninstallString to get path | ||||
|   ExecWait '"$0" /S _?=$3' ;Do not copy the uninstaller to a temp file | ||||
|  | ||||
|   IfErrors uninst_failed inst | ||||
| uninst_failed: | ||||
|   MessageBox MB_OK|MB_ICONSTOP "Uninstall failed." | ||||
|   Abort | ||||
|  | ||||
|  | ||||
| inst: | ||||
|   ; Reads components status for registry | ||||
|   !insertmacro SectionList "InitSection" | ||||
|  | ||||
|   ; check to see if /D has been used to change | ||||
|   ; the install directory by comparing it to the | ||||
|   ; install directory that is expected to be the | ||||
|   ; default | ||||
|   StrCpy $IS_DEFAULT_INSTALLDIR 0 | ||||
|   StrCmp "$INSTDIR" "@CPACK_NSIS_INSTALL_ROOT@\@CPACK_PACKAGE_INSTALL_DIRECTORY@" 0 +2 | ||||
|     StrCpy $IS_DEFAULT_INSTALLDIR 1 | ||||
|  | ||||
|   StrCpy $SV_ALLUSERS "JustMe" | ||||
|   ; if default install dir then change the default | ||||
|   ; if it is installed for JustMe | ||||
|   StrCmp "$IS_DEFAULT_INSTALLDIR" "1" 0 +2 | ||||
|     StrCpy $INSTDIR "$DOCUMENTS\@CPACK_PACKAGE_INSTALL_DIRECTORY@" | ||||
|  | ||||
|   ClearErrors | ||||
|   UserInfo::GetName | ||||
|   IfErrors noLM | ||||
|   Pop $0 | ||||
|   UserInfo::GetAccountType | ||||
|   Pop $1 | ||||
|   StrCmp $1 "Admin" 0 +4 | ||||
|     SetShellVarContext all | ||||
|     ;MessageBox MB_OK 'User "$0" is in the Admin group' | ||||
|     StrCpy $SV_ALLUSERS "AllUsers" | ||||
|     Goto done | ||||
|   StrCmp $1 "Power" 0 +4 | ||||
|     SetShellVarContext all | ||||
|     ;MessageBox MB_OK 'User "$0" is in the Power Users group' | ||||
|     StrCpy $SV_ALLUSERS "AllUsers" | ||||
|     Goto done | ||||
|  | ||||
|   noLM: | ||||
|     StrCpy $SV_ALLUSERS "AllUsers" | ||||
|     ;Get installation folder from registry if available | ||||
|  | ||||
|   done: | ||||
|   StrCmp $SV_ALLUSERS "AllUsers" 0 +3 | ||||
|     StrCmp "$IS_DEFAULT_INSTALLDIR" "1" 0 +2 | ||||
|       StrCpy $INSTDIR "@CPACK_NSIS_INSTALL_ROOT@\@CPACK_PACKAGE_INSTALL_DIRECTORY@" | ||||
|  | ||||
|   StrCmp "@CPACK_NSIS_MODIFY_PATH@" "ON" 0 noOptionsPage | ||||
|     !insertmacro MUI_INSTALLOPTIONS_EXTRACT "NSIS.InstallOptions.ini" | ||||
|  | ||||
|   noOptionsPage: | ||||
| FunctionEnd | ||||
							
								
								
									
										210
									
								
								CI/appveyor.yml
									
									
									
									
									
								
							
							
						
						
									
										210
									
								
								CI/appveyor.yml
									
									
									
									
									
								
							| @@ -1,105 +1,105 @@ | ||||
| # Common configuration for all branches | ||||
| version: 1.0.{build} | ||||
| max_jobs: 2 | ||||
| clone_depth: 10 | ||||
| clone_folder: c:\projects\vcmi\source | ||||
| install: | ||||
| - bash c:\projects\vcmi\source\CI\msvc\install.sh | ||||
| build_script: | ||||
| - cmd: c:\projects\vcmi\source\CI\msvc\build_script.bat | ||||
| artifacts: | ||||
| - path: build_$(VCMI_BUILD_PLATFORM)\*.exe | ||||
| notifications: | ||||
|   - provider: Slack | ||||
|     incoming_webhook: | ||||
|       secure: zxT3HTnxL744HiSv7ig7sjGL4LmJ8n3MsY8PEA/kinbVMkmcxrSgVBVkHV79RfSWSyq4oLMSRvMMpG8SuDWnf6oK/qvgaiAWfwwlCIiA7uQ= | ||||
|  | ||||
| # Branch-specific configuration | ||||
| for: | ||||
| # Extended configuration for toolchain_test branch | ||||
| - | ||||
|   branches: | ||||
|     only: | ||||
|       - toolchain_test | ||||
|   environment: | ||||
|     matrix: | ||||
|       - NAME: MSVS 2015 x86 - Release | ||||
|         APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 | ||||
|         VCMI_GENERATOR: Visual Studio 14 2015 | ||||
|         VCMI_BUILD_PLATFORM: x86 | ||||
|         VCMI_BUILD_CONFIGURATION: Release | ||||
|       - NAME: MSVS 2015 x86 - Debug | ||||
|         APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 | ||||
|         VCMI_GENERATOR: Visual Studio 14 2015 | ||||
|         VCMI_BUILD_PLATFORM: x86 | ||||
|         VCMI_BUILD_CONFIGURATION: Debug | ||||
|  | ||||
|       - NAME: MSVS 2015 x64 - Release | ||||
|         APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 | ||||
|         VCMI_GENERATOR: Visual Studio 14 2015 Win64 | ||||
|         VCMI_BUILD_PLATFORM: x64 | ||||
|         VCMI_BUILD_CONFIGURATION: Release | ||||
|       - NAME: MSVS 2015 x64 - Debug | ||||
|         APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 | ||||
|         VCMI_GENERATOR: Visual Studio 14 2015 Win64 | ||||
|         VCMI_BUILD_PLATFORM: x64 | ||||
|         VCMI_BUILD_CONFIGURATION: Debug | ||||
|  | ||||
|       - NAME: MSVS 2017 x86 - Release | ||||
|         APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 | ||||
|         VCMI_GENERATOR: Visual Studio 15 2017 | ||||
|         VCMI_BUILD_PLATFORM: x86 | ||||
|         VCMI_BUILD_CONFIGURATION: Release | ||||
|       - NAME: MSVS 2017 x86 - Debug | ||||
|         APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 | ||||
|         VCMI_GENERATOR: Visual Studio 15 2017 | ||||
|         VCMI_BUILD_PLATFORM: x86 | ||||
|         VCMI_BUILD_CONFIGURATION: Debug | ||||
|  | ||||
|       - NAME: MSVS 2017 x64 - Release | ||||
|         APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 | ||||
|         VCMI_GENERATOR: Visual Studio 15 2017 Win64 | ||||
|         VCMI_BUILD_PLATFORM: x64 | ||||
|         VCMI_BUILD_CONFIGURATION: Release | ||||
|       - NAME: MSVS 2017 x64 - Debug | ||||
|         APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 | ||||
|         VCMI_GENERATOR: Visual Studio 15 2017 Win64 | ||||
|         VCMI_BUILD_PLATFORM: x64 | ||||
|         VCMI_BUILD_CONFIGURATION: Debug | ||||
|  | ||||
| # Special configuration for coverity_scan branch | ||||
| - | ||||
|   branches: | ||||
|     only: | ||||
|       - coverity_scan | ||||
|   environment: | ||||
|     matrix: | ||||
|       - NAME: Coverity - MSVS 2017 x86 - Release | ||||
|         APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 | ||||
|         VCMI_GENERATOR: Visual Studio 15 2017 | ||||
|         VCMI_BUILD_PLATFORM: x86 | ||||
|         VCMI_BUILD_CONFIGURATION: Release | ||||
|         environment: | ||||
|     coverity_token: | ||||
|       secure: XNnpYevnZxGmXW1zLu+3js2S+pqfWPQmL26hVgOTBTI= | ||||
|     coverity_email: | ||||
|       secure: JDd5yXvYaq/yJEVjoadEhA== | ||||
|   build_script: | ||||
|     - cmd: c:\projects\vcmi\source\CI\msvc\coverity_build_script.bat | ||||
|   after_test: | ||||
|     - ps: c:\projects\vcmi\source\CI\msvc\coverity_upload_script.ps | ||||
|  | ||||
| # Default configuration for all other branches | ||||
| - | ||||
|   environment: | ||||
|     matrix: | ||||
|       - NAME: MSVS 2017 x86 - Release | ||||
|         APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 | ||||
|         VCMI_GENERATOR: Visual Studio 15 2017 | ||||
|         VCMI_BUILD_PLATFORM: x86 | ||||
|         VCMI_BUILD_CONFIGURATION: Release | ||||
|       - NAME: MSVS 2017 x64 - Release | ||||
|         APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 | ||||
|         VCMI_GENERATOR: Visual Studio 15 2017 Win64 | ||||
|         VCMI_BUILD_PLATFORM: x64 | ||||
|         VCMI_BUILD_CONFIGURATION: Release | ||||
| # Common configuration for all branches | ||||
| version: 1.0.{build} | ||||
| max_jobs: 2 | ||||
| clone_depth: 10 | ||||
| clone_folder: c:\projects\vcmi\source | ||||
| install: | ||||
| - bash c:\projects\vcmi\source\CI\msvc\install.sh | ||||
| build_script: | ||||
| - cmd: c:\projects\vcmi\source\CI\msvc\build_script.bat | ||||
| artifacts: | ||||
| - path: build_$(VCMI_BUILD_PLATFORM)\*.exe | ||||
| notifications: | ||||
|   - provider: Slack | ||||
|     incoming_webhook: | ||||
|       secure: zxT3HTnxL744HiSv7ig7sjGL4LmJ8n3MsY8PEA/kinbVMkmcxrSgVBVkHV79RfSWSyq4oLMSRvMMpG8SuDWnf6oK/qvgaiAWfwwlCIiA7uQ= | ||||
|  | ||||
| # Branch-specific configuration | ||||
| for: | ||||
| # Extended configuration for toolchain_test branch | ||||
| - | ||||
|   branches: | ||||
|     only: | ||||
|       - toolchain_test | ||||
|   environment: | ||||
|     matrix: | ||||
|       - NAME: MSVS 2015 x86 - Release | ||||
|         APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 | ||||
|         VCMI_GENERATOR: Visual Studio 14 2015 | ||||
|         VCMI_BUILD_PLATFORM: x86 | ||||
|         VCMI_BUILD_CONFIGURATION: Release | ||||
|       - NAME: MSVS 2015 x86 - Debug | ||||
|         APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 | ||||
|         VCMI_GENERATOR: Visual Studio 14 2015 | ||||
|         VCMI_BUILD_PLATFORM: x86 | ||||
|         VCMI_BUILD_CONFIGURATION: Debug | ||||
|  | ||||
|       - NAME: MSVS 2015 x64 - Release | ||||
|         APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 | ||||
|         VCMI_GENERATOR: Visual Studio 14 2015 Win64 | ||||
|         VCMI_BUILD_PLATFORM: x64 | ||||
|         VCMI_BUILD_CONFIGURATION: Release | ||||
|       - NAME: MSVS 2015 x64 - Debug | ||||
|         APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 | ||||
|         VCMI_GENERATOR: Visual Studio 14 2015 Win64 | ||||
|         VCMI_BUILD_PLATFORM: x64 | ||||
|         VCMI_BUILD_CONFIGURATION: Debug | ||||
|  | ||||
|       - NAME: MSVS 2017 x86 - Release | ||||
|         APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 | ||||
|         VCMI_GENERATOR: Visual Studio 15 2017 | ||||
|         VCMI_BUILD_PLATFORM: x86 | ||||
|         VCMI_BUILD_CONFIGURATION: Release | ||||
|       - NAME: MSVS 2017 x86 - Debug | ||||
|         APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 | ||||
|         VCMI_GENERATOR: Visual Studio 15 2017 | ||||
|         VCMI_BUILD_PLATFORM: x86 | ||||
|         VCMI_BUILD_CONFIGURATION: Debug | ||||
|  | ||||
|       - NAME: MSVS 2017 x64 - Release | ||||
|         APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 | ||||
|         VCMI_GENERATOR: Visual Studio 15 2017 Win64 | ||||
|         VCMI_BUILD_PLATFORM: x64 | ||||
|         VCMI_BUILD_CONFIGURATION: Release | ||||
|       - NAME: MSVS 2017 x64 - Debug | ||||
|         APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 | ||||
|         VCMI_GENERATOR: Visual Studio 15 2017 Win64 | ||||
|         VCMI_BUILD_PLATFORM: x64 | ||||
|         VCMI_BUILD_CONFIGURATION: Debug | ||||
|  | ||||
| # Special configuration for coverity_scan branch | ||||
| - | ||||
|   branches: | ||||
|     only: | ||||
|       - coverity_scan | ||||
|   environment: | ||||
|     matrix: | ||||
|       - NAME: Coverity - MSVS 2017 x86 - Release | ||||
|         APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 | ||||
|         VCMI_GENERATOR: Visual Studio 15 2017 | ||||
|         VCMI_BUILD_PLATFORM: x86 | ||||
|         VCMI_BUILD_CONFIGURATION: Release | ||||
|         environment: | ||||
|     coverity_token: | ||||
|       secure: XNnpYevnZxGmXW1zLu+3js2S+pqfWPQmL26hVgOTBTI= | ||||
|     coverity_email: | ||||
|       secure: JDd5yXvYaq/yJEVjoadEhA== | ||||
|   build_script: | ||||
|     - cmd: c:\projects\vcmi\source\CI\msvc\coverity_build_script.bat | ||||
|   after_test: | ||||
|     - ps: c:\projects\vcmi\source\CI\msvc\coverity_upload_script.ps | ||||
|  | ||||
| # Default configuration for all other branches | ||||
| - | ||||
|   environment: | ||||
|     matrix: | ||||
|       - NAME: MSVS 2017 x86 - Release | ||||
|         APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 | ||||
|         VCMI_GENERATOR: Visual Studio 15 2017 | ||||
|         VCMI_BUILD_PLATFORM: x86 | ||||
|         VCMI_BUILD_CONFIGURATION: Release | ||||
|       - NAME: MSVS 2017 x64 - Release | ||||
|         APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 | ||||
|         VCMI_GENERATOR: Visual Studio 15 2017 Win64 | ||||
|         VCMI_BUILD_PLATFORM: x64 | ||||
|         VCMI_BUILD_CONFIGURATION: Release | ||||
|   | ||||
| @@ -13,6 +13,13 @@ then | ||||
| 	TMP_BRANCH="$APPVEYOR_REPO_BRANCH" | ||||
| 	TMP_PRID="$APPVEYOR_PULL_REQUEST_NUMBER" | ||||
| 	TMP_COMMIT="$APPVEYOR_REPO_COMMIT" | ||||
| elif [ ! -z "${GITHUB_RUN_ID}" ]; | ||||
| then | ||||
| 	echo "Using Github environment variables!" | ||||
| 	TMP_JOBID="$GITHUB_RUN_ID" | ||||
| 	TMP_BRANCH=${GITHUB_REF#refs/heads/} | ||||
| 	TMP_PRID="$PULL_REQUEST" | ||||
| 	TMP_COMMIT=$(git rev-parse --short "$GITHUB_SHA") | ||||
| else | ||||
| 	echo "No Travir or AppVeyor environment variables found!" | ||||
| 	exit | ||||
|   | ||||
| @@ -1,27 +1,16 @@ | ||||
| #!/bin/sh | ||||
|  | ||||
| #new Clang | ||||
| sudo add-apt-repository --yes ppa:h-rayflood/llvm | ||||
| sudo apt-get update | ||||
|  | ||||
| #new SDL2 | ||||
| sudo add-apt-repository --yes ppa:zoogie/sdl2-snapshots | ||||
| # Boost | ||||
| wget -nv https://boostorg.jfrog.io/artifactory/main/release/1.66.0/source/boost_1_66_0.tar.gz | ||||
| tar xfz boost_1_66_0.tar.gz | ||||
| cd boost_1_66_0 | ||||
| ./bootstrap.sh --with-libraries=program_options,filesystem,system,thread,locale,date_time | ||||
| ./b2 | ||||
| sudo ./b2 install | ||||
|  | ||||
| #new Qt | ||||
| sudo add-apt-repository --yes ppa:beineri/opt-qt571-trusty | ||||
|  | ||||
| #new CMake | ||||
| sudo add-apt-repository --yes ppa:george-edison55/cmake-3.x | ||||
|  | ||||
| sudo apt-get update -qq | ||||
|  | ||||
| sudo apt-get install -qq $SUPPORT | ||||
| sudo apt-get install -qq $PACKAGE | ||||
| sudo apt-get install -qq cmake ninja-build libboost1.54-all-dev zlib1g-dev | ||||
| sudo apt-get install -qq libsdl2-dev libsdl2-image-dev libsdl2-mixer-dev libsdl2-ttf-dev | ||||
| sudo apt-get install -qq libavformat-dev libswscale-dev | ||||
| sudo apt-get install -qq qt57declarative | ||||
| sudo apt-get install -qq libluajit-5.1-dev | ||||
|  | ||||
| #setup compiler | ||||
| source /opt/qt57/bin/qt57-env.sh | ||||
| export CC=${REAL_CC} CXX=${REAL_CXX} | ||||
| # Dependencies | ||||
| sudo apt-get install libsdl2-dev libsdl2-image-dev libsdl2-mixer-dev libsdl2-ttf-dev | ||||
| sudo apt-get install qtbase5-dev | ||||
| sudo apt-get install ninja-build zlib1g-dev libavformat-dev libswscale-dev libtbb-dev libluajit-5.1-dev | ||||
| @@ -1,7 +1,7 @@ | ||||
| #!/bin/sh | ||||
|  | ||||
| brew update | ||||
| brew install smpeg2 libpng freetype sdl2 sdl2_ttf sdl2_image qt5 ffmpeg ninja luajit | ||||
| brew install sdl2_mixer | ||||
| brew install smpeg2 libpng freetype qt5 ffmpeg ninja boost tbb luajit | ||||
| brew install sdl2 sdl2_ttf sdl2_image sdl2_mixer | ||||
|  | ||||
| export CMAKE_PREFIX_PATH="/usr/local/opt/qt5:$CMAKE_PREFIX_PATH" | ||||
| echo CMAKE_PREFIX_PATH="/usr/local/opt/qt5:$CMAKE_PREFIX_PATH" >> $GITHUB_ENV | ||||
|   | ||||
| @@ -1,15 +0,0 @@ | ||||
| #!/bin/sh | ||||
| if [ -z "$encrypted_1d30f79f8582_key" ]; | ||||
| then | ||||
| 	# Due to security measures travis not expose encryption keys for PR from forks | ||||
| 	exit 0 | ||||
| fi | ||||
| cpack | ||||
|  | ||||
| touch /tmp/deploy_rsa | ||||
| chmod 600 /tmp/deploy_rsa | ||||
| openssl aes-256-cbc -K $encrypted_1d30f79f8582_key -iv $encrypted_1d30f79f8582_iv -in $TRAVIS_BUILD_DIR/CI/deploy_rsa.enc -out /tmp/deploy_rsa -d | ||||
| eval "$(ssh-agent -s)" | ||||
| ssh-add /tmp/deploy_rsa | ||||
|  | ||||
| sftp -r -o StrictHostKeyChecking=no travis@beholder.vcmi.eu <<< "put $VCMI_PACKAGE_FILE_NAME.dmg /incoming/$VCMI_PACKAGE_FILE_NAME.dmg" | ||||
| @@ -4,7 +4,7 @@ | ||||
| sudo apt-get install -qq nsis ninja-build | ||||
|  | ||||
| # MXE repository was too slow for Travis far too often | ||||
| wget https://github.com/vcmi/vcmi-deps-mxe/releases/download/2019-06-28/mxe-i686-w64-mingw32.shared-2019-06-28.tar | ||||
| wget -nv https://github.com/vcmi/vcmi-deps-mxe/releases/download/2019-06-28/mxe-i686-w64-mingw32.shared-2019-06-28.tar | ||||
| tar -xvf mxe-i686-w64-mingw32.shared-2019-06-28.tar | ||||
| sudo dpkg -i mxe-*.deb | ||||
| sudo apt-get install -f --yes | ||||
| @@ -36,5 +36,7 @@ mxe-i686-w64-mingw32.static-luajit | ||||
| fi # Disable | ||||
|  | ||||
| # alias for CMake | ||||
| sudo mv /usr/bin/cmake /usr/bin/cmake.orig | ||||
| sudo ln -s /usr/lib/mxe/usr/bin/$MXE_TARGET-cmake /usr/bin/cmake | ||||
|  | ||||
| CMAKE_LOCATION=$(which cmake) | ||||
| sudo mv $CMAKE_LOCATION $CMAKE_LOCATION.orig | ||||
| sudo ln -s /usr/lib/mxe/usr/bin/$MXE_TARGET-cmake $CMAKE_LOCATION | ||||
|   | ||||
| @@ -1,16 +0,0 @@ | ||||
| #!/bin/sh | ||||
| if [ -z "$encrypted_1d30f79f8582_key" ]; | ||||
| then | ||||
| 	# Due to security measures travis not expose encryption keys for PR from forks | ||||
| 	exit 0 | ||||
| fi | ||||
|  | ||||
| cpack | ||||
|  | ||||
| touch /tmp/deploy_rsa | ||||
| chmod 600 /tmp/deploy_rsa | ||||
| openssl aes-256-cbc -K $encrypted_1d30f79f8582_key -iv $encrypted_1d30f79f8582_iv -in $TRAVIS_BUILD_DIR/CI/deploy_rsa.enc -out /tmp/deploy_rsa -d | ||||
| eval "$(ssh-agent -s)" | ||||
| ssh-add /tmp/deploy_rsa | ||||
|  | ||||
| sftp -r -o StrictHostKeyChecking=no travis@beholder.vcmi.eu <<< "put $VCMI_PACKAGE_FILE_NAME.exe /incoming/$VCMI_PACKAGE_FILE_NAME.exe" | ||||
							
								
								
									
										15
									
								
								CI/upload_package.sh
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								CI/upload_package.sh
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,15 @@ | ||||
| #!/bin/sh | ||||
| if [ -z "$DEPLOY_RSA" ]; | ||||
| then | ||||
| 	# Due to security measures travis not expose encryption keys for PR from forks | ||||
| 	echo "Build generation is skipped for forks" | ||||
| 	exit 0 | ||||
| fi | ||||
|  | ||||
| echo "$DEPLOY_RSA" > /tmp/deploy_rsa | ||||
| chmod 600 /tmp/deploy_rsa | ||||
|  | ||||
| eval "$(ssh-agent -s)" | ||||
| ssh-add /tmp/deploy_rsa | ||||
|  | ||||
| sftp -r -o StrictHostKeyChecking=no travis@beholder.vcmi.eu <<< "put $VCMI_PACKAGE_FILE_NAME.$PACKAGE_EXTENSION /incoming/$VCMI_PACKAGE_FILE_NAME.$PACKAGE_EXTENSION" | ||||
| @@ -64,7 +64,7 @@ set(PACKAGE_FILE_NAME "" CACHE STRING "Override for CPack package filename") | ||||
| #        Miscellaneous options             # | ||||
| ############################################ | ||||
|  | ||||
| set(CMAKE_MODULE_PATH ${CMAKE_HOME_DIRECTORY}/cmake_modules) | ||||
| set(CMAKE_MODULE_PATH ${CMAKE_HOME_DIRECTORY}/cmake_modules ${PROJECT_SOURCE_DIR}/CI) | ||||
| # Contains custom functions and macros, but don't altering any options | ||||
| include(VCMIUtils) | ||||
| vcmi_print_important_variables() | ||||
| @@ -88,7 +88,7 @@ define_property( | ||||
| # Generate Version.cpp | ||||
| if(ENABLE_GITVERSION) | ||||
| 	add_custom_target(update_version ALL | ||||
| 		COMMAND ${CMAKE_COMMAND} -DGIT_SHA1="${GIT_SHA1}" -P "${CMAKE_MODULE_PATH}/Version.cmake" | ||||
| 		COMMAND ${CMAKE_COMMAND} -DGIT_SHA1="${GIT_SHA1}" -P "${PROJECT_SOURCE_DIR}/cmake_modules/Version.cmake" | ||||
| 	) | ||||
| else() | ||||
| 	add_definitions(-DVCMI_NO_EXTRA_VERSION) | ||||
|   | ||||
							
								
								
									
										2
									
								
								Global.h
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								Global.h
									
									
									
									
									
								
							| @@ -191,7 +191,7 @@ static_assert(sizeof(bool) == 1, "Bool needs to be 1 byte in size."); | ||||
| #include <boost/format.hpp> | ||||
| #include <boost/functional/hash.hpp> | ||||
| #include <boost/lexical_cast.hpp> | ||||
| #ifndef VCMI_ANDROID | ||||
| #ifdef VCMI_WINDOWS | ||||
| #include <boost/locale/generator.hpp> | ||||
| #endif | ||||
| #include <boost/logic/tribool.hpp> | ||||
|   | ||||
| @@ -656,19 +656,20 @@ CFocusable::~CFocusable() | ||||
|  | ||||
| 	focusables -= this; | ||||
| } | ||||
|  | ||||
| void CFocusable::giveFocus() | ||||
| { | ||||
| 	focus = true; | ||||
| 	focusGot(); | ||||
| 	redraw(); | ||||
|  | ||||
| 	if(inputWithFocus) | ||||
| 	{ | ||||
| 		inputWithFocus->focus = false; | ||||
| 		inputWithFocus->focusLost(); | ||||
| 		inputWithFocus->redraw(); | ||||
| 	} | ||||
|  | ||||
| 	focus = true; | ||||
| 	inputWithFocus = this; | ||||
| 	focusGot(); | ||||
| 	redraw(); | ||||
| } | ||||
|  | ||||
| void CFocusable::moveFocus() | ||||
|   | ||||
| @@ -1158,7 +1158,7 @@ CGameState::CrossoverHeroesList CGameState::getCrossoverHeroesFromPreviousScenar | ||||
|  | ||||
| 	auto campaignState = scenarioOps->campState; | ||||
| 	auto bonus = campaignState->getBonusForCurrentMap(); | ||||
| 	if (bonus && bonus->type == CScenarioTravel::STravelBonus::HEROES_FROM_PREVIOUS_SCENARIO) | ||||
| 	if(bonus && bonus->type == CScenarioTravel::STravelBonus::HEROES_FROM_PREVIOUS_SCENARIO) | ||||
| 	{ | ||||
| 		std::vector<CGHeroInstance *> heroes; | ||||
| 		for(auto & node : campaignState->camp->scenarios[bonus->info2].crossoverHeroes) | ||||
| @@ -1172,12 +1172,8 @@ CGameState::CrossoverHeroesList CGameState::getCrossoverHeroesFromPreviousScenar | ||||
| 	{ | ||||
| 		if(!campaignState->mapsConquered.empty()) | ||||
| 		{ | ||||
| 			std::vector<CGHeroInstance *> heroes; | ||||
| 			for(auto & node : campaignState->camp->scenarios[campaignState->mapsConquered.back()].crossoverHeroes) | ||||
| 			{ | ||||
| 				auto h = CCampaignState::crossoverDeserialize(node); | ||||
| 				heroes.push_back(h); | ||||
| 			} | ||||
| 			std::vector<CGHeroInstance *> heroes = {}; | ||||
|  | ||||
| 			crossoverHeroes.heroesFromAnyPreviousScenarios = crossoverHeroes.heroesFromPreviousScenario = heroes; | ||||
| 			crossoverHeroes.heroesFromPreviousScenario = heroes; | ||||
|  | ||||
| @@ -1190,7 +1186,7 @@ CGameState::CrossoverHeroesList CGameState::getCrossoverHeroesFromPreviousScenar | ||||
| 				// remove heroes which didn't reached the end of the scenario, but were available at the start | ||||
| 				for(auto hero : lostCrossoverHeroes) | ||||
| 				{ | ||||
| //					auto hero = CCampaignState::crossoverDeserialize(node); | ||||
| 					//					auto hero = CCampaignState::crossoverDeserialize(node); | ||||
| 					vstd::erase_if(crossoverHeroes.heroesFromAnyPreviousScenarios, [hero](CGHeroInstance * h) | ||||
| 					{ | ||||
| 						return hero->subID == h->subID; | ||||
| @@ -1202,11 +1198,12 @@ CGameState::CrossoverHeroesList CGameState::getCrossoverHeroesFromPreviousScenar | ||||
| 				{ | ||||
| 					auto hero = CCampaignState::crossoverDeserialize(node); | ||||
| 					// add new heroes and replace old heroes with newer ones | ||||
| 					auto it = range::find_if(crossoverHeroes.heroesFromAnyPreviousScenarios,  [hero](CGHeroInstance * h) | ||||
| 					auto it = range::find_if(crossoverHeroes.heroesFromAnyPreviousScenarios, [hero](CGHeroInstance * h) | ||||
| 					{ | ||||
| 						return hero->subID == h->subID; | ||||
| 					}); | ||||
| 					if (it != crossoverHeroes.heroesFromAnyPreviousScenarios.end()) | ||||
|  | ||||
| 					if(it != crossoverHeroes.heroesFromAnyPreviousScenarios.end()) | ||||
| 					{ | ||||
| 						// replace old hero with newer one | ||||
| 						crossoverHeroes.heroesFromAnyPreviousScenarios[it - crossoverHeroes.heroesFromAnyPreviousScenarios.begin()] = hero; | ||||
| @@ -1216,6 +1213,11 @@ CGameState::CrossoverHeroesList CGameState::getCrossoverHeroesFromPreviousScenar | ||||
| 						// add new hero | ||||
| 						crossoverHeroes.heroesFromAnyPreviousScenarios.push_back(hero); | ||||
| 					} | ||||
|  | ||||
| 					if(mapNr == campaignState->mapsConquered.back()) | ||||
| 					{ | ||||
| 						crossoverHeroes.heroesFromPreviousScenario.push_back(hero); | ||||
| 					} | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
|   | ||||
| @@ -719,46 +719,68 @@ bool CModHandler::checkDependencies(const std::vector <TModID> & input) const | ||||
| 	return true; | ||||
| } | ||||
|  | ||||
| std::vector <TModID> CModHandler::resolveDependencies(std::vector <TModID> modsToResolve) const | ||||
| // Returned vector affects the resource loaders call order (see CFilesystemList::load). | ||||
| // The loaders call order matters when dependent mod overrides resources in its dependencies. | ||||
| std::vector <TModID> CModHandler::validateAndSortDependencies(std::vector <TModID> modsToResolve) const | ||||
| { | ||||
| 	std::vector<TModID> brokenMods; | ||||
| 	// Topological sort algorithm. | ||||
| 	// TODO: Investigate possible ways to improve performance. | ||||
| 	boost::range::sort(modsToResolve); // Sort mods per name | ||||
| 	std::vector <TModID> sortedValidMods; // Vector keeps order of elements (LIFO)  | ||||
| 	sortedValidMods.reserve(modsToResolve.size()); // push_back calls won't cause memory reallocation | ||||
| 	std::set <TModID> resolvedModIDs; // Use a set for validation for performance reason, but set does not keep order of elements | ||||
|  | ||||
| 	auto looksValid = [&](const CModInfo & mod) -> bool | ||||
| 	// Mod is resolved if it has not dependencies or all its dependencies are already resolved | ||||
| 	auto isResolved = [&](const CModInfo & mod) -> CModInfo::EValidationStatus | ||||
| 	{ | ||||
| 		auto res = true; | ||||
| 		if(mod.dependencies.size() > resolvedModIDs.size()) | ||||
| 			return CModInfo::PENDING; | ||||
|  | ||||
| 		for(const TModID & dependency : mod.dependencies) | ||||
| 		{ | ||||
| 			if(!vstd::contains(modsToResolve, dependency)) | ||||
| 			{ | ||||
| 				logMod->error("Mod '%s' will not work: it depends on mod '%s', which is not installed.", mod.name, dependency); | ||||
| 				res = false; //continue iterations, since we should show all errors for the current mod. | ||||
| 			} | ||||
| 			if(!vstd::contains(resolvedModIDs, dependency)) | ||||
| 				return CModInfo::PENDING; | ||||
| 		} | ||||
| 		return res; | ||||
| 		return CModInfo::PASSED; | ||||
| 	}; | ||||
|  | ||||
| 	while(true) | ||||
| 	{ | ||||
| 		for(auto mod : modsToResolve) | ||||
| 		std::set <TModID> resolvedOnCurrentTreeLevel; | ||||
| 		for(auto it = modsToResolve.begin(); it != modsToResolve.end();) // One iteration - one level of mods tree | ||||
| 		{ | ||||
| 			if(!looksValid(this->allMods.at(mod))) | ||||
| 				brokenMods.push_back(mod); | ||||
| 		} | ||||
| 		if(!brokenMods.empty()) | ||||
| 		{ | ||||
| 			vstd::erase_if(modsToResolve, [&](TModID mid) | ||||
| 			if(isResolved(allMods.at(*it)) == CModInfo::PASSED) | ||||
| 			{ | ||||
| 				return brokenMods.end() != std::find(brokenMods.begin(), brokenMods.end(), mid); | ||||
| 			}); | ||||
| 			brokenMods.clear(); | ||||
| 				resolvedOnCurrentTreeLevel.insert(*it); // Not to the resolvedModIDs, so current node childs will be resolved on the next iteration | ||||
| 				sortedValidMods.push_back(*it); | ||||
| 				it = modsToResolve.erase(it); | ||||
| 				continue; | ||||
| 			} | ||||
| 			it++; | ||||
| 		} | ||||
| 		if(resolvedOnCurrentTreeLevel.size()) | ||||
| 		{ | ||||
| 			resolvedModIDs.insert(resolvedOnCurrentTreeLevel.begin(), resolvedOnCurrentTreeLevel.end()); | ||||
| 		            continue; | ||||
| 		} | ||||
| 		// If there're no valid mods on the current mods tree level, no more mod can be resolved, should be end. | ||||
| 		break; | ||||
| 	} | ||||
| 	boost::range::sort(modsToResolve); | ||||
| 	return modsToResolve; | ||||
|  | ||||
| 	// Left mods have unresolved dependencies, output all to log. | ||||
| 	for(const auto & brokenModID : modsToResolve) | ||||
| 	{ | ||||
| 		const CModInfo & brokenMod = allMods.at(brokenModID); | ||||
| 		for(const TModID & dependency : brokenMod.dependencies) | ||||
| 		{ | ||||
| 			if(!vstd::contains(resolvedModIDs, dependency)) | ||||
| 				logMod->error("Mod '%s' will not work: it depends on mod '%s', which is not installed.", brokenMod.name, dependency); | ||||
| 		} | ||||
| 	} | ||||
| 	return sortedValidMods; | ||||
| } | ||||
|  | ||||
|  | ||||
| std::vector<std::string> CModHandler::getModList(std::string path) | ||||
| { | ||||
| 	std::string modDir = boost::to_upper_copy(path + "MODS/"); | ||||
| @@ -898,7 +920,7 @@ static ui32 calculateModChecksum(const std::string modName, ISimpleResourceLoade | ||||
|  | ||||
| void CModHandler::loadModFilesystems() | ||||
| { | ||||
| 	activeMods = resolveDependencies(activeMods); | ||||
| 	activeMods = validateAndSortDependencies(activeMods); | ||||
|  | ||||
| 	coreMod.updateChecksum(calculateModChecksum("core", CResourceHandler::get("core"))); | ||||
|  | ||||
|   | ||||
| @@ -242,9 +242,15 @@ class DLL_LINKAGE CModHandler | ||||
| 	// - circular dependencies | ||||
| 	bool checkDependencies(const std::vector <TModID> & input) const; | ||||
|  | ||||
| 	// returns load order in which all dependencies are resolved, e.g. loaded after required mods | ||||
| 	// function assumes that input list is valid (checkDependencies returned true) | ||||
| 	std::vector <TModID> resolveDependencies(std::vector<TModID> input) const; | ||||
| 	/** | ||||
| 	* 1. Set apart mods with resolved dependencies from mods which have unresolved dependencies | ||||
| 	* 2. Sort resolved mods using topological algorithm | ||||
| 	* 3. Log all problem mods and their unresolved dependencies | ||||
| 	* | ||||
| 	* @param modsToResolve list of valid mod IDs (checkDependencies returned true - TODO: Clarify it.) | ||||
| 	* @return a vector of the topologically sorted resolved mods: child nodes (dependent mods) have greater index than parents | ||||
| 	*/ | ||||
| 	std::vector <TModID> validateAndSortDependencies(std::vector <TModID> modsToResolve) const; | ||||
|  | ||||
| 	std::vector<std::string> getModList(std::string path); | ||||
| 	void loadMods(std::string path, std::string parent, const JsonNode & modSettings, bool enableMods); | ||||
|   | ||||
| @@ -261,6 +261,28 @@ bool JsonNode::isCompact() const | ||||
| 	} | ||||
| } | ||||
|  | ||||
| bool JsonNode::TryBoolFromString(bool & success) const | ||||
| { | ||||
| 	success = true; | ||||
| 	if(type == JsonNode::JsonType::DATA_BOOL) | ||||
| 		return Bool(); | ||||
|  | ||||
| 	success = type == JsonNode::JsonType::DATA_STRING; | ||||
| 	if(success) | ||||
| 	{ | ||||
| 		auto boolParamStr = String(); | ||||
| 		boost::algorithm::trim(boolParamStr); | ||||
| 		boost::algorithm::to_lower(boolParamStr); | ||||
| 		success = boolParamStr == "true"; | ||||
|  | ||||
| 		if(success) | ||||
| 			return true; | ||||
| 		 | ||||
| 		success = boolParamStr == "false"; | ||||
| 	} | ||||
| 	return false; | ||||
| } | ||||
|  | ||||
| void JsonNode::clear() | ||||
| { | ||||
| 	setType(JsonType::DATA_NULL); | ||||
| @@ -632,7 +654,17 @@ std::shared_ptr<ILimiter> JsonUtils::parseLimiter(const JsonNode & limiter) | ||||
| 				{ | ||||
| 					creatureLimiter->setCreature(CreatureID(creature)); | ||||
| 				}); | ||||
| 				creatureLimiter->includeUpgrades = parameters.size() > 1 ? parameters[1].Bool() : false; | ||||
| 				auto includeUpgrades = false; | ||||
|  | ||||
| 				if(parameters.size() > 1) | ||||
| 				{ | ||||
| 					bool success = true; | ||||
| 					includeUpgrades = parameters[1].TryBoolFromString(success); | ||||
|  | ||||
| 					if(!success) | ||||
| 						logMod->error("Second parameter of '%s' limiter should be Bool", limiterType); | ||||
| 				} | ||||
| 				creatureLimiter->includeUpgrades = includeUpgrades; | ||||
| 				return creatureLimiter; | ||||
| 			} | ||||
| 			else if(limiterType == "HAS_ANOTHER_BONUS_LIMITER") | ||||
|   | ||||
| @@ -87,6 +87,9 @@ public: | ||||
| 	/// removes all data from node and sets type to null | ||||
| 	void clear(); | ||||
|  | ||||
| 	/// returns bool or bool equivalent of string value if 'success' is true, or false otherwise | ||||
| 	bool TryBoolFromString(bool & success) const; | ||||
|  | ||||
| 	/// non-const accessors, node will change type on type mismatch | ||||
| 	bool & Bool(); | ||||
| 	double & Float(); | ||||
|   | ||||
| @@ -654,7 +654,7 @@ namespace VCMIDirs | ||||
| 		static bool initialized = false; | ||||
| 		if (!initialized) | ||||
| 		{ | ||||
| 			#ifndef VCMI_ANDROID | ||||
| 			#ifdef VCMI_WINDOWS | ||||
| 			std::locale::global(boost::locale::generator().generate("en_US.UTF-8")); | ||||
| 			#endif | ||||
| 			boost::filesystem::path::imbue(std::locale()); | ||||
|   | ||||
| @@ -148,30 +148,43 @@ std::vector<JsonNode> CObjectClassesHandler::loadLegacyData(size_t dataSize) | ||||
|  | ||||
| /// selects preferred ID (or subID) for new object | ||||
| template<typename Map> | ||||
| si32 selectNextID(const JsonNode & fixedID, const Map & map, si32 defaultID) | ||||
| si32 selectNextID(const JsonNode & fixedID, const Map & map, si32 fixedObjectsBound) | ||||
| { | ||||
| 	if (!fixedID.isNull() && (si32)fixedID.Float() < defaultID) | ||||
| 		return static_cast<si32>(fixedID.Float()); // H3M object with fixed ID | ||||
| 	assert(fixedObjectsBound > 0); | ||||
| 	if(fixedID.isNull()) | ||||
| 	{ | ||||
| 		auto lastID = map.empty() ? 0 : map.rbegin()->first; | ||||
| 		return lastID < fixedObjectsBound ? fixedObjectsBound : lastID + 1; | ||||
| 	} | ||||
| 	auto id = static_cast<si32>(fixedID.Float()); | ||||
| 	if(id >= fixedObjectsBound) | ||||
| 		logGlobal->error("Getting next ID overflowed: %d >= %d", id, fixedObjectsBound); | ||||
|  | ||||
| 	if (map.empty()) | ||||
| 		return defaultID; // no objects loaded, keep gap for H3M objects | ||||
| 	if (map.rbegin()->first >= defaultID) | ||||
| 		return map.rbegin()->first + 1; // some modded objects loaded, return next available | ||||
|  | ||||
| 	return defaultID; // some H3M objects loaded, first modded found | ||||
| 	return id; | ||||
| } | ||||
|  | ||||
| void CObjectClassesHandler::loadObjectEntry(const std::string & identifier, const JsonNode & entry, ObjectContainter * obj) | ||||
| void CObjectClassesHandler::loadObjectEntry(const std::string & identifier, const JsonNode & entry, ObjectContainter * obj, bool isSubobject) | ||||
| { | ||||
| 	if (!handlerConstructors.count(obj->handlerName)) | ||||
| 	static const si32 fixedObjectsBound = 1000; // legacy value for backward compatibilitty | ||||
| 	static const si32 fixedSubobjectsBound = 10000000; // large enough arbitrary value to avoid ID-collisions | ||||
| 	si32 usedBound = fixedObjectsBound; | ||||
|  | ||||
| 	if(!handlerConstructors.count(obj->handlerName)) | ||||
| 	{ | ||||
| 		logGlobal->error("Handler with name %s was not found!", obj->handlerName); | ||||
| 		return; | ||||
| 	} | ||||
| 	const auto convertedId = VLC->modh->normalizeIdentifier(entry.meta, "core", identifier); | ||||
| 	const auto & entryIndex = entry["index"]; | ||||
| 	bool useSelectNextID = !isSubobject || entryIndex.isNull(); | ||||
|  | ||||
| 	std::string convertedId = VLC->modh->normalizeIdentifier(entry.meta, "core", identifier); | ||||
|  | ||||
| 	si32 id = selectNextID(entry["index"], obj->subObjects, 1000); | ||||
| 	if(useSelectNextID && isSubobject) | ||||
| 	{ | ||||
| 		usedBound = fixedSubobjectsBound; | ||||
| 		logGlobal->error("Subobject index is Null. convertedId = '%s' obj->id = %d", convertedId, obj->id); | ||||
| 	} | ||||
| 	si32 id = useSelectNextID ? selectNextID(entryIndex, obj->subObjects, usedBound)  | ||||
| 		: (si32)entryIndex.Float(); | ||||
|  | ||||
| 	auto handler = handlerConstructors.at(obj->handlerName)(); | ||||
| 	handler->setType(obj->id, id); | ||||
| @@ -196,46 +209,54 @@ void CObjectClassesHandler::loadObjectEntry(const std::string & identifier, cons | ||||
|  | ||||
| 	//some mods redefine content handlers in the decoration.json in such way: | ||||
| 	//"core:sign" : { "types" : { "forgeSign" : { ... | ||||
| 	static const std::vector<std::string> knownProblemObjects | ||||
| 	static const std::vector<std::string> breakersRMG | ||||
| 	{ | ||||
| 		"hota.hota decorations:hotaPandoraBox" | ||||
| 		, "hota.hota decorations:hotaSubterreanGate" | ||||
| 	}; | ||||
| 	bool overrideForce = !obj->subObjects.count(id) || | ||||
| 	std::any_of(knownProblemObjects.begin(), knownProblemObjects.end(), [obj, id](const std::string & str) | ||||
| 	{ | ||||
| 		return str.compare(obj->subObjects[id]->subTypeName) == 0; | ||||
| 	}); | ||||
| 	const bool isExistingKey = obj->subObjects.count(id) > 0; | ||||
| 	const bool isBreaker = std::any_of(breakersRMG.begin(), breakersRMG.end(), | ||||
| 		[&handler](const std::string & str) | ||||
| 		{ | ||||
| 			return str.compare(handler->subTypeName) == 0; | ||||
| 		}); | ||||
| 	const bool passedHandler = !isExistingKey && !isBreaker; | ||||
|  | ||||
| 	if(overrideForce) // DO NOT override mod handlers by default | ||||
| 	if(passedHandler) | ||||
| 	{ | ||||
| 		obj->subObjects[id] = handler; | ||||
| 		obj->subIds[convertedId] = id; | ||||
| 	} | ||||
| 	else if(isExistingKey) //It's supposed that fan mods handlers are not overridden by default handlers | ||||
| 	{ | ||||
| 		logGlobal->trace("Handler '%s' has not been overridden with handler '%s' in object %s(%d)::%s(%d)", | ||||
| 			obj->subObjects[id]->subTypeName, obj->handlerName, obj->identifier, obj->id, convertedId, id); | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| 		logGlobal->warn("Don't override handler %s in object %s(%d)::%s(%d) subTypeName : %s" | ||||
| 			, obj->handlerName, obj->identifier, obj->id, convertedId, id, obj->subObjects[id]->subTypeName); | ||||
| 		logGlobal->warn("Handler '%s' for object %s(%d)::%s(%d) has not been activated as RMG breaker", | ||||
| 			obj->handlerName, obj->identifier, obj->id, convertedId, id); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| CObjectClassesHandler::ObjectContainter * CObjectClassesHandler::loadFromJson(const std::string & scope, const JsonNode & json, const std::string & name) | ||||
| { | ||||
| 	auto obj = new ObjectContainter(); | ||||
| 	static const si32 fixedObjectsBound = 256; //Legacy value for backward compatibility | ||||
|  | ||||
| 	obj->identifier = name; | ||||
| 	obj->name = json["name"].String(); | ||||
| 	obj->handlerName = json["handler"].String(); | ||||
| 	obj->base = json["base"]; | ||||
| 	obj->id = selectNextID(json["index"], objects, 256); | ||||
| 	obj->id = selectNextID(json["index"], objects, fixedObjectsBound); | ||||
|  | ||||
| 	if(json["defaultAiValue"].isNull()) | ||||
| 		obj->groupDefaultAiValue = boost::none; | ||||
| 	else | ||||
| 		obj->groupDefaultAiValue = static_cast<boost::optional<si32>>(json["defaultAiValue"].Integer()); | ||||
|  | ||||
| 	for (auto entry : json["types"].Struct()) | ||||
| 	{ | ||||
| 		loadObjectEntry(entry.first, entry.second, obj); | ||||
| 	} | ||||
|  | ||||
| 	return obj; | ||||
| } | ||||
| @@ -257,6 +278,8 @@ void CObjectClassesHandler::loadObject(std::string scope, std::string name, cons | ||||
|  | ||||
| void CObjectClassesHandler::loadSubObject(const std::string & identifier, JsonNode config, si32 ID, boost::optional<si32> subID) | ||||
| { | ||||
| 	static const bool isSubObject = true; | ||||
|  | ||||
| 	config.setType(JsonNode::JsonType::DATA_STRUCT); // ensure that input is not NULL | ||||
| 	assert(objects.count(ID)); | ||||
| 	if (subID) | ||||
| @@ -265,10 +288,8 @@ void CObjectClassesHandler::loadSubObject(const std::string & identifier, JsonNo | ||||
| 		assert(config["index"].isNull()); | ||||
| 		config["index"].Float() = subID.get(); | ||||
| 	} | ||||
|  | ||||
| 	inheritNodeWithMeta(config, objects.at(ID)->base); | ||||
|  | ||||
| 	loadObjectEntry(identifier, config, objects[ID]); | ||||
| 	loadObjectEntry(identifier, config, objects[ID], isSubObject); | ||||
| } | ||||
|  | ||||
| void CObjectClassesHandler::removeSubObject(si32 ID, si32 subID) | ||||
|   | ||||
| @@ -283,8 +283,9 @@ class DLL_LINKAGE CObjectClassesHandler : public IHandlerBase | ||||
| 	/// format: customNames[primaryID][secondaryID] -> name | ||||
| 	std::map<si32, std::vector<std::string>> customNames; | ||||
|  | ||||
| 	void loadObjectEntry(const std::string & identifier, const JsonNode & entry, ObjectContainter * obj); | ||||
| 	void loadObjectEntry(const std::string & identifier, const JsonNode & entry, ObjectContainter * obj, bool isSubobject = false); | ||||
| 	ObjectContainter * loadFromJson(const std::string & scope, const JsonNode & json, const std::string & name); | ||||
|  | ||||
| public: | ||||
| 	CObjectClassesHandler(); | ||||
| 	~CObjectClassesHandler(); | ||||
|   | ||||
| @@ -144,21 +144,24 @@ CDwellingInstanceConstructor::CDwellingInstanceConstructor() | ||||
| void CDwellingInstanceConstructor::initTypeData(const JsonNode & input) | ||||
| { | ||||
| 	const JsonVector & levels = input["creatures"].Vector(); | ||||
| 	availableCreatures.resize(levels.size()); | ||||
| 	for (size_t i=0; i<levels.size(); i++) | ||||
| 	const auto totalLevels = levels.size(); | ||||
|  | ||||
| 	availableCreatures.resize(totalLevels); | ||||
| 	for(auto currentLevel = 0; currentLevel < totalLevels; currentLevel++) | ||||
| 	{ | ||||
| 		const JsonVector & creatures = levels[i].Vector(); | ||||
| 		availableCreatures[i].resize(creatures.size()); | ||||
| 		for (size_t j=0; j<creatures.size(); j++) | ||||
| 		const JsonVector & creaturesOnLevel = levels[currentLevel].Vector(); | ||||
| 		const auto creaturesNumber = creaturesOnLevel.size(); | ||||
| 		availableCreatures[currentLevel].resize(creaturesNumber); | ||||
|  | ||||
| 		for(auto currentCreature = 0; currentCreature < creaturesNumber; currentCreature++) | ||||
| 		{ | ||||
| 			VLC->modh->identifiers.requestIdentifier("creature", creatures[j], [=] (si32 index) | ||||
| 			VLC->modh->identifiers.requestIdentifier("creature", creaturesOnLevel[currentCreature], [=] (si32 index) | ||||
| 			{ | ||||
| 				availableCreatures[i][j] = VLC->creh->objects[index]; | ||||
| 				availableCreatures[currentLevel][currentCreature] = VLC->creh->objects[index]; | ||||
| 			}); | ||||
| 		} | ||||
| 		assert(!availableCreatures[i].empty()); | ||||
| 		assert(!availableCreatures[currentLevel].empty()); | ||||
| 	} | ||||
|  | ||||
| 	guards = input["guards"]; | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -30,7 +30,7 @@ SHeroName::SHeroName() : heroId(-1) | ||||
|  | ||||
| PlayerInfo::PlayerInfo(): canHumanPlay(false), canComputerPlay(false), | ||||
| 	aiTactic(EAiTactic::RANDOM), isFactionRandom(false), hasRandomHero(false), mainCustomHeroPortrait(-1), mainCustomHeroId(-1), hasMainTown(false), | ||||
| 	generateHeroAtMainTown(false), team(TeamID::NO_TEAM), /* following are unused */ generateHero(false), p7(0), powerPlaceholders(-1) | ||||
| 	generateHeroAtMainTown(false), posOfMainTown(-1), team(TeamID::NO_TEAM), /* following are unused */ generateHero(false), p7(0), powerPlaceholders(-1) | ||||
| { | ||||
| 	allowedFactions = VLC->townh->getAllowedFactions(); | ||||
| } | ||||
|   | ||||
| @@ -1,4 +1,4 @@ | ||||
|     GNU GENERAL PUBLIC LICENSE | ||||
|     GNU GENERAL PUBLIC LICENSE | ||||
| 		       Version 2, June 1991 | ||||
|  | ||||
|  Copyright (C) 1989, 1991 Free Software Foundation, Inc., | ||||
|   | ||||
| @@ -11,10 +11,16 @@ if(APPLE) | ||||
| 		") | ||||
| 	endif() | ||||
|  | ||||
| 	# Manually fix VCMI library links in AI libraries with install_name_tool | ||||
| 	install(CODE " | ||||
| 		set(BU_CHMOD_BUNDLE_ITEMS ON) | ||||
| 		include(BundleUtilities) | ||||
| 		fixup_bundle(\"\${CMAKE_INSTALL_PREFIX}/${APP_BUNDLE_DIR}\" \"\" \"\") | ||||
| 		execute_process(COMMAND ${CMAKE_INSTALL_NAME_TOOL} -change \"libvcmi.dylib\" \"@executable_path/../Frameworks/libvcmi.dylib\" \"\${CMAKE_INSTALL_PREFIX}/${APP_BUNDLE_BINARY_DIR}/AI/libBattleAI.dylib\") | ||||
| 		execute_process(COMMAND ${CMAKE_INSTALL_NAME_TOOL} -change \"libvcmi.dylib\" \"@executable_path/../Frameworks/libvcmi.dylib\" \"\${CMAKE_INSTALL_PREFIX}/${APP_BUNDLE_BINARY_DIR}/AI/libEmptyAI.dylib\") | ||||
| 		execute_process(COMMAND ${CMAKE_INSTALL_NAME_TOOL} -change \"libvcmi.dylib\" \"@executable_path/../Frameworks/libvcmi.dylib\" \"\${CMAKE_INSTALL_PREFIX}/${APP_BUNDLE_BINARY_DIR}/AI/libStupidAI.dylib\") | ||||
| 		execute_process(COMMAND ${CMAKE_INSTALL_NAME_TOOL} -change \"libvcmi.dylib\" \"@executable_path/../Frameworks/libvcmi.dylib\" \"\${CMAKE_INSTALL_PREFIX}/${APP_BUNDLE_BINARY_DIR}/AI/libVCAI.dylib\") | ||||
| 		execute_process(COMMAND rm \"\${CMAKE_INSTALL_PREFIX}/${APP_BUNDLE_BINARY_DIR}/libvcmi.dylib\") | ||||
| 	" COMPONENT Runtime) | ||||
| endif(APPLE) | ||||
|  | ||||
| @@ -22,7 +28,7 @@ endif(APPLE) | ||||
| if(WIN32) | ||||
| 	if(ENABLE_LAUNCHER) | ||||
| 		# Temporary ugly fix for Qt deployment since windeployqt broken in Vcpkg | ||||
| 		 | ||||
|  | ||||
| 		#there are some weird issues with variables used in path not evaluated properly when trying to remove code duplication from below lines | ||||
| 		if(EXISTS ${CMAKE_BINARY_DIR}/../../vcpkg) #current path to vcpkg main folder on appveyor CI | ||||
| 			if(CMAKE_SIZEOF_VOID_P EQUAL 8) #64 bit build | ||||
|   | ||||
| @@ -1306,11 +1306,11 @@ void CGameHandler::handleClientDisconnection(std::shared_ptr<CConnection> c) | ||||
| { | ||||
| 	for(auto playerConns : connections) | ||||
| 	{ | ||||
| 		for(auto conn : playerConns.second) | ||||
| 		for(auto i = playerConns.second.begin(); i != playerConns.second.end(); ) | ||||
| 		{ | ||||
| 			if(lobby->state != EServerState::SHUTDOWN && conn == c) | ||||
| 			if(lobby->state != EServerState::SHUTDOWN && *i == c) | ||||
| 			{ | ||||
| 				vstd::erase_if_present(playerConns.second, conn); | ||||
| 				i = playerConns.second.erase(i); | ||||
| 				if(playerConns.second.size()) | ||||
| 					continue; | ||||
| 				PlayerCheated pc; | ||||
| @@ -1319,6 +1319,8 @@ void CGameHandler::handleClientDisconnection(std::shared_ptr<CConnection> c) | ||||
| 				sendAndApply(&pc); | ||||
| 				checkVictoryLossConditionsForPlayer(playerConns.first); | ||||
| 			} | ||||
| 			else | ||||
| 				++i; | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| @@ -5426,7 +5428,8 @@ void CGameHandler::checkVictoryLossConditionsForAll() | ||||
| void CGameHandler::checkVictoryLossConditionsForPlayer(PlayerColor player) | ||||
| { | ||||
| 	const PlayerState * p = getPlayerState(player); | ||||
| 	if (p->status != EPlayerStatus::INGAME) return; | ||||
|  | ||||
| 	if(!p || p->status != EPlayerStatus::INGAME) return; | ||||
|  | ||||
| 	auto victoryLossCheckResult = gs->checkForVictoryAndLoss(player); | ||||
|  | ||||
|   | ||||
| @@ -90,11 +90,7 @@ set(test_SRCS | ||||
|  		spells/targetConditions/ReceptiveFeatureConditionTest.cpp | ||||
|  		spells/targetConditions/SpellEffectConditionTest.cpp | ||||
|  		spells/targetConditions/TargetConditionItemFixture.cpp | ||||
|  | ||||
| 		vcai/mock_ResourceManager.cpp | ||||
| 		vcai/mock_VCAI.cpp | ||||
| 		vcai/ResurceManagerTest.cpp | ||||
|  | ||||
| 		 | ||||
| 		mock/BattleFake.cpp | ||||
|  		mock/mock_IGameCallback.cpp | ||||
|  		mock/mock_MapService.cpp | ||||
| @@ -147,16 +143,12 @@ set(mock_HEADERS | ||||
| 		mock/mock_UnitInfo.h | ||||
| 		mock/mock_vstd_RNG.h | ||||
| 		mock/mock_CPSICallback.h | ||||
|  | ||||
| 		vcai/mock_ResourceManager.h | ||||
| 		vcai/mock_VCAI.h | ||||
| 		vcai/mock_VCAI_CGoal.h | ||||
| ) | ||||
|  | ||||
| add_subdirectory_with_folder("3rdparty" googletest EXCLUDE_FROM_ALL) | ||||
|  | ||||
| add_executable(vcmitest ${test_SRCS} ${test_HEADERS} ${mock_HEADERS}) | ||||
| target_link_libraries(vcmitest PRIVATE gtest gmock vcmi ${SYSTEM_LIBS} VCAI) | ||||
| target_link_libraries(vcmitest PRIVATE gtest gmock vcmi ${SYSTEM_LIBS}) | ||||
|  | ||||
| target_include_directories(vcmitest | ||||
| 		PUBLIC	${CMAKE_CURRENT_SOURCE_DIR} | ||||
|   | ||||
| @@ -42,6 +42,12 @@ TEST(MapFormat, Random) | ||||
| 	SCOPED_TRACE("MapFormat_Random start"); | ||||
|  | ||||
| 	CMapGenOptions opt; | ||||
| 	CRmgTemplate tmpl; | ||||
|  | ||||
| 	const_cast<CRmgTemplate::CPlayerCountRange &>(tmpl.getCpuPlayers()).addRange(1, 4); | ||||
| 	const_cast<CRmgTemplate::Zones &>(tmpl.getZones())[0] = std::make_shared<rmg::ZoneOptions>(); | ||||
|  | ||||
| 	opt.setMapTemplate(&tmpl); | ||||
|  | ||||
| 	opt.setHeight(CMapHeader::MAP_SIZE_MIDDLE); | ||||
| 	opt.setWidth(CMapHeader::MAP_SIZE_MIDDLE); | ||||
| @@ -84,7 +90,7 @@ static JsonNode getFromArchive(CZipLoader & archive, const std::string & archive | ||||
| 	ResourceID resource(archiveFilename, EResType::TEXT); | ||||
|  | ||||
| 	if(!archive.existsResource(resource)) | ||||
| 		throw std::runtime_error(archiveFilename+" not found"); | ||||
| 		throw std::runtime_error(archiveFilename + " not found"); | ||||
|  | ||||
| 	auto data = archive.load(resource)->readAll(); | ||||
|  | ||||
| @@ -144,14 +150,14 @@ TEST(MapFormat, Objects) | ||||
| { | ||||
| 	static const std::string MAP_DATA_PATH = "test/ObjectPropertyTest/"; | ||||
|  | ||||
| 	const JsonNode initialHeader(ResourceID(MAP_DATA_PATH+CMapFormatJson::HEADER_FILE_NAME)); | ||||
| 	const JsonNode expectedHeader(ResourceID(MAP_DATA_PATH+CMapFormatJson::HEADER_FILE_NAME));//same as initial for now | ||||
| 	const JsonNode initialHeader(ResourceID(MAP_DATA_PATH + CMapFormatJson::HEADER_FILE_NAME)); | ||||
| 	const JsonNode expectedHeader(ResourceID(MAP_DATA_PATH + CMapFormatJson::HEADER_FILE_NAME));//same as initial for now | ||||
|  | ||||
| 	const JsonNode initialObjects(ResourceID(MAP_DATA_PATH+CMapFormatJson::OBJECTS_FILE_NAME)); | ||||
| 	const JsonNode expectedObjects(ResourceID(MAP_DATA_PATH+"objects.ex.json")); | ||||
| 	const JsonNode initialObjects(ResourceID(MAP_DATA_PATH + CMapFormatJson::OBJECTS_FILE_NAME)); | ||||
| 	const JsonNode expectedObjects(ResourceID(MAP_DATA_PATH + "objects.ex.json")); | ||||
|  | ||||
| 	const JsonNode expectedSurface(ResourceID(MAP_DATA_PATH+"surface_terrain.json")); | ||||
| 	const JsonNode expectedUnderground(ResourceID(MAP_DATA_PATH+"underground_terrain.json")); | ||||
| 	const JsonNode expectedSurface(ResourceID(MAP_DATA_PATH + "surface_terrain.json")); | ||||
| 	const JsonNode expectedUnderground(ResourceID(MAP_DATA_PATH + "underground_terrain.json")); | ||||
|  | ||||
| 	std::unique_ptr<CMap> originalMap = loadOriginal(initialHeader, initialObjects, expectedSurface, expectedUnderground); | ||||
|  | ||||
| @@ -183,11 +189,11 @@ TEST(MapFormat, Terrain) | ||||
| { | ||||
| 	static const std::string MAP_DATA_PATH = "test/TerrainTest/"; | ||||
|  | ||||
| 	const JsonNode expectedHeader(ResourceID(MAP_DATA_PATH+CMapFormatJson::HEADER_FILE_NAME)); | ||||
| 	const JsonNode expectedObjects(ResourceID(MAP_DATA_PATH+CMapFormatJson::OBJECTS_FILE_NAME)); | ||||
| 	const JsonNode expectedHeader(ResourceID(MAP_DATA_PATH + CMapFormatJson::HEADER_FILE_NAME)); | ||||
| 	const JsonNode expectedObjects(ResourceID(MAP_DATA_PATH + CMapFormatJson::OBJECTS_FILE_NAME)); | ||||
|  | ||||
| 	const JsonNode expectedSurface(ResourceID(MAP_DATA_PATH+"surface_terrain.json")); | ||||
| 	const JsonNode expectedUnderground(ResourceID(MAP_DATA_PATH+"underground_terrain.json")); | ||||
| 	const JsonNode expectedSurface(ResourceID(MAP_DATA_PATH + "surface_terrain.json")); | ||||
| 	const JsonNode expectedUnderground(ResourceID(MAP_DATA_PATH + "underground_terrain.json")); | ||||
|  | ||||
| 	std::unique_ptr<CMap> originalMap = loadOriginal(expectedHeader, expectedObjects, expectedSurface, expectedUnderground); | ||||
|  | ||||
|   | ||||
| @@ -194,6 +194,7 @@ TEST_F(TargetConditionTest, StoresNormalLevelCondition) | ||||
|  | ||||
| TEST_F(TargetConditionTest, StoresReceptiveFeature) | ||||
| { | ||||
| 	redirectFactoryToStub(); | ||||
| 	auto itemStub = std::make_shared<StrictMock<ItemMock>>(); | ||||
| 	EXPECT_CALL(factoryMock, createReceptiveFeature()).WillOnce(Return(itemStub)); | ||||
| 	setupSubject(JsonNode()); | ||||
|   | ||||
		Reference in New Issue
	
	Block a user