cmake_minimum_required(VERSION 3.22)
project(bot5_physics_validator LANGUAGES CXX)
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)
if(APPLE AND CMAKE_SYSTEM_PROCESSOR MATCHES "^(arm64|aarch64)$")
  if(CMAKE_OSX_ARCHITECTURES AND NOT CMAKE_OSX_ARCHITECTURES STREQUAL "arm64")
    message(FATAL_ERROR "The Apple Silicon bundle builds arm64; use a native Apple Silicon terminal and -DCMAKE_OSX_ARCHITECTURES=arm64")
  endif()
  set(PHYSICS_PLATFORM "macos-arm64")
  set(MJ_RELATIVE_LIBRARY "lib/mujoco.framework/Versions/A/libmujoco.3.17.0.dylib")
  set(EXPECTED_MJ_SHA "454d51fa639100018579716bd68e61285e9b53c9241b029680d82dec95bc8d53")
elseif(CMAKE_SYSTEM_NAME STREQUAL "Linux" AND CMAKE_SYSTEM_PROCESSOR MATCHES "^(x86_64|amd64|AMD64)$")
  set(PHYSICS_PLATFORM "linux-x86_64")
  set(MJ_RELATIVE_LIBRARY "lib/libmujoco.so.3.17.0")
  set(EXPECTED_MJ_SHA "23496b023ee80fb61ab71167e94bc649f9941710fde96b18bb8204fb332523ad")
else()
  message(FATAL_ERROR "Supported targets: Linux x86-64 and native macOS Apple Silicon (arm64)")
endif()
find_package(tinyxml2 REQUIRED)
find_package(nlohmann_json REQUIRED)
find_package(OpenSSL REQUIRED)
find_package(Threads REQUIRED)
set(MUJOCO_ROOT "${CMAKE_CURRENT_SOURCE_DIR}/vendor/mujoco" CACHE PATH "MuJoCo 3.17.0 SDK")
set(MUJOCO_LIBRARY "${MUJOCO_ROOT}/${MJ_RELATIVE_LIBRARY}")
if(NOT EXISTS "${MUJOCO_LIBRARY}")
  message(FATAL_ERROR "Use the complete physics-engine-${PHYSICS_PLATFORM}.zip, including vendor/mujoco")
endif()
file(SHA256 "${MUJOCO_LIBRARY}" MJ_SHA)
if(NOT MJ_SHA STREQUAL EXPECTED_MJ_SHA)
  message(FATAL_ERROR "MuJoCo library differs from the pinned ${PHYSICS_PLATFORM} dependency")
endif()
# Preserve the official macOS library's framework install name and signature.
# Its @rpath/mujoco.framework/Versions/A/... ID resolves from this directory.
set(CMAKE_BUILD_RPATH "${MUJOCO_ROOT}/lib")
add_library(mujoco_external SHARED IMPORTED)
set_target_properties(mujoco_external PROPERTIES IMPORTED_LOCATION "${MUJOCO_LIBRARY}")
if(APPLE)
  set_target_properties(mujoco_external PROPERTIES IMPORTED_SONAME "@rpath/mujoco.framework/Versions/A/libmujoco.3.17.0.dylib")
endif()
file(GLOB_RECURSE PHYSICS_INPUTS CONFIGURE_DEPENDS src/* include/* model/*)
set(SOURCE_DIGEST "bot5-public-physics-v1")
foreach(INPUT IN LISTS PHYSICS_INPUTS)
  file(SHA256 "${INPUT}" INPUT_SHA)
  string(APPEND SOURCE_DIGEST "${INPUT_SHA}")
endforeach()
string(SHA256 SOURCE_SHA "${SOURCE_DIGEST}")
add_library(arena_physics STATIC src/world.cpp src/candidate_runtime.cpp src/strategy_runtime.cpp src/rules.cpp src/damage.cpp)
target_include_directories(arena_physics PUBLIC include include/common_controller PRIVATE src "${MUJOCO_ROOT}/include")
target_link_libraries(arena_physics PUBLIC mujoco_external tinyxml2::tinyxml2 nlohmann_json::nlohmann_json OpenSSL::Crypto Threads::Threads ${CMAKE_DL_LIBS})
target_compile_options(arena_physics PRIVATE -O3 -Wall -Wextra -Wpedantic)
target_compile_definitions(arena_physics PRIVATE PRACTICAL_SOURCE_SHA256="${SOURCE_SHA}" PRACTICAL_MUJOCO_SHA256="${MJ_SHA}" PREDICTIVE_CLEARANCE=0.03 BOT5_MODEL_PATH="${CMAKE_CURRENT_SOURCE_DIR}/model/arena.xml")
add_executable(validate_bot validate_bot.cpp)
target_link_libraries(validate_bot PRIVATE arena_physics)
add_library(pd_hold MODULE examples/pd_hold_controller.cpp)
target_include_directories(pd_hold PRIVATE include)
target_link_libraries(pd_hold PRIVATE nlohmann_json::nlohmann_json)
set_target_properties(pd_hold PROPERTIES PREFIX "")
enable_testing()
add_executable(physics_checks tests/checks.cpp)
target_link_libraries(physics_checks PRIVATE arena_physics)
add_test(NAME physics_and_controller_limits COMMAND physics_checks)
add_executable(physics_probe tests/probe.cpp)
target_link_libraries(physics_probe PRIVATE arena_physics)
add_test(NAME example_controller COMMAND validate_bot --controller $<TARGET_FILE:pd_hold> --seconds 0.3)
add_test(NAME actions_example COMMAND validate_bot --actions ${CMAKE_CURRENT_SOURCE_DIR}/examples/actions.json --seconds 0.3)
add_library(throwing_controller MODULE tests/throwing_controller.cpp)
target_include_directories(throwing_controller PRIVATE include)
target_link_libraries(throwing_controller PRIVATE nlohmann_json::nlohmann_json)
add_test(NAME plugin_error_is_reported COMMAND validate_bot --controller $<TARGET_FILE:throwing_controller> --seconds 0.3)
set_tests_properties(plugin_error_is_reported PROPERTIES WILL_FAIL TRUE)
