CMAKE_MINIMUM_REQUIRED(VERSION 3.17.0)

IF(DEFINED ENV{VCPKG_ROOT} AND NOT DEFINED CMAKE_TOOLCHAIN_FILE)
	MESSAGE(STATUS "Using vcpkg env variable")
	SET(CMAKE_TOOLCHAIN_FILE "$ENV{VCPKG_ROOT}/scripts/buildsystems/vcpkg.cmake" CACHE STRING "")
ELSEIF(NOT DEFINED CMAKE_TOOLCHAIN_FILE)
	MESSAGE(STATUS "Using vcpkg submodule")
	SET(CMAKE_TOOLCHAIN_FILE "${CMAKE_CURRENT_SOURCE_DIR}/submodules/vcpkg/scripts/buildsystems/vcpkg.cmake" CACHE STRING "")
ENDIF()

PROJECT(EQEmu)

IF(NOT CMAKE_BUILD_TYPE)
	SET(CMAKE_BUILD_TYPE RelWithDebInfo CACHE STRING "Choose the type of build." FORCE)
ENDIF(NOT CMAKE_BUILD_TYPE)

SET(CMAKE_CXX_STANDARD 20)
SET(CMAKE_CXX_STANDARD_REQUIRED ON)
SET(CMAKE_CXX_EXTENSIONS OFF)

OPTION(EQEMU_BUILD_STATIC "Build with static linking" OFF)
OPTION(EQEMU_BUILD_PCH "Build with precompiled headers (Windows)" ON)

IF (EQEMU_BUILD_STATIC)
	SET(BUILD_SHARED_LIBS OFF)
	SET(CMAKE_FIND_LIBRARY_SUFFIXES ".lib" ".a")
	MESSAGE(STATUS "Building with static linking")
	SET(CMAKE_EXE_LINKER_FLAGS "-static-libgcc -static-libstdc++")
	IF (UNIX)
		SET(PERL_LIBRARY "/opt/eqemu-perl/lib/5.32.1/x86_64-linux-thread-multi/CORE/libperl.so")
		SET(PERL_INCLUDE_PATH "/opt/eqemu-perl/lib/5.32.1/x86_64-linux-thread-multi/CORE/")
		SET(PERL_EXECUTABLE "/opt/eqemu-perl/bin/perl")
	ENDIF ()
ENDIF (EQEMU_BUILD_STATIC)


# Requires libgoogle-perftools-dev google-perftools packages for linux (debian)
IF(EQEMU_ADD_PROFILER)
	SET(CMAKE_EXE_LINKER_FLAGS "-Wl,--no-as-needed,-lprofiler,--as-needed")
ENDIF(EQEMU_ADD_PROFILER)

IF(USE_MAP_MMFS)
	ADD_DEFINITIONS(-DUSE_MAP_MMFS)
ENDIF (USE_MAP_MMFS)

IF(MSVC)
	add_compile_options(/bigobj)
	ADD_DEFINITIONS(-D_CRT_SECURE_NO_WARNINGS)
	ADD_DEFINITIONS(-DNOMINMAX)
	ADD_DEFINITIONS(-DCRASH_LOGGING)
	ADD_DEFINITIONS(-D_HAS_AUTO_PTR_ETC) # for Luabind on C++17

	SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /MP")

	OPTION(EQEMU_DISABLE_MSVC_WARNINGS "Disable MSVC compile warnings." ON)
	IF(EQEMU_DISABLE_MSVC_WARNINGS)
		ADD_DEFINITIONS( "/W0 /D_CRT_SECURE_NO_WARNINGS /wd4005 /wd4996 /nologo /Os")
	ENDIF(EQEMU_DISABLE_MSVC_WARNINGS)
ELSE(MSVC)
	ADD_DEFINITIONS(-DHAS_UNION_SEMUN)
ENDIF(MSVC)

#FreeBSD support
IF(UNIX)
	IF(CMAKE_SYSTEM_NAME MATCHES "FreeBSD")
		ADD_DEFINITIONS(-DFREEBSD)
		ADD_DEFINITIONS(-D_GLIBCXX_USE_C99)
		SET(FREEBSD TRUE)
	ENDIF(CMAKE_SYSTEM_NAME MATCHES "FreeBSD")
	IF(CMAKE_SYSTEM_NAME MATCHES "Darwin")
		ADD_DEFINITIONS(-DDARWIN)
		SET(DARWIN TRUE)
	ENDIF(CMAKE_SYSTEM_NAME MATCHES "Darwin")
ENDIF(UNIX)

