mirror of
				https://github.com/vcmi/vcmi.git
				synced 2025-10-31 00:07:39 +02:00 
			
		
		
		
	[launcher] build for Android
also embeds icons and translations as Qt resources instead of reading from disk
This commit is contained in:
		| @@ -58,13 +58,22 @@ option(ENABLE_CCACHE "Speed up recompilation by caching previous compilations" O | ||||
| # Platform-specific options | ||||
|  | ||||
| if(ANDROID) | ||||
| 	set(ANDROID_TARGET_SDK_VERSION "33" CACHE STRING "Android target SDK version") | ||||
| 	set(ANDROIDDEPLOYQT_OPTIONS "" CACHE STRING "Additional androiddeployqt options separated by semi-colon") | ||||
| 	set(ANDROID_GRADLE_PROPERTIES "" CACHE STRING "Additional Gradle properties separated by semi-colon") | ||||
|  | ||||
| 	set(ENABLE_STATIC_LIBS ON) | ||||
| 	set(ENABLE_LAUNCHER OFF) | ||||
| 	set(ENABLE_LAUNCHER ON) | ||||
| else() | ||||
| 	option(ENABLE_STATIC_LIBS "Build library and all components such as AI statically" OFF) | ||||
| 	option(ENABLE_LAUNCHER "Enable compilation of launcher" ON) | ||||
| endif() | ||||
|  | ||||
| if(APPLE_IOS) | ||||
| 	set(BUNDLE_IDENTIFIER_PREFIX "" CACHE STRING "Bundle identifier prefix") | ||||
| 	set(APP_DISPLAY_NAME "VCMI" CACHE STRING "App name on the home screen") | ||||
| endif() | ||||
|  | ||||
| if(APPLE_IOS OR ANDROID) | ||||
| 	set(ENABLE_MONOLITHIC_INSTALL OFF) | ||||
| 	set(ENABLE_SINGLE_APP_BUILD ON) | ||||
| @@ -100,11 +109,6 @@ if (ENABLE_STATIC_LIBS AND CMAKE_CXX_COMPILER_ID STREQUAL "GNU") | ||||
| 	set(CMAKE_POSITION_INDEPENDENT_CODE ON) | ||||
| endif() | ||||
|  | ||||
| if(APPLE_IOS) | ||||
| 	set(BUNDLE_IDENTIFIER_PREFIX "" CACHE STRING "Bundle identifier prefix") | ||||
| 	set(APP_DISPLAY_NAME "VCMI" CACHE STRING "App name on the home screen") | ||||
| endif() | ||||
|  | ||||
| if(ENABLE_COLORIZED_COMPILER_OUTPUT) | ||||
| 	if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang") | ||||
| 		add_compile_options(-fcolor-diagnostics) | ||||
| @@ -147,10 +151,6 @@ set(CMAKE_MODULE_PATH ${CMAKE_HOME_DIRECTORY}/cmake_modules ${PROJECT_SOURCE_DIR | ||||
|  | ||||
| include(VCMIUtils) | ||||
| include(VersionDefinition) | ||||
| if(ANDROID) | ||||
| 	set(VCMI_VERSION "${APP_SHORT_VERSION}") | ||||
| 	configure_file("android/GeneratedVersion.java.in" "${CMAKE_SOURCE_DIR}/android/vcmi-app/src/main/java/eu/vcmi/vcmi/util/GeneratedVersion.java" @ONLY) | ||||
| endif() | ||||
|  | ||||
| vcmi_print_important_variables() | ||||
|  | ||||
| @@ -575,8 +575,12 @@ elseif(APPLE) | ||||
| 	endif() | ||||
| elseif(ANDROID) | ||||
| 	include(GNUInstallDirs) | ||||
| 	set(LIB_DIR "jniLibs/${ANDROID_ABI}") | ||||
| 	set(DATA_DIR "assets") | ||||
| 	set(LIB_DIR "libs/${ANDROID_ABI}") | ||||
|  | ||||
| 	# required by Qt | ||||
| 	set(androidPackageSourceDir "${CMAKE_SOURCE_DIR}/android") | ||||
| 	set(androidQtBuildDir "${CMAKE_BINARY_DIR}/android-build") | ||||
| 	set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${androidQtBuildDir}/${LIB_DIR}") | ||||
| else() | ||||
| 	# includes lib path which determines where to install shared libraries (either /lib or /lib64) | ||||
| 	include(GNUInstallDirs) | ||||
| @@ -621,6 +625,13 @@ else() | ||||
| 	set(SCRIPTING_LIB_DIR "${LIB_DIR}/scripting") | ||||
| endif() | ||||
|  | ||||
| # common Qt paths | ||||
| if(ENABLE_LAUNCHER OR ENABLE_EDITOR) | ||||
| 	get_target_property(qmakePath Qt${QT_VERSION_MAJOR}::qmake IMPORTED_LOCATION) | ||||
| 	get_filename_component(qtDir "${qmakePath}/../../" ABSOLUTE) | ||||
| 	set(qtBinDir "${qtDir}/bin") | ||||
| endif() | ||||
|  | ||||
| ####################################### | ||||
| #        Add subdirectories           # | ||||
| ####################################### | ||||
| @@ -682,32 +693,15 @@ endif() | ||||
| ####################################### | ||||
|  | ||||
| if(ANDROID) | ||||
| 	string(REPLACE ";" "\n" ANDROID_GRADLE_PROPERTIES_MULTILINE "${ANDROID_GRADLE_PROPERTIES}") | ||||
| 	file(WRITE "${androidPackageSourceDir}/vcmi-app/gradle.properties" "signingRoot=${CMAKE_SOURCE_DIR}/CI/android\n${ANDROID_GRADLE_PROPERTIES_MULTILINE}") | ||||
|  | ||||
| 	if(ANDROID_STL MATCHES "_shared$") | ||||
| 		set(stlLibName "${CMAKE_SHARED_LIBRARY_PREFIX}${ANDROID_STL}${CMAKE_SHARED_LIBRARY_SUFFIX}") | ||||
| 		install(FILES "${CMAKE_SYSROOT}/usr/lib/${ANDROID_SYSROOT_LIB_SUBDIR}/${stlLibName}" | ||||
| 			DESTINATION ${LIB_DIR} | ||||
| 		) | ||||
| 	endif() | ||||
|  | ||||
| 	# zip internal assets - 'config' and 'Mods' dirs, save md5 of the zip | ||||
| 	install(CODE " | ||||
| 		cmake_path(ABSOLUTE_PATH CMAKE_INSTALL_PREFIX | ||||
| 			OUTPUT_VARIABLE absolute_install_prefix | ||||
| 		) | ||||
| 		set(absolute_data_dir \"\${absolute_install_prefix}/${DATA_DIR}\") | ||||
| 		file(MAKE_DIRECTORY \"\${absolute_data_dir}\") | ||||
|  | ||||
| 		set(internal_data_zip \"\${absolute_data_dir}/internalData.zip\") | ||||
| 		execute_process(COMMAND | ||||
| 			\"${CMAKE_COMMAND}\" -E tar c \"\${internal_data_zip}\" --format=zip -- config Mods | ||||
| 			WORKING_DIRECTORY \"${CMAKE_SOURCE_DIR}\" | ||||
| 		) | ||||
|  | ||||
| 		file(MD5 \"\${internal_data_zip}\" internal_data_zip_md5) | ||||
| 		file(WRITE \"\${absolute_data_dir}/internalDataHash.txt\" | ||||
| 			\${internal_data_zip_md5} | ||||
| 		) | ||||
| 	") | ||||
| else() | ||||
| 	install(DIRECTORY config DESTINATION ${DATA_DIR}) | ||||
| 	if (ENABLE_CLIENT OR ENABLE_SERVER) | ||||
|   | ||||
| @@ -395,6 +395,9 @@ assign_source_group(${client_SRCS} ${client_HEADERS} VCMI_client.rc) | ||||
|  | ||||
| if(ANDROID) | ||||
| 	add_library(vcmiclient SHARED ${client_SRCS} ${client_HEADERS}) | ||||
| 	set_target_properties(vcmiclient PROPERTIES | ||||
| 		OUTPUT_NAME "vcmiclient_${ANDROID_ABI}" # required by Qt | ||||
| 	) | ||||
| else() | ||||
| 	add_executable(vcmiclient ${client_SRCS} ${client_HEADERS}) | ||||
| endif() | ||||
| @@ -517,11 +520,19 @@ if(APPLE_IOS) | ||||
| 	) | ||||
| 	install(TARGETS vcmiclient DESTINATION Payload COMPONENT app) # for ipa generation with cpack | ||||
| elseif(ANDROID) | ||||
| 	vcmi_install_conan_deps("\${CMAKE_INSTALL_PREFIX}/${LIB_DIR}") | ||||
| 	add_custom_command(TARGET vcmiclient POST_BUILD | ||||
| 		COMMAND ${CMAKE_COMMAND} --install "${CMAKE_BINARY_DIR}" --config "$<CONFIG>" --prefix "${CMAKE_SOURCE_DIR}/android/vcmi-app/src/main" | ||||
| 	find_program(androidDeployQt androiddeployqt | ||||
| 		PATHS "${qtBinDir}" | ||||
| 	) | ||||
| 	install(TARGETS vcmiclient DESTINATION ${LIB_DIR}) | ||||
| 	vcmi_install_conan_deps("\${CMAKE_INSTALL_PREFIX}/${LIB_DIR}") | ||||
|  | ||||
| 	add_custom_target(android_deploy ALL | ||||
| 		COMMAND ${CMAKE_COMMAND} --install "${CMAKE_BINARY_DIR}" --config "$<CONFIG>" --prefix "${androidQtBuildDir}" | ||||
| 		COMMAND "${androidDeployQt}" --input "${CMAKE_BINARY_DIR}/androiddeployqt.json" --output "${androidQtBuildDir}" --android-platform "android-${ANDROID_TARGET_SDK_VERSION}" --verbose $<$<NOT:$<CONFIG:Debug>>:--release> ${ANDROIDDEPLOYQT_OPTIONS} | ||||
| 		COMMAND_EXPAND_LISTS | ||||
| 		VERBATIM | ||||
| 		COMMENT "Create android package" | ||||
| 	) | ||||
| 	add_dependencies(android_deploy vcmiclient) | ||||
| else() | ||||
| 	install(TARGETS vcmiclient DESTINATION ${BIN_DIR}) | ||||
| endif() | ||||
|   | ||||
| @@ -7,16 +7,22 @@ | ||||
| macro(vcmi_set_output_dir name dir) | ||||
| 	# Multi-config builds for Visual Studio, Xcode | ||||
| 	foreach(OUTPUTCONFIG ${CMAKE_CONFIGURATION_TYPES}) | ||||
| 		 string(TOUPPER ${OUTPUTCONFIG} OUTPUTCONFIGUPPERCASE) | ||||
| 		 set_target_properties(${name} PROPERTIES RUNTIME_OUTPUT_DIRECTORY_${OUTPUTCONFIGUPPERCASE} ${CMAKE_BINARY_DIR}/bin/${OUTPUTCONFIG}/${dir}) | ||||
| 		 set_target_properties(${name} PROPERTIES LIBRARY_OUTPUT_DIRECTORY_${OUTPUTCONFIGUPPERCASE} ${CMAKE_BINARY_DIR}/bin/${OUTPUTCONFIG}/${dir}) | ||||
| 		 set_target_properties(${name} PROPERTIES ARCHIVE_OUTPUT_DIRECTORY_${OUTPUTCONFIGUPPERCASE} ${CMAKE_BINARY_DIR}/bin/${OUTPUTCONFIG}/${dir}) | ||||
| 		string(TOUPPER ${OUTPUTCONFIG} OUTPUTCONFIGUPPERCASE) | ||||
| 		set_target_properties(${name} PROPERTIES RUNTIME_OUTPUT_DIRECTORY_${OUTPUTCONFIGUPPERCASE} ${CMAKE_BINARY_DIR}/bin/${OUTPUTCONFIG}/${dir}) | ||||
| 		if(ANDROID) | ||||
| 			set_target_properties(${name} PROPERTIES LIBRARY_OUTPUT_DIRECTORY_${OUTPUTCONFIGUPPERCASE} "${CMAKE_LIBRARY_OUTPUT_DIRECTORY}") | ||||
| 		else() | ||||
| 			set_target_properties(${name} PROPERTIES LIBRARY_OUTPUT_DIRECTORY_${OUTPUTCONFIGUPPERCASE} ${CMAKE_BINARY_DIR}/bin/${OUTPUTCONFIG}/${dir}) | ||||
| 		endif() | ||||
| 		set_target_properties(${name} PROPERTIES ARCHIVE_OUTPUT_DIRECTORY_${OUTPUTCONFIGUPPERCASE} ${CMAKE_BINARY_DIR}/bin/${OUTPUTCONFIG}/${dir}) | ||||
| 	endforeach() | ||||
|  | ||||
| 	# Generic no-config case for Makefiles, Ninja. | ||||
| 	# This is what Qt Creator is using | ||||
| 	set_target_properties(${name} PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin/${dir}) | ||||
| 	set_target_properties(${name} PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin/${dir}) | ||||
| 	if(NOT ANDROID) | ||||
| 		set_target_properties(${name} PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin/${dir}) | ||||
| 	endif() | ||||
| 	set_target_properties(${name} PROPERTIES ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin/${dir}) | ||||
| endmacro() | ||||
|  | ||||
|   | ||||
| @@ -21,7 +21,13 @@ set(launcher_SRCS | ||||
| 		launcherdirs.cpp | ||||
| 		jsonutils.cpp | ||||
| 		updatedialog_moc.cpp | ||||
| 		prepare.cpp | ||||
| ) | ||||
| if(APPLE_IOS) | ||||
| 	list(APPEND launcher_SRCS | ||||
| 		ios/launchGame.m | ||||
| 	) | ||||
| endif() | ||||
|  | ||||
| set(launcher_HEADERS | ||||
| 		StdInc.h | ||||
| @@ -40,7 +46,8 @@ set(launcher_HEADERS | ||||
| 		jsonutils.h | ||||
| 		updatedialog_moc.h | ||||
| 		main.h | ||||
| 		helper.cpp | ||||
| 		helper.h | ||||
| 		prepare.h | ||||
| ) | ||||
|  | ||||
| set(launcher_FORMS | ||||
| @@ -53,30 +60,60 @@ set(launcher_FORMS | ||||
| 		updatedialog_moc.ui | ||||
| ) | ||||
|  | ||||
| set(launcher_TS | ||||
| 	translation/chinese.ts | ||||
| 	translation/czech.ts | ||||
| 	translation/english.ts | ||||
| 	translation/french.ts | ||||
| 	translation/german.ts | ||||
| 	translation/polish.ts | ||||
| 	translation/portuguese.ts	 | ||||
| 	translation/russian.ts | ||||
| 	translation/spanish.ts | ||||
| 	translation/ukrainian.ts | ||||
| 	translation/vietnamese.ts | ||||
| set(launcher_RESOURCES | ||||
| 	resources.qrc | ||||
| ) | ||||
|  | ||||
| if(APPLE_IOS) | ||||
| 	list(APPEND launcher_SRCS | ||||
| 		ios/main.m | ||||
| 	) | ||||
| set(translationsDir "translation") | ||||
| set(launcher_TS | ||||
| 	"${translationsDir}/chinese.ts" | ||||
| 	"${translationsDir}/czech.ts" | ||||
| 	"${translationsDir}/english.ts" | ||||
| 	"${translationsDir}/french.ts" | ||||
| 	"${translationsDir}/german.ts" | ||||
| 	"${translationsDir}/polish.ts" | ||||
| 	"${translationsDir}/portuguese.ts" | ||||
| 	"${translationsDir}/russian.ts" | ||||
| 	"${translationsDir}/spanish.ts" | ||||
| 	"${translationsDir}/ukrainian.ts" | ||||
| 	"${translationsDir}/vietnamese.ts" | ||||
| ) | ||||
| if(ENABLE_TRANSLATIONS) | ||||
| 	if(TARGET Qt5::Core) | ||||
| 		file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/${translationsDir}") | ||||
| 		set_source_files_properties(${launcher_TS} PROPERTIES OUTPUT_LOCATION "${translationsDir}") | ||||
| 		qt5_add_translation(launcher_QM ${launcher_TS}) | ||||
|  | ||||
| 		set(translationsResource "${CMAKE_CURRENT_BINARY_DIR}/translations.qrc") | ||||
| 		list(APPEND launcher_RESOURCES "${translationsResource}") | ||||
|  | ||||
| 		set(rccQmFiles "") | ||||
| 		foreach(qmFile ${launcher_QM}) | ||||
| 			string(APPEND rccQmFiles "<file>${qmFile}</file>\n") | ||||
| 		endforeach() | ||||
| 		file(WRITE "${translationsResource}" | ||||
| "<!DOCTYPE RCC> | ||||
| <RCC version=\"1.0\"> | ||||
| <qresource prefix=\"/\"> | ||||
| ${rccQmFiles} | ||||
| </qresource> | ||||
| </RCC>" | ||||
| 		) | ||||
| 	endif() | ||||
| endif() | ||||
|  | ||||
| assign_source_group(${launcher_SRCS} ${launcher_HEADERS} VCMI_launcher.rc) | ||||
| if(WIN32) | ||||
| 	set(launcher_ICON VCMI_launcher.rc) | ||||
| endif() | ||||
|  | ||||
| # Tell CMake to run moc when necessary: | ||||
| assign_source_group(${launcher_SRCS} ${launcher_HEADERS} ${launcher_RESOURCES} ${launcher_TS} ${launcher_ICON}) | ||||
|  | ||||
| # TODO: enabling AUTORCC breaks msvc build on CI | ||||
| set(CMAKE_AUTOMOC ON) | ||||
| set(CMAKE_AUTOUIC ON) | ||||
| if(NOT (MSVC AND "$ENV{GITHUB_ACTIONS}" STREQUAL true)) | ||||
| 	set(CMAKE_AUTORCC ON) | ||||
| endif() | ||||
|  | ||||
| if(POLICY CMP0071) | ||||
| 	cmake_policy(SET CMP0071 NEW) | ||||
| @@ -86,38 +123,55 @@ endif() | ||||
| # to always look for includes there: | ||||
| set(CMAKE_INCLUDE_CURRENT_DIR ON) | ||||
|  | ||||
| if(TARGET Qt6::Core) | ||||
| 	qt_wrap_ui(launcher_UI_HEADERS ${launcher_FORMS}) | ||||
| if(ENABLE_SINGLE_APP_BUILD OR ANDROID) | ||||
| 	add_library(vcmilauncher OBJECT ${launcher_QM}) | ||||
| else() | ||||
| 	qt5_wrap_ui(launcher_UI_HEADERS ${launcher_FORMS}) | ||||
| 	if(ENABLE_TRANSLATIONS) | ||||
| 		set_source_files_properties(${launcher_TS} PROPERTIES OUTPUT_LOCATION ${CMAKE_CURRENT_BINARY_DIR}/translation) | ||||
| 		qt5_add_translation( launcher_QM ${launcher_TS} ) | ||||
| 	endif() | ||||
| 	add_executable(vcmilauncher WIN32 ${launcher_QM} ${launcher_ICON}) | ||||
| endif() | ||||
|  | ||||
|  | ||||
| if(WIN32) | ||||
| 	set(launcher_ICON VCMI_launcher.rc) | ||||
| endif() | ||||
|  | ||||
| if(ENABLE_SINGLE_APP_BUILD) | ||||
| 	add_library(vcmilauncher STATIC ${launcher_QM} ${launcher_SRCS} ${launcher_HEADERS} ${launcher_UI_HEADERS}) | ||||
| else() | ||||
| 	add_executable(vcmilauncher WIN32 ${launcher_QM} ${launcher_SRCS} ${launcher_HEADERS} ${launcher_UI_HEADERS} ${launcher_ICON}) | ||||
| endif() | ||||
|  | ||||
| if(TARGET Qt6::Core) | ||||
| 	if(ENABLE_TRANSLATIONS) | ||||
| 		set_source_files_properties(${launcher_TS} PROPERTIES OUTPUT_LOCATION ${CMAKE_CURRENT_BINARY_DIR}/translation) | ||||
| if(ENABLE_TRANSLATIONS) | ||||
| 	if(TARGET Qt6::Core) | ||||
| 		qt_add_translations(vcmilauncher | ||||
| 			TS_FILES ${launcher_TS} | ||||
| 			QM_FILES_OUTPUT_VARIABLE launcher_QM | ||||
| 			RESOURCE_PREFIX "/${translationsDir}" | ||||
| 			INCLUDE_DIRECTORIES | ||||
| 				${CMAKE_CURRENT_BINARY_DIR}) | ||||
| 	endif() | ||||
| endif() | ||||
|  | ||||
| if(ANDROID) | ||||
| 	get_target_property(rccPath Qt${QT_VERSION_MAJOR}::rcc IMPORTED_LOCATION) | ||||
| 	get_filename_component(qtDir "${rccPath}/../../" ABSOLUTE) | ||||
| 	set(qtDir "${qtDir}" PARENT_SCOPE) | ||||
|   | ||||
| 	function(generate_binary_resource resourceName resourceDir) | ||||
| 		file(CREATE_LINK "${resourceDir}" "${CMAKE_CURRENT_BINARY_DIR}/${resourceName}" | ||||
| 			COPY_ON_ERROR | ||||
| 			SYMBOLIC | ||||
| 		) | ||||
| 		set(qrcFile "${CMAKE_CURRENT_BINARY_DIR}/${resourceName}.qrc") | ||||
| 		execute_process(COMMAND | ||||
| 			"${rccPath}" --project | ||||
| 			WORKING_DIRECTORY "${resourceDir}" | ||||
| 			OUTPUT_VARIABLE rccOutput | ||||
| 		) | ||||
| 		# add parent directory | ||||
| 		string(REPLACE "<file>." "<file>${resourceName}" rccOutput "${rccOutput}") | ||||
| 		file(WRITE "${qrcFile}" "${rccOutput}") | ||||
| 	endfunction() | ||||
|   | ||||
| 	generate_binary_resource("config" "${CMAKE_SOURCE_DIR}/config") | ||||
| 	list(APPEND launcher_RESOURCES "${CMAKE_CURRENT_BINARY_DIR}/config.qrc") | ||||
| 	generate_binary_resource("Mods" "${CMAKE_SOURCE_DIR}/Mods") | ||||
| 	list(APPEND launcher_RESOURCES "${CMAKE_CURRENT_BINARY_DIR}/Mods.qrc") | ||||
| endif() | ||||
|  | ||||
| target_sources(vcmilauncher PRIVATE | ||||
| 	${launcher_SRCS} | ||||
| 	${launcher_HEADERS} | ||||
| 	${launcher_RESOURCES} | ||||
| ) | ||||
|  | ||||
| if(WIN32) | ||||
| 	set_target_properties(vcmilauncher | ||||
| 		PROPERTIES | ||||
| @@ -139,7 +193,9 @@ if(APPLE) | ||||
| 	set_property(GLOBAL PROPERTY AUTOGEN_TARGETS_FOLDER vcmilauncher) | ||||
| endif() | ||||
|  | ||||
| if (NOT APPLE_IOS AND NOT ANDROID) | ||||
| if(ANDROID) | ||||
| 	target_link_libraries(vcmilauncher Qt${QT_VERSION_MAJOR}::AndroidExtras) | ||||
| elseif(NOT APPLE_IOS) | ||||
| 	target_link_libraries(vcmilauncher SDL2::SDL2) | ||||
| endif() | ||||
|  | ||||
| @@ -155,9 +211,7 @@ if(ENABLE_INNOEXTRACT) | ||||
| endif() | ||||
|  | ||||
| if(APPLE_IOS) | ||||
| 	set(RESOURCES_DESTINATION ${DATA_DIR}) | ||||
|  | ||||
| 	# TODO: remove after fixing Conan's Qt recipe | ||||
| 	# TODO: remove after switching prebuilt deps to a newer Conan's Qt recipe | ||||
| 	if(XCODE_VERSION VERSION_GREATER_EQUAL 14.0) | ||||
| 		target_link_libraries(vcmilauncher "-framework IOKit") | ||||
| 	endif() | ||||
| @@ -167,22 +221,19 @@ if(APPLE_IOS) | ||||
| 		file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/QIOSIntegrationPlugin.h | ||||
| 			"#include <QtPlugin>\nQ_IMPORT_PLUGIN(QIOSIntegrationPlugin)" | ||||
| 		) | ||||
| 		# target_include_directories(vcmilauncher PRIVATE ${CMAKE_BINARY_DIR}) | ||||
| 		target_link_libraries(vcmilauncher | ||||
| 			Qt${QT_VERSION_MAJOR}::QIOSIntegrationPlugin | ||||
| 			qt::QIOSIntegrationPlugin | ||||
| 		) | ||||
| 	endif() | ||||
| else() | ||||
| 	set(RESOURCES_DESTINATION ${DATA_DIR}/launcher) | ||||
|  | ||||
| 	# Link to build directory for easier debugging | ||||
| 	add_custom_command(TARGET vcmilauncher POST_BUILD | ||||
| 		COMMAND ${CMAKE_COMMAND} -E make_directory ${CMAKE_BINARY_DIR}/bin/${CMAKE_CFG_INTDIR}/launcher | ||||
| 		COMMAND ${CMAKE_COMMAND} -P ${CMAKE_SOURCE_DIR}/cmake_modules/create_link.cmake ${CMAKE_SOURCE_DIR}/launcher/icons ${CMAKE_BINARY_DIR}/bin/${CMAKE_CFG_INTDIR}/launcher/icons | ||||
| 		COMMAND ${CMAKE_COMMAND} -P ${CMAKE_SOURCE_DIR}/cmake_modules/create_link.cmake ${CMAKE_CURRENT_BINARY_DIR}/translation ${CMAKE_BINARY_DIR}/bin/${CMAKE_CFG_INTDIR}/launcher/translation | ||||
| elseif(ANDROID) | ||||
| 	set(androidSdkDir "$ENV{ANDROID_HOME}") | ||||
| 	configure_file( | ||||
| 		"${androidPackageSourceDir}/androiddeployqt.json.in" | ||||
| 		"${CMAKE_BINARY_DIR}/androiddeployqt.json" | ||||
| 		@ONLY | ||||
| 	) | ||||
|  | ||||
| else() | ||||
| 	install(TARGETS vcmilauncher DESTINATION ${BIN_DIR}) | ||||
|  | ||||
| 	# Install icons and desktop file on Linux | ||||
| @@ -191,8 +242,3 @@ else() | ||||
| 		install(FILES "eu.vcmi.VCMI.metainfo.xml" DESTINATION share/metainfo) | ||||
| 	endif() | ||||
| endif() | ||||
|  | ||||
| install(DIRECTORY icons DESTINATION ${RESOURCES_DESTINATION}) | ||||
| if(ENABLE_TRANSLATIONS) | ||||
| 	install(FILES ${launcher_QM} DESTINATION ${RESOURCES_DESTINATION}/translation) | ||||
| endif() | ||||
|   | ||||
| @@ -363,7 +363,7 @@ void FirstLaunchView::extractGogData() | ||||
|  | ||||
| void FirstLaunchView::copyHeroesData(const QString & path, bool move) | ||||
| { | ||||
| 	QDir sourceRoot = QDir(path); | ||||
| 	QDir sourceRoot{path}; | ||||
| 	 | ||||
| 	if(path.isEmpty()) | ||||
| 		sourceRoot.setPath(QFileDialog::getExistingDirectory(this, {}, {}, QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks)); | ||||
| @@ -387,9 +387,10 @@ void FirstLaunchView::copyHeroesData(const QString & path, bool move) | ||||
| 	QStringList dirMaps = sourceRoot.entryList({"maps"}, QDir::Filter::Dirs); | ||||
| 	QStringList dirMp3 = sourceRoot.entryList({"mp3"}, QDir::Filter::Dirs); | ||||
|  | ||||
| 	const auto noDataMessage = tr("Failed to detect valid Heroes III data in chosen directory.\nPlease select directory with installed Heroes III data."); | ||||
| 	if(dirData.empty()) | ||||
| 	{ | ||||
| 		QMessageBox::critical(this, tr("Heroes III data not found!"), tr("Failed to detect valid Heroes III data in chosen directory.\nPlease select directory with installed Heroes III data.")); | ||||
| 		QMessageBox::critical(this, tr("Heroes III data not found!"), noDataMessage); | ||||
| 		return; | ||||
| 	} | ||||
|  | ||||
| @@ -403,7 +404,7 @@ void FirstLaunchView::copyHeroesData(const QString & path, bool move) | ||||
| 		if (roeFiles.empty()) | ||||
| 		{ | ||||
| 			// Directory structure is correct (Data/Maps/Mp3) but no .lod archives that should be present in any install | ||||
| 			QMessageBox::critical(this, tr("Heroes III data not found!"), tr("Failed to detect valid Heroes III data in chosen directory.\nPlease select directory with installed Heroes III data.")); | ||||
| 			QMessageBox::critical(this, tr("Heroes III data not found!"), noDataMessage); | ||||
| 			return; | ||||
| 		} | ||||
|  | ||||
|   | ||||
| @@ -96,5 +96,4 @@ private slots: | ||||
|  | ||||
| private: | ||||
| 	Ui::FirstLaunchView * ui; | ||||
|  | ||||
| }; | ||||
|   | ||||
| @@ -10,24 +10,35 @@ | ||||
| #include "StdInc.h" | ||||
| #include "main.h" | ||||
| #include "mainwindow_moc.h" | ||||
| #include "launcherdirs.h" | ||||
| #include "prepare.h" | ||||
|  | ||||
| #include "../lib/VCMIDirs.h" | ||||
|  | ||||
| #include <QApplication> | ||||
| #include <QProcess> | ||||
| #include <QMessageBox> | ||||
|  | ||||
| // Conan workaround https://github.com/conan-io/conan-center-index/issues/13332 | ||||
| #ifdef VCMI_IOS | ||||
| #if __has_include("QIOSIntegrationPlugin.h") | ||||
| #include "QIOSIntegrationPlugin.h" | ||||
| #endif | ||||
| # if __has_include("QIOSIntegrationPlugin.h") | ||||
| #  include "QIOSIntegrationPlugin.h" | ||||
| # endif | ||||
| int argcForClient; | ||||
| char ** argvForClient; | ||||
| #endif | ||||
| #elif defined(VCMI_ANDROID) | ||||
| # include <QAndroidJniObject> | ||||
| # include <QtAndroid> | ||||
| #else | ||||
| # include <QMessageBox> | ||||
| # include <QProcess> | ||||
| #endif // VCMI_IOS | ||||
|  | ||||
| int main(int argc, char * argv[]) | ||||
| // android must export main explicitly to make it visible in the shared library | ||||
| #ifdef VCMI_ANDROID | ||||
| # define MAIN_EXPORT ELF_VISIBILITY | ||||
| #else | ||||
| # define MAIN_EXPORT | ||||
| #endif // VCMI_ANDROID | ||||
|  | ||||
| int MAIN_EXPORT main(int argc, char * argv[]) | ||||
| { | ||||
| 	int result; | ||||
| #ifdef VCMI_IOS | ||||
| @@ -35,7 +46,7 @@ int main(int argc, char * argv[]) | ||||
| #endif | ||||
| 	QApplication vcmilauncher(argc, argv); | ||||
|  | ||||
| 	CLauncherDirs::prepare(); | ||||
| 	launcher::prepare(); | ||||
|  | ||||
| 	MainWindow mainWindow; | ||||
| 	mainWindow.show(); | ||||
| @@ -53,7 +64,7 @@ void startGame(const QStringList & args) | ||||
| { | ||||
| 	logGlobal->warn("Starting game with the arguments: %s", args.join(" ").toStdString()); | ||||
|  | ||||
| #ifdef Q_OS_IOS | ||||
| #ifdef VCMI_IOS | ||||
| 	static const char clientName[] = "vcmiclient"; | ||||
| 	argcForClient = args.size() + 1; //first argument is omitted | ||||
| 	argvForClient = new char*[argcForClient]; | ||||
| @@ -61,11 +72,13 @@ void startGame(const QStringList & args) | ||||
| 	strcpy(argvForClient[0], clientName); | ||||
| 	for(int i = 1; i < argcForClient; ++i) | ||||
| 	{ | ||||
|         std::string s = args.at(i - 1).toStdString(); | ||||
|         argvForClient[i] = new char[s.size() + 1]; | ||||
|         strcpy(argvForClient[i], s.c_str()); | ||||
| 		std::string s = args.at(i - 1).toStdString(); | ||||
| 		argvForClient[i] = new char[s.size() + 1]; | ||||
| 		strcpy(argvForClient[i], s.c_str()); | ||||
| 	} | ||||
| 	qApp->quit(); | ||||
| #elif defined(VCMI_ANDROID) | ||||
| 	QtAndroid::androidActivity().callMethod<void>("onLaunchGameBtnPressed"); | ||||
| #else | ||||
| 	startExecutable(pathToQString(VCMIDirs::get().clientPath()), args); | ||||
| #endif | ||||
| @@ -78,7 +91,7 @@ void startEditor(const QStringList & args) | ||||
| #endif | ||||
| } | ||||
|  | ||||
| #ifndef Q_OS_IOS | ||||
| #ifndef VCMI_MOBILE | ||||
| void startExecutable(QString name, const QStringList & args) | ||||
| { | ||||
| 	QProcess process; | ||||
| @@ -91,11 +104,9 @@ void startExecutable(QString name, const QStringList & args) | ||||
| 	else | ||||
| 	{ | ||||
| 		QMessageBox::critical(qApp->activeWindow(), | ||||
| 							  "Error starting executable", | ||||
| 							  "Failed to start " + name + "\n" | ||||
| 							  "Reason: " + process.errorString(), | ||||
| 							  QMessageBox::Ok, | ||||
| 							  QMessageBox::Ok); | ||||
| 			QObject::tr("Error starting executable"), | ||||
| 			QObject::tr("Failed to start %1\nReason: %2").arg(name, process.errorString()) | ||||
| 		); | ||||
| 	} | ||||
| } | ||||
| #endif | ||||
|   | ||||
| @@ -29,7 +29,7 @@ void MainWindow::load() | ||||
| 	// This is important on Mac for relative paths to work inside DMG. | ||||
| 	QDir::setCurrent(QApplication::applicationDirPath()); | ||||
|  | ||||
| #ifndef VCMI_IOS | ||||
| #ifndef VCMI_MOBILE | ||||
| 	console = new CConsoleHandler(); | ||||
| #endif | ||||
| 	CBasicLogConfigurator logConfig(VCMIDirs::get().userLogsPath() / "VCMI_Launcher_log.txt", console); | ||||
| @@ -38,14 +38,6 @@ void MainWindow::load() | ||||
| 	CResourceHandler::initialize(); | ||||
| 	CResourceHandler::load("config/filesystem.json"); | ||||
|  | ||||
| #ifdef Q_OS_IOS | ||||
| 	QDir::addSearchPath("icons", pathToQString(VCMIDirs::get().binaryPath() / "icons")); | ||||
| #else | ||||
| 	for(auto & string : VCMIDirs::get().dataPaths()) | ||||
| 		QDir::addSearchPath("icons", pathToQString(string / "launcher" / "icons")); | ||||
| 	QDir::addSearchPath("icons", pathToQString(VCMIDirs::get().userDataPath() / "launcher" / "icons")); | ||||
| #endif | ||||
|  | ||||
| 	Helper::loadSettings(); | ||||
| } | ||||
|  | ||||
| @@ -85,7 +77,15 @@ MainWindow::MainWindow(QWidget * parent) | ||||
| 	updateTranslation(); // load translation | ||||
|  | ||||
| 	ui->setupUi(this); | ||||
| 	 | ||||
|  | ||||
| 	setWindowIcon(QIcon{":/icons/menu-game.png"}); | ||||
| 	ui->modslistButton->setIcon(QIcon{":/icons/menu-mods.png"}); | ||||
| 	ui->settingsButton->setIcon(QIcon{":/icons/menu-settings.png"}); | ||||
| 	ui->aboutButton->setIcon(QIcon{":/icons/about-project.png"}); | ||||
| 	ui->startEditorButton->setIcon(QIcon{":/icons/menu-editor.png"}); | ||||
| 	ui->startGameButton->setIcon(QIcon{":/icons/menu-game.png"}); | ||||
|  | ||||
| #ifndef VCMI_MOBILE | ||||
| 	//load window settings | ||||
| 	QSettings s(Ui::teamName, Ui::appName); | ||||
|  | ||||
| @@ -99,6 +99,7 @@ MainWindow::MainWindow(QWidget * parent) | ||||
| 	{ | ||||
| 		move(position); | ||||
| 	} | ||||
| #endif | ||||
|  | ||||
| #ifndef ENABLE_EDITOR | ||||
| 	ui->startEditorButton->hide(); | ||||
| @@ -183,10 +184,12 @@ void MainWindow::changeEvent(QEvent *event) | ||||
|  | ||||
| MainWindow::~MainWindow() | ||||
| { | ||||
| #ifndef VCMI_MOBILE | ||||
| 	//save window settings | ||||
| 	QSettings s(Ui::teamName, Ui::appName); | ||||
| 	s.setValue("MainWindow/Size", size()); | ||||
| 	s.setValue("MainWindow/Position", pos()); | ||||
| #endif | ||||
|  | ||||
| 	delete ui; | ||||
| } | ||||
| @@ -231,32 +234,16 @@ void MainWindow::on_aboutButton_clicked() | ||||
| void MainWindow::updateTranslation() | ||||
| { | ||||
| #ifdef ENABLE_QT_TRANSLATIONS | ||||
| 	std::string translationFile = settings["general"]["language"].String() + ".qm"; | ||||
| 	const std::string translationFile = settings["general"]["language"].String() + ".qm"; | ||||
| 	logGlobal->info("Loading translation '%s'", translationFile); | ||||
|  | ||||
| 	QVector<QString> searchPaths; | ||||
|  | ||||
| #ifdef Q_OS_IOS | ||||
| 	searchPaths.push_back(pathToQString(VCMIDirs::get().binaryPath() / "translation" / translationFile)); | ||||
| #else | ||||
| 	for(auto const & string : VCMIDirs::get().dataPaths()) | ||||
| 		searchPaths.push_back(pathToQString(string / "launcher" / "translation" / translationFile)); | ||||
| 	searchPaths.push_back(pathToQString(VCMIDirs::get().userDataPath() / "launcher" / "translation" / translationFile)); | ||||
| #endif | ||||
|  | ||||
| 	for(auto const & string : boost::adaptors::reverse(searchPaths)) | ||||
| 	if (!translator.load(QString{":/translation/%1"}.arg(translationFile.c_str()))) | ||||
| 	{ | ||||
| 		logGlobal->info("Searching for translation at '%s'", string.toStdString()); | ||||
| 		if (translator.load(string)) | ||||
| 		{ | ||||
| 			logGlobal->info("Translation found"); | ||||
| 			if (!qApp->installTranslator(&translator)) | ||||
| 				logGlobal->error("Failed to install translator"); | ||||
| 			return; | ||||
| 		} | ||||
| 		logGlobal->error("Failed to load translation"); | ||||
| 		return; | ||||
| 	} | ||||
|  | ||||
| 	logGlobal->error("Failed to find translation"); | ||||
|  | ||||
| 	if (!qApp->installTranslator(&translator)) | ||||
| 		logGlobal->error("Failed to install translator"); | ||||
| #endif | ||||
| } | ||||
|   | ||||
| @@ -19,10 +19,6 @@ | ||||
|   <property name="windowTitle"> | ||||
|    <string>VCMI Launcher</string> | ||||
|   </property> | ||||
|   <property name="windowIcon"> | ||||
|    <iconset> | ||||
|     <normaloff>icons:menu-game.png</normaloff>icons:menu-game.png</iconset> | ||||
|   </property> | ||||
|   <property name="iconSize"> | ||||
|    <size> | ||||
|     <width>64</width> | ||||
| @@ -56,10 +52,6 @@ | ||||
|         <property name="text"> | ||||
|          <string>Mods</string> | ||||
|         </property> | ||||
|         <property name="icon"> | ||||
|          <iconset> | ||||
|           <normaloff>icons:menu-mods.png</normaloff>icons:menu-mods.png</iconset> | ||||
|         </property> | ||||
|         <property name="iconSize"> | ||||
|          <size> | ||||
|           <width>64</width> | ||||
| @@ -106,10 +98,6 @@ | ||||
|         <property name="text"> | ||||
|          <string>Settings</string> | ||||
|         </property> | ||||
|         <property name="icon"> | ||||
|          <iconset> | ||||
|           <normaloff>icons:menu-settings.png</normaloff>icons:menu-settings.png</iconset> | ||||
|         </property> | ||||
|         <property name="iconSize"> | ||||
|          <size> | ||||
|           <width>64</width> | ||||
| @@ -156,10 +144,6 @@ | ||||
|         <property name="text"> | ||||
|          <string>Help</string> | ||||
|         </property> | ||||
|         <property name="icon"> | ||||
|          <iconset> | ||||
|           <normaloff>icons:about-project.png</normaloff>icons:about-project.png</iconset> | ||||
|         </property> | ||||
|         <property name="iconSize"> | ||||
|          <size> | ||||
|           <width>32</width> | ||||
| @@ -225,10 +209,6 @@ | ||||
|         <property name="text"> | ||||
|          <string>Map Editor</string> | ||||
|         </property> | ||||
|         <property name="icon"> | ||||
|          <iconset> | ||||
|           <normaloff>icons:menu-editor.png</normaloff>icons:menu-editor.png</iconset> | ||||
|         </property> | ||||
|         <property name="iconSize"> | ||||
|          <size> | ||||
|           <width>32</width> | ||||
| @@ -278,10 +258,6 @@ | ||||
|         <property name="text"> | ||||
|          <string>Start game</string> | ||||
|         </property> | ||||
|         <property name="icon"> | ||||
|          <iconset> | ||||
|           <normaloff>icons:menu-game.png</normaloff>icons:menu-game.png</iconset> | ||||
|         </property> | ||||
|         <property name="iconSize"> | ||||
|          <size> | ||||
|           <width>64</width> | ||||
|   | ||||
| @@ -14,11 +14,11 @@ | ||||
|  | ||||
| namespace ModStatus | ||||
| { | ||||
| static const QString iconDelete = "icons:mod-delete.png"; | ||||
| static const QString iconDisabled = "icons:mod-disabled.png"; | ||||
| static const QString iconDownload = "icons:mod-download.png"; | ||||
| static const QString iconEnabled = "icons:mod-enabled.png"; | ||||
| static const QString iconUpdate = "icons:mod-update.png"; | ||||
| static const QString iconDelete = ":/icons/mod-delete.png"; | ||||
| static const QString iconDisabled = ":/icons/mod-disabled.png"; | ||||
| static const QString iconDownload = ":/icons/mod-download.png"; | ||||
| static const QString iconEnabled = ":/icons/mod-enabled.png"; | ||||
| static const QString iconUpdate = ":/icons/mod-update.png"; | ||||
| } | ||||
|  | ||||
| CModListModel::CModListModel(QObject * parent) | ||||
|   | ||||
| @@ -130,6 +130,12 @@ CModListView::CModListView(QWidget * parent) | ||||
|  | ||||
| 	setAcceptDrops(true); | ||||
|  | ||||
| 	ui->uninstallButton->setIcon(QIcon{":/icons/mod-delete.png"}); | ||||
| 	ui->enableButton->setIcon(QIcon{":/icons/mod-enabled.png"}); | ||||
| 	ui->disableButton->setIcon(QIcon{":/icons/mod-disabled.png"}); | ||||
| 	ui->updateButton->setIcon(QIcon{":/icons/mod-update.png"}); | ||||
| 	ui->installButton->setIcon(QIcon{":/icons/mod-download.png"}); | ||||
|  | ||||
| 	setupModModel(); | ||||
| 	setupFilterModel(); | ||||
| 	setupModsView(); | ||||
| @@ -393,14 +399,15 @@ void CModListView::selectMod(const QModelIndex & index) | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| 		auto mod = modModel->getMod(index.data(ModRoles::ModNameRole).toString()); | ||||
| 		const auto modName = index.data(ModRoles::ModNameRole).toString(); | ||||
| 		auto mod = modModel->getMod(modName); | ||||
|  | ||||
| 		ui->modInfoBrowser->setHtml(genModInfoText(mod)); | ||||
| 		ui->changelogBrowser->setHtml(genChangelogText(mod)); | ||||
|  | ||||
| 		bool hasInvalidDeps = !findInvalidDependencies(index.data(ModRoles::ModNameRole).toString()).empty(); | ||||
| 		bool hasBlockingMods = !findBlockingMods(index.data(ModRoles::ModNameRole).toString()).empty(); | ||||
| 		bool hasDependentMods = !findDependentMods(index.data(ModRoles::ModNameRole).toString(), true).empty(); | ||||
| 		bool hasInvalidDeps = !findInvalidDependencies(modName).empty(); | ||||
| 		bool hasBlockingMods = !findBlockingMods(modName).empty(); | ||||
| 		bool hasDependentMods = !findDependentMods(modName, true).empty(); | ||||
|  | ||||
| 		ui->disableButton->setVisible(mod.isEnabled()); | ||||
| 		ui->enableButton->setVisible(mod.isDisabled()); | ||||
|   | ||||
| @@ -423,10 +423,6 @@ hr { height: 1px; border-width: 0; } | ||||
|        <property name="text"> | ||||
|         <string>Uninstall</string> | ||||
|        </property> | ||||
|        <property name="icon"> | ||||
|         <iconset> | ||||
|          <normaloff>icons:mod-delete.png</normaloff>icons:mod-delete.png</iconset> | ||||
|        </property> | ||||
|        <property name="iconSize"> | ||||
|         <size> | ||||
|          <width>20</width> | ||||
| @@ -458,10 +454,6 @@ hr { height: 1px; border-width: 0; } | ||||
|        <property name="text"> | ||||
|         <string>Enable</string> | ||||
|        </property> | ||||
|        <property name="icon"> | ||||
|         <iconset> | ||||
|          <normaloff>icons:mod-enabled.png</normaloff>icons:mod-enabled.png</iconset> | ||||
|        </property> | ||||
|        <property name="iconSize"> | ||||
|         <size> | ||||
|          <width>20</width> | ||||
| @@ -493,10 +485,6 @@ hr { height: 1px; border-width: 0; } | ||||
|        <property name="text"> | ||||
|         <string>Disable</string> | ||||
|        </property> | ||||
|        <property name="icon"> | ||||
|         <iconset> | ||||
|          <normaloff>icons:mod-disabled.png</normaloff>icons:mod-disabled.png</iconset> | ||||
|        </property> | ||||
|        <property name="iconSize"> | ||||
|         <size> | ||||
|          <width>20</width> | ||||
| @@ -528,10 +516,6 @@ hr { height: 1px; border-width: 0; } | ||||
|        <property name="text"> | ||||
|         <string>Update</string> | ||||
|        </property> | ||||
|        <property name="icon"> | ||||
|         <iconset> | ||||
|          <normaloff>icons:mod-update.png</normaloff>icons:mod-update.png</iconset> | ||||
|        </property> | ||||
|        <property name="iconSize"> | ||||
|         <size> | ||||
|          <width>20</width> | ||||
| @@ -563,10 +547,6 @@ hr { height: 1px; border-width: 0; } | ||||
|        <property name="text"> | ||||
|         <string>Install</string> | ||||
|        </property> | ||||
|        <property name="icon"> | ||||
|         <iconset> | ||||
|          <normaloff>icons:mod-download.png</normaloff>icons:mod-download.png</iconset> | ||||
|        </property> | ||||
|        <property name="iconSize"> | ||||
|         <size> | ||||
|          <width>20</width> | ||||
|   | ||||
| @@ -20,6 +20,8 @@ | ||||
| #include "../jsonutils.h" | ||||
| #include "../launcherdirs.h" | ||||
|  | ||||
| #include <future> | ||||
|  | ||||
| namespace | ||||
| { | ||||
| QString detectModArchive(QString path, QString modName, std::vector<std::string> & filesToExtract) | ||||
| @@ -360,7 +362,7 @@ bool CModManager::removeModDir(QString path) | ||||
| 	 | ||||
| 	if(!checkDir.cdUp() || QString::compare("Mods", checkDir.dirName(), Qt::CaseInsensitive)) | ||||
| 		return false; | ||||
| #ifndef VCMI_IOS //ios applications are stored in the isolated container | ||||
| #ifndef VCMI_MOBILE // ios and android applications are stored in the isolated container | ||||
| 	if(!checkDir.cdUp() || QString::compare("vcmi", checkDir.dirName(), Qt::CaseInsensitive)) | ||||
| 		return false; | ||||
|  | ||||
|   | ||||
							
								
								
									
										85
									
								
								launcher/prepare.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										85
									
								
								launcher/prepare.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,85 @@ | ||||
| /* | ||||
|  * prepare.cpp, part of VCMI engine | ||||
|  * | ||||
|  * Authors: listed in file AUTHORS in main folder | ||||
|  * | ||||
|  * License: GNU General Public License v2.0 or later | ||||
|  * Full text of license available in license.txt file, in main folder | ||||
|  * | ||||
|  */ | ||||
| #include "StdInc.h" | ||||
| #include "prepare.h" | ||||
| #include "launcherdirs.h" | ||||
|  | ||||
| #include <QDir> | ||||
| #include <QFile> | ||||
| #include <QFileInfo> | ||||
|  | ||||
| #ifdef VCMI_ANDROID | ||||
| #include "../lib/CAndroidVMHelper.h" | ||||
|  | ||||
| #include <QAndroidJniEnvironment> | ||||
| #include <QAndroidJniObject> | ||||
| #include <QtAndroid> | ||||
|  | ||||
| namespace | ||||
| { | ||||
| // https://gist.github.com/ssendeavour/7324701 | ||||
| bool copyRecursively(const QString &srcFilePath, const QString &tgtFilePath) | ||||
| { | ||||
| 	QFileInfo srcFileInfo{srcFilePath}; | ||||
| 	if(srcFileInfo.isDir()) { | ||||
| 		QDir targetDir{tgtFilePath}; | ||||
| 		targetDir.cdUp(); | ||||
| 		if(!targetDir.mkpath(QFileInfo{tgtFilePath}.fileName())) | ||||
| 			return false; | ||||
| 		targetDir.setPath(tgtFilePath); | ||||
|  | ||||
| 		QDir sourceDir{srcFilePath}; | ||||
| 		const auto fileNames = sourceDir.entryList(QDir::Files | QDir::Dirs | QDir::NoDotAndDotDot | QDir::Hidden | QDir::System); | ||||
| 		for(const auto & fileName : fileNames) { | ||||
| 			const auto newSrcFilePath = sourceDir.filePath(fileName); | ||||
| 			const auto newTgtFilePath = targetDir.filePath(fileName); | ||||
| 			if(!copyRecursively(newSrcFilePath, newTgtFilePath)) | ||||
| 				return false; | ||||
| 		} | ||||
| 	} else { | ||||
| 		if(!QFile::copy(srcFilePath, tgtFilePath)) | ||||
| 			return false; | ||||
| 	} | ||||
| 	return true; | ||||
| } | ||||
|  | ||||
| void prepareAndroid() | ||||
| { | ||||
| 	QAndroidJniEnvironment jniEnv; | ||||
| 	CAndroidVMHelper::initClassloader(static_cast<JNIEnv *>(jniEnv)); | ||||
|  | ||||
| 	const bool justLaunched = QtAndroid::androidActivity().getField<jboolean>("justLaunched") == JNI_TRUE; | ||||
| 	if(!justLaunched) | ||||
| 		return; | ||||
|  | ||||
| 	// copy core data to internal directory | ||||
| 	const auto vcmiDir = QAndroidJniObject::callStaticObjectMethod<jstring>("eu/vcmi/vcmi/NativeMethods", "internalDataRoot").toString(); | ||||
| 	for(auto vcmiFilesResource : {QLatin1String{"config"}, QLatin1String{"Mods"}}) | ||||
| 	{ | ||||
| 		QDir destDir = QString{"%1/%2"}.arg(vcmiDir, vcmiFilesResource); | ||||
| 		destDir.removeRecursively(); | ||||
| 		copyRecursively(QString{":/%1"}.arg(vcmiFilesResource), destDir.absolutePath()); | ||||
| 	} | ||||
| } | ||||
| } | ||||
| #endif | ||||
|  | ||||
|  | ||||
| namespace launcher | ||||
| { | ||||
| void prepare() | ||||
| { | ||||
| #ifdef VCMI_ANDROID | ||||
| 	prepareAndroid(); | ||||
| #endif | ||||
|  | ||||
| 	CLauncherDirs::prepare(); | ||||
| } | ||||
| } | ||||
							
								
								
									
										15
									
								
								launcher/prepare.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								launcher/prepare.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,15 @@ | ||||
| /* | ||||
|  * prepare.h, part of VCMI engine | ||||
|  * | ||||
|  * Authors: listed in file AUTHORS in main folder | ||||
|  * | ||||
|  * License: GNU General Public License v2.0 or later | ||||
|  * Full text of license available in license.txt file, in main folder | ||||
|  * | ||||
|  */ | ||||
| #pragma once | ||||
|  | ||||
| namespace launcher | ||||
| { | ||||
| void prepare(); | ||||
| } | ||||
							
								
								
									
										14
									
								
								launcher/resources.qrc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								launcher/resources.qrc
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,14 @@ | ||||
| <RCC> | ||||
|     <qresource prefix="/"> | ||||
|         <file>icons/about-project.png</file> | ||||
|         <file>icons/menu-editor.png</file> | ||||
|         <file>icons/menu-game.png</file> | ||||
|         <file>icons/menu-mods.png</file> | ||||
|         <file>icons/menu-settings.png</file> | ||||
|         <file>icons/mod-delete.png</file> | ||||
|         <file>icons/mod-disabled.png</file> | ||||
|         <file>icons/mod-download.png</file> | ||||
|         <file>icons/mod-enabled.png</file> | ||||
|         <file>icons/mod-update.png</file> | ||||
|     </qresource> | ||||
| </RCC> | ||||
| @@ -7,7 +7,6 @@ if(APPLE_MACOS) | ||||
| 	if(ENABLE_LAUNCHER OR ENABLE_EDITOR) | ||||
| 		if(USING_CONAN) | ||||
| 			# simulate macdeployqt behavior, main Qt libs are copied by conan | ||||
| 			get_target_property(qmakePath Qt5::qmake IMPORTED_LOCATION) | ||||
| 			execute_process(COMMAND | ||||
| 				"${qmakePath}" -query QT_INSTALL_PLUGINS | ||||
| 				OUTPUT_VARIABLE qtPluginsDir | ||||
| @@ -25,7 +24,7 @@ if(APPLE_MACOS) | ||||
| 		else() | ||||
| 			# note: cross-compiled Qt 5 builds macdeployqt for target platform instead of host | ||||
| 			# deploy Qt dylibs with macdeployqt | ||||
| 			find_program(TOOL_MACDEPLOYQT NAMES macdeployqt PATHS ${qt_base_dir}/bin) | ||||
| 			find_program(TOOL_MACDEPLOYQT NAMES macdeployqt PATHS "${qtBinDir}") | ||||
| 			if(TOOL_MACDEPLOYQT) | ||||
| 				install(CODE " | ||||
| 					execute_process(COMMAND | ||||
|   | ||||
		Reference in New Issue
	
	Block a user