cmake_minimum_required(VERSION 3.16)

project(GameServer LANGUAGES CXX)

set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)

set(GAME_ROOT "${CMAKE_CURRENT_LIST_DIR}/..")

find_package(Threads REQUIRED)
find_package(Eigen3 3.3 CONFIG QUIET)
if(NOT TARGET Eigen3::Eigen)
	set(EIGEN_BUNDLED_DIR "${GAME_ROOT}/thirdparty/eigen-5.0.0")
	if(NOT EXISTS "${EIGEN_BUNDLED_DIR}/Eigen/Core")
		message(FATAL_ERROR
			"Eigen3 was not found. Install Eigen3 or configure the graphical "
			"project once to populate thirdparty/eigen-5.0.0.")
	endif()
	add_library(game_server_eigen INTERFACE)
	target_include_directories(game_server_eigen INTERFACE "${EIGEN_BUNDLED_DIR}")
	add_library(Eigen3::Eigen ALIAS game_server_eigen)
endif()

add_library(game_server_core STATIC
	"${GAME_ROOT}/src/Campaign.cpp"
	"${GAME_ROOT}/src/Campaign.h"
	"${GAME_ROOT}/src/CharacterState.cpp"
	"${GAME_ROOT}/src/CharacterState.h"
	"${GAME_ROOT}/src/GameState.cpp"
	"${GAME_ROOT}/src/GameState.h"
	"${GAME_ROOT}/src/ISaveable.h"
	"${GAME_ROOT}/src/Localization.cpp"
	"${GAME_ROOT}/src/Localization.h"
	"${GAME_ROOT}/src/LocationGameState.cpp"
	"${GAME_ROOT}/src/LocationGameState.h"
	"${GAME_ROOT}/src/LocationState.cpp"
	"${GAME_ROOT}/src/LocationState.h"
	"${GAME_ROOT}/src/NpcCar.cpp"
	"${GAME_ROOT}/src/NpcCar.h"
	"${GAME_ROOT}/src/content/LocationDefinition.cpp"
	"${GAME_ROOT}/src/content/LocationDefinition.h"
	"${GAME_ROOT}/src/game_server/IGameServer.h"
	"${GAME_ROOT}/src/game_server/IGameServerLifecycle.h"
	"${GAME_ROOT}/src/game_server/InternalGameServer.cpp"
	"${GAME_ROOT}/src/game_server/InternalGameServer.h"
	"${GAME_ROOT}/src/items/InteractiveObjectState.cpp"
	"${GAME_ROOT}/src/items/InteractiveObjectState.h"
	"${GAME_ROOT}/src/items/Inventory.cpp"
	"${GAME_ROOT}/src/items/Item.h"
	"${GAME_ROOT}/src/navigation/PathFinder.cpp"
	"${GAME_ROOT}/src/navigation/PathFinder.h"
	"${GAME_ROOT}/src/quest/QuestJournal.cpp"
	"${GAME_ROOT}/src/quest/QuestJournal.h"
	"${GAME_ROOT}/src/quest/QuestTypes.h"
	"${GAME_ROOT}/src/utils/HeadlessUtils.cpp"
	"${GAME_ROOT}/src/utils/Utils.h"
)

source_group(TREE "${GAME_ROOT}/src" PREFIX "Source" FILES
	"${GAME_ROOT}/src/Campaign.cpp"
	"${GAME_ROOT}/src/Campaign.h"
	"${GAME_ROOT}/src/CharacterState.cpp"
	"${GAME_ROOT}/src/CharacterState.h"
	"${GAME_ROOT}/src/GameState.cpp"
	"${GAME_ROOT}/src/GameState.h"
	"${GAME_ROOT}/src/ISaveable.h"
	"${GAME_ROOT}/src/Localization.cpp"
	"${GAME_ROOT}/src/Localization.h"
	"${GAME_ROOT}/src/LocationGameState.cpp"
	"${GAME_ROOT}/src/LocationGameState.h"
	"${GAME_ROOT}/src/LocationState.cpp"
	"${GAME_ROOT}/src/LocationState.h"
	"${GAME_ROOT}/src/NpcCar.cpp"
	"${GAME_ROOT}/src/NpcCar.h"
	"${GAME_ROOT}/src/content/LocationDefinition.cpp"
	"${GAME_ROOT}/src/content/LocationDefinition.h"
	"${GAME_ROOT}/src/game_server/IGameServer.h"
	"${GAME_ROOT}/src/game_server/IGameServerLifecycle.h"
	"${GAME_ROOT}/src/game_server/InternalGameServer.cpp"
	"${GAME_ROOT}/src/game_server/InternalGameServer.h"
	"${GAME_ROOT}/src/items/InteractiveObjectState.cpp"
	"${GAME_ROOT}/src/items/InteractiveObjectState.h"
	"${GAME_ROOT}/src/items/Inventory.cpp"
	"${GAME_ROOT}/src/items/Item.h"
	"${GAME_ROOT}/src/navigation/PathFinder.cpp"
	"${GAME_ROOT}/src/navigation/PathFinder.h"
	"${GAME_ROOT}/src/quest/QuestJournal.cpp"
	"${GAME_ROOT}/src/quest/QuestJournal.h"
	"${GAME_ROOT}/src/quest/QuestTypes.h"
	"${GAME_ROOT}/src/utils/HeadlessUtils.cpp"
	"${GAME_ROOT}/src/utils/Utils.h"
)