ADD_DEFINITIONS(-DGLM_FORCE_RADIANS)
ADD_DEFINITIONS(-DGLM_FORCE_CTOR_INIT)
ADD_DEFINITIONS(-DGLM_ENABLE_EXPERIMENTAL)

find_package(PkgConfig)
find_package(Boost REQUIRED COMPONENTS dynamic_bitset foreach tuple)
find_package(cereal CONFIG REQUIRED)
find_package(fmt CONFIG REQUIRED)
find_package(glm CONFIG REQUIRED)
find_package(unofficial-libmariadb CONFIG REQUIRED)
find_package(libuv CONFIG REQUIRED)
find_package(OpenSSL REQUIRED)
find_package(recastnavigation CONFIG REQUIRED)
find_package(ZLIB REQUIRED)
pkg_check_modules(luajit REQUIRED luajit)
find_package(PerlLibs)

MESSAGE(STATUS "**************************************************")
MESSAGE(STATUS "* Library Detection                              *")
MESSAGE(STATUS "**************************************************")

IF(MARIADB_FOUND)
	MESSAGE(STATUS "* MariaDB:                                 FOUND *")
ELSE()
	MESSAGE(STATUS "* MariaDB:                               MISSING *")
ENDIF()

IF(ZLIB_FOUND)
	MESSAGE(STATUS "* ZLIB:                                    FOUND *")
ELSE()
	MESSAGE(STATUS "* ZLIB:                                  MISSING *")
ENDIF()

IF(LuaJit_FOUND)
	MESSAGE(STATUS "* LuaJIT:                                  FOUND *")
ELSE()
	MESSAGE(STATUS "* LuaJIT:                                MISSING *")
ENDIF()

IF(PerlLibs_FOUND)
	MESSAGE(STATUS "* Perl:                                    FOUND *")
ELSE()
	MESSAGE(STATUS "* Perl:                                  MISSING *")
ENDIF()

IF(OpenSSL_FOUND)
	MESSAGE(STATUS "* OpenSSL:                                 FOUND *")
ELSE()
	MESSAGE(STATUS "* OpenSSL:                               MISSING *")
ENDIF()

MESSAGE(STATUS "PERL_INCLUDE_PATH: ${PERL_INCLUDE_PATH}")
MESSAGE(STATUS "PERL_LIBRARY: ${PERL_LIBRARY}")
MESSAGE(STATUS "PERL_INCLUDE_DIR: ${PERL_INCLUDE_DIR}")
MESSAGE(STATUS "PERL_INCLUDE_DIRS: ${PERL_INCLUDE_DIRS}")
MESSAGE(STATUS "PERL_LIBRARIES: ${PERL_LIBRARIES}")
MESSAGE(STATUS "PERL_VERSION: ${PERL_VERSION}")
MESSAGE(STATUS "**************************************************")

INCLUDE_DIRECTORIES(SYSTEM "${CMAKE_CURRENT_SOURCE_DIR}/submodules/websocketpp")

ADD_DEFINITIONS(-DBOOST_BIND_GLOBAL_PLACEHOLDERS)

#options
OPTION(EQEMU_COMMANDS_LOGGING "Enable GM Command logs" ON)
OPTION(EQEMU_BUILD_SERVER "Build the game server." ON)
OPTION(EQEMU_BUILD_LOGIN "Build the login server." ON)
OPTION(EQEMU_BUILD_TESTS "Build utility tests." OFF)
OPTION(EQEMU_BUILD_CLIENT_FILES "Build Client Import/Export Data Programs." ON)
OPTION(EQEMU_PREFER_LUA "Build with normal Lua even if LuaJIT is found." OFF)

#PRNG options
OPTION(EQEMU_ADDITIVE_LFIB_PRNG "Use Additive LFib for PRNG." OFF)
MARK_AS_ADVANCED(EQEMU_ADDITIVE_LFIB_PRNG)
OPTION(EQEMU_BIASED_INT_DIST "Use biased int dist instead of uniform." OFF)
MARK_AS_ADVANCED(EQEMU_BIASED_INT_DIST)
SET(EQEMU_CUSTOM_PRNG_ENGINE "" CACHE STRING "Custom random engine. (ex. std::default_random_engine)")
MARK_AS_ADVANCED(EQEMU_CUSTOM_PRNG_ENGINE)

IF(CMAKE_COMPILER_IS_GNUCXX)
	OPTION(EQEMU_SFMT19937 "Use GCC's extention for SIMD Fast MT19937." OFF)
	MARK_AS_ADVANCED(EQEMU_SFMT19937)
