Kelsidavis-WoWee/CMakeLists.txt
Kelsi eb549a9b7a Fix Windows build process and add Windows asset extraction scripts
- Add missing MSYS2 packages to CI: vulkan-loader, vulkan-headers,
  shaderc, stormlib (both x86-64 and arm64), unicorn (arm64)
- Make vulkan-1.dll copy conditional via find_file (fixes MSYS2 builds)
- Use find_library for wininet/bz2 in asset_extract (graceful fallback)
- Add extract_assets.ps1 and extract_assets.bat for Windows users
- Expand BUILD_INSTRUCTIONS.md with MSYS2, vcpkg, and macOS sections
- Update README.md to reference Windows scripts and platforms
2026-02-23 18:32:47 -08:00

834 lines
28 KiB
CMake

cmake_minimum_required(VERSION 3.15)
project(wowee VERSION 1.0.0 LANGUAGES CXX)
include(GNUInstallDirs)
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
# Output directories
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
# Options
option(BUILD_SHARED_LIBS "Build shared libraries" OFF)
option(WOWEE_BUILD_TESTS "Build tests" OFF)
option(WOWEE_ENABLE_ASAN "Enable AddressSanitizer (Debug builds)" OFF)
# Opcode registry generation/validation
find_package(Python3 COMPONENTS Interpreter QUIET)
if(Python3_Interpreter_FOUND)
add_custom_target(opcodes-generate
COMMAND ${Python3_EXECUTABLE} ${CMAKE_SOURCE_DIR}/tools/gen_opcode_registry.py
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
COMMENT "Generating opcode registry include fragments"
)
add_custom_target(opcodes-validate
COMMAND ${Python3_EXECUTABLE} ${CMAKE_SOURCE_DIR}/tools/validate_opcode_maps.py --root ${CMAKE_SOURCE_DIR}
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
DEPENDS opcodes-generate
COMMENT "Validating canonical opcode registry and expansion maps"
)
endif()
# Find required packages
find_package(SDL2 REQUIRED)
find_package(Vulkan REQUIRED)
# GL/GLEW kept temporarily for unconverted sub-renderers during Vulkan migration.
# These files compile against GL types but their code is never called — the Vulkan
# path is the only active rendering backend. Remove in Phase 7 when all renderers
# are converted and grep confirms zero GL references.
find_package(OpenGL QUIET)
find_package(GLEW QUIET)
find_package(OpenSSL REQUIRED)
find_package(Threads REQUIRED)
find_package(ZLIB REQUIRED)
if(WIN32)
find_package(PkgConfig QUIET)
else()
find_package(PkgConfig REQUIRED)
endif()
if(PkgConfig_FOUND)
pkg_check_modules(FFMPEG libavformat libavcodec libswscale libavutil)
else()
# Fallback for MSVC/vcpkg — find FFmpeg libraries manually
find_path(FFMPEG_INCLUDE_DIRS libavformat/avformat.h)
find_library(AVFORMAT_LIB NAMES avformat)
find_library(AVCODEC_LIB NAMES avcodec)
find_library(AVUTIL_LIB NAMES avutil)
find_library(SWSCALE_LIB NAMES swscale)
set(FFMPEG_LIBRARIES ${AVFORMAT_LIB} ${AVCODEC_LIB} ${AVUTIL_LIB} ${SWSCALE_LIB})
endif()
if(FFMPEG_INCLUDE_DIRS AND AVFORMAT_LIB)
set(HAVE_FFMPEG TRUE)
message(STATUS "Found FFmpeg: ${AVFORMAT_LIB}")
elseif(FFMPEG_FOUND)
set(HAVE_FFMPEG TRUE)
else()
set(HAVE_FFMPEG FALSE)
message(WARNING "FFmpeg not found — video_player will be disabled. Install via vcpkg: ffmpeg:x64-windows")
endif()
# Unicorn Engine (x86 emulator for cross-platform Warden module execution)
find_library(UNICORN_LIBRARY NAMES unicorn)
find_path(UNICORN_INCLUDE_DIR unicorn/unicorn.h)
if(NOT UNICORN_LIBRARY OR NOT UNICORN_INCLUDE_DIR)
message(WARNING "Unicorn Engine not found. Install with: sudo apt-get install libunicorn-dev")
message(WARNING "Warden emulation will be disabled")
set(HAVE_UNICORN FALSE)
else()
message(STATUS "Found Unicorn Engine: ${UNICORN_LIBRARY}")
set(HAVE_UNICORN TRUE)
endif()
# GLM (header-only math library)
find_package(glm QUIET)
if(NOT glm_FOUND)
message(STATUS "GLM not found, will use system includes or download")
endif()
# GLM GTX extensions (quaternion, norm, etc.) require this flag on newer GLM versions
add_compile_definitions(GLM_ENABLE_EXPERIMENTAL GLM_FORCE_DEPTH_ZERO_TO_ONE)
if(WIN32)
add_compile_definitions(NOMINMAX _CRT_SECURE_NO_WARNINGS)
endif()
# SPIR-V shader compilation via glslc
find_program(GLSLC glslc HINTS ${Vulkan_GLSLC_EXECUTABLE} "$ENV{VULKAN_SDK}/bin")
if(GLSLC)
message(STATUS "Found glslc: ${GLSLC}")
else()
message(WARNING "glslc not found. Install the Vulkan SDK or vulkan-tools package.")
message(WARNING "Shaders will not be compiled to SPIR-V.")
endif()
# Function to compile GLSL shaders to SPIR-V
function(compile_shaders TARGET_NAME)
set(SHADER_DIR ${CMAKE_CURRENT_SOURCE_DIR}/assets/shaders)
set(SPV_DIR ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/assets/shaders)
file(MAKE_DIRECTORY ${SPV_DIR})
file(GLOB GLSL_SOURCES "${SHADER_DIR}/*.glsl")
set(SPV_OUTPUTS)
foreach(GLSL_FILE ${GLSL_SOURCES})
get_filename_component(FILE_NAME ${GLSL_FILE} NAME)
# e.g. skybox.vert.glsl -> skybox.vert.spv
string(REGEX REPLACE "\\.glsl$" ".spv" SPV_NAME ${FILE_NAME})
set(SPV_FILE ${SPV_DIR}/${SPV_NAME})
# Determine shader stage from filename
if(FILE_NAME MATCHES "\\.vert\\.glsl$")
set(SHADER_STAGE vertex)
elseif(FILE_NAME MATCHES "\\.frag\\.glsl$")
set(SHADER_STAGE fragment)
elseif(FILE_NAME MATCHES "\\.comp\\.glsl$")
set(SHADER_STAGE compute)
elseif(FILE_NAME MATCHES "\\.geom\\.glsl$")
set(SHADER_STAGE geometry)
else()
message(WARNING "Cannot determine shader stage for: ${FILE_NAME}")
continue()
endif()
add_custom_command(
OUTPUT ${SPV_FILE}
COMMAND ${GLSLC} -fshader-stage=${SHADER_STAGE} -O ${GLSL_FILE} -o ${SPV_FILE}
DEPENDS ${GLSL_FILE}
COMMENT "Compiling SPIR-V: ${FILE_NAME} -> ${SPV_NAME}"
VERBATIM
)
list(APPEND SPV_OUTPUTS ${SPV_FILE})
endforeach()
add_custom_target(${TARGET_NAME}_shaders ALL DEPENDS ${SPV_OUTPUTS})
add_dependencies(${TARGET_NAME} ${TARGET_NAME}_shaders)
endfunction()
# StormLib for MPQ extraction tool (not needed for main executable)
find_library(STORMLIB_LIBRARY NAMES StormLib stormlib storm)
find_path(STORMLIB_INCLUDE_DIR StormLib.h PATH_SUFFIXES StormLib)
# Include ImGui as a static library (Vulkan backend)
set(IMGUI_DIR ${CMAKE_CURRENT_SOURCE_DIR}/extern/imgui)
if(EXISTS ${IMGUI_DIR})
add_library(imgui STATIC
${IMGUI_DIR}/imgui.cpp
${IMGUI_DIR}/imgui_draw.cpp
${IMGUI_DIR}/imgui_tables.cpp
${IMGUI_DIR}/imgui_widgets.cpp
${IMGUI_DIR}/imgui_demo.cpp
${IMGUI_DIR}/backends/imgui_impl_sdl2.cpp
${IMGUI_DIR}/backends/imgui_impl_vulkan.cpp
)
target_include_directories(imgui PUBLIC
${IMGUI_DIR}
${IMGUI_DIR}/backends
)
target_link_libraries(imgui PUBLIC SDL2::SDL2 Vulkan::Vulkan ${CMAKE_DL_LIBS})
else()
message(WARNING "ImGui not found in extern/imgui. Clone it with:")
message(WARNING " git clone https://github.com/ocornut/imgui.git extern/imgui")
endif()
# vk-bootstrap (Vulkan device/instance setup)
set(VK_BOOTSTRAP_DIR ${CMAKE_CURRENT_SOURCE_DIR}/extern/vk-bootstrap)
if(EXISTS ${VK_BOOTSTRAP_DIR})
add_library(vk-bootstrap STATIC
${VK_BOOTSTRAP_DIR}/src/VkBootstrap.cpp
)
target_include_directories(vk-bootstrap PUBLIC ${VK_BOOTSTRAP_DIR}/src)
target_link_libraries(vk-bootstrap PUBLIC Vulkan::Vulkan)
else()
message(FATAL_ERROR "vk-bootstrap not found in extern/vk-bootstrap")
endif()
# Source files
set(WOWEE_SOURCES
# Core
src/core/application.cpp
src/core/window.cpp
src/core/input.cpp
src/core/logger.cpp
src/core/memory_monitor.cpp
# Network
src/network/socket.cpp
src/network/packet.cpp
src/network/tcp_socket.cpp
src/network/world_socket.cpp
# Auth
src/auth/auth_handler.cpp
src/auth/auth_opcodes.cpp
src/auth/auth_packets.cpp
src/auth/pin_auth.cpp
src/auth/integrity.cpp
src/auth/srp.cpp
src/auth/big_num.cpp
src/auth/crypto.cpp
src/auth/rc4.cpp
src/auth/vanilla_crypt.cpp
# Game
src/game/expansion_profile.cpp
src/game/opcode_table.cpp
src/game/update_field_table.cpp
src/game/game_handler.cpp
src/game/warden_crypto.cpp
src/game/warden_module.cpp
src/game/warden_emulator.cpp
src/game/warden_memory.cpp
src/game/transport_manager.cpp
src/game/world.cpp
src/game/player.cpp
src/game/entity.cpp
src/game/opcodes.cpp
src/game/world_packets.cpp
src/game/packet_parsers_tbc.cpp
src/game/packet_parsers_classic.cpp
src/game/character.cpp
src/game/zone_manager.cpp
src/game/inventory.cpp
# Audio
src/audio/audio_engine.cpp
src/audio/music_manager.cpp
src/audio/footstep_manager.cpp
src/audio/activity_sound_manager.cpp
src/audio/mount_sound_manager.cpp
src/audio/npc_voice_manager.cpp
src/audio/ambient_sound_manager.cpp
src/audio/ui_sound_manager.cpp
src/audio/combat_sound_manager.cpp
src/audio/spell_sound_manager.cpp
src/audio/movement_sound_manager.cpp
# Pipeline (asset loaders)
src/pipeline/blp_loader.cpp
src/pipeline/dbc_loader.cpp
src/pipeline/asset_manager.cpp
src/pipeline/asset_manifest.cpp
src/pipeline/loose_file_reader.cpp
src/pipeline/m2_loader.cpp
src/pipeline/wmo_loader.cpp
src/pipeline/adt_loader.cpp
src/pipeline/dbc_layout.cpp
src/pipeline/terrain_mesh.cpp
# Rendering (Vulkan infrastructure)
src/rendering/vk_context.cpp
src/rendering/vk_utils.cpp
src/rendering/vk_shader.cpp
src/rendering/vk_texture.cpp
src/rendering/vk_buffer.cpp
src/rendering/vk_pipeline.cpp
src/rendering/vk_render_target.cpp
# Rendering
src/rendering/renderer.cpp
src/rendering/shader.cpp
src/rendering/texture.cpp
src/rendering/mesh.cpp
src/rendering/camera.cpp
src/rendering/camera_controller.cpp
src/rendering/material.cpp
src/rendering/scene.cpp
src/rendering/terrain_renderer.cpp
src/rendering/terrain_manager.cpp
src/rendering/frustum.cpp
src/rendering/performance_hud.cpp
src/rendering/water_renderer.cpp
src/rendering/skybox.cpp
src/rendering/celestial.cpp
src/rendering/starfield.cpp
src/rendering/clouds.cpp
src/rendering/lens_flare.cpp
src/rendering/weather.cpp
src/rendering/lightning.cpp
src/rendering/lighting_manager.cpp
src/rendering/sky_system.cpp
src/rendering/character_renderer.cpp
src/rendering/character_preview.cpp
src/rendering/wmo_renderer.cpp
src/rendering/m2_renderer.cpp
src/rendering/quest_marker_renderer.cpp
src/rendering/minimap.cpp
src/rendering/world_map.cpp
src/rendering/swim_effects.cpp
src/rendering/mount_dust.cpp
src/rendering/levelup_effect.cpp
src/rendering/charge_effect.cpp
src/rendering/loading_screen.cpp
$<$<BOOL:${HAVE_FFMPEG}>:${CMAKE_CURRENT_SOURCE_DIR}/src/rendering/video_player.cpp>
# UI
src/ui/ui_manager.cpp
src/ui/auth_screen.cpp
src/ui/realm_screen.cpp
src/ui/character_create_screen.cpp
src/ui/character_screen.cpp
src/ui/game_screen.cpp
src/ui/inventory_screen.cpp
src/ui/quest_log_screen.cpp
src/ui/spellbook_screen.cpp
src/ui/talent_screen.cpp
# Main
src/main.cpp
)
set(WOWEE_HEADERS
include/core/application.hpp
include/core/window.hpp
include/core/input.hpp
include/core/logger.hpp
include/network/socket.hpp
include/network/packet.hpp
include/network/tcp_socket.hpp
include/network/world_socket.hpp
include/network/net_platform.hpp
include/platform/process.hpp
include/auth/auth_handler.hpp
include/auth/auth_opcodes.hpp
include/auth/auth_packets.hpp
include/auth/srp.hpp
include/auth/big_num.hpp
include/auth/crypto.hpp
include/game/game_handler.hpp
include/game/world.hpp
include/game/player.hpp
include/game/entity.hpp
include/game/opcodes.hpp
include/game/zone_manager.hpp
include/game/inventory.hpp
include/game/spell_defines.hpp
include/game/group_defines.hpp
include/game/world_packets.hpp
include/game/character.hpp
include/audio/audio_engine.hpp
include/audio/music_manager.hpp
include/audio/footstep_manager.hpp
include/audio/activity_sound_manager.hpp
include/audio/mount_sound_manager.hpp
include/audio/npc_voice_manager.hpp
include/audio/ambient_sound_manager.hpp
include/audio/ui_sound_manager.hpp
include/audio/combat_sound_manager.hpp
include/audio/spell_sound_manager.hpp
include/audio/movement_sound_manager.hpp
include/pipeline/blp_loader.hpp
include/pipeline/asset_manifest.hpp
include/pipeline/loose_file_reader.hpp
include/pipeline/m2_loader.hpp
include/pipeline/wmo_loader.hpp
include/pipeline/adt_loader.hpp
include/pipeline/dbc_loader.hpp
include/pipeline/terrain_mesh.hpp
include/rendering/vk_context.hpp
include/rendering/vk_utils.hpp
include/rendering/vk_shader.hpp
include/rendering/vk_texture.hpp
include/rendering/vk_buffer.hpp
include/rendering/vk_pipeline.hpp
include/rendering/vk_render_target.hpp
include/rendering/renderer.hpp
include/rendering/shader.hpp
include/rendering/texture.hpp
include/rendering/mesh.hpp
include/rendering/camera.hpp
include/rendering/camera_controller.hpp
include/rendering/material.hpp
include/rendering/scene.hpp
include/rendering/terrain_renderer.hpp
include/rendering/terrain_manager.hpp
include/rendering/frustum.hpp
include/rendering/performance_hud.hpp
include/rendering/water_renderer.hpp
include/rendering/skybox.hpp
include/rendering/celestial.hpp
include/rendering/starfield.hpp
include/rendering/clouds.hpp
include/rendering/lens_flare.hpp
include/rendering/weather.hpp
include/rendering/lightning.hpp
include/rendering/swim_effects.hpp
include/rendering/world_map.hpp
include/rendering/character_renderer.hpp
include/rendering/character_preview.hpp
include/rendering/wmo_renderer.hpp
include/rendering/loading_screen.hpp
include/rendering/video_player.hpp
include/ui/ui_manager.hpp
include/ui/auth_screen.hpp
include/ui/realm_screen.hpp
include/ui/character_create_screen.hpp
include/ui/character_screen.hpp
include/ui/game_screen.hpp
include/ui/inventory_screen.hpp
include/ui/spellbook_screen.hpp
include/ui/talent_screen.hpp
)
set(WOWEE_PLATFORM_SOURCES)
if(WIN32)
# Copy icon into build tree so llvm-rc can find it via the relative path in wowee.rc
configure_file(
${CMAKE_CURRENT_SOURCE_DIR}/assets/Wowee.ico
${CMAKE_CURRENT_BINARY_DIR}/assets/wowee.ico
COPYONLY
)
list(APPEND WOWEE_PLATFORM_SOURCES resources/wowee.rc)
endif()
# Create executable
add_executable(wowee ${WOWEE_SOURCES} ${WOWEE_HEADERS} ${WOWEE_PLATFORM_SOURCES})
if(TARGET opcodes-generate)
add_dependencies(wowee opcodes-generate)
endif()
# Compile GLSL shaders to SPIR-V
if(GLSLC)
compile_shaders(wowee)
endif()
# Include directories
target_include_directories(wowee PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}/include
${CMAKE_CURRENT_SOURCE_DIR}/src
${CMAKE_CURRENT_SOURCE_DIR}/extern
${CMAKE_CURRENT_SOURCE_DIR}/extern/vk-bootstrap/src
)
if(HAVE_FFMPEG)
target_include_directories(wowee PRIVATE ${FFMPEG_INCLUDE_DIRS})
endif()
# Link libraries
target_link_libraries(wowee PRIVATE
SDL2::SDL2
Vulkan::Vulkan
OpenSSL::SSL
OpenSSL::Crypto
Threads::Threads
ZLIB::ZLIB
${CMAKE_DL_LIBS}
)
# GL/GLEW linked temporarily for unconverted sub-renderers (removed in Phase 7)
if(TARGET OpenGL::GL)
target_link_libraries(wowee PRIVATE OpenGL::GL)
endif()
if(TARGET GLEW::GLEW)
target_link_libraries(wowee PRIVATE GLEW::GLEW)
endif()
if(HAVE_FFMPEG)
target_compile_definitions(wowee PRIVATE HAVE_FFMPEG)
target_link_libraries(wowee PRIVATE ${FFMPEG_LIBRARIES})
if(FFMPEG_LIBRARY_DIRS)
target_link_directories(wowee PRIVATE ${FFMPEG_LIBRARY_DIRS})
endif()
endif()
# Platform-specific libraries
if(UNIX AND NOT APPLE)
target_link_libraries(wowee PRIVATE X11)
endif()
if(WIN32)
target_link_libraries(wowee PRIVATE ws2_32)
# SDL2main provides WinMain entry point on Windows
if(TARGET SDL2::SDL2main)
target_link_libraries(wowee PRIVATE SDL2::SDL2main)
endif()
endif()
# Link ImGui if available
if(TARGET imgui)
target_link_libraries(wowee PRIVATE imgui)
endif()
# Link vk-bootstrap
if(TARGET vk-bootstrap)
target_link_libraries(wowee PRIVATE vk-bootstrap)
endif()
# Link Unicorn if available
if(HAVE_UNICORN)
target_link_libraries(wowee PRIVATE ${UNICORN_LIBRARY})
target_include_directories(wowee PRIVATE ${UNICORN_INCLUDE_DIR})
target_compile_definitions(wowee PRIVATE HAVE_UNICORN)
endif()
# Link GLM if found
if(TARGET glm::glm)
target_link_libraries(wowee PRIVATE glm::glm)
elseif(glm_FOUND)
target_include_directories(wowee PRIVATE ${GLM_INCLUDE_DIRS})
endif()
# Compiler warnings
if(MSVC)
target_compile_options(wowee PRIVATE /W4)
else()
target_compile_options(wowee PRIVATE -Wall -Wextra -Wpedantic)
endif()
# Debug build flags
if(MSVC)
# /ZI — Edit-and-Continue debug info (works with hot-reload in VS 2022)
# /RTC1 — stack-frame and uninitialised-variable runtime checks (Debug only)
# /sdl — additional SDL security checks
# /Od — disable optimisation so stepping matches source lines exactly
target_compile_options(wowee PRIVATE
$<$<CONFIG:Debug>:/ZI /RTC1 /sdl /Od>
)
# Ensure the linker emits a .pdb alongside the .exe for every config
target_link_options(wowee PRIVATE
$<$<CONFIG:Debug>:/DEBUG:FULL>
$<$<CONFIG:RelWithDebInfo>:/DEBUG:FASTLINK>
)
else()
# -g3 — maximum DWARF debug info (includes macro definitions)
# -Og — optimise for debugging (better than -O0, keeps most frames)
# -fno-omit-frame-pointer — preserve frame pointers so stack traces are clean
target_compile_options(wowee PRIVATE
$<$<CONFIG:Debug>:-g3 -Og -fno-omit-frame-pointer>
$<$<CONFIG:RelWithDebInfo>:-g -fno-omit-frame-pointer>
)
endif()
# AddressSanitizer — catch buffer overflows, use-after-free, etc.
# Enable with: cmake ... -DWOWEE_ENABLE_ASAN=ON -DCMAKE_BUILD_TYPE=Debug
if(WOWEE_ENABLE_ASAN)
if(MSVC)
target_compile_options(wowee PRIVATE /fsanitize=address)
# ASAN on MSVC requires the dynamic CRT (/MD or /MDd)
target_compile_options(wowee PRIVATE
$<$<CONFIG:Debug>:/MDd>
$<$<CONFIG:Release>:/MD>
)
else()
target_compile_options(wowee PRIVATE -fsanitize=address -fno-omit-frame-pointer)
target_link_options(wowee PRIVATE -fsanitize=address)
endif()
message(STATUS "AddressSanitizer: ENABLED")
endif()
# Release build optimizations
include(CheckIPOSupported)
check_ipo_supported(RESULT _ipo_supported OUTPUT _ipo_error)
if(_ipo_supported)
set_property(TARGET wowee PROPERTY INTERPROCEDURAL_OPTIMIZATION_RELEASE TRUE)
endif()
if(NOT MSVC)
# -O3: more aggressive inlining and auto-vectorization vs CMake's default -O2
target_compile_options(wowee PRIVATE $<$<CONFIG:Release>:-O3>)
# -fvisibility=hidden: keeps all symbols internal by default, shrinks binary
# and gives the linker and optimizer more freedom to dead-strip and inline
target_compile_options(wowee PRIVATE $<$<CONFIG:Release>:-fvisibility=hidden -fvisibility-inlines-hidden>)
endif()
# Copy assets next to the executable (runs every build, not just configure).
# Uses $<TARGET_FILE_DIR:wowee> so MSVC multi-config generators place assets
# in bin/Debug/ or bin/Release/ alongside the exe, not the common bin/ parent.
add_custom_command(TARGET wowee POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_directory
${CMAKE_CURRENT_SOURCE_DIR}/assets
$<TARGET_FILE_DIR:wowee>/assets
COMMENT "Syncing assets to $<TARGET_FILE_DIR:wowee>/assets"
)
# On Windows, SDL 2.28+ uses LoadLibraryExW with LOAD_LIBRARY_SEARCH_DEFAULT_DIRS
# which does NOT include System32. Copy vulkan-1.dll into the output directory so
# SDL_Vulkan_LoadLibrary can locate it without needing a full system PATH search.
if(WIN32)
find_file(VULKAN_DLL vulkan-1.dll
PATHS "$ENV{SystemRoot}/System32" "$ENV{VULKAN_SDK}/Bin"
NO_DEFAULT_PATH)
if(VULKAN_DLL)
add_custom_command(TARGET wowee POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_if_different
"${VULKAN_DLL}" "$<TARGET_FILE_DIR:wowee>/vulkan-1.dll"
COMMENT "Copying vulkan-1.dll to output directory"
)
else()
message(STATUS " vulkan-1.dll not found — skipping copy (MSYS2 provides it via PATH)")
endif()
endif()
# Install targets
install(TARGETS wowee
RUNTIME DESTINATION bin
LIBRARY DESTINATION lib
ARCHIVE DESTINATION lib
)
# Note: tool install rules are placed next to each target definition below.
# Install built-in assets (exclude proprietary music)
install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/assets
DESTINATION bin
PATTERN "Original Music" EXCLUDE)
# On Windows, install any DLLs that were bundled into the build output dir
# (populated by the CI workflow's DLL-bundling step before cpack runs)
if(WIN32)
install(DIRECTORY "${CMAKE_BINARY_DIR}/bin/"
DESTINATION bin
FILES_MATCHING PATTERN "*.dll")
endif()
# Linux desktop integration (launcher + icon)
if(UNIX AND NOT APPLE)
set(WOWEE_LINUX_ICON_PATH "${CMAKE_INSTALL_FULL_DATAROOTDIR}/icons/hicolor/256x256/apps/wowee.png")
configure_file(
${CMAKE_CURRENT_SOURCE_DIR}/resources/wowee.desktop.in
${CMAKE_CURRENT_BINARY_DIR}/wowee.desktop
@ONLY
)
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/wowee.desktop
DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/applications)
install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/assets/Wowee.png
DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/icons/hicolor/256x256/apps
RENAME wowee.png)
endif()
# ---- Tool: asset_extract (MPQ → loose files) ----
if(STORMLIB_LIBRARY AND STORMLIB_INCLUDE_DIR)
add_executable(asset_extract
tools/asset_extract/main.cpp
tools/asset_extract/extractor.cpp
tools/asset_extract/path_mapper.cpp
tools/asset_extract/manifest_writer.cpp
src/pipeline/dbc_loader.cpp
src/core/logger.cpp
)
target_include_directories(asset_extract PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}/include
${CMAKE_CURRENT_SOURCE_DIR}/tools/asset_extract
${STORMLIB_INCLUDE_DIR}
)
target_link_libraries(asset_extract PRIVATE
${STORMLIB_LIBRARY}
ZLIB::ZLIB
Threads::Threads
)
if(WIN32)
find_library(WININET_LIB wininet)
find_library(BZ2_LIB bz2)
if(WININET_LIB)
target_link_libraries(asset_extract PRIVATE ${WININET_LIB})
endif()
if(BZ2_LIB)
target_link_libraries(asset_extract PRIVATE ${BZ2_LIB})
endif()
endif()
set_target_properties(asset_extract PROPERTIES
RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin
)
install(TARGETS asset_extract RUNTIME DESTINATION bin)
message(STATUS " asset_extract tool: ENABLED")
else()
message(STATUS " asset_extract tool: DISABLED (requires StormLib)")
endif()
# ---- Tool: dbc_to_csv (DBC → CSV text) ----
add_executable(dbc_to_csv
tools/dbc_to_csv/main.cpp
src/pipeline/dbc_loader.cpp
src/core/logger.cpp
)
target_include_directories(dbc_to_csv PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}/include
)
target_link_libraries(dbc_to_csv PRIVATE Threads::Threads)
set_target_properties(dbc_to_csv PROPERTIES
RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin
)
install(TARGETS dbc_to_csv RUNTIME DESTINATION bin)
# ---- Tool: auth_probe (LOGON_CHALLENGE probe) ----
add_executable(auth_probe
tools/auth_probe/main.cpp
src/auth/auth_packets.cpp
src/auth/auth_opcodes.cpp
src/auth/crypto.cpp
src/network/packet.cpp
src/network/socket.cpp
src/network/tcp_socket.cpp
src/core/logger.cpp
)
target_include_directories(auth_probe PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}/include
)
target_link_libraries(auth_probe PRIVATE Threads::Threads OpenSSL::Crypto
$<$<BOOL:${WIN32}>:ws2_32>)
set_target_properties(auth_probe PROPERTIES
RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin
)
install(TARGETS auth_probe RUNTIME DESTINATION bin)
# ---- Tool: auth_login_probe (challenge + proof probe) ----
add_executable(auth_login_probe
tools/auth_login_probe/main.cpp
src/auth/auth_packets.cpp
src/auth/auth_opcodes.cpp
src/auth/crypto.cpp
src/auth/integrity.cpp
src/auth/big_num.cpp
src/auth/srp.cpp
src/network/packet.cpp
src/network/socket.cpp
src/network/tcp_socket.cpp
src/core/logger.cpp
)
target_include_directories(auth_login_probe PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}/include
)
target_link_libraries(auth_login_probe PRIVATE Threads::Threads OpenSSL::Crypto
$<$<BOOL:${WIN32}>:ws2_32>)
set_target_properties(auth_login_probe PROPERTIES
RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin
)
install(TARGETS auth_login_probe RUNTIME DESTINATION bin)
# ---- Tool: blp_convert (BLP ↔ PNG) ----
add_executable(blp_convert
tools/blp_convert/main.cpp
src/pipeline/blp_loader.cpp
src/core/logger.cpp
)
target_include_directories(blp_convert PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}/include
${CMAKE_CURRENT_SOURCE_DIR}/extern
)
target_link_libraries(blp_convert PRIVATE Threads::Threads)
set_target_properties(blp_convert PROPERTIES
RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin
)
install(TARGETS blp_convert RUNTIME DESTINATION bin)
# Print configuration summary
message(STATUS "")
message(STATUS "Wowee Configuration:")
message(STATUS " C++ Standard: ${CMAKE_CXX_STANDARD}")
message(STATUS " Build Type: ${CMAKE_BUILD_TYPE}")
message(STATUS " SDL2: ${SDL2_VERSION}")
message(STATUS " OpenSSL: ${OPENSSL_VERSION}")
message(STATUS " ImGui: ${IMGUI_DIR}")
message(STATUS " ASAN: ${WOWEE_ENABLE_ASAN}")
message(STATUS "")
# ---- CPack packaging ----
set(CPACK_PACKAGE_NAME "wowee")
set(CPACK_PACKAGE_VERSION "${PROJECT_VERSION}")
set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "World of Warcraft client emulator")
set(CPACK_PACKAGE_VENDOR "Wowee")
set(CPACK_PACKAGE_INSTALL_DIRECTORY "Wowee")
set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/LICENSE")
if(WIN32)
set(CPACK_GENERATOR "NSIS")
set(CPACK_NSIS_DISPLAY_NAME "Wowee")
set(CPACK_NSIS_PACKAGE_NAME "Wowee")
set(CPACK_NSIS_INSTALL_ROOT "$PROGRAMFILES64")
set(CPACK_NSIS_ENABLE_UNINSTALL_BEFORE_INSTALL ON)
# Run wowee from bin/ so that ./assets/ resolves correctly.
# SetOutPath sets the shortcut's working directory in NSIS.
set(CPACK_NSIS_CREATE_ICONS_EXTRA
"SetOutPath '$INSTDIR\\\\bin'\nCreateShortCut '$SMPROGRAMS\\\\$STARTMENU_FOLDER\\\\Wowee.lnk' '$INSTDIR\\\\bin\\\\wowee.exe'")
set(CPACK_NSIS_DELETE_ICONS_EXTRA
"Delete '$SMPROGRAMS\\\\$STARTMENU_FOLDER\\\\Wowee.lnk'")
elseif(APPLE)
set(CPACK_GENERATOR "DragNDrop")
else()
# Linux — generate postinst/prerm wrapper scripts
file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/packaging)
# postinst: write a wrapper script at /usr/local/bin/wowee that cd's to
# the install dir so ./assets/ resolves correctly.
file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/packaging/postinst
[[#!/bin/sh
cat > /usr/local/bin/wowee << 'WOWEE_WRAPPER'
#!/bin/sh
cd /opt/wowee/bin
exec ./wowee "$@"
WOWEE_WRAPPER
chmod +x /usr/local/bin/wowee
]])
file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/packaging/prerm
"#!/bin/sh\nrm -f /usr/local/bin/wowee\n")
file(CHMOD
${CMAKE_CURRENT_BINARY_DIR}/packaging/postinst
${CMAKE_CURRENT_BINARY_DIR}/packaging/prerm
PERMISSIONS
OWNER_EXECUTE OWNER_WRITE OWNER_READ
GROUP_EXECUTE GROUP_READ
WORLD_EXECUTE WORLD_READ)
set(CPACK_GENERATOR "DEB")
set(CPACK_PACKAGING_INSTALL_PREFIX "/opt/wowee")
set(CPACK_DEBIAN_PACKAGE_MAINTAINER "Wowee")
set(CPACK_DEBIAN_PACKAGE_SECTION "games")
set(CPACK_DEBIAN_PACKAGE_DEPENDS
"libsdl2-2.0-0, libvulkan1, libssl3, zlib1g")
set(CPACK_DEBIAN_PACKAGE_CONTROL_EXTRA
"${CMAKE_CURRENT_BINARY_DIR}/packaging/postinst;${CMAKE_CURRENT_BINARY_DIR}/packaging/prerm")
if(CMAKE_SYSTEM_PROCESSOR MATCHES "x86_64|AMD64")
set(CPACK_DEBIAN_PACKAGE_ARCHITECTURE "amd64")
elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "aarch64|ARM64")
set(CPACK_DEBIAN_PACKAGE_ARCHITECTURE "arm64")
endif()
endif()
include(CPack)