target_include_directories(game_server_core PUBLIC "${GAME_ROOT}/src")
target_link_libraries(game_server_core PUBLIC Eigen3::Eigen Threads::Threads)
target_compile_definitions(game_server_core PRIVATE FRG_HEADLESS_SERVER=1)

if(MSVC)
	target_compile_options(game_server_core PRIVATE /W4 /permissive-)
else()
	target_compile_options(game_server_core PRIVATE -Wall -Wextra -Wpedantic)
endif()

add_executable(GameServer src/main.cpp README.md)
source_group("Server" FILES src/main.cpp README.md)
target_link_libraries(GameServer PRIVATE game_server_core)
if(WIN32)
	set(BOOST_BUNDLED_DIR "${GAME_ROOT}/thirdparty/boost_1_90_0")
	if(NOT EXISTS "${BOOST_BUNDLED_DIR}/boost/asio.hpp")
		message(FATAL_ERROR
			"Boost was not found at thirdparty/boost_1_90_0. Configure the "
			"graphical project once to populate it.")
	endif()
	target_sources(GameServer PRIVATE
		"${GAME_ROOT}/src/game_server/NetworkProtocol.cpp"
		"${GAME_ROOT}/src/game_server/NetworkProtocol.h"
		"${GAME_ROOT}/src/game_server/WebsocketGameServer.cpp"
		"${GAME_ROOT}/src/game_server/WebsocketGameServer.h")
	target_include_directories(GameServer PRIVATE "${BOOST_BUNDLED_DIR}")
	target_compile_definitions(
		GameServer PRIVATE NETWORK WIN32_LEAN_AND_MEAN _WIN32_WINNT=0x0A00)
	target_link_libraries(GameServer PRIVATE ws2_32 mswsock)
endif()

include(CTest)
if(BUILD_TESTING)
	add_executable(
		GameServerStateTests tests/LocationGameStateTests.cpp)
	target_link_libraries(GameServerStateTests PRIVATE game_server_core)
	source_group(
		"Server\\Tests" FILES tests/LocationGameStateTests.cpp)
	add_test(
		NAME GameServer.LocationState
		COMMAND GameServerStateTests)
	if(WIN32)
		add_executable(
			GameServerNetworkProtocolTests
			tests/NetworkProtocolTests.cpp
			"${GAME_ROOT}/src/game_server/NetworkProtocol.cpp"
			"${GAME_ROOT}/src/game_server/NetworkProtocol.h")
		target_link_libraries(
			GameServerNetworkProtocolTests PRIVATE game_server_core)
		add_test(
			NAME GameServer.NetworkProtocol
			COMMAND GameServerNetworkProtocolTests)
		add_executable(
			GameServerWebsocketLockstepTests
			tests/WebsocketLockstepTests.cpp
			"${GAME_ROOT}/src/game_server/NetworkProtocol.cpp"
			"${GAME_ROOT}/src/game_server/WebsocketGameClient.cpp"
			"${GAME_ROOT}/src/game_server/WebsocketGameServer.cpp")
		target_include_directories(
			GameServerWebsocketLockstepTests PRIVATE "${BOOST_BUNDLED_DIR}")
		target_compile_definitions(
			GameServerWebsocketLockstepTests PRIVATE
			NETWORK WIN32_LEAN_AND_MEAN _WIN32_WINNT=0x0A00)
		target_link_libraries(
			GameServerWebsocketLockstepTests PRIVATE
			game_server_core ws2_32 mswsock)
		add_test(
			NAME GameServer.WebsocketLockstep
			COMMAND GameServerWebsocketLockstepTests)
	endif()
	add_test(
		NAME GameServer.IdleSmoke
		COMMAND GameServer --ticks 2 --no-sleep)
	add_test(
		NAME GameServer.BattleZoneSharedPlayer
		COMMAND GameServer --campaign battle_zone --location uni_exterior
			--ticks 2 --no-sleep)
	set_tests_properties(
		GameServer.BattleZoneSharedPlayer
		PROPERTIES WORKING_DIRECTORY "${GAME_ROOT}")
endif()