ENDIF()

IF(EQEMU_ADDITIVE_LFIB_PRNG)
	ADD_DEFINITIONS(-DUSE_ADDITIVE_LFIB_PRNG)
	IF(EQEMU_SFMT19937)
		MESSAGE(STATUS "SFMT19937 and ADDITITVE_LFIB_PRNG both set, SFMT19937 ignored.")
		SET(EQEMU_SFMT19937 OFF)
	ENDIF()
	IF(NOT EQEMU_CUSTOM_PRNG_ENGINE STREQUAL "")
		MESSAGE(STATUS "CUSTOM_PRNG_ENGINE and ADDITITVE_LFIB_PRNG both set, CUSTOM_PRNG_ENGINE ignored.")
		SET(EQEMU_CUSTOM_PRNG_ENGINE "")
	ENDIF()
ENDIF()

IF(EQEMU_SFMT19937)
	ADD_DEFINITIONS(-DUSE_SFMT19937)
	IF(NOT EQEMU_CUSTOM_PRNG_ENGINE STREQUAL "")
		MESSAGE(STATUS "CUSTOM_PRNG_ENGINE and SFMT19937 both set, CUSTOM_PRNG_ENGINE ignored.")
		SET(EQEMU_CUSTOM_PRNG_ENGINE "")
	ENDIF()
ENDIF()

IF(NOT EQEMU_CUSTOM_PRNG_ENGINE STREQUAL "")
	ADD_DEFINITIONS(-DUSE_CUSTOM_PRNG_ENGINE=${EQEMU_CUSTOM_PRNG_ENGINE})
ENDIF()

IF(EQEMU_BIASED_INT_DIST)
	ADD_DEFINITIONS(-DBIASED_INT_DIST)
ENDIF()

IF(EQEMU_COMMANDS_LOGGING)
	ADD_DEFINITIONS(-DCOMMANDS_LOGGING)
ENDIF(EQEMU_COMMANDS_LOGGING)

SET(DATABASE_LIBRARY_TYPE "MariaDB")
SET(DATABASE_LIBRARY_LIBS ${MariaDB_LIBRARIES})
SET(DATABASE_LIBRARY_INCLUDE ${MariaDB_INCLUDE_DIR})
SET(TLS_LIBRARY_TYPE " OpenSSL")
SET(TLS_LIBRARY_ENABLED ON)
SET(TLS_LIBRARY_LIBS ${OPENSSL_LIBRARIES})
SET(TLS_LIBRARY_INCLUDE ${OPENSSL_INCLUDE_DIR})
ADD_DEFINITIONS(-DEQEMU_USE_OPENSSL)
IF(${OPENSSL_VERSION} VERSION_GREATER_EQUAL "1.1.1")
	ADD_DEFINITIONS(-DCPPHTTPLIB_OPENSSL_SUPPORT)
ENDIF()

SET(LUA_LIBRARY_TYPE "  LuaJIT")
SET(LUA_LIBRARY_ENABLED ON)

IF(PerlLibs_FOUND)
	SET(PERL_LIBRARY_TYPE "    Perl")
	SET(PERL_LIBRARY_ENABLED ON)
	SET(PERL_LIBRARY_LIBS ${PERL_LIBRARY})
	SET(PERL_LIBRARY_INCLUDE ${PERL_INCLUDE_PATH})
ELSE()
	SET(PERL_LIBRARY_TYPE "Disabled")
	SET(PERL_LIBRARY_ENABLED OFF)
ENDIF()

SET(ZLIB_LIBRARY_TYPE "zlib-ng")
SET(ZLIB_LIBRARY_LIBS "zlibstatic")
SET(ZLIB_LIBRARY_INCLUDE "${CMAKE_CURRENT_SOURCE_DIR}/libs/zlibng")
IF (EQEMU_BUILD_STATIC)
	SET(ZLIB_LIBRARY_LIBS libz.a)
ENDIF(EQEMU_BUILD_STATIC)
MESSAGE(STATUS "")
MESSAGE(STATUS "**************************************************")
MESSAGE(STATUS "* Library Usage                                  *")
MESSAGE(STATUS "**************************************************")
MESSAGE(STATUS "* Database:                              ${DATABASE_LIBRARY_TYPE} *")
MESSAGE(STATUS "* TLS:                                  ${TLS_LIBRARY_TYPE} *")
MESSAGE(STATUS "* Lua:                                  ${LUA_LIBRARY_TYPE} *")
MESSAGE(STATUS "* Perl:                                 ${PERL_LIBRARY_TYPE} *")
MESSAGE(STATUS "* zlib:                                  ${ZLIB_LIBRARY_TYPE} *")
MESSAGE(STATUS "**************************************************")


