From d2e39d2f50684151490da446156622e69dd84a48 Mon Sep 17 00:00:00 2001 From: heinrich5991 Date: Mon, 26 Nov 2018 20:47:20 +0100 Subject: [PATCH 1/5] Add CMake (cherry picked from commit ee2afdac33f43d96a457bcf692a817489d6f896e) --- .gitignore | 40 +- CMakeLists.txt | 1824 +++++++++++++++++ bam.lua | 2 + cmake/FindFreetype.cmake | 37 + cmake/FindPnglite.cmake | 46 + cmake/FindSDL2.cmake | 48 + cmake/FindWavpack.cmake | 52 + cmake/FindZLIB.cmake | 50 + cmake/toolchains/darwin.toolchain | 11 + cmake/toolchains/mingw32.toolchain | 10 + cmake/toolchains/mingw64.toolchain | 10 + other/bundle/client/Info.plist.in | 24 + other/bundle/client/PkgInfo | 1 + other/bundle/server/Info.plist.in | 20 + other/bundle/server/PkgInfo | 1 + other/freetype/freetype.lua | 4 +- .../icons/{Teeworlds.icns => teeworlds.icns} | Bin other/icons/{Teeworlds.ico => teeworlds.ico} | Bin other/icons/teeworlds.rc | 1 + ...{Teeworlds_srv.icns => teeworlds_srv.icns} | Bin .../{Teeworlds_srv.ico => teeworlds_srv.ico} | Bin other/icons/teeworlds_srv.rc | 1 + other/icons/teeworlds_srv_cl.rc | 2 +- other/icons/teeworlds_srv_gcc.rc | 2 +- other/sdl/sdl.lua | 4 +- scripts/darwin_change_dylib.py | 63 + scripts/dmg.py | 106 + scripts/git_revision.py | 21 + src/base/system.c | 13 +- src/base/system.h | 15 + src/engine/client/backend_sdl.cpp | 2 +- src/engine/client/graphics_threaded.cpp | 3 +- src/engine/client/sound.cpp | 78 +- src/engine/client/sound.h | 4 - src/osxlaunch/server.mm | 112 + 35 files changed, 2570 insertions(+), 37 deletions(-) create mode 100644 CMakeLists.txt create mode 100644 cmake/FindFreetype.cmake create mode 100644 cmake/FindPnglite.cmake create mode 100644 cmake/FindSDL2.cmake create mode 100644 cmake/FindWavpack.cmake create mode 100644 cmake/FindZLIB.cmake create mode 100644 cmake/toolchains/darwin.toolchain create mode 100644 cmake/toolchains/mingw32.toolchain create mode 100644 cmake/toolchains/mingw64.toolchain create mode 100644 other/bundle/client/Info.plist.in create mode 100644 other/bundle/client/PkgInfo create mode 100644 other/bundle/server/Info.plist.in create mode 100644 other/bundle/server/PkgInfo rename other/icons/{Teeworlds.icns => teeworlds.icns} (100%) rename other/icons/{Teeworlds.ico => teeworlds.ico} (100%) create mode 100644 other/icons/teeworlds.rc rename other/icons/{Teeworlds_srv.icns => teeworlds_srv.icns} (100%) rename other/icons/{Teeworlds_srv.ico => teeworlds_srv.ico} (100%) create mode 100644 other/icons/teeworlds_srv.rc create mode 100644 scripts/darwin_change_dylib.py create mode 100644 scripts/dmg.py create mode 100644 scripts/git_revision.py create mode 100644 src/osxlaunch/server.mm diff --git a/.gitignore b/.gitignore index 2fbc9201f..3d102c096 100644 --- a/.gitignore +++ b/.gitignore @@ -1,10 +1,12 @@ -/bam /.bam -/config.lua +/bam /build -/other/*/lib +/config.lua +/objs /other/*/include +/other/*/lib __pycache__/ +*.dll *.pyc *.pyo scripts/work/ @@ -12,3 +14,35 @@ scripts/work/ /freetype.dll /autoexec.cfg _test.exe +Info.plist + +crapnet* +fake_server* +map_resave* +map_version* +mastersrv* +packetgen* +teeworlds* +teeworlds_srv* +versionsrv* + +# CMake +data +generated + +.ninja_deps +.ninja_log +CMakeCache.txt +CMakeFiles +CMakeSettings* +CPackConfig.cmake +CPackSourceConfig.cmake +Debug +Makefile +Release +_CPack_Packages/ +build.ninja +cmake_install.cmake +install_manifest.txt +pack_*/ +rules.ninja diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 000000000..f5be54e07 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,1824 @@ +cmake_minimum_required(VERSION 2.8) + +file(STRINGS src/game/version.h VERSION_LINE + LIMIT_COUNT 1 + REGEX GAME_RELEASE_VERSION +) + +if(VERSION_LINE MATCHES "\"([0-9]+)\\.([0-9]+)\\.([0-9]+)\"") + set(VERSION_MAJOR ${CMAKE_MATCH_1}) + set(VERSION_MINOR ${CMAKE_MATCH_2}) + set(VERSION_PATCH ${CMAKE_MATCH_3}) +elseif(VERSION_LINE MATCHES "\"([0-9]+)\\.([0-9]+)\"") + set(VERSION_MAJOR ${CMAKE_MATCH_1}) + set(VERSION_MINOR ${CMAKE_MATCH_2}) + set(VERSION_PATCH "0") +else() + message(FATAL_ERROR "Couldn't parse version from src/game/version.h") +endif() + +if(POLICY CMP0048) + cmake_policy(SET CMP0048 NEW) + project(teeworlds VERSION ${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}) +else() + project(teeworlds) + set(PROJECT_VERSION_MAJOR ${VERSION_MAJOR}) + set(PROJECT_VERSION_MINOR ${VERSION_MINOR}) + set(PROJECT_VERSION_PATCH ${VERSION_PATCH}) + set(PROJECT_VERSION ${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}) +endif() + +set(ORIGINAL_CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH}) +set(ORIGINAL_CMAKE_REQUIRED_INCLUDES ${CMAKE_REQUIRED_INCLUDES}) +set(ORIGINAL_CMAKE_REQUIRED_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES}) +set(OWN_CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${PROJECT_SOURCE_DIR}/cmake) +set(CMAKE_MODULE_PATH ${OWN_CMAKE_MODULE_PATH}) + +if(CMAKE_SIZEOF_VOID_P EQUAL 8) + set(TARGET_BITS "64") +elseif(CMAKE_SIZEOF_VOID_P EQUAL 4) + set(TARGET_BITS "32") +endif() + +if(CMAKE_SYSTEM_NAME STREQUAL "Windows") + set(TARGET_OS "windows") +elseif(CMAKE_SYSTEM_NAME STREQUAL "Linux") + set(TARGET_OS "linux") +elseif(CMAKE_SYSTEM_NAME STREQUAL "Darwin") + set(TARGET_OS "mac") +endif() + +include(CheckCCompilerFlag) +include(CheckCXXCompilerFlag) +include(CheckSymbolExists) + +check_symbol_exists(__i386 "" TARGET_ARCH_X86_i386) +if(TARGET_ARCH_X86_i386) + set(TARGET_ARCH x86) +else() + set(TARGET_ARCH) +endif() + +set(AUTO_DEPENDENCIES_DEFAULT OFF) +if(TARGET_OS STREQUAL "windows") + set(AUTO_DEPENDENCIES_DEFAULT ON) +endif() + +option(CLIENT "Compile client" ON) +option(PREFER_BUNDLED_LIBS "Prefer bundled libraries over system libraries" ${AUTO_DEPENDENCIES_DEFAULT}) +option(DEV "Don't generate stuff necessary for packaging" OFF) + +# Set the default build type to Release +if(NOT(CMAKE_BUILD_TYPE)) + if(DEV) + set(CMAKE_BUILD_TYPE Release) + else() + set(CMAKE_BUILD_TYPE Debug) + endif() +endif() + +set(DBG $,$>) + +set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS + src/game/version.h +) + +set(SERVER_EXECUTABLE teeworlds_srv CACHE STRING "Name of the built server executable") +set(CLIENT_EXECUTABLE teeworlds CACHE STRING "Name of the build client executable") + +######################################################################## +# Compiler flags +######################################################################## + +function(add_c_compiler_flag_if_supported VARIABLE FLAG) + if(ARGC GREATER 2) + set(CHECKED_FLAG "${ARGV2}") + else() + set(CHECKED_FLAG "${FLAG}") + endif() + string(REGEX REPLACE "[^A-Za-z0-9]" "_" CONFIG_VARIABLE "FLAG_SUPPORTED${CHECKED_FLAG}") + check_c_compiler_flag("${CHECKED_FLAG}" ${CONFIG_VARIABLE}) + if(${CONFIG_VARIABLE}) + if(${VARIABLE}) + set("${VARIABLE}" "${${VARIABLE}};${FLAG}" PARENT_SCOPE) + else() + set("${VARIABLE}" "${FLAG}" PARENT_SCOPE) + endif() + endif() +endfunction() + +if(NOT MSVC) + # Protect the stack pointer. + # -fstack-protector-all doesn't work on MinGW. + add_c_compiler_flag_if_supported(OUR_FLAGS -fstack-protector-all) + + # Inaccurate floating point numbers cause problems on mingw-w64-gcc when + # compiling for x86, might cause problems elsewhere. So don't store floats + # in registers but keep them at higher accuracy. + + if(TARGET_ARCH STREQUAL "x86") + add_c_compiler_flag_if_supported(OUR_FLAGS -ffloat-store) + endif() + + if(TARGET_OS STREQUAL "mac") + add_c_compiler_flag_if_supported(OUR_FLAGS -stdlib=libc++) + add_c_compiler_flag_if_supported(OUR_FLAGS -mmacosx-version-min=10.7) + endif() + + add_c_compiler_flag_if_supported(OUR_FLAGS_OWN -Wall) + if(CMAKE_VERSION VERSION_GREATER 3.3 OR CMAKE_VERSION VERSION_EQUAL 3.3) + add_c_compiler_flag_if_supported(OUR_FLAGS_OWN + $<$:-Wdeclaration-after-statement> + -Wdeclaration-after-statement + ) + endif() + add_c_compiler_flag_if_supported(OUR_FLAGS_OWN -Wextra) + add_c_compiler_flag_if_supported(OUR_FLAGS_OWN -Wno-unused-parameter) + add_c_compiler_flag_if_supported(OUR_FLAGS_OWN -Wno-missing-field-initializers) + add_c_compiler_flag_if_supported(OUR_FLAGS_OWN -Wformat=2) # Warn about format strings. + add_c_compiler_flag_if_supported(OUR_FLAGS_DEP -Wno-implicit-function-declaration) +endif() + +if(NOT MSVC) + check_c_compiler_flag("-O2;-Wp,-Werror;-D_FORTIFY_SOURCE=2" DEFINE_FORTIFY_SOURCE) # Some distributions define _FORTIFY_SOURCE by themselves. +endif() + +######################################################################## +# COMMON FUNCTIONS +######################################################################## + +function(set_glob VAR GLOBBING EXTS DIRECTORY) # ... + set(GLOBS) + foreach(ext ${EXTS}) + list(APPEND GLOBS "${DIRECTORY}/*.${ext}") + endforeach() + file(${GLOBBING} GLOB_RESULT ${GLOBS}) + list(SORT GLOB_RESULT) + set(FILES) + foreach(file ${ARGN}) + list(APPEND FILES "${PROJECT_SOURCE_DIR}/${DIRECTORY}/${file}") + endforeach() + + if(NOT FILES STREQUAL GLOB_RESULT) + message(AUTHOR_WARNING "${VAR} does not contain every file from directory ${DIRECTORY}") + set(LIST_BUT_NOT_GLOB) + if(POLICY CMP0057) + cmake_policy(SET CMP0057 NEW) + foreach(file ${FILES}) + if(NOT file IN_LIST GLOB_RESULT) + list(APPEND LIST_BUT_NOT_GLOB ${file}) + endif() + endforeach() + if(LIST_BUT_NOT_GLOB) + message(AUTHOR_WARNING "Entries only present in ${VAR}: ${LIST_BUT_NOT_GLOB}") + endif() + set(GLOB_BUT_NOT_LIST) + foreach(file ${GLOB_RESULT}) + if(NOT file IN_LIST FILES) + list(APPEND GLOB_BUT_NOT_LIST ${file}) + endif() + endforeach() + if(GLOB_BUT_NOT_LIST) + message(AUTHOR_WARNING "Entries only present in ${DIRECTORY}: ${GLOB_BUT_NOT_LIST}") + endif() + endif() + endif() + + set(${VAR} ${FILES} PARENT_SCOPE) +endfunction() + +function(set_src VAR GLOBBING DIRECTORY) # ... + set_glob(${VAR} ${GLOBBING} "c;cpp;h" ${DIRECTORY} ${ARGN}) + set(${VAR} ${${VAR}} PARENT_SCOPE) +endfunction() + +######################################################################## +# INITIALIZE TARGET LISTS +######################################################################## + +set(TARGETS_OWN) +set(TARGETS_DEP) + +set(TARGETS_LINK) # Targets with a linking stage. + +######################################################################## +# DEPENDENCIES +######################################################################## + +function(set_extra_dirs_lib VARIABLE NAME) + set("PATHS_${VARIABLE}_LIBDIR" PARENT_SCOPE) + set("HINTS_${VARIABLE}_LIBDIR" PARENT_SCOPE) + if(PREFER_BUNDLED_LIBS) + set(TYPE HINTS) + else() + set(TYPE PATHS) + endif() + if(TARGET_BITS AND TARGET_OS) + set(DIR "other/${NAME}/${TARGET_OS}/lib${TARGET_BITS}") + set("${TYPE}_${VARIABLE}_LIBDIR" "${DIR}" PARENT_SCOPE) + set("EXTRA_${VARIABLE}_LIBDIR" "${DIR}" PARENT_SCOPE) + endif() +endfunction() + +function(set_extra_dirs_include VARIABLE NAME LIBRARY) + set("PATHS_${VARIABLE}_INCLUDEDIR" PARENT_SCOPE) + set("HINTS_${VARIABLE}_INCLUDEDIR" PARENT_SCOPE) + is_bundled(IS_BUNDLED "${LIBRARY}") + if(IS_BUNDLED) + set("HINTS_${VARIABLE}_INCLUDEDIR" "other/${NAME}/include" "other/${NAME}/include/${TARGET_OS}" PARENT_SCOPE) + endif() +endfunction() + +if(CMAKE_CROSSCOMPILING) + set(CROSSCOMPILING_NO_CMAKE_SYSTEM_PATH NO_CMAKE_SYSTEM_PATH) +else() + set(CROSSCOMPILING_NO_CMAKE_SYSTEM_PATH) +endif() + +function(is_bundled VARIABLE PATH) + if(PATH) + string(FIND "${PATH}" "${PROJECT_SOURCE_DIR}" LOCAL_PATH_POS) + if(LOCAL_PATH_POS EQUAL 0 AND TARGET_BITS AND TARGET_OS) + set("${VARIABLE}" ON PARENT_SCOPE) + else() + set("${VARIABLE}" OFF PARENT_SCOPE) + endif() + else() + set("${VARIABLE}" OFF PARENT_SCOPE) + endif() +endfunction() + +if(NOT CMAKE_CROSSCOMPILING) + # Check for PkgConfig once so all the other `find_package` calls can do it + # quietly. + find_package(PkgConfig) +endif() +find_package(ZLIB) +find_package(Freetype) +find_package(Git) +find_package(Pnglite) +find_package(PythonInterp) +find_package(SDL2) +find_package(Threads) +find_package(Wavpack) + + +if(TARGET_OS AND TARGET_OS STREQUAL "mac") + find_program(CMAKE_OTOOL otool) + find_program(DMG dmg) + find_program(HFSPLUS hfsplus) + find_program(NEWFS_HFS newfs_hfs) + if(DMG AND HFSPLUS AND NEWFS_HFS) + set(DMGTOOLS_FOUND ON) + else() + set(DMGTOOLS_FOUND OFF) + endif() + + find_program(HDIUTIL hdiutil) +endif() + +message(STATUS "******** Teeworlds ********") +message(STATUS "Target OS: ${TARGET_OS} ${TARGET_BITS}bit") +message(STATUS "Compiler: ${CMAKE_CXX_COMPILER}") +message(STATUS "Build type: ${CMAKE_BUILD_TYPE}") + +message(STATUS "Dependencies:") +function(show_dependency_status OUTPUT_NAME NAME) + if(${NAME}_FOUND) + if(${NAME}_BUNDLED) + message(STATUS " * ${OUTPUT_NAME} not found (using bundled version)") + else() + message(STATUS " * ${OUTPUT_NAME} found") + endif() + else() + message(STATUS " * ${OUTPUT_NAME} not found") + endif() +endfunction() + +if(TARGET_OS AND TARGET_OS STREQUAL "mac") + show_dependency_status("Dmg tools" DMGTOOLS) +endif() +show_dependency_status("Freetype" FREETYPE) +if(TARGET_OS AND TARGET_OS STREQUAL "mac") + show_dependency_status("Hdiutil" HDIUTIL) +endif() +show_dependency_status("Pnglite" PNGLITE) +show_dependency_status("PythonInterp" PYTHONINTERP) +show_dependency_status("SDL2" SDL2) +show_dependency_status("Wavpack" WAVPACK) +show_dependency_status("Zlib" ZLIB) + +if(NOT(PYTHONINTERP_FOUND)) + message(SEND_ERROR "You must install Python to compile Teeworlds") +endif() + +if(CLIENT AND NOT(FREETYPE_FOUND)) + message(SEND_ERROR "You must install Freetype to compile the Teeworlds client") +endif() +if(CLIENT AND NOT(SDL2_FOUND)) + message(SEND_ERROR "You must install SDL2 to compile the Teeworlds client") +endif() + +if(TARGET_OS STREQUAL "windows") + set(PLATFORM_CLIENT) + set(PLATFORM_CLIENT_LIBS opengl32 glu32 winmm) + set(PLATFORM_LIBS ws2_32) # Windows sockets +elseif(TARGET_OS STREQUAL "mac") + find_library(CARBON Carbon) + find_library(COCOA Cocoa) + find_library(OPENGL OpenGL) + set(PLATFORM_CLIENT + src/osxlaunch/client.h + src/osxlaunch/client.m + ) + set(PLATFORM_CLIENT_LIBS ${COCOA} ${OPENGL}) + set(PLATFORM_LIBS ${CARBON}) +else() + set(PLATFORM_CLIENT) + set(PLATFORM_CLIENT_LIBS GL GLU X11) + if(TARGET_OS STREQUAL "linux") + set(PLATFORM_LIBS rt) # clock_gettime for glibc < 2.17 + else() + set(PLATFORM_LIBS) + endif() +endif() + +######################################################################## +# DEPENDENCY COMPILATION +######################################################################## + +set_src(DEP_JSON_SRC GLOB src/engine/external/json-parser json.c json.h) +add_library(json EXCLUDE_FROM_ALL OBJECT ${DEP_JSON_SRC}) + +set_src(DEP_MD5_SRC GLOB src/engine/external/md5 md5.c md5.h) +add_library(md5 EXCLUDE_FROM_ALL OBJECT ${DEP_MD5_SRC}) + +list(APPEND TARGETS_DEP json md5) +set(DEP_MD5 $ $) + +######################################################################## +# DATA +######################################################################## + +set_glob(DATA GLOB_RECURSE "json;map;png;rules;ttf;txt;wv" datasrc + audio/foley_body_impact-01.wv + audio/foley_body_impact-02.wv + audio/foley_body_impact-03.wv + audio/foley_body_splat-01.wv + audio/foley_body_splat-02.wv + audio/foley_body_splat-03.wv + audio/foley_body_splat-04.wv + audio/foley_dbljump-01.wv + audio/foley_dbljump-02.wv + audio/foley_dbljump-03.wv + audio/foley_foot_left-01.wv + audio/foley_foot_left-02.wv + audio/foley_foot_left-03.wv + audio/foley_foot_left-04.wv + audio/foley_foot_right-01.wv + audio/foley_foot_right-02.wv + audio/foley_foot_right-03.wv + audio/foley_foot_right-04.wv + audio/foley_land-01.wv + audio/foley_land-02.wv + audio/foley_land-03.wv + audio/foley_land-04.wv + audio/hook_attach-01.wv + audio/hook_attach-02.wv + audio/hook_attach-03.wv + audio/hook_loop-01.wv + audio/hook_loop-02.wv + audio/hook_noattach-01.wv + audio/hook_noattach-02.wv + audio/hook_noattach-03.wv + audio/music_menu.wv + audio/sfx_ctf_cap_pl.wv + audio/sfx_ctf_drop.wv + audio/sfx_ctf_grab_en.wv + audio/sfx_ctf_grab_pl.wv + audio/sfx_ctf_rtn.wv + audio/sfx_hit_strong-01.wv + audio/sfx_hit_strong-02.wv + audio/sfx_hit_weak-01.wv + audio/sfx_hit_weak-02.wv + audio/sfx_hit_weak-03.wv + audio/sfx_msg-client.wv + audio/sfx_msg-highlight.wv + audio/sfx_msg-server.wv + audio/sfx_pickup_arm-01.wv + audio/sfx_pickup_arm-02.wv + audio/sfx_pickup_arm-03.wv + audio/sfx_pickup_arm-04.wv + audio/sfx_pickup_gun.wv + audio/sfx_pickup_hrt-01.wv + audio/sfx_pickup_hrt-02.wv + audio/sfx_pickup_launcher.wv + audio/sfx_pickup_ninja.wv + audio/sfx_pickup_sg.wv + audio/sfx_skid-01.wv + audio/sfx_skid-02.wv + audio/sfx_skid-03.wv + audio/sfx_skid-04.wv + audio/sfx_spawn_wpn-01.wv + audio/sfx_spawn_wpn-02.wv + audio/sfx_spawn_wpn-03.wv + audio/vo_teefault_cry-01.wv + audio/vo_teefault_cry-02.wv + audio/vo_teefault_ninja-01.wv + audio/vo_teefault_ninja-02.wv + audio/vo_teefault_ninja-03.wv + audio/vo_teefault_ninja-04.wv + audio/vo_teefault_pain_long-01.wv + audio/vo_teefault_pain_long-02.wv + audio/vo_teefault_pain_short-01.wv + audio/vo_teefault_pain_short-02.wv + audio/vo_teefault_pain_short-03.wv + audio/vo_teefault_pain_short-04.wv + audio/vo_teefault_pain_short-05.wv + audio/vo_teefault_pain_short-06.wv + audio/vo_teefault_pain_short-07.wv + audio/vo_teefault_pain_short-08.wv + audio/vo_teefault_pain_short-09.wv + audio/vo_teefault_pain_short-10.wv + audio/vo_teefault_pain_short-11.wv + audio/vo_teefault_pain_short-12.wv + audio/vo_teefault_sledge-01.wv + audio/vo_teefault_sledge-02.wv + audio/vo_teefault_sledge-03.wv + audio/vo_teefault_spawn-01.wv + audio/vo_teefault_spawn-02.wv + audio/vo_teefault_spawn-03.wv + audio/vo_teefault_spawn-04.wv + audio/vo_teefault_spawn-05.wv + audio/vo_teefault_spawn-06.wv + audio/vo_teefault_spawn-07.wv + audio/wp_flump_explo-01.wv + audio/wp_flump_explo-02.wv + audio/wp_flump_explo-03.wv + audio/wp_flump_launch-01.wv + audio/wp_flump_launch-02.wv + audio/wp_flump_launch-03.wv + audio/wp_gun_fire-01.wv + audio/wp_gun_fire-02.wv + audio/wp_gun_fire-03.wv + audio/wp_hammer_hit-01.wv + audio/wp_hammer_hit-02.wv + audio/wp_hammer_hit-03.wv + audio/wp_hammer_swing-01.wv + audio/wp_hammer_swing-02.wv + audio/wp_hammer_swing-03.wv + audio/wp_laser_bnce-01.wv + audio/wp_laser_bnce-02.wv + audio/wp_laser_bnce-03.wv + audio/wp_laser_fire-01.wv + audio/wp_laser_fire-02.wv + audio/wp_laser_fire-03.wv + audio/wp_ninja_attack-01.wv + audio/wp_ninja_attack-02.wv + audio/wp_ninja_attack-03.wv + audio/wp_ninja_attack-04.wv + audio/wp_ninja_hit-01.wv + audio/wp_ninja_hit-02.wv + audio/wp_ninja_hit-03.wv + audio/wp_ninja_hit-04.wv + audio/wp_noammo-01.wv + audio/wp_noammo-02.wv + audio/wp_noammo-03.wv + audio/wp_noammo-04.wv + audio/wp_noammo-05.wv + audio/wp_shotty_fire-01.wv + audio/wp_shotty_fire-02.wv + audio/wp_shotty_fire-03.wv + audio/wp_switch-01.wv + audio/wp_switch-02.wv + audio/wp_switch-03.wv + countryflags/AD.png + countryflags/AE.png + countryflags/AF.png + countryflags/AG.png + countryflags/AI.png + countryflags/AL.png + countryflags/AM.png + countryflags/AO.png + countryflags/AR.png + countryflags/AS.png + countryflags/AT.png + countryflags/AU.png + countryflags/AW.png + countryflags/AX.png + countryflags/AZ.png + countryflags/BA.png + countryflags/BB.png + countryflags/BD.png + countryflags/BE.png + countryflags/BF.png + countryflags/BG.png + countryflags/BH.png + countryflags/BI.png + countryflags/BJ.png + countryflags/BL.png + countryflags/BM.png + countryflags/BN.png + countryflags/BO.png + countryflags/BR.png + countryflags/BS.png + countryflags/BT.png + countryflags/BW.png + countryflags/BY.png + countryflags/BZ.png + countryflags/CA.png + countryflags/CC.png + countryflags/CD.png + countryflags/CF.png + countryflags/CG.png + countryflags/CH.png + countryflags/CI.png + countryflags/CK.png + countryflags/CL.png + countryflags/CM.png + countryflags/CN.png + countryflags/CO.png + countryflags/CR.png + countryflags/CU.png + countryflags/CV.png + countryflags/CW.png + countryflags/CX.png + countryflags/CY.png + countryflags/CZ.png + countryflags/DE.png + countryflags/DJ.png + countryflags/DK.png + countryflags/DM.png + countryflags/DO.png + countryflags/DZ.png + countryflags/EC.png + countryflags/EE.png + countryflags/EG.png + countryflags/EH.png + countryflags/ER.png + countryflags/ES.png + countryflags/ET.png + countryflags/FI.png + countryflags/FJ.png + countryflags/FK.png + countryflags/FM.png + countryflags/FO.png + countryflags/FR.png + countryflags/GA.png + countryflags/GB.png + countryflags/GD.png + countryflags/GE.png + countryflags/GF.png + countryflags/GG.png + countryflags/GH.png + countryflags/GI.png + countryflags/GL.png + countryflags/GM.png + countryflags/GN.png + countryflags/GP.png + countryflags/GQ.png + countryflags/GR.png + countryflags/GS.png + countryflags/GT.png + countryflags/GU.png + countryflags/GW.png + countryflags/GY.png + countryflags/HK.png + countryflags/HN.png + countryflags/HR.png + countryflags/HT.png + countryflags/HU.png + countryflags/ID.png + countryflags/IE.png + countryflags/IL.png + countryflags/IM.png + countryflags/IN.png + countryflags/IO.png + countryflags/IQ.png + countryflags/IR.png + countryflags/IS.png + countryflags/IT.png + countryflags/JE.png + countryflags/JM.png + countryflags/JO.png + countryflags/JP.png + countryflags/KE.png + countryflags/KG.png + countryflags/KH.png + countryflags/KI.png + countryflags/KM.png + countryflags/KN.png + countryflags/KP.png + countryflags/KR.png + countryflags/KW.png + countryflags/KY.png + countryflags/KZ.png + countryflags/LA.png + countryflags/LB.png + countryflags/LC.png + countryflags/LI.png + countryflags/LK.png + countryflags/LR.png + countryflags/LS.png + countryflags/LT.png + countryflags/LU.png + countryflags/LV.png + countryflags/LY.png + countryflags/MA.png + countryflags/MC.png + countryflags/MD.png + countryflags/ME.png + countryflags/MF.png + countryflags/MG.png + countryflags/MH.png + countryflags/MK.png + countryflags/ML.png + countryflags/MM.png + countryflags/MN.png + countryflags/MO.png + countryflags/MP.png + countryflags/MQ.png + countryflags/MR.png + countryflags/MS.png + countryflags/MT.png + countryflags/MU.png + countryflags/MV.png + countryflags/MW.png + countryflags/MX.png + countryflags/MY.png + countryflags/MZ.png + countryflags/NA.png + countryflags/NC.png + countryflags/NE.png + countryflags/NF.png + countryflags/NG.png + countryflags/NI.png + countryflags/NL.png + countryflags/NO.png + countryflags/NP.png + countryflags/NR.png + countryflags/NU.png + countryflags/NZ.png + countryflags/OM.png + countryflags/PA.png + countryflags/PE.png + countryflags/PF.png + countryflags/PG.png + countryflags/PH.png + countryflags/PK.png + countryflags/PL.png + countryflags/PM.png + countryflags/PN.png + countryflags/PR.png + countryflags/PS.png + countryflags/PT.png + countryflags/PW.png + countryflags/PY.png + countryflags/QA.png + countryflags/RE.png + countryflags/RO.png + countryflags/RS.png + countryflags/RU.png + countryflags/RW.png + countryflags/SA.png + countryflags/SB.png + countryflags/SC.png + countryflags/SD.png + countryflags/SE.png + countryflags/SG.png + countryflags/SH.png + countryflags/SI.png + countryflags/SK.png + countryflags/SL.png + countryflags/SM.png + countryflags/SN.png + countryflags/SO.png + countryflags/SR.png + countryflags/SS.png + countryflags/ST.png + countryflags/SV.png + countryflags/SX.png + countryflags/SY.png + countryflags/SZ.png + countryflags/TC.png + countryflags/TD.png + countryflags/TF.png + countryflags/TG.png + countryflags/TH.png + countryflags/TJ.png + countryflags/TK.png + countryflags/TL.png + countryflags/TM.png + countryflags/TN.png + countryflags/TO.png + countryflags/TR.png + countryflags/TT.png + countryflags/TV.png + countryflags/TW.png + countryflags/TZ.png + countryflags/UA.png + countryflags/UG.png + countryflags/US.png + countryflags/UY.png + countryflags/UZ.png + countryflags/VA.png + countryflags/VC.png + countryflags/VE.png + countryflags/VG.png + countryflags/VI.png + countryflags/VN.png + countryflags/VU.png + countryflags/WF.png + countryflags/WS.png + countryflags/XBZ.png + countryflags/XCA.png + countryflags/XEN.png + countryflags/XES.png + countryflags/XGA.png + countryflags/XNI.png + countryflags/XSC.png + countryflags/XWA.png + countryflags/YE.png + countryflags/ZA.png + countryflags/ZM.png + countryflags/ZW.png + countryflags/default.png + countryflags/index.json + deadtee.png + editor/automap/grass_doodads.json + editor/automap/grass_main.json + editor/background.png + editor/checker.png + editor/cursor.png + editor/desert_main.rules + editor/entities.png + editor/grass_main.rules + editor/jungle_main.rules + editor/winter_main.rules + emoticons.png + fonts/DejaVuSans.ttf + game.png + languages/belarusian.json + languages/bosnian.json + languages/brazilian_portuguese.json + languages/breton.json + languages/bulgarian.json + languages/catalan.json + languages/chinese.json + languages/chuvash.json + languages/czech.json + languages/danish.json + languages/dutch.json + languages/esperanto.json + languages/estonian.json + languages/finnish.json + languages/french.json + languages/gaelic_scottish.json + languages/galician.json + languages/german.json + languages/greek.json + languages/hungarian.json + languages/index.json + languages/irish.json + languages/italian.json + languages/japanese.json + languages/korean.json + languages/kyrgyz.json + languages/license.txt + languages/lithuanian.json + languages/norwegian.json + languages/polish.json + languages/portuguese.json + languages/readme.txt + languages/romanian.json + languages/russian.json + languages/serbian.json + languages/simplified_chinese.json + languages/slovak.json + languages/slovenian.json + languages/spanish.json + languages/swedish.json + languages/turkish.json + languages/ukrainian.json + mapres/bg_cloud1.png + mapres/bg_cloud2.png + mapres/bg_cloud3.png + mapres/desert_doodads.png + mapres/desert_main.png + mapres/desert_mountains.png + mapres/desert_mountains2.png + mapres/desert_sun.png + mapres/generic_deathtiles.png + mapres/generic_lamps.png + mapres/generic_shadows.png + mapres/generic_unhookable.png + mapres/grass_doodads.png + mapres/grass_main.png + mapres/jungle_background.png + mapres/jungle_deathtiles.png + mapres/jungle_doodads.png + mapres/jungle_main.png + mapres/jungle_midground.png + mapres/jungle_unhookables.png + mapres/light.png + mapres/moon.png + mapres/mountains.png + mapres/snow.png + mapres/stars.png + mapres/sun.png + mapres/winter_doodads.png + mapres/winter_main.png + mapres/winter_mountains.png + mapres/winter_mountains2.png + mapres/winter_mountains3.png + maps/ctf1.map + maps/ctf2.map + maps/ctf3.map + maps/ctf4.map + maps/ctf5.map + maps/ctf6.map + maps/ctf7.map + maps/ctf8.map + maps/dm1.map + maps/dm2.map + maps/dm3.map + maps/dm6.map + maps/dm7.map + maps/dm8.map + maps/dm9.map + maps/license.txt + maps/lms1.map + maps/readme.txt + particles.png + skins/bluekitty.json + skins/bluestripe.json + skins/body/bear.png + skins/body/kitty.png + skins/body/standard.png + skins/body/x_ninja.png + skins/brownbear.json + skins/cammo.json + skins/cammostripes.json + skins/decoration/hair.png + skins/decoration/twinbopp.png + skins/decoration/unibop.png + skins/default.json + skins/eyes/standard.png + skins/eyes/standardreal.png + skins/eyes/x_ninja.png + skins/feet/standard.png + skins/hands/standard.png + skins/koala.json + skins/limekitty.json + skins/marking/bear.png + skins/marking/cammo1.png + skins/marking/cammo2.png + skins/marking/cammostripes.png + skins/marking/donny.png + skins/marking/duodonny.png + skins/marking/saddo.png + skins/marking/stripe.png + skins/marking/stripes.png + skins/marking/toptri.png + skins/marking/twintri.png + skins/marking/uppy.png + skins/marking/warpaint.png + skins/marking/whisker.png + skins/pinky.json + skins/redbopp.json + skins/redstripe.json + skins/saddo.json + skins/toptri.json + skins/twinbop.json + skins/twintri.json + skins/warpaint.json + skins/x_ninja.json + skins/xmas_hat.png + ui/blob.png + ui/console.png + ui/console_bar.png + ui/debug_font.png + ui/demo_buttons.png + ui/file_icons.png + ui/gametypes/ctf.png + ui/gametypes/dm.png + ui/gametypes/lms.png + ui/gametypes/lts.png + ui/gametypes/mod.png + ui/gametypes/tdm.png + ui/gui_buttons.png + ui/gui_cursor.png + ui/gui_icons.png + ui/gui_logo.png + ui/icons/arrows.png + ui/icons/browse.png + ui/icons/chat_whisper.png + ui/icons/friend.png + ui/icons/info.png + ui/icons/level.png + ui/icons/menu.png + ui/icons/sidebar.png + ui/icons/tools.png + ui/menuimages/demos.png + ui/menuimages/editor.png + ui/menuimages/local_server.png + ui/menuimages/play_game.png + ui/menuimages/settings.png + ui/no_skinpart.png + ui/themes/heavens.png + ui/themes/heavens_day.map + ui/themes/heavens_night.map + ui/themes/jungle.png + ui/themes/jungle_day.map + ui/themes/jungle_night.map + ui/themes/none.png +) + +######################################################################## +# COPY DATA AND DLLS +######################################################################## + +foreach(datafile ${DATA}) + file(RELATIVE_PATH OUT ${PROJECT_SOURCE_DIR}/datasrc ${datafile}) + get_filename_component(DESTINATION data/${OUT} PATH) + file(MAKE_DIRECTORY ${DESTINATION}) + file(COPY ${datafile} DESTINATION ${DESTINATION}) +endforeach() +set(COPY_FILES + ${FREETYPE_COPY_FILES} + ${SDL2_COPY_FILES} +) +file(COPY ${COPY_FILES} DESTINATION .) + +######################################################################## +# CODE GENERATION +######################################################################## + +function(chash output_file) + add_custom_command(OUTPUT ${output_file} + COMMAND ${PYTHON_EXECUTABLE} scripts/cmd5.py ${ARGN} + > "${PROJECT_BINARY_DIR}/${output_file}" + DEPENDS scripts/cmd5.py ${ARGN} + WORKING_DIRECTORY ${PROJECT_SOURCE_DIR} + ) +endfunction() + +function(generate_source output_file script_parameter) + add_custom_command(OUTPUT ${output_file} + COMMAND ${PYTHON_EXECUTABLE} datasrc/compile.py ${script_parameter} + > "${PROJECT_BINARY_DIR}/${output_file}" + DEPENDS + datasrc/compile.py + datasrc/content.py + datasrc/datatypes.py + datasrc/network.py + WORKING_DIRECTORY ${PROJECT_SOURCE_DIR} + ) +endfunction() + +file(MAKE_DIRECTORY "${PROJECT_BINARY_DIR}/src/generated/") +if(GIT_FOUND) + execute_process(COMMAND ${GIT_EXECUTABLE} rev-parse --git-dir + ERROR_QUIET + OUTPUT_VARIABLE PROJECT_GIT_DIR + OUTPUT_STRIP_TRAILING_WHITESPACE + RESULT_VARIABLE PROJECT_GIT_DIR_ERROR + ) + if(NOT PROJECT_GIT_DIR_ERROR) + set(GIT_REVISION_EXTRA_DEPS + ${PROJECT_GIT_DIR}/index + ${PROJECT_GIT_DIR}/logs/HEAD + ) + endif() +endif() +add_custom_command(OUTPUT ${PROJECT_BINARY_DIR}/src/generated/git_revision.cpp + COMMAND ${PYTHON_EXECUTABLE} + scripts/git_revision.py + > ${PROJECT_BINARY_DIR}/src/generated/git_revision.cpp + WORKING_DIRECTORY ${PROJECT_SOURCE_DIR} + DEPENDS + ${GIT_REVISION_EXTRA_DEPS} + scripts/git_revision.py +) +chash("src/generated/nethash.cpp" + "src/engine/shared/protocol.h" + "src/game/tuning.h" + "src/game/gamecore.cpp" + "${PROJECT_BINARY_DIR}/src/generated/protocol.h" +) +generate_source("src/generated/client_data.cpp" "client_content_source") +generate_source("src/generated/client_data.h" "client_content_header") +generate_source("src/generated/protocol.cpp" "network_source") +generate_source("src/generated/protocol.h" "network_header") +generate_source("src/generated/server_data.cpp" "server_content_source") +generate_source("src/generated/server_data.h" "server_content_header") + + +######################################################################## +# SHARED +######################################################################## + +# Sources +set_src(BASE GLOB_RECURSE src/base + color.h + detect.h + math.h + system.c + system.h + tl/algorithm.h + tl/allocator.h + tl/array.h + tl/base.h + tl/range.h + tl/sorted_array.h + tl/string.h + tl/threading.h + vmath.h +) +set_src(ENGINE_INTERFACE GLOB src/engine + client.h + config.h + console.h + demo.h + editor.h + engine.h + friends.h + graphics.h + input.h + kernel.h + keys.h + map.h + masterserver.h + message.h + server.h + serverbrowser.h + sound.h + storage.h + textrender.h +) +set_src(ENGINE_SHARED GLOB src/engine/shared + compression.cpp + compression.h + config.cpp + config.h + config_variables.h + console.cpp + console.h + datafile.cpp + datafile.h + demo.cpp + demo.h + econ.cpp + econ.h + engine.cpp + filecollection.cpp + filecollection.h + huffman.cpp + huffman.h + jobs.cpp + jobs.h + kernel.cpp + linereader.cpp + linereader.h + map.cpp + mapchecker.cpp + mapchecker.h + masterserver.cpp + memheap.cpp + memheap.h + message.h + netban.cpp + netban.h + network.cpp + network.h + network_client.cpp + network_conn.cpp + network_console.cpp + network_console_conn.cpp + network_server.cpp + network_token.cpp + packer.cpp + packer.h + protocol.h + ringbuffer.cpp + ringbuffer.h + snapshot.cpp + snapshot.h + storage.cpp +) +set(ENGINE_GENERATED_SHARED src/generated/protocol.cpp src/generated/protocol.h) +set_src(GAME_SHARED GLOB src/game + collision.cpp + collision.h + gamecore.cpp + gamecore.h + layers.cpp + layers.h + mapitems.h + tuning.h + variables.h + version.h + voting.h +) +set(GAME_GENERATED_SHARED + src/generated/git_revision.cpp + src/generated/nethash.cpp + src/generated/protocol.h +) + +set(DEPS ${DEP_MD5} ${ZLIB_DEP}) + +# Libraries +set(LIBS ${CMAKE_THREAD_LIBS_INIT} ${ZLIB_LIBRARIES} ${PLATFORM_LIBS}) + +# Targets +add_library(engine-shared EXCLUDE_FROM_ALL OBJECT ${ENGINE_INTERFACE} ${ENGINE_SHARED} ${ENGINE_GENERATED_SHARED} ${BASE}) +add_library(game-shared EXCLUDE_FROM_ALL OBJECT ${GAME_SHARED} ${GAME_GENERATED_SHARED}) +list(APPEND TARGETS_OWN engine-shared game-shared) + + +######################################################################## +# CLIENT +######################################################################## + +if(CLIENT) + # Sources + set_src(ENGINE_CLIENT GLOB src/engine/client + backend_sdl.cpp + backend_sdl.h + client.cpp + client.h + friends.cpp + friends.h + graphics_threaded.cpp + graphics_threaded.h + input.cpp + input.h + keynames.h + serverbrowser.cpp + serverbrowser.h + serverbrowser_entry.h + serverbrowser_fav.cpp + serverbrowser_fav.h + serverbrowser_filter.cpp + serverbrowser_filter.h + sound.cpp + sound.h + text.cpp + ) + set_src(GAME_CLIENT GLOB_RECURSE src/game/client + animstate.cpp + animstate.h + component.h + components/binds.cpp + components/binds.h + components/broadcast.cpp + components/broadcast.h + components/camera.cpp + components/camera.h + components/chat.cpp + components/chat.h + components/console.cpp + components/console.h + components/controls.cpp + components/controls.h + components/countryflags.cpp + components/countryflags.h + components/damageind.cpp + components/damageind.h + components/debughud.cpp + components/debughud.h + components/effects.cpp + components/effects.h + components/emoticon.cpp + components/emoticon.h + components/flow.cpp + components/flow.h + components/hud.cpp + components/hud.h + components/items.cpp + components/items.h + components/killmessages.cpp + components/killmessages.h + components/mapimages.cpp + components/mapimages.h + components/maplayers.cpp + components/maplayers.h + components/menus.cpp + components/menus.h + components/menus_browser.cpp + components/menus_callback.cpp + components/menus_demo.cpp + components/menus_ingame.cpp + components/menus_popups.cpp + components/menus_settings.cpp + components/menus_start.cpp + components/motd.cpp + components/motd.h + components/nameplates.cpp + components/nameplates.h + components/particles.cpp + components/particles.h + components/players.cpp + components/players.h + components/scoreboard.cpp + components/scoreboard.h + components/skins.cpp + components/skins.h + components/sounds.cpp + components/sounds.h + components/spectator.cpp + components/spectator.h + components/voting.cpp + components/voting.h + gameclient.cpp + gameclient.h + lineinput.cpp + lineinput.h + localization.cpp + localization.h + render.cpp + render.h + render_map.cpp + ui.cpp + ui.h + ) + set_src(GAME_EDITOR GLOB src/game/editor + auto_map.cpp + auto_map.h + editor.cpp + editor.h + io.cpp + layer_game.cpp + layer_quads.cpp + layer_tiles.cpp + popups.cpp + ) + set(GAME_GENERATED_CLIENT + src/generated/client_data.cpp + src/generated/client_data.h + ) + set(CLIENT_SRC ${PLATFORM_CLIENT} ${ENGINE_CLIENT} ${GAME_CLIENT} ${GAME_EDITOR} ${GAME_GENERATED_CLIENT}) + + set(DEPS_CLIENT ${DEPS} ${PNGLITE_DEP} ${WAVPACK_DEP}) + + # Libraries + set(LIBS_CLIENT + ${LIBS} + ${FREETYPE_LIBRARIES} + ${PNGLITE_LIBRARIES} + ${SDL2_LIBRARIES} + ${WAVPACK_LIBRARIES} + ${PLATFORM_CLIENT_LIBS} + ) + + if(TARGET_OS STREQUAL "windows") + set(CLIENT_ICON "other/icons/${CLIENT_EXECUTABLE}.rc") + else() + set(CLIENT_ICON) + endif() + + # Target + set(TARGET_CLIENT ${CLIENT_EXECUTABLE}) + add_executable(${TARGET_CLIENT} + ${CLIENT_SRC} + ${CLIENT_ICON} + ${CLIENT_MANIFEST} + ${DEPS_CLIENT} + $ + $ + ) + target_link_libraries(${TARGET_CLIENT} ${LIBS_CLIENT}) + + target_include_directories(${TARGET_CLIENT} PRIVATE + ${FREETYPE_INCLUDE_DIRS} + ${PNGLITE_INCLUDE_DIRS} + ${SDL2_INCLUDE_DIRS} + ${WAVPACK_INCLUDE_DIRS} + ) + + set(PARAMS "${WAVPACK_INCLUDE_DIRS};${WAVPACK_INCLUDE_DIRS}") + if(NOT(WAVPACK_OPEN_FILE_INPUT_EX_PARAMS STREQUAL PARAMS)) + unset(WAVPACK_OPEN_FILE_INPUT_EX CACHE) + endif() + set(WAVPACK_OPEN_FILE_INPUT_EX_PARAMS "${PARAMS}" CACHE INTERNAL "") + + set(CMAKE_REQUIRED_INCLUDES ${ORIGINAL_CMAKE_REQUIRED_INCLUDES} ${WAVPACK_INCLUDE_DIRS}) + set(CMAKE_REQUIRED_LIBRARIES ${ORIGINAL_CMAKE_REQUIRED_LIBRARIES} ${WAVPACK_LIBRARIES}) + check_symbol_exists(WavpackOpenFileInputEx wavpack.h WAVPACK_OPEN_FILE_INPUT_EX) + set(CMAKE_REQUIRED_INCLUDES ${ORIGINAL_CMAKE_REQUIRED_INCLUDES}) + set(CMAKE_REQUIRED_LIBRARIES ${ORIGINAL_CMAKE_REQUIRED_LIBRARIES}) + + if(WAVPACK_OPEN_FILE_INPUT_EX) + target_compile_definitions(${TARGET_CLIENT} PRIVATE CONF_WAVPACK_OPEN_FILE_INPUT_EX) + endif() + + list(APPEND TARGETS_OWN ${TARGET_CLIENT}) + list(APPEND TARGETS_LINK ${TARGET_CLIENT}) +endif() + + +######################################################################## +# SERVER +######################################################################## + +# Sources +set_src(ENGINE_SERVER GLOB src/engine/server + register.cpp + register.h + server.cpp + server.h +) +set_src(GAME_SERVER GLOB_RECURSE src/game/server + alloc.h + entities/character.cpp + entities/character.h + entities/flag.cpp + entities/flag.h + entities/laser.cpp + entities/laser.h + entities/pickup.cpp + entities/pickup.h + entities/projectile.cpp + entities/projectile.h + entity.cpp + entity.h + eventhandler.cpp + eventhandler.h + gamecontext.cpp + gamecontext.h + gamecontroller.cpp + gamecontroller.h + gamemodes/ctf.cpp + gamemodes/ctf.h + gamemodes/dm.cpp + gamemodes/dm.h + gamemodes/lms.cpp + gamemodes/lms.h + gamemodes/lts.cpp + gamemodes/lts.h + gamemodes/mod.cpp + gamemodes/mod.h + gamemodes/tdm.cpp + gamemodes/tdm.h + gameworld.cpp + gameworld.h + player.cpp + player.h +) +set(GAME_GENERATED_SERVER + src/generated/server_data.cpp + src/generated/server_data.h +) +set(SERVER_SRC ${ENGINE_SERVER} ${GAME_SERVER} ${GAME_GENERATED_SERVER}) +if(TARGET_OS STREQUAL "windows") + set(SERVER_ICON "other/icons/${SERVER_EXECUTABLE}.rc") +else() + set(SERVER_ICON) +endif() + +# Libraries +set(LIBS_SERVER ${LIBS}) + +# Target +set(TARGET_SERVER ${SERVER_EXECUTABLE}) +add_executable(${TARGET_SERVER} + ${DEPS} + ${SERVER_SRC} + ${SERVER_ICON} + $ + $ +) +target_link_libraries(${TARGET_SERVER} ${LIBS_SERVER}) +list(APPEND TARGETS_OWN ${TARGET_SERVER}) +list(APPEND TARGETS_LINK ${TARGET_SERVER}) + +if(TARGET_OS AND TARGET_OS STREQUAL "mac") + set(SERVER_LAUNCHER_SRC src/osxlaunch/server.mm) + set(TARGET_SERVER_LAUNCHER ${TARGET_SERVER}-Launcher) + add_executable(${TARGET_SERVER_LAUNCHER} ${SERVER_LAUNCHER_SRC}) + target_link_libraries(${TARGET_SERVER_LAUNCHER} ${COCOA}) + list(APPEND TARGETS_OWN ${TARGET_SERVER_LAUNCHER}) + list(APPEND TARGETS_LINK ${TARGET_SERVER_LAUNCHER}) +endif() + +######################################################################## +# VARIOUS TARGETS +######################################################################## + +set_src(MASTERSRV_SRC GLOB src/mastersrv mastersrv.cpp mastersrv.h) +set_src(VERSIONSRV_SRC GLOB src/versionsrv mapversions.h versionsrv.cpp versionsrv.h) + +set(TARGET_MASTERSRV mastersrv) +set(TARGET_VERSIONSRV versionsrv) + +add_executable(${TARGET_MASTERSRV} EXCLUDE_FROM_ALL ${MASTERSRV_SRC} $ ${DEPS}) +add_executable(${TARGET_VERSIONSRV} EXCLUDE_FROM_ALL ${VERSIONSRV_SRC} $ ${DEPS}) + +target_link_libraries(${TARGET_MASTERSRV} ${LIBS}) +target_link_libraries(${TARGET_VERSIONSRV} ${LIBS}) + +list(APPEND TARGETS_OWN ${TARGET_MASTERSRV} ${TARGET_VERSIONSRV}) +list(APPEND TARGETS_LINK ${TARGET_MASTERSRV} ${TARGET_VERSIONSRV}) + +set(TARGETS_TOOLS) +set_src(TOOLS GLOB src/tools + crapnet.cpp + fake_server.cpp + map_resave.cpp + map_version.cpp + packetgen.cpp +) +foreach(ABS_T ${TOOLS}) + file(RELATIVE_PATH T "${PROJECT_SOURCE_DIR}/src/tools/" ${ABS_T}) + if(T MATCHES "\\.cpp$") + string(REGEX REPLACE "\\.cpp$" "" TOOL "${T}") + add_executable(${TOOL} EXCLUDE_FROM_ALL + ${DEPS} + src/tools/${TOOL}.cpp + ${EXTRA_TOOL_SRC} + $ + ) + target_link_libraries(${TOOL} ${LIBS}) + list(APPEND TARGETS_TOOLS ${TOOL}) + endif() +endforeach() + +list(APPEND TARGETS_OWN ${TARGETS_TOOLS}) +list(APPEND TARGETS_LINK ${TARGETS_TOOLS}) + +add_custom_target(tools DEPENDS ${TARGETS_TOOLS}) +add_custom_target(everything DEPENDS ${TARGETS_OWN}) + +######################################################################## +# INSTALLATION +######################################################################## + +function(escape_regex VAR STRING) + string(REGEX REPLACE "([][^$.+*?|()\\\\])" "\\\\\\1" ESCAPED "${STRING}") + set(${VAR} ${ESCAPED} PARENT_SCOPE) +endfunction() + +function(escape_backslashes VAR STRING) + string(REGEX REPLACE "\\\\" "\\\\\\\\" ESCAPED "${STRING}") + set(${VAR} ${ESCAPED} PARENT_SCOPE) +endfunction() + +function(max_length VAR) + set(MAX_LENGTH 0) + foreach(str ${ARGN}) + string(LENGTH ${str} LENGTH) + if(LENGTH GREATER MAX_LENGTH) + set(MAX_LENGTH ${LENGTH}) + endif() + endforeach() + set(${VAR} ${MAX_LENGTH} PARENT_SCOPE) +endfunction() + +# Tries to generate a list of regex that matches everything except the given +# parameters. +function(regex_inverted VAR) + max_length(MAX_LENGTH ${ARGN}) + math(EXPR UPPER_BOUND "${MAX_LENGTH}-1") + + set(REMAINING ${ARGN}) + set(RESULT) + + foreach(i RANGE ${UPPER_BOUND}) + set(TEMP ${REMAINING}) + set(REMAINING) + foreach(str ${TEMP}) + string(LENGTH ${str} LENGTH) + if(i LESS LENGTH) + list(APPEND REMAINING ${str}) + endif() + endforeach() + + set(ADDITIONAL) + foreach(outer ${REMAINING}) + string(SUBSTRING ${outer} 0 ${i} OUTER_PREFIX) + set(CHARS "") + foreach(inner ${REMAINING}) + string(SUBSTRING ${inner} 0 ${i} INNER_PREFIX) + if(OUTER_PREFIX STREQUAL INNER_PREFIX) + string(SUBSTRING ${inner} ${i} 1 INNER_NEXT) + set(CHARS "${CHARS}${INNER_NEXT}") + endif() + endforeach() + escape_regex(OUTER_PREFIX_ESCAPED "${OUTER_PREFIX}") + + list(APPEND ADDITIONAL "${OUTER_PREFIX_ESCAPED}([^${CHARS}]|$)") + endforeach() + list(REMOVE_DUPLICATES ADDITIONAL) + list(APPEND RESULT ${ADDITIONAL}) + endforeach() + set(${VAR} ${RESULT} PARENT_SCOPE) +endfunction() + +set(CPACK_PACKAGE_NAME ${PROJECT_NAME}) +set(CPACK_GENERATOR TGZ TXZ) +set(CPACK_ARCHIVE_COMPONENT_INSTALL ON) +set(CPACK_STRIP_FILES TRUE) +set(CPACK_COMPONENTS_ALL portable) +set(CPACK_SOURCE_GENERATOR ZIP TGZ TBZ2 TXZ) +set(CPACK_PACKAGE_VERSION_MAJOR ${PROJECT_VERSION_MAJOR}) +set(CPACK_PACKAGE_VERSION_MINOR ${PROJECT_VERSION_MINOR}) +set(CPACK_PACKAGE_VERSION_PATCH ${PROJECT_VERSION_PATCH}) +set(CPACK_PACKAGE_VERSION ${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSION_MINOR}.${CPACK_PACKAGE_VERSION_PATCH}) +set(CPACK_SYSTEM_NAME ${CMAKE_SYSTEM_NAME}) + +if(TARGET_OS AND TARGET_BITS) + if(TARGET_OS STREQUAL "windows") + set(CPACK_SYSTEM_NAME "win${TARGET_BITS}") + set(CPACK_GENERATOR ZIP) + elseif(TARGET_OS STREQUAL "linux") + # Assuming Intel here. + if(TARGET_BITS EQUAL 32) + set(CPACK_SYSTEM_NAME "linux_x86") + elseif(TARGET_BITS EQUAL 64) + set(CPACK_SYSTEM_NAME "linux_x86_64") + endif() + elseif(TARGET_OS STREQUAL "mac") + set(CPACK_SYSTEM_NAME "osx") + set(CPACK_GENERATOR DMG) + endif() +endif() + +set(CPACK_PACKAGE_FILE_NAME ${CPACK_PACKAGE_NAME}-${CPACK_PACKAGE_VERSION}-${CPACK_SYSTEM_NAME}) +set(CPACK_ARCHIVE_PORTABLE_FILE_NAME ${CPACK_PACKAGE_FILE_NAME}) +set(CPACK_SOURCE_PACKAGE_FILE_NAME ${CPACK_PACKAGE_NAME}-${CPACK_PACKAGE_VERSION}-src) +set(CPACK_SOURCE_FILES + CMakeLists.txt + bam.lua + cmake/ + configure.lua + datasrc/ + license.txt + other/ + readme.md + scripts/ + src/ + storage.cfg +) +set(CPACK_SOURCE_IGNORE_FILES + "\\\\.o$" + "\\\\.pyc$" + "/\\\\.git" + "/__pycache__/" +) + +regex_inverted(CPACK_SOURCE_FILES_INVERTED ${CPACK_SOURCE_FILES}) +escape_regex(PROJECT_SOURCE_DIR_ESCAPED ${PROJECT_SOURCE_DIR}) + +foreach(str ${CPACK_SOURCE_FILES_INVERTED}) + escape_backslashes(STR_ESCAPED "${PROJECT_SOURCE_DIR_ESCAPED}/${str}") + list(APPEND CPACK_SOURCE_IGNORE_FILES "${STR_ESCAPED}") +endforeach() + +set(CMAKE_INSTALL_DEFAULT_COMPONENT_NAME ${PROJECT_NAME}) + +set(CPACK_TARGETS + ${TARGET_CLIENT} + ${TARGET_SERVER} +) +set(CPACK_DIRS ${PROJECT_BINARY_DIR}/data) +set(CPACK_FILES + license.txt + storage.cfg + ${COPY_FILES} +) +if(TARGET_OS STREQUAL "windows") + list(APPEND CPACK_FILES other/config_directory.bat) +endif() + +if(NOT DEV) + install(DIRECTORY ${PROJECT_BINARY_DIR}/data DESTINATION share/${PROJECT_NAME} COMPONENT data) + install(TARGETS ${TARGET_CLIENT} DESTINATION bin COMPONENT client) + install(TARGETS ${TARGET_SERVER} DESTINATION bin COMPONENT server) +endif() + +if(DEV) + # Don't generate CPack targets. +elseif(CMAKE_VERSION VERSION_LESS 3.6 OR CMAKE_VERSION VERSION_EQUAL 3.6) + message(WARNING "Cannot create CPack targets, CMake version too old. Use CMake 3.6 or newer.") +else() + set(EXTRA_ARGS DESTINATION ${CPACK_PACKAGE_FILE_NAME} COMPONENT portable EXCLUDE_FROM_ALL) + install(TARGETS ${CPACK_TARGETS} ${EXTRA_ARGS}) + install(DIRECTORY ${CPACK_DIRS} ${EXTRA_ARGS}) + install(FILES ${CPACK_FILES} ${EXTRA_ARGS}) +endif() + +set(PACKAGE_TARGETS) + +if(CLIENT AND (DMGTOOLS_FOUND OR HDIUTIL)) + file(MAKE_DIRECTORY bundle/client/) + file(MAKE_DIRECTORY bundle/server/) + configure_file(other/bundle/client/Info.plist.in bundle/client/Info.plist) + configure_file(other/bundle/server/Info.plist.in bundle/server/Info.plist) + + if(HDIUTIL) + set(DMG_PARAMS --hdiutil ${HDIUTIL}) + elseif(DMGTOOLS_FOUND) + set(DMG_PARAMS --dmgtools ${DMG} ${HFSPLUS} ${NEWFS_HFS}) + endif() + set(DMG_TMPDIR pack_${CPACK_PACKAGE_FILE_NAME}_dmg) + set(DMG_MKDIRS + ${TARGET_CLIENT}.app + ${TARGET_CLIENT}.app/Contents + ${TARGET_CLIENT}.app/Contents/Frameworks + ${TARGET_CLIENT}.app/Contents/MacOS + ${TARGET_CLIENT}.app/Contents/Resources + ${TARGET_SERVER}.app + ${TARGET_SERVER}.app/Contents + ${TARGET_SERVER}.app/Contents/MacOS + ${TARGET_SERVER}.app/Contents/Resources + ${TARGET_SERVER}.app/Contents/Resources/data + # Needed so the server recognizes the data directory. + ${TARGET_SERVER}.app/Contents/Resources/data/mapres + ) + set(DMG_MKDIR_COMMANDS) + foreach(dir ${DMG_MKDIRS}) + list(APPEND DMG_MKDIR_COMMANDS COMMAND ${CMAKE_COMMAND} -E make_directory ${DMG_TMPDIR}/${dir}) + endforeach() + add_custom_command(OUTPUT ${CPACK_PACKAGE_FILE_NAME}.dmg + COMMAND ${CMAKE_COMMAND} -E remove_directory ${DMG_TMPDIR} + ${DMG_MKDIR_COMMANDS} + + # CLIENT + COMMAND ${CMAKE_COMMAND} -E copy_directory data ${DMG_TMPDIR}/${TARGET_CLIENT}.app/Contents/Resources/data + COMMAND ${CMAKE_COMMAND} -E copy ${PROJECT_SOURCE_DIR}/other/icons/${TARGET_CLIENT}.icns ${DMG_TMPDIR}/${TARGET_CLIENT}.app/Contents/Resources/ + COMMAND ${CMAKE_COMMAND} -E copy bundle/client/Info.plist ${PROJECT_SOURCE_DIR}/other/bundle/client/PkgInfo ${DMG_TMPDIR}/${TARGET_CLIENT}.app/Contents/ + COMMAND ${CMAKE_COMMAND} -E copy $ ${DMG_TMPDIR}/${TARGET_CLIENT}.app/Contents/MacOS/ + COMMAND ${CMAKE_COMMAND} -E copy_directory ${PROJECT_SOURCE_DIR}/other/sdl/mac/lib64/SDL2.framework ${DMG_TMPDIR}/${TARGET_CLIENT}.app/Contents/Frameworks/SDL2.framework + COMMAND ${CMAKE_COMMAND} -E copy ${PROJECT_SOURCE_DIR}/other/freetype/mac/lib64/libfreetype.6.dylib ${DMG_TMPDIR}/${TARGET_CLIENT}.app/Contents/Frameworks/ + COMMAND ${PYTHON_EXECUTABLE} ${PROJECT_SOURCE_DIR}/scripts/darwin_change_dylib.py change --tools ${CMAKE_INSTALL_NAME_TOOL} ${CMAKE_OTOOL} ${DMG_TMPDIR}/${TARGET_CLIENT}.app/Contents/MacOS/${TARGET_CLIENT} SDL2 @executable_path/../Frameworks/SDL2.framework/SDL2 + COMMAND ${PYTHON_EXECUTABLE} ${PROJECT_SOURCE_DIR}/scripts/darwin_change_dylib.py change --tools ${CMAKE_INSTALL_NAME_TOOL} ${CMAKE_OTOOL} ${DMG_TMPDIR}/${TARGET_CLIENT}.app/Contents/MacOS/${TARGET_CLIENT} libfreetype @executable_path/../Frameworks/libfreetype.6.dylib + + # SERVER + COMMAND ${CMAKE_COMMAND} -E copy_directory data/maps ${DMG_TMPDIR}/${TARGET_SERVER}.app/Contents/Resources/data/maps + COMMAND ${CMAKE_COMMAND} -E copy ${PROJECT_SOURCE_DIR}/other/icons/${TARGET_SERVER}.icns ${DMG_TMPDIR}/${TARGET_SERVER}.app/Contents/Resources/ + COMMAND ${CMAKE_COMMAND} -E copy bundle/server/Info.plist ${PROJECT_SOURCE_DIR}/other/bundle/server/PkgInfo ${DMG_TMPDIR}/${TARGET_SERVER}.app/Contents/ + COMMAND ${CMAKE_COMMAND} -E copy $ $ ${DMG_TMPDIR}/${TARGET_SERVER}.app/Contents/MacOS/ + + # DMG + COMMAND ${PYTHON_EXECUTABLE} ${PROJECT_SOURCE_DIR}/scripts/dmg.py create ${DMG_PARAMS} ${CPACK_PACKAGE_FILE_NAME}.dmg ${CPACK_PACKAGE_FILE_NAME} ${DMG_TMPDIR} + + DEPENDS + ${TARGET_CLIENT} + ${TARGET_SERVER_LAUNCHER} + ${TARGET_SERVER} + ${PROJECT_BINARY_DIR}/bundle/client/Info.plist + ${PROJECT_BINARY_DIR}/bundle/server/Info.plist + other/bundle/client/PkgInfo + other/bundle/server/PkgInfo + other/icons/${TARGET_CLIENT}.icns + other/icons/${TARGET_SERVER}.icns + scripts/dmg.py + ) + add_custom_target(package_dmg DEPENDS ${CPACK_PACKAGE_FILE_NAME}.dmg) + list(APPEND PACKAGE_TARGETS package_dmg) +endif() + +foreach(ext zip tar.gz tar.xz) + set(TAR_MODE c) + set(TAR_EXTRA_ARGS) + string(REPLACE . _ EXT_SLUG ${ext}) + + set(TMPDIR pack_${CPACK_PACKAGE_FILE_NAME}_${EXT_SLUG}/${CPACK_PACKAGE_FILE_NAME}) + + set(COPY_FILE_COMMANDS) + set(COPY_DIR_COMMANDS) + set(COPY_TARGET_COMMANDS) + set(STRIP_TARGET_COMMANDS) + foreach(file ${CPACK_FILES}) + list(APPEND COPY_FILE_COMMANDS COMMAND ${CMAKE_COMMAND} -E copy ${PROJECT_SOURCE_DIR}/${file} ${TMPDIR}/) + endforeach() + foreach(dir ${CPACK_DIRS}) + get_filename_component(NAME ${dir} NAME) + list(APPEND COPY_DIR_COMMANDS COMMAND ${CMAKE_COMMAND} -E copy_directory ${dir} ${TMPDIR}/${NAME}) + endforeach() + foreach(target ${CPACK_TARGETS}) + list(APPEND COPY_TARGET_COMMANDS COMMAND ${CMAKE_COMMAND} -E copy $ ${TMPDIR}/) + endforeach() + + if(ext STREQUAL zip) + set(TAR_EXTRA_ARGS --format=zip) + elseif(ext STREQUAL tar.gz) + set(TAR_MODE cz) + elseif(ext STREQUAL tar.xz) + set(TAR_MODE cJ) + endif() + add_custom_command(OUTPUT ${CPACK_PACKAGE_FILE_NAME}.${ext} + COMMAND ${CMAKE_COMMAND} -E remove_directory ${TMPDIR} + COMMAND ${CMAKE_COMMAND} -E make_directory ${TMPDIR} + ${COPY_FILE_COMMANDS} + ${COPY_DIR_COMMANDS} + ${COPY_TARGET_COMMANDS} + ${STRIP_TARGET_COMMANDS} + COMMAND ${CMAKE_COMMAND} -E chdir pack_${CPACK_PACKAGE_FILE_NAME}_${EXT_SLUG} ${CMAKE_COMMAND} -E tar ${TAR_MODE} ../${CPACK_PACKAGE_FILE_NAME}.${ext} ${TAR_EXTRA_ARGS} -- ${CPACK_PACKAGE_FILE_NAME}/ + DEPENDS ${CPACK_TARGETS} + ) + add_custom_target(package_${EXT_SLUG} DEPENDS ${CPACK_PACKAGE_FILE_NAME}.${ext}) + list(APPEND PACKAGE_TARGETS package_${EXT_SLUG}) +endforeach() + +set(PACKAGE_DEFAULT tar_xz) +if(TARGET_OS STREQUAL "windows") + set(PACKAGE_DEFAULT zip) +elseif(TARGET_OS STREQUAL "mac") + set(PACKAGE_DEFAULT dmg) +endif() +add_custom_target(package_default DEPENDS package_${PACKAGE_DEFAULT}) + +add_custom_target(package_all DEPENDS ${PACKAGE_TARGETS}) + +# Unset these variables, they might do something in the future of CPack. +unset(CPACK_SOURCE_FILES) +unset(CPACK_SOURCE_FILES_INVERTED) +unset(CPACK_TARGETS) +unset(CPACK_DIRS) +unset(CPACK_FILES) + +include(CPack) + +######################################################################## +# COMPILER-SPECIFICS +######################################################################## + +# In the future (CMake 3.8.0+), use source_group(TREE ...) +macro(source_group_tree dir) + file(GLOB ents RELATIVE ${PROJECT_SOURCE_DIR}/${dir} ${PROJECT_SOURCE_DIR}/${dir}/*) + foreach(ent ${ents}) + if(IS_DIRECTORY ${PROJECT_SOURCE_DIR}/${dir}/${ent}) + source_group_tree(${dir}/${ent}) + else() + string(REPLACE "/" "\\" group ${dir}) + source_group(${group} FILES ${PROJECT_SOURCE_DIR}/${dir}/${ent}) + endif() + endforeach() +endmacro() +source_group_tree(src) + +set(TARGETS ${TARGETS_OWN} ${TARGETS_DEP}) + +foreach(target ${TARGETS}) + if(MSVC) + target_compile_options(${target} PRIVATE $<$:/MT> $<${DBG}:/MTd>) # Use static CRT + target_compile_options(${target} PRIVATE /MP) # Use multiple cores + target_compile_options(${target} PRIVATE /EHsc) # Only catch C++ exceptions with catch. + target_compile_options(${target} PRIVATE /GS) # Protect the stack pointer. + target_compile_options(${target} PRIVATE /wd4996) # Use of non-_s functions. + endif() + if(OUR_FLAGS) + target_compile_options(${target} PRIVATE ${OUR_FLAGS}) + endif() + if(DEFINE_FORTIFY_SOURCE) + target_compile_definitions(${target} PRIVATE $<$>:_FORTIFY_SOURCE=2>) # Detect some buffer overflows. + endif() +endforeach() + +foreach(target ${TARGETS_LINK}) + if(MSVC) + set_property(TARGET ${target} APPEND PROPERTY LINK_FLAGS /SAFESEH:NO) # Disable SafeSEH because the shipped libraries don't support it (would cause error LNK2026 otherwise). + endif() + if(TARGET_OS STREQUAL "mac") + target_link_libraries(${target} -stdlib=libc++) + target_link_libraries(${target} -mmacosx-version-min=10.7) + endif() + if((MINGW OR TARGET_OS STREQUAL "linux") AND PREFER_BUNDLED_LIBS) + # Statically link the standard libraries with on MinGW/Linux so we don't + # have to ship them as DLLs. + target_link_libraries(${target} -static-libgcc) + target_link_libraries(${target} -static-libstdc++) + if(MINGW) + # Link pthread library statically instead of dynamically. + # Solution from https://stackoverflow.com/a/28001261. + target_link_libraries(${target} -Wl,-Bstatic -lstdc++ -lpthread -Wl,-Bdynamic) + endif() + endif() +endforeach() + +foreach(target ${TARGETS_OWN}) + if(MSVC) + target_compile_options(${target} PRIVATE /wd4244) # Possible loss of data (float -> int, int -> float, etc.). + target_compile_options(${target} PRIVATE /wd4267) # Possible loss of data (size_t - int on win64). + target_compile_options(${target} PRIVATE /wd4800) # Implicit conversion of int to bool. + endif() + if(OUR_FLAGS_OWN) + target_compile_options(${target} PRIVATE ${OUR_FLAGS_OWN}) + endif() + target_include_directories(${target} PRIVATE ${PROJECT_BINARY_DIR}/src) + target_include_directories(${target} PRIVATE src) + target_compile_definitions(${target} PRIVATE $<$:CONF_DEBUG>) + target_include_directories(${target} PRIVATE ${CURL_INCLUDE_DIRS}) + target_include_directories(${target} PRIVATE ${ZLIB_INCLUDE_DIRS}) +endforeach() + +foreach(target ${TARGETS_DEP}) + if(MSVC) + target_compile_options(${target} PRIVATE /W0) + endif() + if(OUR_FLAGS_DEP) + target_compile_options(${target} PRIVATE ${OUR_FLAGS_DEP}) + endif() +endforeach() diff --git a/bam.lua b/bam.lua index 77a1aab72..1988d217c 100644 --- a/bam.lua +++ b/bam.lua @@ -414,6 +414,8 @@ function GenerateSettings(conf, arch, builddir, compiler) end settings.cc.includes:Add("src") + settings.cc.includes:Add("src/engine/external/pnglite") + settings.cc.includes:Add("src/engine/external/wavpack") settings.cc.includes:Add(generated_src_dir) if family == "windows" then diff --git a/cmake/FindFreetype.cmake b/cmake/FindFreetype.cmake new file mode 100644 index 000000000..347b68442 --- /dev/null +++ b/cmake/FindFreetype.cmake @@ -0,0 +1,37 @@ +if(NOT CMAKE_CROSSCOMPILING) + find_package(PkgConfig QUIET) + pkg_check_modules(PC_FREETYPE freetype2) +endif() + +set_extra_dirs_lib(FREETYPE freetype) +find_library(FREETYPE_LIBRARY + NAMES freetype freetype.6 + HINTS ${HINTS_FREETYPE_LIBDIR} ${PC_FREETYPE_LIBDIR} ${PC_FREETYPE_LIBRARY_DIRS} + PATHS ${PATHS_FREETYPE_LIBDIR} + ${CROSSCOMPILING_NO_CMAKE_SYSTEM_PATH} +) +set_extra_dirs_include(FREETYPE freetype "${FREETYPE_LIBRARY}") +find_path(FREETYPE_INCLUDEDIR + NAMES config/ftheader.h freetype/config/ftheader.h + PATH_SUFFIXES freetype2 + HINTS ${HINTS_FREETYPE_INCLUDEDIR} ${PC_FREETYPE_INCLUDEDIR} ${PC_FREETYPE_INCLUDE_DIRS} + PATHS ${PATHS_FREETYPE_INCLUDEDIR} + ${CROSSCOMPILING_NO_CMAKE_SYSTEM_PATH} +) + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(Freetype DEFAULT_MSG FREETYPE_LIBRARY FREETYPE_INCLUDEDIR) + +mark_as_advanced(FREETYPE_LIBRARY FREETYPE_INCLUDEDIR) + +if(FREETYPE_FOUND) + set(FREETYPE_LIBRARIES ${FREETYPE_LIBRARY}) + set(FREETYPE_INCLUDE_DIRS ${FREETYPE_INCLUDEDIR}) + + is_bundled(FREETYPE_BUNDLED "${FREETYPE_LIBRARY}") + if(FREETYPE_BUNDLED AND TARGET_OS STREQUAL "windows") + set(FREETYPE_COPY_FILES "${EXTRA_FREETYPE_LIBDIR}/freetype.dll") + else() + set(FREETYPE_COPY_FILES) + endif() +endif() diff --git a/cmake/FindPnglite.cmake b/cmake/FindPnglite.cmake new file mode 100644 index 000000000..6a877c257 --- /dev/null +++ b/cmake/FindPnglite.cmake @@ -0,0 +1,46 @@ +if(NOT PREFER_BUNDLED_LIBS) + if(NOT CMAKE_CROSSCOMPILING) + find_package(PkgConfig QUIET) + pkg_check_modules(PC_PNGLITE pnglite) + endif() + + find_library(PNGLITE_LIBRARY + NAMES pnglite + HINTS ${PC_PNGLITE_LIBDIR} ${PC_PNGLITE_LIBRARY_DIRS} + ${CROSSCOMPILING_NO_CMAKE_SYSTEM_PATH} + ) + find_path(PNGLITE_INCLUDEDIR + NAMES pnglite.h + HINTS ${PC_PNGLITE_INCLUDEDIR} ${PC_PNGLITE_INCLUDE_DIRS} + ${CROSSCOMPILING_NO_CMAKE_SYSTEM_PATH} + ) + + mark_as_advanced(PNGLITE_LIBRARY PNGLITE_INCLUDEDIR) + + if(PNGLITE_LIBRARY AND PNGLITE_INCLUDEDIR) + include(FindPackageHandleStandardArgs) + find_package_handle_standard_args(Pnglite DEFAULT_MSG PNGLITE_LIBRARY PNGLITE_INCLUDEDIR) + + set(PNGLITE_LIBRARIES ${PNGLITE_LIBRARY}) + set(PNGLITE_INCLUDE_DIRS ${PNGLITE_INCLUDEDIR}) + set(PNGLITE_BUNDLED OFF) + endif() +endif() + +if(NOT PNGLITE_FOUND) + set(PNGLITE_SRC_DIR src/engine/external/pnglite) + set_src(PNGLITE_SRC GLOB ${PNGLITE_SRC_DIR} pnglite.c pnglite.h) + add_library(pnglite EXCLUDE_FROM_ALL OBJECT ${PNGLITE_SRC}) + list(APPEND TARGETS_DEP pnglite) + + set(PNGLITE_INCLUDEDIR ${PNGLITE_SRC_DIR}) + target_include_directories(pnglite PRIVATE ${ZLIB_INCLUDE_DIRS}) + + set(PNGLITE_DEP $) + set(PNGLITE_INCLUDE_DIRS ${PNGLITE_INCLUDEDIR}) + set(PNGLITE_LIBRARIES) + + include(FindPackageHandleStandardArgs) + find_package_handle_standard_args(Pnglite DEFAULT_MSG PNGLITE_INCLUDEDIR) + set(PNGLITE_BUNDLED ON) +endif() diff --git a/cmake/FindSDL2.cmake b/cmake/FindSDL2.cmake new file mode 100644 index 000000000..94e293294 --- /dev/null +++ b/cmake/FindSDL2.cmake @@ -0,0 +1,48 @@ +if(NOT PREFER_BUNDLED_LIBS) + set(CMAKE_MODULE_PATH ${ORIGINAL_CMAKE_MODULE_PATH}) + find_package(SDL2) + set(CMAKE_MODULE_PATH ${OWN_CMAKE_MODULE_PATH}) + if(SDL2_FOUND) + set(SDL2_BUNDLED OFF) + set(SDL2_DEP) + endif() +endif() + +if(NOT CMAKE_CROSSCOMPILING) + find_package(PkgConfig QUIET) + pkg_check_modules(PC_SDL2 sdl2) +endif() + +set_extra_dirs_lib(SDL2 sdl) +find_library(SDL2_LIBRARY + NAMES SDL2 + HINTS ${HINTS_SDL2_LIBDIR} ${PC_SDL2_LIBDIR} ${PC_SDL2_LIBRARY_DIRS} + PATHS ${PATHS_SDL2_LIBDIR} + ${CROSSCOMPILING_NO_CMAKE_SYSTEM_PATH} +) +set(CMAKE_FIND_FRAMEWORK FIRST) +set_extra_dirs_include(SDL2 sdl "${SDL2_LIBRARY}") +# Looking for 'SDL.h' directly might accidentally find a SDL 1 instead of SDL 2 +# installation. Look for a header file only present in SDL 2 instead. +find_path(SDL2_INCLUDEDIR SDL_assert.h + PATH_SUFFIXES SDL + HINTS ${HINTS_SDL2_INCLUDEDIR} ${PC_SDL2_INCLUDEDIR} ${PC_SDL2_INCLUDE_DIRS} + PATHS ${PATHS_SDL2_INCLUDEDIR} +) + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(SDL2 DEFAULT_MSG SDL2_LIBRARY SDL2_INCLUDEDIR) + +mark_as_advanced(SDL2_LIBRARY SDL2_INCLUDEDIR) + +if(SDL2_FOUND) + set(SDL2_LIBRARIES ${SDL2_LIBRARY}) + set(SDL2_INCLUDE_DIRS ${SDL2_INCLUDEDIR}) + + is_bundled(SDL2_BUNDLED "${SDL2_LIBRARY}") + if(SDL2_BUNDLED AND TARGET_OS STREQUAL "windows") + set(SDL2_COPY_FILES "${EXTRA_SDL2_LIBDIR}/SDL2.dll") + else() + set(SDL2_COPY_FILES) + endif() +endif() diff --git a/cmake/FindWavpack.cmake b/cmake/FindWavpack.cmake new file mode 100644 index 000000000..b7e855268 --- /dev/null +++ b/cmake/FindWavpack.cmake @@ -0,0 +1,52 @@ +if(NOT PREFER_BUNDLED_LIBS) + if(NOT CMAKE_CROSSCOMPILING) + find_package(PkgConfig QUIET) + pkg_check_modules(PC_WAVPACK wavpack) + endif() + + find_library(WAVPACK_LIBRARY + NAMES wavpack + HINTS ${PC_WAVPACK_LIBDIR} ${PC_WAVPACK_LIBRARY_DIRS} + ${CROSSCOMPILING_NO_CMAKE_SYSTEM_PATH} + ) + find_path(WAVPACK_INCLUDEDIR + NAMES wavpack.h + PATH_SUFFIXES wavpack + HINTS ${PC_WAVPACK_INCLUDEDIR} ${PC_WAVPACK_INCLUDE_DIRS} + ${CROSSCOMPILING_NO_CMAKE_SYSTEM_PATH} + ) + + mark_as_advanced(WAVPACK_LIBRARY WAVPACK_INCLUDEDIR) + + if(WAVPACK_LIBRARY AND WAVPACK_INCLUDEDIR) + include(FindPackageHandleStandardArgs) + find_package_handle_standard_args(Wavpack DEFAULT_MSG WAVPACK_LIBRARY WAVPACK_INCLUDEDIR) + + set(WAVPACK_LIBRARIES ${WAVPACK_LIBRARY}) + set(WAVPACK_INCLUDE_DIRS ${WAVPACK_INCLUDEDIR}) + set(WAVPACK_BUNDLED OFF) + endif() +endif() + +if(NOT WAVPACK_FOUND) + set(WAVPACK_SRC_DIR src/engine/external/wavpack) + set_src(WAVPACK_SRC GLOB ${WAVPACK_SRC_DIR} + bits.c + float.c + metadata.c + unpack.c + wavpack.h + words.c + wputils.c + ) + add_library(wavpack EXCLUDE_FROM_ALL OBJECT ${WAVPACK_SRC}) + set(WAVPACK_DEP $) + set(WAVPACK_INCLUDEDIR ${WAVPACK_SRC_DIR}) + set(WAVPACK_INCLUDE_DIRS ${WAVPACK_INCLUDEDIR}) + + list(APPEND TARGETS_DEP wavpack) + + include(FindPackageHandleStandardArgs) + find_package_handle_standard_args(Wavpack DEFAULT_MSG WAVPACK_INCLUDEDIR) + set(WAVPACK_BUNDLED ON) +endif() diff --git a/cmake/FindZLIB.cmake b/cmake/FindZLIB.cmake new file mode 100644 index 000000000..a8dfca4d3 --- /dev/null +++ b/cmake/FindZLIB.cmake @@ -0,0 +1,50 @@ +if(NOT PREFER_BUNDLED_LIBS) + set(CMAKE_MODULE_PATH ${ORIGINAL_CMAKE_MODULE_PATH}) + find_package(ZLIB) + set(CMAKE_MODULE_PATH ${OWN_CMAKE_MODULE_PATH}) + if(ZLIB_FOUND) + set(ZLIB_BUNDLED OFF) + set(ZLIB_DEP) + endif() +endif() + +if(NOT ZLIB_FOUND) + set(ZLIB_BUNDLED ON) + set(ZLIB_SRC_DIR src/engine/external/zlib) + set_src(ZLIB_SRC GLOB ${ZLIB_SRC_DIR} + adler32.c + compress.c + crc32.c + crc32.h + deflate.c + deflate.h + gzguts.h + infback.c + inffast.c + inffast.h + inffixed.h + inflate.c + inflate.h + inftrees.c + inftrees.h + trees.c + trees.h + uncompr.c + zconf.h + zlib.h + zutil.c + zutil.h + ) + add_library(zlib EXCLUDE_FROM_ALL OBJECT ${ZLIB_SRC}) + set(ZLIB_INCLUDEDIR ${ZLIB_SRC_DIR}) + target_include_directories(zlib PRIVATE ${ZLIB_INCLUDEDIR}) + + set(ZLIB_DEP $) + set(ZLIB_INCLUDE_DIRS ${ZLIB_INCLUDEDIR}) + set(ZLIB_LIBRARIES) + + list(APPEND TARGETS_DEP zlib) + + include(FindPackageHandleStandardArgs) + find_package_handle_standard_args(ZLIB DEFAULT_MSG ZLIB_INCLUDEDIR) +endif() diff --git a/cmake/toolchains/darwin.toolchain b/cmake/toolchains/darwin.toolchain new file mode 100644 index 000000000..6d1d6eb3e --- /dev/null +++ b/cmake/toolchains/darwin.toolchain @@ -0,0 +1,11 @@ +set(CMAKE_SYSTEM_NAME Darwin) + +set(CMAKE_C_COMPILER o64-clang) +set(CMAKE_CXX_COMPILER o64-clang++) +set(CMAKE_INSTALL_NAME_TOOL x86_64-apple-darwin15-install_name_tool) +set(CMAKE_OTOOL x86_64-apple-darwin15-otool) + +set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) +set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) +set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) +set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY) diff --git a/cmake/toolchains/mingw32.toolchain b/cmake/toolchains/mingw32.toolchain new file mode 100644 index 000000000..c4c065b7e --- /dev/null +++ b/cmake/toolchains/mingw32.toolchain @@ -0,0 +1,10 @@ +set(CMAKE_SYSTEM_NAME Windows) + +set(CMAKE_C_COMPILER i686-w64-mingw32-gcc) +set(CMAKE_CXX_COMPILER i686-w64-mingw32-g++) +set(CMAKE_RC_COMPILER i686-w64-mingw32-windres) + +set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) +set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) +set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) +set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY) diff --git a/cmake/toolchains/mingw64.toolchain b/cmake/toolchains/mingw64.toolchain new file mode 100644 index 000000000..bec41e944 --- /dev/null +++ b/cmake/toolchains/mingw64.toolchain @@ -0,0 +1,10 @@ +set(CMAKE_SYSTEM_NAME Windows) + +set(CMAKE_C_COMPILER x86_64-w64-mingw32-gcc) +set(CMAKE_CXX_COMPILER x86_64-w64-mingw32-g++) +set(CMAKE_RC_COMPILER x86_64-w64-mingw32-windres) + +set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) +set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) +set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) +set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY) diff --git a/other/bundle/client/Info.plist.in b/other/bundle/client/Info.plist.in new file mode 100644 index 000000000..34d919702 --- /dev/null +++ b/other/bundle/client/Info.plist.in @@ -0,0 +1,24 @@ + + + + + CFBundleDevelopmentRegion + English + CFBundleExecutable + ${TARGET_CLIENT} + CFBundleIconFile + ${TARGET_CLIENT} + CFBundleInfoDictionaryVersion + 6.0 + CFBundlePackageType + APPL + CFBundleSignature + ???? + CFBundleVersion + ${PROJECT_VERSION} + CFBundleIdentifier + com.teeworlds.app + NSHighResolutionCapable + + + diff --git a/other/bundle/client/PkgInfo b/other/bundle/client/PkgInfo new file mode 100644 index 000000000..6f749b0f3 --- /dev/null +++ b/other/bundle/client/PkgInfo @@ -0,0 +1 @@ +APPL???? diff --git a/other/bundle/server/Info.plist.in b/other/bundle/server/Info.plist.in new file mode 100644 index 000000000..6cdd38f0d --- /dev/null +++ b/other/bundle/server/Info.plist.in @@ -0,0 +1,20 @@ + + + + + CFBundleDevelopmentRegion + English + CFBundleExecutable + ${TARGET_SERVER_LAUNCHER} + CFBundleIconFile + ${TARGET_SERVER} + CFBundleInfoDictionaryVersion + 6.0 + CFBundlePackageType + APPL + CFBundleSignature + ???? + CFBundleVersion + ${PROJECT_VERSION} + + diff --git a/other/bundle/server/PkgInfo b/other/bundle/server/PkgInfo new file mode 100644 index 000000000..6f749b0f3 --- /dev/null +++ b/other/bundle/server/PkgInfo @@ -0,0 +1 @@ +APPL???? diff --git a/other/freetype/freetype.lua b/other/freetype/freetype.lua index bfd6523cc..f2517fd6c 100644 --- a/other/freetype/freetype.lua +++ b/other/freetype/freetype.lua @@ -36,9 +36,9 @@ FreeType = { elseif option.use_winlib > 0 then settings.cc.includes:Add(FreeType.basepath .. "/include") if option.use_winlib == 32 then - settings.link.libpath:Add(FreeType.basepath .. "/lib/x86") + settings.link.libpath:Add(FreeType.basepath .. "/windows/lib32") else - settings.link.libpath:Add(FreeType.basepath .. "/lib/x64") + settings.link.libpath:Add(FreeType.basepath .. "/windows/lib64") end settings.link.libs:Add("freetype") end diff --git a/other/icons/Teeworlds.icns b/other/icons/teeworlds.icns similarity index 100% rename from other/icons/Teeworlds.icns rename to other/icons/teeworlds.icns diff --git a/other/icons/Teeworlds.ico b/other/icons/teeworlds.ico similarity index 100% rename from other/icons/Teeworlds.ico rename to other/icons/teeworlds.ico diff --git a/other/icons/teeworlds.rc b/other/icons/teeworlds.rc new file mode 100644 index 000000000..aa5dcb44f --- /dev/null +++ b/other/icons/teeworlds.rc @@ -0,0 +1 @@ +ID ICON "teeworlds.ico" diff --git a/other/icons/Teeworlds_srv.icns b/other/icons/teeworlds_srv.icns similarity index 100% rename from other/icons/Teeworlds_srv.icns rename to other/icons/teeworlds_srv.icns diff --git a/other/icons/Teeworlds_srv.ico b/other/icons/teeworlds_srv.ico similarity index 100% rename from other/icons/Teeworlds_srv.ico rename to other/icons/teeworlds_srv.ico diff --git a/other/icons/teeworlds_srv.rc b/other/icons/teeworlds_srv.rc new file mode 100644 index 000000000..44287bb51 --- /dev/null +++ b/other/icons/teeworlds_srv.rc @@ -0,0 +1 @@ +ID ICON "teeworlds_srv.ico" diff --git a/other/icons/teeworlds_srv_cl.rc b/other/icons/teeworlds_srv_cl.rc index f7b046d92..8e18b64ce 100644 --- a/other/icons/teeworlds_srv_cl.rc +++ b/other/icons/teeworlds_srv_cl.rc @@ -1 +1 @@ -50h ICON "Teeworlds_srv.ico" +50h ICON "teeworlds_srv.ico" diff --git a/other/icons/teeworlds_srv_gcc.rc b/other/icons/teeworlds_srv_gcc.rc index 3b7c78a56..44287bb51 100644 --- a/other/icons/teeworlds_srv_gcc.rc +++ b/other/icons/teeworlds_srv_gcc.rc @@ -1 +1 @@ -ID ICON "Teeworlds_srv.ico" +ID ICON "teeworlds_srv.ico" diff --git a/other/sdl/sdl.lua b/other/sdl/sdl.lua index 19196ba2d..4bf5fe0f9 100644 --- a/other/sdl/sdl.lua +++ b/other/sdl/sdl.lua @@ -36,9 +36,9 @@ SDL = { elseif option.use_winlib > 0 then settings.cc.includes:Add(SDL.basepath .. "/include") if option.use_winlib == 32 then - settings.link.libpath:Add(SDL.basepath .. "/lib/x86") + settings.link.libpath:Add(SDL.basepath .. "/windows/lib32") else - settings.link.libpath:Add(SDL.basepath .. "/lib/x64") + settings.link.libpath:Add(SDL.basepath .. "/windows/lib64") end settings.link.libs:Add("SDL2") settings.link.libs:Add("SDL2main") diff --git a/scripts/darwin_change_dylib.py b/scripts/darwin_change_dylib.py new file mode 100644 index 000000000..6f3922572 --- /dev/null +++ b/scripts/darwin_change_dylib.py @@ -0,0 +1,63 @@ +from collections import namedtuple +import os +import re +import shlex +import subprocess + +Config = namedtuple('Config', 'install_name_tool otool verbose') + +def dylib_regex(name): + return re.compile(r'\S*{}\S*'.format(re.escape(name))) + +class ChangeDylib: + def __init__(self, config): + self.config = config + def _check_call(self, process_args, *args, **kwargs): + if self.config.verbose >= 1: + print("EXECUTING {}".format(" ".join(shlex.quote(x) for x in process_args))) + if not (self.config.verbose >= 2 and "stdout" not in kwargs): + kwargs["stdout"] = open(os.devnull, 'wb') + return subprocess.check_call(process_args, *args, **kwargs) + def _check_output(self, process_args, *args, **kwargs): + if self.config.verbose >= 1: + print("EXECUTING {} FOR OUTPUT".format(" ".join(shlex.quote(x) for x in process_args))) + return subprocess.check_output(process_args, *args, **kwargs) + def _install_name_tool(self, *args): + return self._check_call((self.config.install_name_tool,) + args) + def _otool(self, *args): + return self._check_output((self.config.otool,) + args) + + def change(self, filename, from_, to): + lines = self._otool("-L", filename).decode().splitlines() + regex = dylib_regex(from_) + matches = sum([regex.findall(l) for l in lines], []) + if len(matches) != 1: + if matches: + raise ValueError("More than one match found for {}: {}".format(from_, matches)) + else: + raise ValueError("No matches found for {}".format(from_)) + actual_from = matches[0] + self._install_name_tool("-change", actual_from, to, filename) + +def main(): + import argparse + p = argparse.ArgumentParser(description="Manipulate shared library dependencies for macOS") + + subcommands = p.add_subparsers(help="Subcommand", dest='command', metavar="COMMAND") + subcommands.required = True + + change = subcommands.add_parser("change", help="Change a shared library dependency to a given value") + change.add_argument('-v', '--verbose', action='count', help="Verbose output") + change.add_argument('--tools', nargs=2, help="Paths to the install_name_tool and otool", default=("install_name_tool", "otool")) + change.add_argument('filename', metavar="FILE", help="Filename of the executable to manipulate") + change.add_argument('from_', metavar="FROM", help="Fuzzily matched library name to change") + change.add_argument('to', metavar="TO", help="Exact name that the library dependency should be changed to") + args = p.parse_args() + + verbose = args.verbose or 0 + install_name_tool, otool = args.tools + dylib = ChangeDylib(Config(install_name_tool, otool, verbose)) + dylib.change(filename=args.filename, from_=args.from_, to=args.to) + +if __name__ == '__main__': + main() diff --git a/scripts/dmg.py b/scripts/dmg.py new file mode 100644 index 000000000..8f2d4cfc1 --- /dev/null +++ b/scripts/dmg.py @@ -0,0 +1,106 @@ +from collections import namedtuple +import os +import shlex +import subprocess +import tempfile + +ConfigDmgtools = namedtuple('Config', 'dmg hfsplus newfs_hfs verbose') +ConfigHdiutil = namedtuple('Config', 'hdiutil verbose') + +def chunks(l, n): + """ + Yield successive n-sized chunks from l. + + From https://stackoverflow.com/a/312464. + """ + for i in range(0, len(l), n): + yield l[i:i + n] + +class Dmg: + def __init__(self, config): + self.config = config + + def _check_call(self, process_args, *args, **kwargs): + if self.config.verbose >= 1: + print("EXECUTING {}".format(" ".join(shlex.quote(x) for x in process_args))) + if not (self.config.verbose >= 2 and "stdout" not in kwargs): + kwargs["stdout"] = open(os.devnull, 'wb') + subprocess.check_call(process_args, *args, **kwargs) + +class Dmgtools(Dmg): + def _mkfs_hfs(self, *args): + self._check_call((self.config.newfs_hfs,) + args) + def _hfs(self, *args): + self._check_call((self.config.hfsplus,) + args) + def _dmg(self, *args): + self._check_call((self.config.dmg,) + args) + + def _create_hfs(self, hfs, volume_name, size): + if self.config.verbose >= 1: + print("TRUNCATING {} to {} bytes".format(hfs, size)) + with open(hfs, 'wb') as f: + f.truncate(size) + self._mkfs_hfs('-v', volume_name, hfs) + + def _symlink(self, hfs, target, link_name): + self._hfs(hfs, 'symlink', link_name, target) + + def _add(self, hfs, directory): + self._hfs(hfs, 'addall', directory) + + def _finish(self, hfs, dmg): + self._dmg('build', hfs, dmg) + + def create(self, dmg, volume_name, directory, symlinks): + input_size = sum(os.stat(os.path.join(path, f)).st_size for path, dirs, files in os.walk(directory) for f in files) + output_size = max(input_size * 2, 1024**2) + hfs = tempfile.mktemp(prefix=dmg + '.', suffix='.hfs') + self._create_hfs(hfs, volume_name, output_size) + self._add(hfs, directory) + for target, link_name in symlinks: + self._symlink(hfs, target, link_name) + self._finish(hfs, dmg) + if self.config.verbose >= 1: + print("REMOVING {}".format(hfs)) + os.remove(hfs) + +class Hdiutil(Dmg): + def _hdiutil(self, *args): + self._check_call((self.config.hdiutil,) + args) + + def create(self, dmg, volume_name, directory, symlinks): + if symlinks: + raise NotImplementedError("symlinks are not yet implemented") + self._hdiutil('create', '-volname', volume_name, '-srcdir', directory, dmg) + +def main(): + import argparse + p = argparse.ArgumentParser(description="Manipulate dmg archives") + + subcommands = p.add_subparsers(help="Subcommand", dest='command', metavar="COMMAND") + subcommands.required = True + + create = subcommands.add_parser("create", help="Create a dmg archive from files or directories") + create.add_argument('-v', '--verbose', action='count', help="Verbose output") + createx = create.add_mutually_exclusive_group(required=True) + createx.add_argument('--dmgtools', nargs=3, help="Paths to the dmg and hfsplus executable (https://github.com/mozilla/libdmg-hfsplus) and the newfs_hfs executable (http://pkgs.fedoraproject.org/repo/pkgs/hfsplus-tools/diskdev_cmds-540.1.linux3.tar.gz/0435afc389b919027b69616ad1b05709/diskdev_cmds-540.1.linux3.tar.gz)") + createx.add_argument('--hdiutil', help="Path to the hdiutil (only exists for macOS at time of writing)") + create.add_argument('output', metavar="OUTPUT", help="Filename of the output dmg archive") + create.add_argument('volume_name', metavar="VOLUME_NAME", help="Name of the dmg archive") + create.add_argument('directory', metavar="DIR", help="Directory to create the archive from") + create.add_argument('--symlink', metavar="SYMLINK", nargs=2, action="append", help="Symlink the first argument under the second name") + args = p.parse_args() + + verbose = args.verbose or 0 + symlinks = args.symlink or [] + if args.dmgtools: + dmg, hfsplus, newfs_hfs = args.dmgtools + dmg = Dmgtools(ConfigDmgtools(dmg=dmg, hfsplus=hfsplus, newfs_hfs=newfs_hfs, verbose=verbose)) + elif args.hdiutil: + dmg = Hdiutil(ConfigHdiutil(hdiutil=args.hdiutil, verbose=verbose)) + else: + raise RuntimeError("unreachable") + dmg.create(volume_name=args.volume_name, directory=args.directory, dmg=args.output, symlinks=symlinks) + +if __name__ == '__main__': + main() diff --git a/scripts/git_revision.py b/scripts/git_revision.py new file mode 100644 index 000000000..ae1186c42 --- /dev/null +++ b/scripts/git_revision.py @@ -0,0 +1,21 @@ +import errno +import subprocess +try: + from subprocess import DEVNULL +except ImportError: + import os + DEVNULL = open(os.devnull, 'wb') +try: + FileNotFoundError +except NameError: + FileNotFoundError = OSError +try: + git_hash = subprocess.check_output(["git", "rev-parse", "--short=16", "HEAD"], stderr=DEVNULL).decode().strip() + definition = '"{}"'.format(git_hash) +except FileNotFoundError as e: + if e.errno != errno.ENOENT: + raise + definition = "0" +except subprocess.CalledProcessError: + definition = "0"; +print("const char *GIT_SHORTREV_HASH = {};".format(definition)) diff --git a/src/base/system.c b/src/base/system.c index bcab1771e..92e090622 100644 --- a/src/base/system.c +++ b/src/base/system.c @@ -334,6 +334,11 @@ unsigned io_read(IOHANDLE io, void *buffer, unsigned size) return fread(buffer, 1, size, (FILE*)io); } +unsigned io_unread_byte(IOHANDLE io, unsigned char byte) +{ + return ungetc(byte, (FILE*)io) == EOF; +} + unsigned io_skip(IOHANDLE io, int size) { fseek((FILE*)io, size, SEEK_CUR); @@ -1439,6 +1444,10 @@ int fs_storage_path(const char *appname, char *path, int max) return 0; #else char *home = getenv("HOME"); + int i; + char *xdgdatahome = getenv("XDG_DATA_HOME"); + char xdgpath[max]; + if(!home) return -1; @@ -1447,10 +1456,6 @@ int fs_storage_path(const char *appname, char *path, int max) return 0; #endif - int i; - char *xdgdatahome = getenv("XDG_DATA_HOME"); - char xdgpath[max]; - /* old folder location */ snprintf(path, max, "%s/.%s", home, appname); for(i = strlen(home)+2; path[i]; i++) diff --git a/src/base/system.h b/src/base/system.h index 3f842279e..318b4f3d9 100644 --- a/src/base/system.h +++ b/src/base/system.h @@ -212,6 +212,21 @@ IOHANDLE io_open(const char *filename, int flags); */ unsigned io_read(IOHANDLE io, void *buffer, unsigned size); +/* + Function: io_unread_byte + "Unreads" a single byte, making it available for future read + operations. + + Parameters: + io - Handle to the file to unread the byte from. + byte - Byte to unread. + + Returns: + Returns 0 on success and 1 on failure. + +*/ +unsigned io_unread_byte(IOHANDLE io, unsigned char byte); + /* Function: io_skip Skips data in a file. diff --git a/src/engine/client/backend_sdl.cpp b/src/engine/client/backend_sdl.cpp index 1bf9ae531..81de48b0b 100644 --- a/src/engine/client/backend_sdl.cpp +++ b/src/engine/client/backend_sdl.cpp @@ -16,7 +16,7 @@ #if defined(CONF_FAMILY_WINDOWS) PFNGLTEXIMAGE3DPROC glTexImage3DInternal; - GLAPI void GLAPIENTRY glTexImage3D(GLenum target, GLint level, GLint internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid *pixels) + void GLAPIENTRY glTexImage3D(GLenum target, GLint level, GLint internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid *pixels) { glTexImage3DInternal(target, level, internalFormat, width, height, depth, border, format, type, pixels); } diff --git a/src/engine/client/graphics_threaded.cpp b/src/engine/client/graphics_threaded.cpp index 7807fc8ab..abf00ad83 100644 --- a/src/engine/client/graphics_threaded.cpp +++ b/src/engine/client/graphics_threaded.cpp @@ -6,7 +6,8 @@ #include #include -#include + +#include #include #include diff --git a/src/engine/client/sound.cpp b/src/engine/client/sound.cpp index 6d7088f33..0c627640b 100644 --- a/src/engine/client/sound.cpp +++ b/src/engine/client/sound.cpp @@ -12,8 +12,9 @@ #include "sound.h" -extern "C" { // wavpack - #include +extern "C" +{ + #include } #include @@ -68,6 +69,8 @@ static int m_NextVoice = 0; static int *m_pMixBuffer = 0; // buffer only used by the thread callback function static unsigned m_MaxFrames = 0; +static IOHANDLE s_File; + // TODO: there should be a faster way todo this static short Int2Short(int i) { @@ -325,11 +328,43 @@ void CSound::RateConvert(int SampleID) pSample->m_NumFrames = NumFrames; } -int CSound::ReadData(void *pBuffer, int Size) +static int ReadDataOld(void *pBuffer, int Size) { - return io_read(ms_File, pBuffer, Size); + return io_read(s_File, pBuffer, Size); } +#if defined(CONF_WAVPACK_OPEN_FILE_INPUT_EX) +static int ReadData(void *pId, void *pBuffer, int Size) +{ + (void)pId; + return ReadDataOld(pBuffer, Size); +} + +static int ReturnFalse(void *pId) +{ + (void)pId; + return 0; +} + +static unsigned int GetPos(void *pId) +{ + (void)pId; + return io_tell(s_File); +} + +static unsigned int GetLength(void *pId) +{ + (void)pId; + return io_length(s_File); +} + +static int PushBackByte(void *pId, int Char) +{ + (void)pId; + return io_unread_byte(s_File, Char); +} +#endif + ISound::CSampleHandle CSound::LoadWV(const char *pFilename) { CSample *pSample; @@ -349,8 +384,8 @@ ISound::CSampleHandle CSound::LoadWV(const char *pFilename) return CSampleHandle(); lock_wait(m_SoundLock); - ms_File = m_pStorage->OpenFile(pFilename, IOFLAG_READ, IStorage::TYPE_ALL); - if(!ms_File) + s_File = m_pStorage->OpenFile(pFilename, IOFLAG_READ, IStorage::TYPE_ALL); + if(!s_File) { dbg_msg("sound/wv", "failed to open file. filename='%s'", pFilename); lock_unlock(m_SoundLock); @@ -360,14 +395,24 @@ ISound::CSampleHandle CSound::LoadWV(const char *pFilename) SampleID = AllocID(); if(SampleID < 0) { - io_close(ms_File); - ms_File = 0; + io_close(s_File); + s_File = 0; lock_unlock(m_SoundLock); return CSampleHandle(); } pSample = &m_aSamples[SampleID]; - pContext = WavpackOpenFileInput(ReadData, aError); +#if defined(CONF_WAVPACK_OPEN_FILE_INPUT_EX) + WavpackStreamReader Callback = {0}; + Callback.can_seek = ReturnFalse; + Callback.get_length = GetLength; + Callback.get_pos = GetPos; + Callback.push_back_byte = PushBackByte; + Callback.read_bytes = ReadData; + pContext = WavpackOpenFileInputEx(&Callback, (void *)1, 0, aError, 0, 0); +#else + pContext = WavpackOpenFileInput(ReadDataOld, aError); +#endif if (pContext) { int m_aSamples = WavpackGetNumSamples(pContext); @@ -385,8 +430,8 @@ ISound::CSampleHandle CSound::LoadWV(const char *pFilename) if(pSample->m_Channels > 2) { dbg_msg("sound/wv", "file is not mono or stereo. filename='%s'", pFilename); - io_close(ms_File); - ms_File = 0; + io_close(s_File); + s_File = 0; lock_unlock(m_SoundLock); return CSampleHandle(); } @@ -401,8 +446,8 @@ ISound::CSampleHandle CSound::LoadWV(const char *pFilename) if(BitsPerSample != 16) { dbg_msg("sound/wv", "bps is %d, not 16, filname='%s'", BitsPerSample, pFilename); - io_close(ms_File); - ms_File = 0; + io_close(s_File); + s_File = 0; lock_unlock(m_SoundLock); return CSampleHandle(); } @@ -429,8 +474,8 @@ ISound::CSampleHandle CSound::LoadWV(const char *pFilename) dbg_msg("sound/wv", "failed to open %s: %s", pFilename, aError); } - io_close(ms_File); - ms_File = NULL; + io_close(s_File); + s_File = NULL; if(g_Config.m_Debug) dbg_msg("sound/wv", "loaded %s", pFilename); @@ -560,7 +605,4 @@ bool CSound::IsPlaying(CSampleHandle SampleID) return Ret; } -IOHANDLE CSound::ms_File = 0; - IEngineSound *CreateEngineSound() { return new CSound; } - diff --git a/src/engine/client/sound.h b/src/engine/client/sound.h index ff357c047..cec2cdeda 100644 --- a/src/engine/client/sound.h +++ b/src/engine/client/sound.h @@ -21,10 +21,6 @@ public: static void RateConvert(int SampleID); - // TODO: Refactor: clean this mess up - static IOHANDLE ms_File; - static int ReadData(void *pBuffer, int Size); - virtual bool IsSoundEnabled() { return m_SoundEnabled != 0; } virtual CSampleHandle LoadWV(const char *pFilename); diff --git a/src/osxlaunch/server.mm b/src/osxlaunch/server.mm new file mode 100644 index 000000000..5ad2d4eda --- /dev/null +++ b/src/osxlaunch/server.mm @@ -0,0 +1,112 @@ +#import + +@interface ServerView : NSTextView +{ + NSTask *task; + NSFileHandle *file; +} +- (void)listenTo: (NSTask*)t; +@end + +@implementation ServerView +- (void)listenTo: (NSTask*)t; +{ + NSPipe *pipe; + task = t; + pipe = [NSPipe pipe]; + [task setStandardOutput: pipe]; + file = [pipe fileHandleForReading]; + + [[NSNotificationCenter defaultCenter] addObserver: self selector: @selector(outputNotification:) name: NSFileHandleReadCompletionNotification object: file]; + + [file readInBackgroundAndNotify]; +} + +- (void) outputNotification: (NSNotification *) notification +{ + NSData *data = [[[notification userInfo] objectForKey: NSFileHandleNotificationDataItem] retain]; + NSString *string = [[NSString alloc] initWithData: data encoding: NSASCIIStringEncoding]; + NSAttributedString *attrstr = [[NSAttributedString alloc] initWithString: string]; + + [[self textStorage] appendAttributedString: attrstr]; + int length = [[self textStorage] length]; + NSRange range = NSMakeRange(length, 0); + [self scrollRangeToVisible: range]; + + [attrstr release]; + [string release]; + [file readInBackgroundAndNotify]; +} + +-(void)windowWillClose:(NSNotification *)notification +{ + [task terminate]; + [NSApp terminate:self]; +} +@end + +void runServer() +{ + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + NSApp = [NSApplication sharedApplication]; + NSBundle* mainBundle = [NSBundle mainBundle]; + NSTask *task; + task = [[NSTask alloc] init]; + [task setCurrentDirectoryPath: [mainBundle resourcePath]]; + + // get a server config + NSOpenPanel* openDlg = [NSOpenPanel openPanel]; + [openDlg setCanChooseFiles:YES]; + + if([openDlg runModalForDirectory:nil file:nil] != NSOKButton) + return; + + NSArray* filenames = [openDlg filenames]; + if([filenames count] != 1) + return; + + NSString* filename = [filenames objectAtIndex: 0]; + NSArray* arguments = [NSArray arrayWithObjects: @"-f", filename, nil]; + + // run server + NSWindow *window; + ServerView *view; + NSRect graphicsRect; + + graphicsRect = NSMakeRect(100.0, 1000.0, 600.0, 400.0); + + window = [[NSWindow alloc] + initWithContentRect: graphicsRect + styleMask: NSTitledWindowMask + | NSClosableWindowMask + | NSMiniaturizableWindowMask + backing: NSBackingStoreBuffered + defer: NO]; + + [window setTitle: @"Teeworlds Server"]; + + view = [[[ServerView alloc] initWithFrame: graphicsRect] autorelease]; + [view setEditable: NO]; + [view setRulerVisible: YES]; + + [window setContentView: view]; + [window setDelegate: (id)view]; + [window makeKeyAndOrderFront: nil]; + + [view listenTo: task]; + [task setLaunchPath: [mainBundle pathForAuxiliaryExecutable: @"teeworlds_srv"]]; + [task setArguments: arguments]; + [task launch]; + [NSApp run]; + [task terminate]; + + [NSApp release]; + [pool release]; +} + +int main (int argc, char **argv) +{ + runServer(); + + return 0; +} From 6e0d3139c80b32f0be331c006befc815aace2bfe Mon Sep 17 00:00:00 2001 From: heinrich5991 Date: Mon, 24 Dec 2018 22:58:06 +0100 Subject: [PATCH 2/5] Fix a couple of warnings Use autogenerated copy constructors for ranges, don't use fallthrough as control flow, initialize variables, don't cast something to a `const T` in an expression. --- src/base/tl/range.h | 10 ---------- src/engine/shared/console.cpp | 2 +- src/game/client/components/mapimages.cpp | 4 ++-- src/game/client/gameclient.cpp | 13 +++++++------ src/game/client/localization.cpp | 1 + src/game/server/gamecontext.cpp | 1 + 6 files changed, 12 insertions(+), 19 deletions(-) diff --git a/src/base/tl/range.h b/src/base/tl/range.h index 1d225f491..ff89b4663 100644 --- a/src/base/tl/range.h +++ b/src/base/tl/range.h @@ -138,11 +138,6 @@ public: end = 0x0; } - plain_range(const plain_range &r) - { - *this = r; - } - plain_range(T *b, T *e) { begin = b; @@ -184,11 +179,6 @@ public: plain_range_sorted() {} - plain_range_sorted(const plain_range_sorted &r) - { - *this = r; - } - plain_range_sorted(T *b, T *e) : parent(b, e) {} diff --git a/src/engine/shared/console.cpp b/src/engine/shared/console.cpp index fb5f63500..daf966540 100644 --- a/src/engine/shared/console.cpp +++ b/src/engine/shared/console.cpp @@ -553,7 +553,7 @@ static void StrVariableCommand(IConsole::IResult *pResult, void *pUserData) int Length = 0; while(*pString) { - int Size = str_utf8_encode(Temp, static_cast(*pString++)); + int Size = str_utf8_encode(Temp, static_cast(*pString++)); if(Length+Size < pData->m_MaxSize) { mem_copy(pData->m_pStr+Length, &Temp, Size); diff --git a/src/game/client/components/mapimages.cpp b/src/game/client/components/mapimages.cpp index 00398f263..6639dc71d 100644 --- a/src/game/client/components/mapimages.cpp +++ b/src/game/client/components/mapimages.cpp @@ -37,9 +37,9 @@ void CMapImages::LoadMapImages(IMap *pMap, class CLayers *pLayers, int MapType) for(int k = 0; k < pLayers->NumLayers(); k++) { const CMapItemLayer * const pLayer = pLayers->GetLayer(k); - if(!FoundQuadLayer && pLayer->m_Type == LAYERTYPE_QUADS && ((const CMapItemLayerQuads * const)pLayer)->m_Image == i) + if(!FoundQuadLayer && pLayer->m_Type == LAYERTYPE_QUADS && ((const CMapItemLayerQuads *)pLayer)->m_Image == i) FoundQuadLayer = true; - if(!FoundTileLayer && pLayer->m_Type == LAYERTYPE_TILES && ((const CMapItemLayerTilemap * const)pLayer)->m_Image == i) + if(!FoundTileLayer && pLayer->m_Type == LAYERTYPE_TILES && ((const CMapItemLayerTilemap *)pLayer)->m_Image == i) FoundTileLayer = true; } if(FoundTileLayer) diff --git a/src/game/client/gameclient.cpp b/src/game/client/gameclient.cpp index 425f2d9be..246b9d7b8 100644 --- a/src/game/client/gameclient.cpp +++ b/src/game/client/gameclient.cpp @@ -524,12 +524,13 @@ void CGameClient::OnMessage(int MsgId, CUnpacker *pUnpacker) // get paras switch(gs_GameMsgList[GameMsgID].m_ParaType) { - case PARA_III: - aParaI[NumParaI++] = pUnpacker->GetInt(); - case PARA_II: - aParaI[NumParaI++] = pUnpacker->GetInt(); - case PARA_I: - aParaI[NumParaI++] = pUnpacker->GetInt(); + case PARA_I: NumParaI = 1; break; + case PARA_II: NumParaI = 2; break; + case PARA_III: NumParaI = 3; break; + } + for(int i = 0; i < NumParaI; i++) + { + aParaI[i] = pUnpacker->GetInt(); } // check for unpacking errors diff --git a/src/game/client/localization.cpp b/src/game/client/localization.cpp index de11f5e89..84d4ff8ee 100644 --- a/src/game/client/localization.cpp +++ b/src/game/client/localization.cpp @@ -126,6 +126,7 @@ const char *CLocalizationDatabase::FindString(unsigned Hash, unsigned ContextHas { CString String; String.m_Hash = Hash; + String.m_ContextHash = 0; // this is ignored for the search anyway sorted_array::range r = ::find_binary(m_Strings.all(), String); if(r.empty()) return 0; diff --git a/src/game/server/gamecontext.cpp b/src/game/server/gamecontext.cpp index ca0275c26..fb66e40ad 100644 --- a/src/game/server/gamecontext.cpp +++ b/src/game/server/gamecontext.cpp @@ -648,6 +648,7 @@ void CGameContext::OnClientEnter(int ClientID) { CNetMsg_De_ClientEnter Msg; Msg.m_pName = NewClientInfoMsg.m_pName; + Msg.m_ClientID = ClientID; Msg.m_Team = NewClientInfoMsg.m_Team; Server()->SendPackMsg(&Msg, MSGFLAG_NOSEND, -1); } From 2b65014d4efa182a73cf7f2795941478c15cf2b0 Mon Sep 17 00:00:00 2001 From: heinrich5991 Date: Tue, 25 Dec 2018 21:37:06 +0100 Subject: [PATCH 3/5] Add library paths to gitignore Thanks to @ChillerDragon. --- .gitignore | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.gitignore b/.gitignore index 3d102c096..41bc0ea83 100644 --- a/.gitignore +++ b/.gitignore @@ -5,6 +5,9 @@ /objs /other/*/include /other/*/lib +/other/*/linux +/other/*/mac +/other/*/windows __pycache__/ *.dll *.pyc From d6510c88581f8264d8b5e7bc56937b77a986a838 Mon Sep 17 00:00:00 2001 From: heinrich5991 Date: Tue, 25 Dec 2018 21:42:24 +0100 Subject: [PATCH 4/5] Don't hardcode freetype library path --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index f5be54e07..4fbe316bd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1650,7 +1650,7 @@ if(CLIENT AND (DMGTOOLS_FOUND OR HDIUTIL)) COMMAND ${CMAKE_COMMAND} -E copy bundle/client/Info.plist ${PROJECT_SOURCE_DIR}/other/bundle/client/PkgInfo ${DMG_TMPDIR}/${TARGET_CLIENT}.app/Contents/ COMMAND ${CMAKE_COMMAND} -E copy $ ${DMG_TMPDIR}/${TARGET_CLIENT}.app/Contents/MacOS/ COMMAND ${CMAKE_COMMAND} -E copy_directory ${PROJECT_SOURCE_DIR}/other/sdl/mac/lib64/SDL2.framework ${DMG_TMPDIR}/${TARGET_CLIENT}.app/Contents/Frameworks/SDL2.framework - COMMAND ${CMAKE_COMMAND} -E copy ${PROJECT_SOURCE_DIR}/other/freetype/mac/lib64/libfreetype.6.dylib ${DMG_TMPDIR}/${TARGET_CLIENT}.app/Contents/Frameworks/ + COMMAND ${CMAKE_COMMAND} -E copy ${FREETYPE_LIBRARY} ${DMG_TMPDIR}/${TARGET_CLIENT}.app/Contents/Frameworks/ COMMAND ${PYTHON_EXECUTABLE} ${PROJECT_SOURCE_DIR}/scripts/darwin_change_dylib.py change --tools ${CMAKE_INSTALL_NAME_TOOL} ${CMAKE_OTOOL} ${DMG_TMPDIR}/${TARGET_CLIENT}.app/Contents/MacOS/${TARGET_CLIENT} SDL2 @executable_path/../Frameworks/SDL2.framework/SDL2 COMMAND ${PYTHON_EXECUTABLE} ${PROJECT_SOURCE_DIR}/scripts/darwin_change_dylib.py change --tools ${CMAKE_INSTALL_NAME_TOOL} ${CMAKE_OTOOL} ${DMG_TMPDIR}/${TARGET_CLIENT}.app/Contents/MacOS/${TARGET_CLIENT} libfreetype @executable_path/../Frameworks/libfreetype.6.dylib From 4d4a729754ef322ea15f62819f2b482e6127b8d4 Mon Sep 17 00:00:00 2001 From: ChillerDragon Date: Wed, 28 Nov 2018 10:03:35 +0100 Subject: [PATCH 5/5] Delete volume if exist already --- scripts/dmg.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/scripts/dmg.py b/scripts/dmg.py index 8f2d4cfc1..9c797e44c 100644 --- a/scripts/dmg.py +++ b/scripts/dmg.py @@ -71,6 +71,8 @@ class Hdiutil(Dmg): def create(self, dmg, volume_name, directory, symlinks): if symlinks: raise NotImplementedError("symlinks are not yet implemented") + if os.path.exists(volume_name + '.dmg'): + os.remove(volume_name + '.dmg') self._hdiutil('create', '-volname', volume_name, '-srcdir', directory, dmg) def main():