diff --git a/CMake/conan.cmake b/CMake/conan.cmake index bec1a90e..eb688ca8 100644 --- a/CMake/conan.cmake +++ b/CMake/conan.cmake @@ -33,7 +33,7 @@ # but it is only necessary on the end-user side. It is not necessary to create conan # packages, in fact it shouldn't be use for that. Check the project documentation. -# version: 0.16.0-dev +# version: 0.19.0-dev include(CMakeParseArguments) @@ -55,23 +55,14 @@ function(_get_msvc_ide_version result) set(${result} 15 PARENT_SCOPE) elseif(NOT MSVC_VERSION VERSION_LESS 1920 AND MSVC_VERSION VERSION_LESS 1930) set(${result} 16 PARENT_SCOPE) + elseif(NOT MSVC_VERSION VERSION_LESS 1930 AND MSVC_VERSION VERSION_LESS 1940) + set(${result} 17 PARENT_SCOPE) else() message(FATAL_ERROR "Conan: Unknown MSVC compiler version [${MSVC_VERSION}]") endif() endfunction() -function(conan_cmake_settings result) - #message(STATUS "COMPILER " ${CMAKE_CXX_COMPILER}) - #message(STATUS "COMPILER " ${CMAKE_CXX_COMPILER_ID}) - #message(STATUS "VERSION " ${CMAKE_CXX_COMPILER_VERSION}) - #message(STATUS "FLAGS " ${CMAKE_LANG_FLAGS}) - #message(STATUS "LIB ARCH " ${CMAKE_CXX_LIBRARY_ARCHITECTURE}) - #message(STATUS "BUILD TYPE " ${CMAKE_BUILD_TYPE}) - #message(STATUS "GENERATOR " ${CMAKE_GENERATOR}) - #message(STATUS "GENERATOR WIN64 " ${CMAKE_CL_64}) - - message(STATUS "Conan: Automatic detection of conan settings from cmake") - +macro(_conan_detect_build_type) conan_parse_arguments(${ARGV}) if(ARGUMENTS_BUILD_TYPE) @@ -92,10 +83,9 @@ function(conan_cmake_settings result) elseif(_CONAN_SETTING_BUILD_TYPE_UPPER STREQUAL "MINSIZEREL") set(_CONAN_SETTING_BUILD_TYPE "MinSizeRel") endif() +endmacro() - if(ARGUMENTS_ARCH) - set(_CONAN_SETTING_ARCH ${ARGUMENTS_ARCH}) - endif() +macro(_conan_check_system_name) #handle -s os setting if(CMAKE_SYSTEM_NAME AND NOT CMAKE_SYSTEM_NAME STREQUAL "Generic") #use default conan os setting if CMAKE_SYSTEM_NAME is not defined @@ -115,7 +105,9 @@ function(conan_cmake_settings result) message(FATAL_ERROR "cmake system ${CONAN_SYSTEM_NAME} is not supported by conan. Use one of ${CONAN_SUPPORTED_PLATFORMS}") endif() endif() +endmacro() +macro(_conan_check_language) get_property(_languages GLOBAL PROPERTY ENABLED_LANGUAGES) if (";${_languages};" MATCHES ";CXX;") set(LANGUAGE CXX) @@ -126,18 +118,52 @@ function(conan_cmake_settings result) else () message(FATAL_ERROR "Conan: Neither C or C++ was detected as a language for the project. Unabled to detect compiler version.") endif() +endmacro() + +macro(_conan_detect_compiler) - if (${CMAKE_${LANGUAGE}_COMPILER_ID} STREQUAL GNU) - # using GCC + conan_parse_arguments(${ARGV}) + + if(ARGUMENTS_ARCH) + set(_CONAN_SETTING_ARCH ${ARGUMENTS_ARCH}) + endif() + + if(USING_CXX) + set(_CONAN_SETTING_COMPILER_CPPSTD ${CMAKE_CXX_STANDARD}) + endif() + + if (${CMAKE_${LANGUAGE}_COMPILER_ID} STREQUAL GNU OR ${CMAKE_${LANGUAGE}_COMPILER_ID} STREQUAL QCC) + # using GCC or QCC # TODO: Handle other params string(REPLACE "." ";" VERSION_LIST ${CMAKE_${LANGUAGE}_COMPILER_VERSION}) list(GET VERSION_LIST 0 MAJOR) list(GET VERSION_LIST 1 MINOR) - set(COMPILER_VERSION ${MAJOR}.${MINOR}) - if(${MAJOR} GREATER 4) - set(COMPILER_VERSION ${MAJOR}) - endif() - set(_CONAN_SETTING_COMPILER gcc) + + if (${CMAKE_${LANGUAGE}_COMPILER_ID} STREQUAL GNU) + set(_CONAN_SETTING_COMPILER gcc) + # mimic Conan client autodetection + if (${MAJOR} GREATER_EQUAL 5) + set(COMPILER_VERSION ${MAJOR}) + else() + set(COMPILER_VERSION ${MAJOR}.${MINOR}) + endif() + elseif (${CMAKE_${LANGUAGE}_COMPILER_ID} STREQUAL QCC) + set(_CONAN_SETTING_COMPILER qcc) + set(COMPILER_VERSION ${MAJOR}.${MINOR}) + endif () + + set(_CONAN_SETTING_COMPILER_VERSION ${COMPILER_VERSION}) + + if (USING_CXX) + conan_cmake_detect_unix_libcxx(_LIBCXX) + set(_CONAN_SETTING_COMPILER_LIBCXX ${_LIBCXX}) + endif () + elseif (${CMAKE_${LANGUAGE}_COMPILER_ID} STREQUAL Intel) + string(REPLACE "." ";" VERSION_LIST ${CMAKE_${LANGUAGE}_COMPILER_VERSION}) + list(GET VERSION_LIST 0 MAJOR) + list(GET VERSION_LIST 1 MINOR) + set(COMPILER_VERSION ${MAJOR}) + set(_CONAN_SETTING_COMPILER intel) set(_CONAN_SETTING_COMPILER_VERSION ${COMPILER_VERSION}) if (USING_CXX) conan_cmake_detect_unix_libcxx(_LIBCXX) @@ -148,18 +174,39 @@ function(conan_cmake_settings result) string(REPLACE "." ";" VERSION_LIST ${CMAKE_${LANGUAGE}_COMPILER_VERSION}) list(GET VERSION_LIST 0 MAJOR) list(GET VERSION_LIST 1 MINOR) + + # mimic Conan client autodetection + if (${MAJOR} GREATER_EQUAL 13) + set(COMPILER_VERSION ${MAJOR}) + else() + set(COMPILER_VERSION ${MAJOR}.${MINOR}) + endif() + + set(_CONAN_SETTING_COMPILER_VERSION ${COMPILER_VERSION}) + set(_CONAN_SETTING_COMPILER apple-clang) - set(_CONAN_SETTING_COMPILER_VERSION ${MAJOR}.${MINOR}) if (USING_CXX) conan_cmake_detect_unix_libcxx(_LIBCXX) set(_CONAN_SETTING_COMPILER_LIBCXX ${_LIBCXX}) endif () - elseif (${CMAKE_${LANGUAGE}_COMPILER_ID} STREQUAL Clang) + elseif (${CMAKE_${LANGUAGE}_COMPILER_ID} STREQUAL Clang + AND NOT "${CMAKE_${LANGUAGE}_COMPILER_FRONTEND_VARIANT}" STREQUAL "MSVC" + AND NOT "${CMAKE_${LANGUAGE}_SIMULATE_ID}" STREQUAL "MSVC") + string(REPLACE "." ";" VERSION_LIST ${CMAKE_${LANGUAGE}_COMPILER_VERSION}) list(GET VERSION_LIST 0 MAJOR) list(GET VERSION_LIST 1 MINOR) set(_CONAN_SETTING_COMPILER clang) - set(_CONAN_SETTING_COMPILER_VERSION ${MAJOR}.${MINOR}) + + # mimic Conan client autodetection + if (${MAJOR} GREATER_EQUAL 8) + set(COMPILER_VERSION ${MAJOR}) + else() + set(COMPILER_VERSION ${MAJOR}.${MINOR}) + endif() + + set(_CONAN_SETTING_COMPILER_VERSION ${COMPILER_VERSION}) + if(APPLE) cmake_policy(GET CMP0025 APPLE_CLANG_POLICY) if(NOT APPLE_CLANG_POLICY STREQUAL NEW) @@ -167,14 +214,15 @@ function(conan_cmake_settings result) set(_CONAN_SETTING_COMPILER apple-clang) endif() endif() - if(${_CONAN_SETTING_COMPILER} STREQUAL clang AND ${MAJOR} GREATER 7) - set(_CONAN_SETTING_COMPILER_VERSION ${MAJOR}) - endif() if (USING_CXX) conan_cmake_detect_unix_libcxx(_LIBCXX) set(_CONAN_SETTING_COMPILER_LIBCXX ${_LIBCXX}) endif () - elseif(${CMAKE_${LANGUAGE}_COMPILER_ID} STREQUAL MSVC) + elseif(${CMAKE_${LANGUAGE}_COMPILER_ID} STREQUAL MSVC + OR (${CMAKE_${LANGUAGE}_COMPILER_ID} STREQUAL Clang + AND "${CMAKE_${LANGUAGE}_COMPILER_FRONTEND_VARIANT}" STREQUAL "MSVC" + AND "${CMAKE_${LANGUAGE}_SIMULATE_ID}" STREQUAL "MSVC")) + set(_VISUAL "Visual Studio") _get_msvc_ide_version(_VISUAL_VERSION) if("${_VISUAL_VERSION}" STREQUAL "") @@ -197,7 +245,7 @@ function(conan_cmake_settings result) endif() endif() - conan_cmake_detect_vs_runtime(_vs_runtime) + conan_cmake_detect_vs_runtime(_vs_runtime ${ARGV}) message(STATUS "Conan: Detected VS runtime: ${_vs_runtime}") set(_CONAN_SETTING_COMPILER_RUNTIME ${_vs_runtime}) @@ -206,10 +254,34 @@ function(conan_cmake_settings result) elseif(CMAKE_VS_PLATFORM_TOOLSET AND (CMAKE_GENERATOR STREQUAL "Ninja")) set(_CONAN_SETTING_COMPILER_TOOLSET ${CMAKE_VS_PLATFORM_TOOLSET}) endif() - else() + else() message(FATAL_ERROR "Conan: compiler setup not recognized") endif() +endmacro() + +function(conan_cmake_settings result) + #message(STATUS "COMPILER " ${CMAKE_CXX_COMPILER}) + #message(STATUS "COMPILER " ${CMAKE_CXX_COMPILER_ID}) + #message(STATUS "VERSION " ${CMAKE_CXX_COMPILER_VERSION}) + #message(STATUS "FLAGS " ${CMAKE_LANG_FLAGS}) + #message(STATUS "LIB ARCH " ${CMAKE_CXX_LIBRARY_ARCHITECTURE}) + #message(STATUS "BUILD TYPE " ${CMAKE_BUILD_TYPE}) + #message(STATUS "GENERATOR " ${CMAKE_GENERATOR}) + #message(STATUS "GENERATOR WIN64 " ${CMAKE_CL_64}) + + message(STATUS "Conan: Automatic detection of conan settings from cmake") + + conan_parse_arguments(${ARGV}) + + _conan_detect_build_type(${ARGV}) + + _conan_check_system_name() + + _conan_check_language() + + _conan_detect_compiler(${ARGV}) + # If profile is defined it is used if(CMAKE_BUILD_TYPE STREQUAL "Debug" AND ARGUMENTS_DEBUG_PROFILE) set(_APPLIED_PROFILES ${ARGUMENTS_DEBUG_PROFILE}) @@ -233,7 +305,7 @@ function(conan_cmake_settings result) if(NOT _SETTINGS OR ARGUMENTS_PROFILE_AUTO STREQUAL "ALL") set(ARGUMENTS_PROFILE_AUTO arch build_type compiler compiler.version - compiler.runtime compiler.libcxx compiler.toolset) + compiler.runtime compiler.libcxx compiler.toolset) endif() # remove any manually specified settings from the autodetected settings @@ -315,9 +387,9 @@ function(conan_cmake_detect_unix_libcxx result) endif() execute_process( - COMMAND ${CMAKE_COMMAND} -E echo "#include " - COMMAND ${EXPAND_CXX_COMPILER} ${SPLIT_CXX_FLAGS} -x c++ ${xcode_sysroot_option} ${compile_options} -E -dM - - OUTPUT_VARIABLE string_defines + COMMAND ${CMAKE_COMMAND} -E echo "#include " + COMMAND ${EXPAND_CXX_COMPILER} ${SPLIT_CXX_FLAGS} -x c++ ${xcode_sysroot_option} ${compile_options} -E -dM - + OUTPUT_VARIABLE string_defines ) if(string_defines MATCHES "#define __GLIBCXX__") @@ -346,7 +418,19 @@ function(conan_cmake_detect_unix_libcxx result) endfunction() function(conan_cmake_detect_vs_runtime result) - string(TOUPPER "${CMAKE_BUILD_TYPE}" build_type) + + conan_parse_arguments(${ARGV}) + if(ARGUMENTS_BUILD_TYPE) + set(build_type "${ARGUMENTS_BUILD_TYPE}") + elseif(CMAKE_BUILD_TYPE) + set(build_type "${CMAKE_BUILD_TYPE}") + else() + message(FATAL_ERROR "Please specify in command line CMAKE_BUILD_TYPE (-DCMAKE_BUILD_TYPE=Release)") + endif() + + if(build_type) + string(TOUPPER "${build_type}" build_type) + endif() set(variables CMAKE_CXX_FLAGS_${build_type} CMAKE_C_FLAGS_${build_type} CMAKE_CXX_FLAGS CMAKE_C_FLAGS) foreach(variable ${variables}) if(NOT "${${variable}}" STREQUAL "") @@ -367,19 +451,42 @@ function(conan_cmake_detect_vs_runtime result) endif() endfunction() +function(_collect_settings result) + set(ARGUMENTS_PROFILE_AUTO arch build_type compiler compiler.version + compiler.runtime compiler.libcxx compiler.toolset + compiler.cppstd) + foreach(ARG ${ARGUMENTS_PROFILE_AUTO}) + string(TOUPPER ${ARG} _arg_name) + string(REPLACE "." "_" _arg_name ${_arg_name}) + if(_CONAN_SETTING_${_arg_name}) + set(detected_setings ${detected_setings} ${ARG}=${_CONAN_SETTING_${_arg_name}}) + endif() + endforeach() + set(${result} ${detected_setings} PARENT_SCOPE) +endfunction() + +function(conan_cmake_autodetect detected_settings) + _conan_detect_build_type(${ARGV}) + _conan_check_system_name() + _conan_check_language() + _conan_detect_compiler(${ARGV}) + _collect_settings(collected_settings) + set(${detected_settings} ${collected_settings} PARENT_SCOPE) +endfunction() macro(conan_parse_arguments) - set(options BASIC_SETUP CMAKE_TARGETS UPDATE KEEP_RPATHS NO_LOAD NO_OUTPUT_DIRS OUTPUT_QUIET NO_IMPORTS SKIP_STD) - set(oneValueArgs CONANFILE ARCH BUILD_TYPE INSTALL_FOLDER CONAN_COMMAND) - set(multiValueArgs DEBUG_PROFILE RELEASE_PROFILE RELWITHDEBINFO_PROFILE MINSIZEREL_PROFILE - PROFILE REQUIRES OPTIONS IMPORTS SETTINGS BUILD ENV GENERATORS PROFILE_AUTO - INSTALL_ARGS CONFIGURATION_TYPES PROFILE_BUILD) + set(options BASIC_SETUP CMAKE_TARGETS UPDATE KEEP_RPATHS NO_LOAD NO_OUTPUT_DIRS + OUTPUT_QUIET NO_IMPORTS SKIP_STD) + set(oneValueArgs CONANFILE ARCH BUILD_TYPE INSTALL_FOLDER OUTPUT_FOLDER CONAN_COMMAND) + set(multiValueArgs DEBUG_PROFILE RELEASE_PROFILE RELWITHDEBINFO_PROFILE MINSIZEREL_PROFILE + PROFILE REQUIRES OPTIONS IMPORTS SETTINGS BUILD ENV GENERATORS PROFILE_AUTO + INSTALL_ARGS CONFIGURATION_TYPES PROFILE_BUILD BUILD_REQUIRES) cmake_parse_arguments(ARGUMENTS "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) endmacro() -function(conan_cmake_install) +function(old_conan_cmake_install) # Calls "conan install" - # Argument BUILD is equivalant to --build={missing, PkgName,...} or + # Argument BUILD is equivalent to --build={missing, PkgName,...} or # --build when argument is 'BUILD all' (which builds all packages from source) # Argument CONAN_COMMAND, to specify the conan path, e.g. in case of running from source # cmake does not identify conan as command, even if it is +x and it is in the path @@ -401,32 +508,36 @@ function(conan_cmake_install) endif() endforeach() if(ARGUMENTS_CONAN_COMMAND) - set(CONAN_CMD ${ARGUMENTS_CONAN_COMMAND}) + set(CONAN_CMD ${ARGUMENTS_CONAN_COMMAND}) else() conan_check(REQUIRED) endif() set(CONAN_OPTIONS "") if(ARGUMENTS_CONANFILE) - if(IS_ABSOLUTE ${ARGUMENTS_CONANFILE}) - set(CONANFILE ${ARGUMENTS_CONANFILE}) - else() - set(CONANFILE ${CMAKE_CURRENT_SOURCE_DIR}/${ARGUMENTS_CONANFILE}) - endif() + if(IS_ABSOLUTE ${ARGUMENTS_CONANFILE}) + set(CONANFILE ${ARGUMENTS_CONANFILE}) + else() + set(CONANFILE ${CMAKE_CURRENT_SOURCE_DIR}/${ARGUMENTS_CONANFILE}) + endif() else() - set(CONANFILE ".") + set(CONANFILE ".") endif() foreach(ARG ${ARGUMENTS_OPTIONS}) - set(CONAN_OPTIONS ${CONAN_OPTIONS} -o=${ARG}) + set(CONAN_OPTIONS ${CONAN_OPTIONS} -o=${ARG}) endforeach() if(ARGUMENTS_UPDATE) - set(CONAN_INSTALL_UPDATE --update) + set(CONAN_INSTALL_UPDATE --update) endif() if(ARGUMENTS_NO_IMPORTS) - set(CONAN_INSTALL_NO_IMPORTS --no-imports) + set(CONAN_INSTALL_NO_IMPORTS --no-imports) endif() set(CONAN_INSTALL_FOLDER "") if(ARGUMENTS_INSTALL_FOLDER) - set(CONAN_INSTALL_FOLDER -if=${ARGUMENTS_INSTALL_FOLDER}) + set(CONAN_INSTALL_FOLDER -if=${ARGUMENTS_INSTALL_FOLDER}) + endif() + set(CONAN_OUTPUT_FOLDER "") + if(ARGUMENTS_OUTPUT_FOLDER) + set(CONAN_OUTPUT_FOLDER -of=${ARGUMENTS_OUTPUT_FOLDER}) endif() foreach(ARG ${ARGUMENTS_GENERATORS}) set(CONAN_GENERATORS ${CONAN_GENERATORS} -g=${ARG}) @@ -441,59 +552,320 @@ function(conan_cmake_install) if(ARGUMENTS_OUTPUT_QUIET) execute_process(COMMAND ${CONAN_CMD} ${conan_args} - RESULT_VARIABLE return_code - OUTPUT_VARIABLE conan_output - ERROR_VARIABLE conan_output - WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) + RESULT_VARIABLE return_code + OUTPUT_VARIABLE conan_output + ERROR_VARIABLE conan_output + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) else() execute_process(COMMAND ${CONAN_CMD} ${conan_args} - RESULT_VARIABLE return_code - WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) + RESULT_VARIABLE return_code + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) endif() if(NOT "${return_code}" STREQUAL "0") - message(FATAL_ERROR "Conan install failed='${return_code}'") + message(FATAL_ERROR "Conan install failed='${return_code}'") endif() endfunction() +function(conan_cmake_install) + if(DEFINED CONAN_COMMAND) + set(CONAN_CMD ${CONAN_COMMAND}) + else() + conan_check(REQUIRED) + endif() -function(conan_cmake_setup_conanfile) - conan_parse_arguments(${ARGV}) - if(ARGUMENTS_CONANFILE) - get_filename_component(_CONANFILE_NAME ${ARGUMENTS_CONANFILE} NAME) - # configure_file will make sure cmake re-runs when conanfile is updated - configure_file(${ARGUMENTS_CONANFILE} ${CMAKE_CURRENT_BINARY_DIR}/${_CONANFILE_NAME}.junk COPYONLY) - file(REMOVE ${CMAKE_CURRENT_BINARY_DIR}/${_CONANFILE_NAME}.junk) + set(installOptions UPDATE NO_IMPORTS OUTPUT_QUIET ERROR_QUIET) + set(installOneValueArgs PATH_OR_REFERENCE REFERENCE REMOTE LOCKFILE LOCKFILE_OUT LOCKFILE_NODE_ID INSTALL_FOLDER OUTPUT_FOLDER) + set(installMultiValueArgs GENERATOR BUILD ENV ENV_HOST ENV_BUILD OPTIONS_HOST OPTIONS OPTIONS_BUILD PROFILE + PROFILE_HOST PROFILE_BUILD SETTINGS SETTINGS_HOST SETTINGS_BUILD CONF CONF_HOST CONF_BUILD) + cmake_parse_arguments(ARGS "${installOptions}" "${installOneValueArgs}" "${installMultiValueArgs}" ${ARGN}) + foreach(arg ${installOptions}) + if(ARGS_${arg}) + set(${arg} ${${arg}} ${ARGS_${arg}}) + endif() + endforeach() + foreach(arg ${installOneValueArgs}) + if(DEFINED ARGS_${arg}) + if("${arg}" STREQUAL "REMOTE") + set(flag "--remote") + elseif("${arg}" STREQUAL "LOCKFILE") + set(flag "--lockfile") + elseif("${arg}" STREQUAL "LOCKFILE_OUT") + set(flag "--lockfile-out") + elseif("${arg}" STREQUAL "LOCKFILE_NODE_ID") + set(flag "--lockfile-node-id") + elseif("${arg}" STREQUAL "INSTALL_FOLDER") + set(flag "--install-folder") + elseif("${arg}" STREQUAL "OUTPUT_FOLDER") + set(flag "--output-folder") + endif() + set(${arg} ${${arg}} ${flag} ${ARGS_${arg}}) + endif() + endforeach() + foreach(arg ${installMultiValueArgs}) + if(DEFINED ARGS_${arg}) + if("${arg}" STREQUAL "GENERATOR") + set(flag "--generator") + elseif("${arg}" STREQUAL "BUILD") + set(flag "--build") + elseif("${arg}" STREQUAL "ENV") + set(flag "--env") + elseif("${arg}" STREQUAL "ENV_HOST") + set(flag "--env:host") + elseif("${arg}" STREQUAL "ENV_BUILD") + set(flag "--env:build") + elseif("${arg}" STREQUAL "OPTIONS") + set(flag "--options") + elseif("${arg}" STREQUAL "OPTIONS_HOST") + set(flag "--options:host") + elseif("${arg}" STREQUAL "OPTIONS_BUILD") + set(flag "--options:build") + elseif("${arg}" STREQUAL "PROFILE") + set(flag "--profile") + elseif("${arg}" STREQUAL "PROFILE_HOST") + set(flag "--profile:host") + elseif("${arg}" STREQUAL "PROFILE_BUILD") + set(flag "--profile:build") + elseif("${arg}" STREQUAL "SETTINGS") + set(flag "--settings") + elseif("${arg}" STREQUAL "SETTINGS_HOST") + set(flag "--settings:host") + elseif("${arg}" STREQUAL "SETTINGS_BUILD") + set(flag "--settings:build") + elseif("${arg}" STREQUAL "CONF") + set(flag "--conf") + elseif("${arg}" STREQUAL "CONF_HOST") + set(flag "--conf:host") + elseif("${arg}" STREQUAL "CONF_BUILD") + set(flag "--conf:build") + endif() + list(LENGTH ARGS_${arg} numargs) + foreach(item ${ARGS_${arg}}) + if(${item} STREQUAL "all" AND ${arg} STREQUAL "BUILD") + set(${arg} "--build") + break() + endif() + set(${arg} ${${arg}} ${flag} ${item}) + endforeach() + endif() + endforeach() + if(DEFINED UPDATE) + set(UPDATE --update) + endif() + if(DEFINED NO_IMPORTS) + set(NO_IMPORTS --no-imports) + endif() + set(install_args install ${PATH_OR_REFERENCE} ${REFERENCE} ${UPDATE} ${NO_IMPORTS} ${REMOTE} + ${LOCKFILE} ${LOCKFILE_OUT} ${LOCKFILE_NODE_ID} ${INSTALL_FOLDER} + ${OUTPUT_FOLDER} ${GENERATOR} ${BUILD} ${ENV} ${ENV_HOST} ${ENV_BUILD} + ${OPTIONS} ${OPTIONS_HOST} ${OPTIONS_BUILD} ${PROFILE} ${PROFILE_HOST} + ${PROFILE_BUILD} ${SETTINGS} ${SETTINGS_HOST} ${SETTINGS_BUILD} + ${CONF} ${CONF_HOST} ${CONF_BUILD}) + + string(REPLACE ";" " " _install_args "${install_args}") + message(STATUS "Conan executing: ${CONAN_CMD} ${_install_args}") + + if(ARGS_OUTPUT_QUIET) + set(OUTPUT_OPT OUTPUT_QUIET) + endif() + if(ARGS_ERROR_QUIET) + set(ERROR_OPT ERROR_QUIET) + endif() + + execute_process(COMMAND ${CONAN_CMD} ${install_args} + RESULT_VARIABLE return_code + ${OUTPUT_OPT} + ${ERROR_OPT} + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) + + if(NOT "${return_code}" STREQUAL "0") + if (ARGS_ERROR_QUIET) + message(WARNING "Conan install failed='${return_code}'") + else() + message(FATAL_ERROR "Conan install failed='${return_code}'") + endif() + endif() + +endfunction() + +function(conan_cmake_lock_create) + if(DEFINED CONAN_COMMAND) + set(CONAN_CMD ${CONAN_COMMAND}) else() - conan_cmake_generate_conanfile(${ARGV}) + conan_check(REQUIRED) + endif() + + set(lockCreateOptions UPDATE BASE OUTPUT_QUIET ERROR_QUIET) + set(lockCreateOneValueArgs PATH REFERENCE REMOTE LOCKFILE LOCKFILE_OUT) + set(lockCreateMultiValueArgs BUILD ENV ENV_HOST ENV_BUILD OPTIONS_HOST OPTIONS OPTIONS_BUILD PROFILE + PROFILE_HOST PROFILE_BUILD SETTINGS SETTINGS_HOST SETTINGS_BUILD) + cmake_parse_arguments(ARGS "${lockCreateOptions}" "${lockCreateOneValueArgs}" "${lockCreateMultiValueArgs}" ${ARGN}) + foreach(arg ${lockCreateOptions}) + if(ARGS_${arg}) + set(${arg} ${${arg}} ${ARGS_${arg}}) + endif() + endforeach() + foreach(arg ${lockCreateOneValueArgs}) + if(DEFINED ARGS_${arg}) + if("${arg}" STREQUAL "REMOTE") + set(flag "--remote") + elseif("${arg}" STREQUAL "LOCKFILE") + set(flag "--lockfile") + elseif("${arg}" STREQUAL "LOCKFILE_OUT") + set(flag "--lockfile-out") + endif() + set(${arg} ${${arg}} ${flag} ${ARGS_${arg}}) + endif() + endforeach() + foreach(arg ${lockCreateMultiValueArgs}) + if(DEFINED ARGS_${arg}) + if("${arg}" STREQUAL "BUILD") + set(flag "--build") + elseif("${arg}" STREQUAL "ENV") + set(flag "--env") + elseif("${arg}" STREQUAL "ENV_HOST") + set(flag "--env:host") + elseif("${arg}" STREQUAL "ENV_BUILD") + set(flag "--env:build") + elseif("${arg}" STREQUAL "OPTIONS") + set(flag "--options") + elseif("${arg}" STREQUAL "OPTIONS_HOST") + set(flag "--options:host") + elseif("${arg}" STREQUAL "OPTIONS_BUILD") + set(flag "--options:build") + elseif("${arg}" STREQUAL "PROFILE") + set(flag "--profile") + elseif("${arg}" STREQUAL "PROFILE_HOST") + set(flag "--profile:host") + elseif("${arg}" STREQUAL "PROFILE_BUILD") + set(flag "--profile:build") + elseif("${arg}" STREQUAL "SETTINGS") + set(flag "--settings") + elseif("${arg}" STREQUAL "SETTINGS_HOST") + set(flag "--settings:host") + elseif("${arg}" STREQUAL "SETTINGS_BUILD") + set(flag "--settings:build") + endif() + list(LENGTH ARGS_${arg} numargs) + foreach(item ${ARGS_${arg}}) + if(${item} STREQUAL "all" AND ${arg} STREQUAL "BUILD") + set(${arg} "--build") + break() + endif() + set(${arg} ${${arg}} ${flag} ${item}) + endforeach() + endif() + endforeach() + if(DEFINED UPDATE) + set(UPDATE --update) endif() + if(DEFINED BASE) + set(BASE --base) + endif() + set(lock_create_Args lock create ${PATH} ${REFERENCE} ${UPDATE} ${BASE} ${REMOTE} ${LOCKFILE} ${LOCKFILE_OUT} ${LOCKFILE_NODE_ID} ${INSTALL_FOLDER} + ${GENERATOR} ${BUILD} ${ENV} ${ENV_HOST} ${ENV_BUILD} ${OPTIONS} ${OPTIONS_HOST} ${OPTIONS_BUILD} + ${PROFILE} ${PROFILE_HOST} ${PROFILE_BUILD} ${SETTINGS} ${SETTINGS_HOST} ${SETTINGS_BUILD}) + + string(REPLACE ";" " " _lock_create_Args "${lock_create_Args}") + message(STATUS "Conan executing: ${CONAN_CMD} ${_lock_create_Args}") + + if(ARGS_OUTPUT_QUIET) + set(OUTPUT_OPT OUTPUT_QUIET) + endif() + if(ARGS_ERROR_QUIET) + set(ERROR_OPT ERROR_QUIET) + endif() + + execute_process(COMMAND ${CONAN_CMD} ${lock_create_Args} + RESULT_VARIABLE return_code + ${OUTPUT_OPT} + ${ERROR_OPT} + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) + + if(NOT "${return_code}" STREQUAL "0") + if (ARGS_ERROR_QUIET) + message(WARNING "Conan lock create failed='${return_code}'") + else() + message(FATAL_ERROR "Conan lock create failed='${return_code}'") + endif() + endif() +endfunction() + +function(conan_cmake_setup_conanfile) + conan_parse_arguments(${ARGV}) + if(ARGUMENTS_CONANFILE) + get_filename_component(_CONANFILE_NAME ${ARGUMENTS_CONANFILE} NAME) + # configure_file will make sure cmake re-runs when conanfile is updated + configure_file(${ARGUMENTS_CONANFILE} ${CMAKE_CURRENT_BINARY_DIR}/${_CONANFILE_NAME}.junk COPYONLY) + file(REMOVE ${CMAKE_CURRENT_BINARY_DIR}/${_CONANFILE_NAME}.junk) + else() + conan_cmake_generate_conanfile(ON ${ARGV}) + endif() endfunction() -function(conan_cmake_generate_conanfile) - # Generate, writing in disk a conanfile.txt with the requires, options, and imports - # specified as arguments - # This will be considered as temporary file, generated in CMAKE_CURRENT_BINARY_DIR) +function(conan_cmake_configure) + conan_cmake_generate_conanfile(OFF ${ARGV}) +endfunction() + +# Generate, writing in disk a conanfile.txt with the requires, options, and imports +# specified as arguments +# This will be considered as temporary file, generated in CMAKE_CURRENT_BINARY_DIR) +function(conan_cmake_generate_conanfile DEFAULT_GENERATOR) + conan_parse_arguments(${ARGV}) + set(_FN "${CMAKE_CURRENT_BINARY_DIR}/conanfile.txt") + file(WRITE ${_FN} "") - file(WRITE ${_FN} "[generators]\ncmake\n\n[requires]\n") - foreach(ARG ${ARGUMENTS_REQUIRES}) - file(APPEND ${_FN} ${ARG} "\n") - endforeach() + if(DEFINED ARGUMENTS_REQUIRES) + file(APPEND ${_FN} "[requires]\n") + foreach(REQUIRE ${ARGUMENTS_REQUIRES}) + file(APPEND ${_FN} ${REQUIRE} "\n") + endforeach() + endif() + + if (DEFAULT_GENERATOR OR DEFINED ARGUMENTS_GENERATORS) + file(APPEND ${_FN} "[generators]\n") + if (DEFAULT_GENERATOR) + file(APPEND ${_FN} "cmake\n") + endif() + if (DEFINED ARGUMENTS_GENERATORS) + foreach(GENERATOR ${ARGUMENTS_GENERATORS}) + file(APPEND ${_FN} ${GENERATOR} "\n") + endforeach() + endif() + endif() + + if(DEFINED ARGUMENTS_BUILD_REQUIRES) + file(APPEND ${_FN} "[build_requires]\n") + foreach(BUILD_REQUIRE ${ARGUMENTS_BUILD_REQUIRES}) + file(APPEND ${_FN} ${BUILD_REQUIRE} "\n") + endforeach() + endif() + + if(DEFINED ARGUMENTS_IMPORTS) + file(APPEND ${_FN} "[imports]\n") + foreach(IMPORTS ${ARGUMENTS_IMPORTS}) + file(APPEND ${_FN} ${IMPORTS} "\n") + endforeach() + endif() + + if(DEFINED ARGUMENTS_OPTIONS) + file(APPEND ${_FN} "[options]\n") + foreach(OPTION ${ARGUMENTS_OPTIONS}) + file(APPEND ${_FN} ${OPTION} "\n") + endforeach() + endif() - file(APPEND ${_FN} ${ARG} "\n[imports]\n") - foreach(ARG ${ARGUMENTS_IMPORTS}) - file(APPEND ${_FN} ${ARG} "\n") - endforeach() endfunction() macro(conan_load_buildinfo) if(CONAN_CMAKE_MULTI) - set(_CONANBUILDINFO conanbuildinfo_multi.cmake) + set(_CONANBUILDINFO conanbuildinfo_multi.cmake) else() - set(_CONANBUILDINFO conanbuildinfo.cmake) + set(_CONANBUILDINFO conanbuildinfo.cmake) endif() if(ARGUMENTS_INSTALL_FOLDER) set(_CONANBUILDINFOFOLDER ${ARGUMENTS_INSTALL_FOLDER}) @@ -503,10 +875,10 @@ macro(conan_load_buildinfo) # Checks for the existence of conanbuildinfo.cmake, and loads it # important that it is macro, so variables defined at parent scope if(EXISTS "${_CONANBUILDINFOFOLDER}/${_CONANBUILDINFO}") - message(STATUS "Conan: Loading ${_CONANBUILDINFO}") - include(${_CONANBUILDINFOFOLDER}/${_CONANBUILDINFO}) + message(STATUS "Conan: Loading ${_CONANBUILDINFO}") + include(${_CONANBUILDINFOFOLDER}/${_CONANBUILDINFO}) else() - message(FATAL_ERROR "${_CONANBUILDINFO} doesn't exist in ${CMAKE_CURRENT_BINARY_DIR}") + message(FATAL_ERROR "${_CONANBUILDINFO} doesn't exist in ${CMAKE_CURRENT_BINARY_DIR}") endif() endmacro() @@ -537,17 +909,17 @@ macro(conan_cmake_run) foreach(CMAKE_BUILD_TYPE ${ARGUMENTS_CONFIGURATION_TYPES}) set(ENV{CONAN_IMPORT_PATH} ${CMAKE_BUILD_TYPE}) conan_cmake_settings(settings ${ARGV}) - conan_cmake_install(SETTINGS ${settings} ${ARGV}) + old_conan_cmake_install(SETTINGS ${settings} ${ARGV}) endforeach() set(CMAKE_BUILD_TYPE) else() conan_cmake_settings(settings ${ARGV}) - conan_cmake_install(SETTINGS ${settings} ${ARGV}) + old_conan_cmake_install(SETTINGS ${settings} ${ARGV}) endif() endif() if (NOT ARGUMENTS_NO_LOAD) - conan_load_buildinfo() + conan_load_buildinfo() endif() if(ARGUMENTS_BASIC_SETUP) @@ -564,6 +936,30 @@ macro(conan_cmake_run) endif() endmacro() +function(conan_version result) + set(${result} "" PARENT_SCOPE) + + if(NOT CONAN_CMD) + find_program(CONAN_CMD conan) + if(NOT CONAN_CMD AND CONAN_REQUIRED) + message(FATAL_ERROR "Conan executable not found! Please install conan.") + endif() + endif() + + execute_process(COMMAND ${CONAN_CMD} --version + RESULT_VARIABLE return_code + OUTPUT_VARIABLE CONAN_VERSION_OUTPUT + ERROR_VARIABLE CONAN_VERSION_OUTPUT) + + if(NOT "${return_code}" STREQUAL "0") + message(FATAL_ERROR "Conan --version failed='${return_code}'") + endif() + + string(REGEX MATCH ".*Conan version ([0-9]+\\.[0-9]+\\.[0-9]+)" FOO "${CONAN_VERSION_OUTPUT}") + + set(${result} ${CMAKE_MATCH_1} PARENT_SCOPE) +endfunction() + macro(conan_check) # Checks conan availability in PATH # Arguments REQUIRED, DETECT_QUIET and VERSION are optional @@ -583,18 +979,16 @@ macro(conan_check) if(NOT CONAN_DETECT_QUIET) message(STATUS "Conan: Found program ${CONAN_CMD}") endif() - execute_process(COMMAND ${CONAN_CMD} --version - OUTPUT_VARIABLE CONAN_VERSION_OUTPUT - ERROR_VARIABLE CONAN_VERSION_OUTPUT) + + conan_version(CONAN_DETECTED_VERSION) + if(NOT CONAN_DETECT_QUIET) - message(STATUS "Conan: Version found ${CONAN_VERSION_OUTPUT}") + message(STATUS "Conan: Version found ${CONAN_DETECTED_VERSION}") endif() if(DEFINED CONAN_VERSION) - string(REGEX MATCH ".*Conan version ([0-9]+\\.[0-9]+\\.[0-9]+)" FOO - "${CONAN_VERSION_OUTPUT}") - if(${CMAKE_MATCH_1} VERSION_LESS ${CONAN_VERSION}) - message(FATAL_ERROR "Conan outdated. Installed: ${CMAKE_MATCH_1}, \ + if(${CONAN_DETECTED_VERSION} VERSION_LESS ${CONAN_VERSION}) + message(FATAL_ERROR "Conan outdated. Installed: ${CONAN_DETECTED_VERSION}, \ required: ${CONAN_VERSION}. Consider updating via 'pip \ install conan==${CONAN_VERSION}'.") endif() @@ -617,14 +1011,18 @@ function(conan_add_remote) if(DEFINED CONAN_COMMAND) set(CONAN_CMD ${CONAN_COMMAND}) else() - conan_check(REQUIRED) + conan_check(REQUIRED DETECT_QUIET) endif() set(CONAN_VERIFY_SSL_ARG "True") if(DEFINED CONAN_VERIFY_SSL) set(CONAN_VERIFY_SSL_ARG ${CONAN_VERIFY_SSL}) endif() message(STATUS "Conan: Adding ${CONAN_NAME} remote repository (${CONAN_URL}) verify ssl (${CONAN_VERIFY_SSL_ARG})") - execute_process(COMMAND ${CONAN_CMD} remote add ${CONAN_NAME} ${CONAN_INDEX_ARG} -f ${CONAN_URL} ${CONAN_VERIFY_SSL_ARG}) + execute_process(COMMAND ${CONAN_CMD} remote add ${CONAN_NAME} ${CONAN_INDEX_ARG} -f ${CONAN_URL} ${CONAN_VERIFY_SSL_ARG} + RESULT_VARIABLE return_code) + if(NOT "${return_code}" STREQUAL "0") + message(FATAL_ERROR "Conan remote failed='${return_code}'") + endif() endfunction() macro(conan_config_install) @@ -637,37 +1035,112 @@ macro(conan_config_install) set(multiValueArgs ARGS) cmake_parse_arguments(CONAN "" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) - find_program(CONAN_CMD conan) - if(NOT CONAN_CMD AND CONAN_REQUIRED) - message(FATAL_ERROR "Conan executable not found!") + if(DEFINED CONAN_COMMAND) + set(CONAN_CMD ${CONAN_COMMAND}) + else() + conan_check(REQUIRED) endif() if(DEFINED CONAN_VERIFY_SSL) - set(CONAN_VERIFY_SSL_ARG "--verify-ssl=${CONAN_VERIFY_SSL}") + set(CONAN_VERIFY_SSL_ARG "--verify-ssl=${CONAN_VERIFY_SSL}") endif() if(DEFINED CONAN_TYPE) - set(CONAN_TYPE_ARG "--type=${CONAN_TYPE}") + set(CONAN_TYPE_ARG "--type=${CONAN_TYPE}") endif() if(DEFINED CONAN_ARGS) - set(CONAN_ARGS_ARGS "--args=\"${CONAN_ARGS}\"") + # Convert ; seperated multi arg list into space seperated string + string(REPLACE ";" " " l_CONAN_ARGS "${CONAN_ARGS}") + set(CONAN_ARGS_ARGS "--args=${l_CONAN_ARGS}") endif() if(DEFINED CONAN_SOURCE) - set(CONAN_SOURCE_ARGS "--source-folder=${CONAN_SOURCE}") + set(CONAN_SOURCE_ARGS "--source-folder=${CONAN_SOURCE}") endif() if(DEFINED CONAN_TARGET) - set(CONAN_TARGET_ARGS "--target-folder=${CONAN_TARGET}") + set(CONAN_TARGET_ARGS "--target-folder=${CONAN_TARGET}") endif() set (CONAN_CONFIG_INSTALL_ARGS ${CONAN_VERIFY_SSL_ARG} - ${CONAN_TYPE_ARG} - ${CONAN_ARGS_ARGS} - ${CONAN_SOURCE_ARGS} - ${CONAN_TARGET_ARGS}) + ${CONAN_TYPE_ARG} + ${CONAN_ARGS_ARGS} + ${CONAN_SOURCE_ARGS} + ${CONAN_TARGET_ARGS}) message(STATUS "Conan: Installing config from ${CONAN_ITEM}") - execute_process(COMMAND ${CONAN_CMD} config install ${CONAN_ITEM} ${CONAN_CONFIG_INSTALL_ARGS}) + execute_process(COMMAND ${CONAN_CMD} config install ${CONAN_ITEM} ${CONAN_CONFIG_INSTALL_ARGS} + RESULT_VARIABLE return_code) + if(NOT "${return_code}" STREQUAL "0") + message(FATAL_ERROR "Conan config failed='${return_code}'") + endif() endmacro() + + +function(conan_cmake_profile) + set(profileOneValueArgs FILEPATH INCLUDE) + set(profileMultiValueArgs SETTINGS OPTIONS CONF ENV BUILDENV RUNENV TOOL_REQUIRES) + cmake_parse_arguments(ARGS "" "${profileOneValueArgs}" "${profileMultiValueArgs}" ${ARGN}) + + if(DEFINED ARGS_FILEPATH) + set(_FN "${ARGS_FILEPATH}") + else() + set(_FN "${CMAKE_CURRENT_BINARY_DIR}/profile") + endif() + message(STATUS "Conan: Creating profile ${_FN}") + file(WRITE ${_FN} "") + + if(DEFINED ARGS_INCLUDE) + file(APPEND ${_FN} "include(${ARGS_INCLUDE})\n") + endif() + + if(DEFINED ARGS_SETTINGS) + file(APPEND ${_FN} "[settings]\n") + foreach(SETTING ${ARGS_SETTINGS}) + file(APPEND ${_FN} ${SETTING} "\n") + endforeach() + endif() + + if(DEFINED ARGS_OPTIONS) + file(APPEND ${_FN} "[options]\n") + foreach(OPTION ${ARGS_OPTIONS}) + file(APPEND ${_FN} ${OPTION} "\n") + endforeach() + endif() + + if(DEFINED ARGS_CONF) + file(APPEND ${_FN} "[conf]\n") + foreach(CONF ${ARGS_CONF}) + file(APPEND ${_FN} ${CONF} "\n") + endforeach() + endif() + + if(DEFINED ARGS_ENV) + file(APPEND ${_FN} "[env]\n") + foreach(ENV ${ARGS_ENV}) + file(APPEND ${_FN} ${ENV} "\n") + endforeach() + endif() + + if(DEFINED ARGS_BUILDENV) + file(APPEND ${_FN} "[buildenv]\n") + foreach(BUILDENV ${ARGS_BUILDENV}) + file(APPEND ${_FN} ${BUILDENV} "\n") + endforeach() + endif() + + if(DEFINED ARGS_RUNENV) + file(APPEND ${_FN} "[runenv]\n") + foreach(RUNENV ${ARGS_RUNENV}) + file(APPEND ${_FN} ${RUNENV} "\n") + endforeach() + endif() + + if(DEFINED ARGS_TOOL_REQUIRES) + file(APPEND ${_FN} "[tool_requires]\n") + foreach(TOOL_REQUIRE ${ARGS_TOOL_REQUIRES}) + file(APPEND ${_FN} ${TOOL_REQUIRE} "\n") + endforeach() + endif() +endfunction() \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index 7894e09c..274fe8f9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -71,6 +71,7 @@ if (MSVC) add_compile_options( # treat warnings as errors /WX + /wd4996 ) add_link_options( diff --git a/notes/newart.png b/notes/newart.png new file mode 100644 index 00000000..2e7bd2d5 Binary files /dev/null and b/notes/newart.png differ diff --git a/notes/strawberry-lake.md b/notes/strawberry-lake.md new file mode 100644 index 00000000..96b2c622 --- /dev/null +++ b/notes/strawberry-lake.md @@ -0,0 +1,25 @@ +# Manufactring +# Distribution +# Laundering +# Legal + + +# Marijuana + +* pots +* soil +* lights + - different types yield different results +* fans + +# Cocaine + +# Meth + +# Heroin + +# Crack + +# Mushrooms + +# \ No newline at end of file diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index d5279d94..5e3bef0c 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -4,6 +4,7 @@ set(SOURCE_FILES Background.cpp DelayedSound.cpp Engine.cpp + GameState.cpp GameWorld.cpp Intersection.cpp Item.cpp @@ -47,8 +48,9 @@ set(HEADER_FILES Engine.h Item.h ItemFactory.h - GameWorld.h + GameState.h GameTypes.h + GameWorld.h Intersection.h Path.hpp PathFactory.h diff --git a/src/GameState.cpp b/src/GameState.cpp new file mode 100644 index 00000000..c68cc519 --- /dev/null +++ b/src/GameState.cpp @@ -0,0 +1,43 @@ +#include "TTUtils.h" +#include "GameState.h" + +namespace tt +{ + +void from_json(const nl::json& j, GameState& gs) +{ + j["player"].get_to(gs.playerstate); + j["location"].get_to(gs.location); +} + +void to_json(nl::json& j, const GameState& gs) +{ + j["player"] = gs.playerstate; + j["location"] = gs.location; +} + +void from_json(const nl::json& j, PlayerLocation& pl) +{ + j["map"].get_to(pl.map); + j["cords"].get_to(pl.cords); +} + +void to_json(nl::json& j, const PlayerLocation& pl) +{ + j["map"] = pl.map; + j["cords"] = pl.cords; +} + +void from_json(const nl::json& j, PlayerState& ps) +{ + j["health"].get_to(ps.health); + j["cash"].get_to(ps.cash); +} + +void to_json(nl::json& j, const PlayerState& ps) +{ + j["health"] = ps.health; + j["cash"] = ps.cash; +} + +} // namespace tt diff --git a/src/GameState.h b/src/GameState.h new file mode 100644 index 00000000..83a83dfa --- /dev/null +++ b/src/GameState.h @@ -0,0 +1,47 @@ +#pragma + +#include + +#include + +#include + +#include "Player.h" +#include "TTUtils.h" + +namespace tt +{ + +struct GameState; +using GameStatePtr = std::shared_ptr; + +void from_json(const nl::json& j, GameState& pl); +void to_json(nl::json& j, const GameState& b); + +struct PlayerLocation; +void from_json(const nl::json& j, PlayerLocation& pl); +void to_json(nl::json& j, const PlayerLocation& b); + +struct PlayerState; +void from_json(const nl::json& j, PlayerState& pl); +void to_json(nl::json& j, const PlayerState& b); + +struct PlayerLocation +{ + std::string map; + sf::Vector2f cords; +}; + +struct PlayerState +{ + std::uint32_t health = 0; + float cash = 0.f; +}; + +struct GameState +{ + PlayerState playerstate; + PlayerLocation location; +}; + +} // namespace tt diff --git a/src/Item.h b/src/Item.h index 2ed3ae3d..b1247136 100644 --- a/src/Item.h +++ b/src/Item.h @@ -99,6 +99,7 @@ struct ItemCallbacks struct ItemInstanceInfo { std::string objid; // the id of the object this is an instance of + std::optional index; // index of the object in an "instances" array // a null x,y means that the coordinate was not specified, // and a value of -1 means it should be picked randomly @@ -112,6 +113,14 @@ struct ItemInstanceInfo ItemCallbacks callbacks; + ItemInstanceInfo() = default; + ItemInstanceInfo(std::uint32_t idx) + : index{idx} + { + // nothing to do + } + + // will apply the default values if they are set in the `defaults` object // and *not* set in this object. // NOTE: We cannot use a constructor since these objects are constructed diff --git a/src/Player.cpp b/src/Player.cpp index 39579b5c..5f966685 100644 --- a/src/Player.cpp +++ b/src/Player.cpp @@ -6,8 +6,16 @@ namespace tt { -void from_json(const nl::json & j, Player & i) +void from_json(const nl::json& j, Player& p) { + j["health"].get_to(p._health); + j["cash"].get_to(p._cash); +} + +void to_json(nl::json& j, const Player& p) +{ + j["health"] = p.health(); + j["cash"] = p.balance(); } namespace diff --git a/src/Player.h b/src/Player.h index 7ab78a8b..b2470988 100644 --- a/src/Player.h +++ b/src/Player.h @@ -11,7 +11,9 @@ namespace tt class Player; using PlayerPtr = std::shared_ptr; + void from_json(const nl::json& j, Player& i); +void to_json(nl::json& j, const Player& p); class Player : public Item { @@ -19,6 +21,8 @@ class Player : public Item static constexpr auto CLASS_NAME = "Player"; static const struct luaL_Reg LuaMethods[]; + friend void from_json(const nl::json& j, Player& i); + using Item::Item; sf::Vector2f getGlobalCenter() const; diff --git a/src/Scenes/Scene.cpp b/src/Scenes/Scene.cpp index 1aadcfa2..31a34771 100644 --- a/src/Scenes/Scene.cpp +++ b/src/Scenes/Scene.cpp @@ -724,12 +724,14 @@ void Scene::createItems() ItemInstanceInfo groupinfo = data.get(); groupinfo.objid = itemid; // we don't want to require the objid to be set in json - for (const auto& instance : data["instances"]) + for (const auto& instance : (data["instances"] | boost::adaptors::indexed())) { - auto instanceinfo = instance.get(); + auto instanceinfo = instance.value().get(); + instanceinfo.index = static_cast(instance.index()); + instanceinfo.applyDefaults(groupinfo); - auto groupcallbacks = instance.get(); + auto groupcallbacks = instance.value().get(); auto item = _itemFactory.createItem(instanceinfo); if (item) placeItem(item); } diff --git a/src/Screens/GameScreen.h b/src/Screens/GameScreen.h index 5812f223..59470db2 100644 --- a/src/Screens/GameScreen.h +++ b/src/Screens/GameScreen.h @@ -15,6 +15,7 @@ #include "../GameWorld.h" #include "../Settings.h" #include "../AudioService.h" +#include "../GameState.h" #include "Screen.h" @@ -221,6 +222,7 @@ class GameScreen final : public Screen sf::Clock _gameClock; std::shared_ptr _gameCalendar; + tt::GameState _gameState; std::shared_ptr _hud; }; diff --git a/src/Screens/IntroScreen.cpp b/src/Screens/IntroScreen.cpp index 12172948..006b27be 100644 --- a/src/Screens/IntroScreen.cpp +++ b/src/Screens/IntroScreen.cpp @@ -12,60 +12,9 @@ namespace tt { -namespace -{ - - -void createMenu(TextList& menuItems, - const std::vector& textlist, - sf::RenderTarget& window, - sf::Font& font) -{ - - for (const auto& text : textlist) - { - auto temp = std::make_shared(text, font); - menuItems.push_back(temp); - } - - auto ypos = 300.0f; - - for (const auto& item: menuItems) - { - item->setCharacterSize(40); - - // - // Calculate xpos (right align) - // - auto winWidth = window.getSize().x; - auto itemWidth = item->getLocalBounds().width; - auto xpos = (winWidth - itemWidth) - 50.f; - - item->setPosition(xpos, ypos); - - item->setOutlineColor(sf::Color(0,0,0,255)); - item->setOutlineThickness(5); - - // - // Increment ypos to the next item position - // - ypos += item->getLocalBounds().height + 20.0f; - } - -} - -void updateMenu(std::uint16_t selection, TextList& menuItems) -{ - std::for_each(menuItems.begin(), menuItems.end(), - [](TextPtr item) { item->setFillColor(sf::Color(64, 64, 64)); }); - - if (selection < menuItems.size()) - { - menuItems.at(selection)->setFillColor(sf::Color::Yellow); - } -} - -} +constexpr auto BUTTON_HEIGHT = 35u; +constexpr auto BUTTON_WIDTH = 125u; +constexpr auto BUTTON_PADDING = 25u; IntroScreen::IntroScreen( ResourceManager& resmgr, sf::RenderTarget& target ) @@ -172,87 +121,220 @@ IntroScreen::IntroScreen( ResourceManager& resmgr, // addDrawable(textobj); - // - // Add the menu items - // - createMenu(_menuItems, - { - "Play Game", - "Settings", - "Exit Game" - }, _window, _font); - - updateMenu(_selected, _menuItems); - - for (const auto& item: _menuItems) - { - addDrawable(item); - } - tt::AudioLocator::sound()->cacheAudio(SELECTOR_SOUND); tt::AudioLocator::sound()->cacheAudio(TOMWILLKILL_SOUND); + + initGui(); } -PollResult IntroScreen::poll(const sf::Event& e) +void IntroScreen::initGui() { - if (e.type == sf::Event::KeyReleased - && e.key.code == sf::Keyboard::Up) + auto xloc = _window.getSize().x - (BUTTON_WIDTH + BUTTON_PADDING); + auto yloc = (_window.getSize().y / 2) - ((BUTTON_HEIGHT + BUTTON_PADDING) * 2); + + _gui = std::make_unique(_window); + + // New Game + auto tempbtn = tgui::Button::create(); + tempbtn->setText("New Game"); + tempbtn->setSize(BUTTON_WIDTH, BUTTON_HEIGHT); + tempbtn->setPosition(xloc, yloc); + tempbtn->getRenderer()->setBackgroundColor(tgui::Color::White); + tempbtn->getRenderer()->setBackgroundColorHover(tgui::Color::Green); + tempbtn->onMouseEnter([this]() { tt::AudioLocator::sound()->play(SELECTOR_SOUND); }); + tempbtn->onPress([=] { - if (_selected > 0) - { - _selected--; - updateMenu(_selected, _menuItems); - tt::AudioLocator::sound()->play(SELECTOR_SOUND); - } - } - else if (e.type == sf::Event::KeyReleased - && e.key.code == sf::Keyboard::Down) + _menuAction.action.type = ScreenActionType::CHANGE_SCREEN; + _menuAction.action.data = SCREEN_LOADING; + }); + _gui->add(tempbtn); + + // Load Game + tempbtn = tgui::Button::create(); + tempbtn->setText("Load Game"); + tempbtn->setSize(BUTTON_WIDTH, BUTTON_HEIGHT); + yloc += BUTTON_HEIGHT + BUTTON_PADDING; + tempbtn->setPosition(xloc, yloc); + tempbtn->getRenderer()->setBackgroundColor(tgui::Color::White); + tempbtn->getRenderer()->setBackgroundColorHover(tgui::Color::Green); + tempbtn->onMouseEnter([this]() { tt::AudioLocator::sound()->play(SELECTOR_SOUND); }); + _gui->add(tempbtn); + + // Options + tempbtn = tgui::Button::create(); + tempbtn->setText("Options"); + tempbtn->setSize(BUTTON_WIDTH, BUTTON_HEIGHT); + yloc += BUTTON_HEIGHT + BUTTON_PADDING; + tempbtn->setPosition(xloc, yloc); + tempbtn->getRenderer()->setBackgroundColor(tgui::Color::White); + tempbtn->getRenderer()->setBackgroundColorHover(tgui::Color::Green); + tempbtn->onMouseEnter([this]() { tt::AudioLocator::sound()->play(SELECTOR_SOUND); }); + tempbtn->onPress([=] { - if (_selected < _menuItems.size() - 1) - { - _selected++; - updateMenu(_selected, _menuItems); - - tt::AudioLocator::sound()->play(SELECTOR_SOUND); - } - } - else if (e.type == sf::Event::KeyPressed - && (e.key.code == sf::Keyboard::Space - || e.key.code == sf::Keyboard::Enter)) + _menuAction.action.type = ScreenActionType::CHANGE_SCREEN; + _menuAction.action.data = SCREEN_SETTINGS; + }); + _gui->add(tempbtn); + + // Exit + tempbtn = tgui::Button::create(); + tempbtn->setText("Exit Game"); + tempbtn->setSize(BUTTON_WIDTH, BUTTON_HEIGHT); + yloc += BUTTON_HEIGHT + BUTTON_PADDING; + tempbtn->setPosition(xloc, yloc); + tempbtn->getRenderer()->setBackgroundColor(tgui::Color::White); + tempbtn->getRenderer()->setBackgroundColorHover(tgui::Color::Green); + tempbtn->onMouseEnter([this]() { tt::AudioLocator::sound()->play(SELECTOR_SOUND); }); + tempbtn->onPress([=] { - switch (_selected) + tt::AudioLocator::music()->stop(BACKGROUND_SONG); + tt::AudioLocator::sound()->play(TOMWILLKILL_SOUND); + + while (tt::AudioLocator::sound()->getStatus(TOMWILLKILL_SOUND) == sf::Sound::Playing) { - default: - break; + std::this_thread::yield(); + } - case 0: // play game - { - return {true, { ScreenActionType::CHANGE_SCREEN, SCREEN_LOADING }}; - } + // super hack! I'm too lazy and don't care enough right now + sf::RenderWindow* window = dynamic_cast(&_window); + window->close(); + }); + _gui->add(tempbtn); - case 1: // settings - { - return {true, { ScreenActionType::CHANGE_SCREEN, SCREEN_SETTINGS }}; - } + auto temptext = tgui::TextArea::create(); - case 2: // exit - { - tt::AudioLocator::music()->stop(BACKGROUND_SONG); - tt::AudioLocator::sound()->play(TOMWILLKILL_SOUND); +} - while (tt::AudioLocator::sound()->getStatus(TOMWILLKILL_SOUND) == sf::Sound::Playing) - { - std::this_thread::yield(); - } +void IntroScreen::draw() +{ + Screen::draw(); + if (_gui) _gui->draw(); +} - // super hack! I'm too lazy and don't care enough right now - sf::RenderWindow* window = dynamic_cast(&_window); - window->close(); - } - break; +PollResult IntroScreen::poll(const sf::Event& e) +{ + if (_gui) + { + _gui->handleEvent(e); + + if (e.type == sf::Event::KeyReleased + && e.key.code == sf::Keyboard::Escape) + { + _gui.reset(); + } + + if (_menuAction.action.type != tt::ScreenActionType::NONE) + { + return { true, _menuAction.action }; } } +// if (e.type == sf::Event::KeyReleased +// && e.key.code == sf::Keyboard::Up) +// { +// if (_selected > 0) +// { +// _selected--; +// updateMenu(_selected, _menuItems); +// tt::AudioLocator::sound()->play(SELECTOR_SOUND); +// } +// } +// else if (e.type == sf::Event::KeyReleased +// && e.key.code == sf::Keyboard::Down) +// { +// if (_selected < _menuItems.size() - 1) +// { +// _selected++; +// updateMenu(_selected, _menuItems); +// +// tt::AudioLocator::sound()->play(SELECTOR_SOUND); +// } +// } +// else if (e.type == sf::Event::KeyPressed +// && (e.key.code == sf::Keyboard::Space +// || e.key.code == sf::Keyboard::Enter)) +// { +// switch (_selected) +// { +// default: +// break; +// +// case 0: // new game +// { +// _gui = std::make_unique(_window); +// +// auto windowSize = _window.getSize(); +// auto halfWindowWidth = windowSize.x / 2; +// +// auto child = tgui::ChildWindow::create(); +// child->setClientSize({500, 200}); +// auto xpos = (_window.getSize().x / 2) - (child->getSize().x / 2); +// auto ypos = (_window.getSize().y / 2) - (child->getSize().y / 2); +// child->setPosition(xpos, ypos); +// child->setTitleButtons(tgui::ChildWindow::TitleButton::None); +// _gui->add(child); +// +// auto editLbl = tgui::Label::create("Enter name for new game"); +// editLbl->setPosition(20,20); +// editLbl->setTextSize(30); +// child->add(editLbl); +// +// auto editBox = tgui::EditBox::create(); +// editBox->setPosition(20,75); +// editBox->setTextSize(30); +// editBox->setSize(460,35); +// child->add(editBox); +// +// auto okBtn = tgui::Button::create("Ok"); +// okBtn->setWidgetName("sds"); +// okBtn->setSize(50, 45); +// xpos = (child->getSize().x / 2) - (okBtn->getSize().x + 20); +// okBtn->setPosition(xpos, 125); +// child->add(okBtn); +// +// auto cancelBtn = tgui::Button::create("Cancel"); +// cancelBtn->setSize(65, 45); +// xpos = (child->getSize().x / 2) + 20; +// cancelBtn->setPosition(xpos, 125); +// cancelBtn->onPress([=] +// { +// _gui.reset(); +// }); +// child->add(cancelBtn); +// +// editBox->setFocused(true); +// +// break; +// } +// +// case 1: // load game +// { +// return {true, { ScreenActionType::CHANGE_SCREEN, SCREEN_LOADING }}; +// } +// +// case 2: // settings +// { +// return {true, { ScreenActionType::CHANGE_SCREEN, SCREEN_SETTINGS }}; +// } +// +// case 3: // exit +// { +// tt::AudioLocator::music()->stop(BACKGROUND_SONG); +// tt::AudioLocator::sound()->play(TOMWILLKILL_SOUND); +// +// while (tt::AudioLocator::sound()->getStatus(TOMWILLKILL_SOUND) == sf::Sound::Playing) +// { +// std::this_thread::yield(); +// } +// +// // super hack! I'm too lazy and don't care enough right now +// sf::RenderWindow* window = dynamic_cast(&_window); +// window->close(); +// } +// break; +// } +// } + return {}; } diff --git a/src/Screens/IntroScreen.h b/src/Screens/IntroScreen.h index a0fc19ca..17e7f98f 100644 --- a/src/Screens/IntroScreen.h +++ b/src/Screens/IntroScreen.h @@ -2,6 +2,8 @@ #include +#include + #include "Screen.h" #include "../TooterLogger.h" @@ -16,15 +18,20 @@ class IntroScreen : public Screen { public: inline static constexpr auto BACKGROUND_SONG = "music/intro.wav"; - inline static constexpr auto SELECTOR_SOUND = "sounds/selector.wav"; + inline static constexpr auto SELECTOR_SOUND = "sounds/selector2.wav"; inline static constexpr auto TOMWILLKILL_SOUND = "sounds/tomwillkill.wav"; IntroScreen(ResourceManager& res, sf::RenderTarget& target); + void draw() override; PollResult poll(const sf::Event& e) override; + ScreenAction update() override; void close() override; +private: // methods + void initGui(); + private: static const int INTRO_IMAGES = 8; @@ -39,6 +46,11 @@ class IntroScreen : public Screen std::vector _sprite; sf::Clock _clock; + + tt::PollResult _menuAction; + + std::unique_ptr _gui; + }; diff --git a/src/TTUtils.cpp b/src/TTUtils.cpp index 0bf05971..4321f862 100644 --- a/src/TTUtils.cpp +++ b/src/TTUtils.cpp @@ -2,6 +2,7 @@ # include # include # include +# include #else # include # include @@ -63,6 +64,24 @@ void from_json(const nl::json& j, Vector2u& v) } } +void to_json(nl::json& j, const Vector2f& v) +{ + j["x"] = v.x; + j["y"] = v.y; +} + +void to_json(nl::json& j, const Vector2i& v) +{ + j["x"] = v.x; + j["y"] = v.y; +} + +void to_json(nl::json& j, const Vector2u& v) +{ + j["x"] = v.x; + j["y"] = v.y; +} + } namespace tt @@ -132,6 +151,27 @@ std::string getOsString() #endif } +#ifdef _WINDOWS +std::string getWindowsFolder(int csidl) +{ + std::string retval; + + WCHAR path[MAX_PATH]; + if (SUCCEEDED(SHGetFolderPathW(NULL, csidl, NULL, 0, path))) + { + std::wstring temp(path); + std::wstring_convert> convert; + retval = convert.to_bytes(temp); + } + else + { + throw std::runtime_error("could not retrieve user folder"); + } + + return retval; +} +#endif + std::string getUserFolder() { std::string retval; @@ -156,4 +196,18 @@ retval = pw->pw_dir; return retval; } +std::string getDataFolder() +{ + std::string retval; + +#ifdef _WINDOWS + retval = getWindowsFolder(CSIDL_COMMON_APPDATA); +#else + struct passwd *pw = getpwuid(getuid()); + retval = pw->pw_dir; +#endif + + return retval; +} + } // namespace tt diff --git a/src/TTUtils.h b/src/TTUtils.h index 8578f849..0ca492bc 100644 --- a/src/TTUtils.h +++ b/src/TTUtils.h @@ -6,6 +6,8 @@ #include #include +#include + #include #include @@ -14,6 +16,16 @@ namespace nl = nlohmann; +// There's some weirdness going on in Ubuntu where using the / operator +// on Ubuntu was throwing an error in some instances. Instead I set out +// to use boost::filesystem::path::seperator but that turned out to be +// a pain since it is multibyte on Windows! So I did this manually. +#ifdef _WINDOWS +# define PATH_SEPERATOR '\\' +#else +# define PATH_SEPERATOR '/' +#endif + namespace sf { @@ -21,6 +33,10 @@ void from_json(const nl::json& j, Vector2f& v); void from_json(const nl::json& j, Vector2i& v); void from_json(const nl::json& j, Vector2u& v); +void to_json(nl::json& j, const Vector2f& v); +void to_json(nl::json& j, const Vector2i& v); +void to_json(nl::json& j, const Vector2u& v); + template void from_json(const nl::json& j, sf::Rect& r) { @@ -165,5 +181,7 @@ inline float distance(const sf::Vector2f& v1, const sf::Vector2f& v2) void openBrowser(const std::string& url_str); std::string getOsString(); std::string getUserFolder(); +std::string getDataFolder(); + } // namespace tt diff --git a/src/main.cpp b/src/main.cpp index 7ca615d0..53975c43 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -63,6 +63,13 @@ amb::SettingsPtr registerSettings() retval->registerBool("logs.sfx.enabled", false); retval->registerBool("video.fullscreen", true); + // default gamedb folder + const std::string dbfolder = fmt::format("{}{}{}", + tt::getDataFolder(), PATH_SEPERATOR, "TommyTuscon"); + + retval->registerString("database.gamefolder", dbfolder, + std::make_shared()); + return retval; } @@ -103,6 +110,15 @@ void initLogging(std::string_view logfile) } } +void initGameFolder(const std::string& gamefolder) +{ + fs::path folder = gamefolder; + if (!fs::exists(folder)) + { + fs::create_directories(folder); + } +} + int main(int argc, char *argv[]) { po::options_description desc("Allowed options"); @@ -184,6 +200,9 @@ int main(int argc, char *argv[]) return 1; } + // make sure the game folder exists before we start up + initGameFolder(settings->value("database.gamefolder", ""s)); + std::size_t width = window_width; std::size_t height = window_height; if (vm.count("window-size") > 0) @@ -266,6 +285,7 @@ int main(int argc, char *argv[]) win->display(); } + settings->save(); logger->info("game shut down"); return 0; } diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 605879a3..7b03b027 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -35,7 +35,10 @@ set(PROJECT_FILES ../src/DelayedSound.h ../src/DelayedSound.cpp - + + ../src/GameState.h + ../src/GameState.cpp + ../src/Intersection.h ../src/Intersection.cpp diff --git a/tests/test_misc.cpp b/tests/test_misc.cpp index 1756630e..f7660ca5 100644 --- a/tests/test_misc.cpp +++ b/tests/test_misc.cpp @@ -13,12 +13,14 @@ #include "../src/TTUtils.h" #include "../src/Intersection.h" #include "../src/PathFactory.h" +#include "../src/GameState.h" #include "Test.h" using namespace std::string_literals; namespace data = boost::unit_test::data; +namespace fs = boost::filesystem; namespace std { @@ -423,4 +425,35 @@ BOOST_AUTO_TEST_CASE(oneBitSetTest) BOOST_TEST(tt::exactly_one_bit_set(direction) == true); } +BOOST_AUTO_TEST_CASE(gameStateSave) +{ + const auto filename = tt::tempFolder() / "gamestate-test.json"; + + sf::Texture playerTexture; + tt::ItemInfo playerObjInfo; + playerObjInfo.size = sf::Vector2u{ 10, 10 }; + playerObjInfo.texture = &playerTexture; + + tt::GameState gameState; + gameState.playerstate.cash = 69.69; + gameState.playerstate.health = 12; + + gameState.location.map = "TestMap"; + gameState.location.cords = sf::Vector2f{12.34, 56.78}; + + { + std::ofstream o{ filename.c_str() }; + nl::json json = gameState; + o << json.dump(); + } + + { + std::ifstream ifs(filename.c_str()); + nl::json jf = nl::json::parse(ifs); + tt::GameState readState = jf.get(); + BOOST_TEST(readState.playerstate.health == gameState.playerstate.health); + } +// const auto path{ }; +} + BOOST_AUTO_TEST_SUITE_END() // tt