SET(SERVER_LIBS common)
# silence obnoxious deprecation message
ADD_DEFINITIONS(-DBOOST_BIND_GLOBAL_PLACEHOLDERS)

IF(LUA_LIBRARY_ENABLED)
	OPTION(EQEMU_BUILD_LUA "Build Lua parser." ON)

	IF(EQEMU_BUILD_LUA)
		ADD_DEFINITIONS(-DLUA_EQEMU)
		SET(ZONE_LIBS ${pkgcfg_lib_luajit_lua51})
		include_directories(SYSTEM "${VCPKG_INSTALLED_DIR}/${VCPKG_TARGET_TRIPLET}/include/luajit" "${CMAKE_CURRENT_SOURCE_DIR}/libs/luabind")

		OPTION(EQEMU_SANITIZE_LUA_LIBS "Sanitize Lua Libraries (Remove OS and IO standard libraries from being able to run)." ON)
		IF(EQEMU_SANITIZE_LUA_LIBS)
			ADD_DEFINITIONS(-DSANITIZE_LUA_LIBS)
		ENDIF()
	ENDIF()
ENDIF()

IF(PERL_LIBRARY_ENABLED)
	OPTION(EQEMU_BUILD_PERL "Build Perl parser." ON)
	IF(EQEMU_BUILD_PERL)
		SET(SERVER_LIBS ${SERVER_LIBS} ${PERL_LIBRARY_LIBS} perlbind)
		INCLUDE_DIRECTORIES(SYSTEM "${PERL_LIBRARY_INCLUDE}")
		ADD_DEFINITIONS(-DEMBPERL)
		ADD_DEFINITIONS(-DEMBPERL_PLUGIN)
		ADD_DEFINITIONS(-DPERLBIND_NO_STRICT_SCALAR_TYPES)
		IF (UNIX AND EQEMU_BUILD_STATIC)
			SET(SERVER_LIBS ${SERVER_LIBS} libcrypt.a)
		ENDIF ()
	ENDIF()
ENDIF()

IF(WIN32)
	SET(SERVER_LIBS ${SERVER_LIBS} "ws2_32" "psapi" "iphlpapi" "userenv")
ENDIF()

IF(UNIX)
	SET(SERVER_LIBS ${SERVER_LIBS} ${CMAKE_DL_LIBS} "z" "m" "pthread")
	IF(NOT DARWIN)
		SET(SERVER_LIBS ${SERVER_LIBS} "rt")
	ENDIF()
	# Freebsd provides uuids in the C library
	IF(NOT ${CMAKE_SYSTEM_NAME} STREQUAL "FreeBSD")
		SET(SERVER_LIBS ${SERVER_LIBS} "uuid")
	ENDIF()
ENDIF()

SET(ZONE_LIBS ${ZONE_LIBS} ${SERVER_LIBS})

IF(EQEMU_BUILD_LOGIN AND NOT TLS_LIBRARY_ENABLED)
	MESSAGE(FATAL_ERROR "Login server requires a TLS Library to build.")
ENDIF()

IF(EQEMU_BUILD_SERVER OR EQEMU_BUILD_LOGIN OR EQEMU_BUILD_TESTS)
	ADD_SUBDIRECTORY(common)
	ADD_SUBDIRECTORY(libs)
ENDIF(EQEMU_BUILD_SERVER OR EQEMU_BUILD_LOGIN OR EQEMU_BUILD_TESTS)

IF(EQEMU_BUILD_SERVER)
	ADD_SUBDIRECTORY(shared_memory)
	ADD_SUBDIRECTORY(world)
#	ADD_SUBDIRECTORY(zone)
	ADD_SUBDIRECTORY(ucs)
	ADD_SUBDIRECTORY(queryserv)
	ADD_SUBDIRECTORY(eqlaunch)
ENDIF(EQEMU_BUILD_SERVER)

IF(EQEMU_BUILD_LOGIN)
	ADD_SUBDIRECTORY(loginserver)
ENDIF(EQEMU_BUILD_LOGIN)

IF(EQEMU_BUILD_TESTS)
	ADD_SUBDIRECTORY(tests)
ENDIF(EQEMU_BUILD_TESTS)

IF(EQEMU_BUILD_CLIENT_FILES)
	ADD_SUBDIRECTORY(client_files)
ENDIF(EQEMU_BUILD_CLIENT_FILES)