From ee2afdac33f43d96a457bcf692a817489d6f896e Mon Sep 17 00:00:00 2001 From: heinrich5991 Date: Mon, 1 Oct 2018 10:49:19 +0200 Subject: [PATCH] Add CMake --- .gitignore | 17 + CMakeLists.txt | 1243 +++++++++++++++++ bam.lua | 5 +- cmake/FindFreetype.cmake | 37 + cmake/FindPnglite.cmake | 46 + cmake/FindSDL.cmake | 38 + 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 +- .../freetype/{ => windows}/lib32/freetype.dll | Bin .../freetype/{ => windows}/lib32/freetype.lib | Bin .../freetype/{ => windows}/lib64/freetype.dll | Bin .../freetype/{ => windows}/lib64/freetype.lib | Bin .../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 +- other/sdl/{ => windows}/lib32/SDL.dll | Bin other/sdl/{ => windows}/lib32/SDL.lib | Bin other/sdl/{ => windows}/lib32/SDLmain.lib | Bin other/sdl/{ => windows}/lib64/SDL.dll | Bin other/sdl/{ => windows}/lib64/SDL.lib | Bin other/sdl/{ => windows}/lib64/SDLmain.lib | Bin scripts/darwin_change_dylib.py | 63 + scripts/dmg.py | 106 ++ scripts/git_revision.py | 21 + src/base/system.c | 5 + src/base/system.h | 15 + src/engine/client/sound.cpp | 66 +- src/engine/client/sound.h | 4 - src/game/version.h | 4 +- src/osxlaunch/client.m | 374 +---- src/osxlaunch/client.mm | 373 +++++ src/osxlaunch/server.m | 113 +- src/osxlaunch/server.mm | 112 ++ 47 files changed, 2323 insertions(+), 512 deletions(-) create mode 100644 CMakeLists.txt create mode 100644 cmake/FindFreetype.cmake create mode 100644 cmake/FindPnglite.cmake create mode 100644 cmake/FindSDL.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/freetype/{ => windows}/lib32/freetype.dll (100%) rename other/freetype/{ => windows}/lib32/freetype.lib (100%) rename other/freetype/{ => windows}/lib64/freetype.dll (100%) rename other/freetype/{ => windows}/lib64/freetype.lib (100%) 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 rename other/sdl/{ => windows}/lib32/SDL.dll (100%) rename other/sdl/{ => windows}/lib32/SDL.lib (100%) rename other/sdl/{ => windows}/lib32/SDLmain.lib (100%) rename other/sdl/{ => windows}/lib64/SDL.dll (100%) rename other/sdl/{ => windows}/lib64/SDL.lib (100%) rename other/sdl/{ => windows}/lib64/SDLmain.lib (100%) create mode 100644 scripts/darwin_change_dylib.py create mode 100644 scripts/dmg.py create mode 100644 scripts/git_revision.py mode change 100644 => 120000 src/osxlaunch/client.m create mode 100644 src/osxlaunch/client.mm mode change 100644 => 120000 src/osxlaunch/server.m create mode 100644 src/osxlaunch/server.mm diff --git a/.gitignore b/.gitignore index edbb7eab8..c0916ca03 100644 --- a/.gitignore +++ b/.gitignore @@ -8,6 +8,7 @@ src/game/generated SDL.dll freetype.dll autoexec.cfg +Info.plist crapnet* dilate* @@ -20,3 +21,19 @@ teeworlds* teeworlds_srv* tileset_border* versionsrv* + +# CMake +data +!/data +src +!/src + +*.ninja +.ninja* +CMakeCache.txt +CMakeFiles/ +CPackConfig.cmake +CPackSourceConfig.cmake +Makefile +cmake_install.cmake +install_manifest.txt diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 000000000..7a8fb99e0 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,1243 @@ +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) + if(VERSION_PATCH STREQUAL "0") + project(teeworlds VERSION ${VERSION_MAJOR}.${VERSION_MINOR}) + else() + project(teeworlds VERSION ${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}) + endif() +else() + project(teeworlds) + set(PROJECT_VERSION_MAJOR ${VERSION_MAJOR}) + set(PROJECT_VERSION_MINOR ${VERSION_MINOR}) + set(PROJECT_VERSION_PATCH ${VERSION_PATCH}) + if(VERSION_PATCH STREQUAL "0") + set(PROJECT_VERSION ${VERSION_MAJOR}.${VERSION_MINOR}) + else() + set(PROJECT_VERSION ${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}) + endif() +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 DIRECTORY) # ... + file(${GLOBBING} GLOB_RESULT "${DIRECTORY}/*.c" "${DIRECTORY}/*.cpp" "${DIRECTORY}/*.h") + 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() + +######################################################################## +# 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(SDL) +find_package(Threads) +find_package(Wavpack) + + +if(TARGET_OS AND TARGET_OS STREQUAL "mac") + 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("SDL" SDL) +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(SDL_FOUND)) + message(SEND_ERROR "You must install SDL 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_glob(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 md5) +set(DEP_MD5 $) + +######################################################################## +# COPY DATA AND DLLS +######################################################################## + +file(COPY data DESTINATION .) +set(COPY_FILES + ${FREETYPE_COPY_FILES} + ${SDL_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/game/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/game/generated/git_revision.cpp + COMMAND ${PYTHON_EXECUTABLE} + scripts/git_revision.py + > ${PROJECT_BINARY_DIR}/src/game/generated/git_revision.cpp + WORKING_DIRECTORY ${PROJECT_SOURCE_DIR} + DEPENDS + ${GIT_REVISION_EXTRA_DEPS} + scripts/git_revision.py +) +chash("src/game/generated/nethash.cpp" + "src/engine/shared/protocol.h" + "${PROJECT_BINARY_DIR}/src/game/generated/protocol.h" + "src/game/tuning.h" + "src/game/gamecore.cpp" +) +generate_source("src/game/generated/client_data.cpp" "client_content_source") +generate_source("src/game/generated/client_data.h" "client_content_header") +generate_source("src/game/generated/protocol.cpp" "network_source") +generate_source("src/game/generated/protocol.h" "network_header") +generate_source("src/game/generated/server_data.cpp" "server_content_source") +generate_source("src/game/generated/server_data.h" "server_content_header") + + +######################################################################## +# SHARED +######################################################################## + +# Sources +set_glob(BASE GLOB_RECURSE src/base + 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_glob(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_glob(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 + packer.cpp + packer.h + protocol.h + ringbuffer.cpp + ringbuffer.h + snapshot.cpp + snapshot.h + storage.cpp +) +set(ENGINE_GENERATED_SHARED src/game/generated/protocol.cpp src/game/generated/protocol.h) +set_glob(GAME_SHARED GLOB src/game + collision.cpp + collision.h + gamecore.cpp + gamecore.h + layers.cpp + layers.h + localization.cpp + localization.h + mapitems.h + tuning.h + variables.h + version.h + voting.h +) +set(GAME_GENERATED_SHARED + src/game/generated/git_revision.cpp + src/game/generated/nethash.cpp + src/game/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_glob(ENGINE_CLIENT GLOB src/engine/client + backend_sdl.cpp + backend_sdl.h + client.cpp + client.h + friends.cpp + friends.h + graphics.cpp + graphics.h + graphics_threaded.cpp + graphics_threaded.h + input.cpp + input.h + keynames.h + serverbrowser.cpp + serverbrowser.h + sound.cpp + sound.h + text.cpp + ) + set_glob(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_demo.cpp + components/menus_ingame.cpp + components/menus_settings.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 + render.cpp + render.h + render_map.cpp + ui.cpp + ui.h + ) + set_glob(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/game/generated/client_data.cpp + src/game/generated/client_data.h + ) + set(CLIENT_SRC ${ENGINE_CLIENT} ${PLATFORM_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} + ${SDL_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} + ${SDL_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_glob(ENGINE_SERVER GLOB src/engine/server + register.cpp + register.h + server.cpp + server.h +) +set_glob(GAME_SERVER GLOB_RECURSE src/game/server + 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/mod.cpp + gamemodes/mod.h + gamemodes/tdm.cpp + gamemodes/tdm.h + gameworld.cpp + gameworld.h + player.cpp + player.h +) +set(GAME_GENERATED_SERVER + "src/game/generated/server_data.cpp" + "src/game/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_glob(MASTERSRV_SRC GLOB src/mastersrv mastersrv.cpp mastersrv.h) +set_glob(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_glob(TOOLS GLOB src/tools + crapnet.cpp + dilate.cpp + fake_server.cpp + map_resave.cpp + map_version.cpp + packetgen.cpp + tileset_borderadd.cpp + tileset_borderfix.cpp + tileset_borderrem.cpp + tileset_borderset.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}") + set(TOOL_DEPS ${DEPS}) + set(TOOL_LIBS ${LIBS}) + if(TOOL MATCHES "^(tileset_.*|dilate|map_extract|map_replace_image)$") + list(APPEND TOOL_DEPS ${PNGLITE_DEP}) + list(APPEND TOOL_LIBS ${PNGLITE_LIBRARIES}) + list(APPEND TOOL_INCLUDE_DIRS ${PNGLITE_INCLUDE_DIRS}) + endif() + set(EXCLUDE_FROM_ALL) + add_executable(${TOOL} EXCLUDE_FROM_ALL + ${TOOL_DEPS} + src/tools/${TOOL}.cpp + ${EXTRA_TOOL_SRC} + $ + ) + target_include_directories(${TOOL} PRIVATE ${TOOL_INCLUDE_DIRS}) + target_link_libraries(${TOOL} ${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}) +if(VERSION_PATCH STREQUAL "0") + set(CPACK_PACKAGE_VERSION ${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSION_MINOR}) +else() + set(CPACK_PACKAGE_VERSION ${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSION_MINOR}.${CPACK_PACKAGE_VERSION_PATCH}) +endif() +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 + data/ + datasrc/ + docs/ + license.txt + objs/ + other/ + readme.txt + 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 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 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 + ${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 ${PROJECT_SOURCE_DIR}/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/SDL.framework ${DMG_TMPDIR}/${TARGET_CLIENT}.app/Contents/Frameworks/SDL.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} SDL @executable_path/../Frameworks/SDL.framework/SDL + 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 ${PROJECT_SOURCE_DIR}/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 + data + 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}) + list(APPEND COPY_DIR_COMMANDS COMMAND ${CMAKE_COMMAND} -E copy_directory ${PROJECT_SOURCE_DIR}/${dir} ${TMPDIR}/${dir}) + 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 f8b178077..214b9fccf 100644 --- a/bam.lua +++ b/bam.lua @@ -169,6 +169,7 @@ function build(settings) -- set some platform specific settings settings.cc.includes:Add("src") + settings.cc.includes:Add("src/engine/external/wavpack") if family == "unix" then if platform == "macosx" then @@ -252,10 +253,8 @@ function build(settings) -- build tools (TODO: fix this so we don't get double _d_d stuff) tools_src = Collect("src/tools/*.cpp", "src/tools/*.c") - client_osxlaunch = {} server_osxlaunch = {} if platform == "macosx" then - client_osxlaunch = Compile(client_settings, "src/osxlaunch/client.m") server_osxlaunch = Compile(launcher_settings, "src/osxlaunch/server.m") end @@ -268,7 +267,7 @@ function build(settings) -- build client, server, version server and master server client_exe = Link(client_settings, "teeworlds", game_shared, game_client, engine, client, game_editor, md5, zlib, pnglite, wavpack, - client_link_other, client_osxlaunch) + client_link_other) server_exe = Link(server_settings, "teeworlds_srv", engine, server, game_shared, game_server, md5, zlib, server_link_other) 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..b011a5011 --- /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_glob(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/FindSDL.cmake b/cmake/FindSDL.cmake new file mode 100644 index 000000000..137567501 --- /dev/null +++ b/cmake/FindSDL.cmake @@ -0,0 +1,38 @@ +if(NOT CMAKE_CROSSCOMPILING) + find_package(PkgConfig QUIET) + pkg_check_modules(PC_SDL sdl) +endif() + +set_extra_dirs_lib(SDL sdl) +find_library(SDL_LIBRARY + NAMES SDL + HINTS ${HINTS_SDL_LIBDIR} ${PC_SDL_LIBDIR} ${PC_SDL_LIBRARY_DIRS} + PATHS ${PATHS_SDL_LIBDIR} + ${CROSSCOMPILING_NO_CMAKE_SYSTEM_PATH} +) +set(CMAKE_FIND_FRAMEWORK FIRST) +set_extra_dirs_include(SDL sdl "${SDL_LIBRARY}") +# Looking for 'SDL.h' directly might accidentally find a SDL 2 instead of SDL +# installation. Look for a header file only present in SDL instead. +find_path(SDL_INCLUDEDIR SDL_active.h + PATH_SUFFIXES SDL + HINTS ${HINTS_SDL_INCLUDEDIR} ${PC_SDL_INCLUDEDIR} ${PC_SDL_INCLUDE_DIRS} + PATHS ${PATHS_SDL_INCLUDEDIR} +) + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(SDL DEFAULT_MSG SDL_LIBRARY SDL_INCLUDEDIR) + +mark_as_advanced(SDL_LIBRARY SDL_INCLUDEDIR) + +if(SDL_FOUND) + set(SDL_LIBRARIES ${SDL_LIBRARY}) + set(SDL_INCLUDE_DIRS ${SDL_INCLUDEDIR}) + + is_bundled(SDL_BUNDLED "${SDL_LIBRARY}") + if(SDL_BUNDLED AND TARGET_OS STREQUAL "windows") + set(SDL_COPY_FILES "${EXTRA_SDL_LIBDIR}/SDL.dll") + else() + set(SDL_COPY_FILES) + endif() +endif() diff --git a/cmake/FindWavpack.cmake b/cmake/FindWavpack.cmake new file mode 100644 index 000000000..086902ca7 --- /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_glob(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..5c51bd8ba --- /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_glob(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..3346bf5e6 --- /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 + org.DDNetClient.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 9d484afbd..9df4de40a 100644 --- a/other/freetype/freetype.lua +++ b/other/freetype/freetype.lua @@ -39,9 +39,9 @@ FreeType = { elseif option.use_winlib > 0 then if option.use_winlib == 32 then - settings.link.libpath:Add(FreeType.basepath .. "/lib32") + settings.link.libpath:Add(FreeType.basepath .. "/windows/lib32") else - settings.link.libpath:Add(FreeType.basepath .. "/lib64") + settings.link.libpath:Add(FreeType.basepath .. "/windows/lib64") end settings.link.libs:Add("freetype") end diff --git a/other/freetype/lib32/freetype.dll b/other/freetype/windows/lib32/freetype.dll similarity index 100% rename from other/freetype/lib32/freetype.dll rename to other/freetype/windows/lib32/freetype.dll diff --git a/other/freetype/lib32/freetype.lib b/other/freetype/windows/lib32/freetype.lib similarity index 100% rename from other/freetype/lib32/freetype.lib rename to other/freetype/windows/lib32/freetype.lib diff --git a/other/freetype/lib64/freetype.dll b/other/freetype/windows/lib64/freetype.dll similarity index 100% rename from other/freetype/lib64/freetype.dll rename to other/freetype/windows/lib64/freetype.dll diff --git a/other/freetype/lib64/freetype.lib b/other/freetype/windows/lib64/freetype.lib similarity index 100% rename from other/freetype/lib64/freetype.lib rename to other/freetype/windows/lib64/freetype.lib 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 9bf75ea81..5b69901d2 100644 --- a/other/sdl/sdl.lua +++ b/other/sdl/sdl.lua @@ -51,9 +51,9 @@ SDL = { if option.use_winlib > 0 then settings.cc.includes:Add(SDL.basepath .. "/include") if option.use_winlib == 32 then - settings.link.libpath:Add(SDL.basepath .. "/lib32") + settings.link.libpath:Add(SDL.basepath .. "/windows/lib32") else - settings.link.libpath:Add(SDL.basepath .. "/lib64") + settings.link.libpath:Add(SDL.basepath .. "/windows/lib64") end settings.link.libs:Add("SDL") settings.link.libs:Add("SDLmain") diff --git a/other/sdl/lib32/SDL.dll b/other/sdl/windows/lib32/SDL.dll similarity index 100% rename from other/sdl/lib32/SDL.dll rename to other/sdl/windows/lib32/SDL.dll diff --git a/other/sdl/lib32/SDL.lib b/other/sdl/windows/lib32/SDL.lib similarity index 100% rename from other/sdl/lib32/SDL.lib rename to other/sdl/windows/lib32/SDL.lib diff --git a/other/sdl/lib32/SDLmain.lib b/other/sdl/windows/lib32/SDLmain.lib similarity index 100% rename from other/sdl/lib32/SDLmain.lib rename to other/sdl/windows/lib32/SDLmain.lib diff --git a/other/sdl/lib64/SDL.dll b/other/sdl/windows/lib64/SDL.dll similarity index 100% rename from other/sdl/lib64/SDL.dll rename to other/sdl/windows/lib64/SDL.dll diff --git a/other/sdl/lib64/SDL.lib b/other/sdl/windows/lib64/SDL.lib similarity index 100% rename from other/sdl/lib64/SDL.lib rename to other/sdl/windows/lib64/SDL.lib diff --git a/other/sdl/lib64/SDLmain.lib b/other/sdl/windows/lib64/SDLmain.lib similarity index 100% rename from other/sdl/lib64/SDLmain.lib rename to other/sdl/windows/lib64/SDLmain.lib 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 c5765e68a..a6d214717 100644 --- a/src/base/system.c +++ b/src/base/system.c @@ -303,6 +303,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); diff --git a/src/base/system.h b/src/base/system.h index fef36f0b6..c1178e7b0 100644 --- a/src/base/system.h +++ b/src/base/system.h @@ -219,6 +219,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/sound.cpp b/src/engine/client/sound.cpp index 4c64422e8..7f6275836 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 @@ -67,6 +68,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) { @@ -328,11 +331,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 + int CSound::LoadWV(const char *pFilename) { CSample *pSample; @@ -351,8 +386,8 @@ int CSound::LoadWV(const char *pFilename) if(!m_pStorage) return -1; - 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); return -1; @@ -363,7 +398,17 @@ int CSound::LoadWV(const char *pFilename) return -1; 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); @@ -419,8 +464,8 @@ int 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); @@ -527,7 +572,4 @@ void CSound::StopAll() lock_unlock(m_SoundLock); } -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 8112427c3..576f6497b 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 int LoadWV(const char *pFilename); diff --git a/src/game/version.h b/src/game/version.h index 17010c1b0..bc174a24d 100644 --- a/src/game/version.h +++ b/src/game/version.h @@ -2,8 +2,8 @@ /* If you are missing that file, acquire a complete release at teeworlds.com. */ #ifndef GAME_VERSION_H #define GAME_VERSION_H -#include "generated/nethash.cpp" +#include #define GAME_VERSION "0.6.5" #define GAME_NETVERSION "0.6 " GAME_NETVERSION_HASH -static const char GAME_RELEASE_VERSION[8] = {'0', '.', '6', '.', '5', 0}; +static const char GAME_RELEASE_VERSION[8] = "0.6.5"; #endif diff --git a/src/osxlaunch/client.m b/src/osxlaunch/client.m deleted file mode 100644 index 6de919e2a..000000000 --- a/src/osxlaunch/client.m +++ /dev/null @@ -1,373 +0,0 @@ -/* SDLMain.m - main entry point for our Cocoa-ized SDL app - Initial Version: Darrell Walisser - Non-NIB-Code & other changes: Max Horn - - Feel free to customize this file to suit your needs -*/ - -#import -#import "client.h" -#import /* for MAXPATHLEN */ -#import - -/* For some reaon, Apple removed setAppleMenu from the headers in 10.4, - but the method still is there and works. To avoid warnings, we declare - it ourselves here. */ -@interface NSApplication(SDL_Missing_Methods) -- (void)setAppleMenu:(NSMenu *)menu; -@end - -/* Use this flag to determine whether we use SDLMain.nib or not */ -#define SDL_USE_NIB_FILE 0 - -/* Use this flag to determine whether we use CPS (docking) or not */ -#define SDL_USE_CPS 1 -#ifdef SDL_USE_CPS -/* Portions of CPS.h */ -typedef struct CPSProcessSerNum -{ - UInt32 lo; - UInt32 hi; -} CPSProcessSerNum; - -extern OSErr CPSGetCurrentProcess( CPSProcessSerNum *psn); -extern OSErr CPSEnableForegroundOperation( CPSProcessSerNum *psn, UInt32 _arg2, UInt32 _arg3, UInt32 _arg4, UInt32 _arg5); -extern OSErr CPSSetFrontProcess( CPSProcessSerNum *psn); - -#endif /* SDL_USE_CPS */ - -static int gArgc; -static char **gArgv; -static BOOL gFinderLaunch; -static BOOL gCalledAppMainline = FALSE; - -static NSString *getApplicationName(void) -{ - NSDictionary *dict; - NSString *appName = 0; - - /* Determine the application name */ - dict = (NSDictionary *)CFBundleGetInfoDictionary(CFBundleGetMainBundle()); - if (dict) - appName = [dict objectForKey: @"CFBundleName"]; - - if (![appName length]) - appName = [[NSProcessInfo processInfo] processName]; - - return appName; -} - -#if SDL_USE_NIB_FILE -/* A helper category for NSString */ -@interface NSString (ReplaceSubString) -- (NSString *)stringByReplacingRange:(NSRange)aRange with:(NSString *)aString; -@end -#endif - -@interface SDLApplication : NSApplication -@end - -@implementation SDLApplication -/* Invoked from the Quit menu item */ -- (void)terminate:(id)sender -{ - /* Post a SDL_QUIT event */ - SDL_Event event; - event.type = SDL_QUIT; - SDL_PushEvent(&event); -} -@end - -/* The main class of the application, the application's delegate */ -@implementation SDLMain - -/* Set the working directory to the .app's parent directory */ -- (void) setupWorkingDirectory:(BOOL)shouldChdir -{ - NSString *resourcePath = [[NSBundle mainBundle] resourcePath]; - [[NSFileManager defaultManager] changeCurrentDirectoryPath:resourcePath]; -} - -#if SDL_USE_NIB_FILE - -/* Fix menu to contain the real app name instead of "SDL App" */ -- (void)fixMenu:(NSMenu *)aMenu withAppName:(NSString *)appName -{ - NSRange aRange; - NSEnumerator *enumerator; - NSMenuItem *menuItem; - - aRange = [[aMenu title] rangeOfString:@"SDL App"]; - if (aRange.length != 0) - [aMenu setTitle: [[aMenu title] stringByReplacingRange:aRange with:appName]]; - - enumerator = [[aMenu itemArray] objectEnumerator]; - while ((menuItem = [enumerator nextObject])) - { - aRange = [[menuItem title] rangeOfString:@"SDL App"]; - if (aRange.length != 0) - [menuItem setTitle: [[menuItem title] stringByReplacingRange:aRange with:appName]]; - if ([menuItem hasSubmenu]) - [self fixMenu:[menuItem submenu] withAppName:appName]; - } - [ aMenu sizeToFit ]; -} - -#else - -static void setApplicationMenu(void) -{ - /* warning: this code is very odd */ - NSMenu *appleMenu; - NSMenuItem *menuItem; - NSString *title; - NSString *appName; - - appName = getApplicationName(); - appleMenu = [[NSMenu alloc] initWithTitle:@""]; - - /* Add menu items */ - title = [@"About " stringByAppendingString:appName]; - [appleMenu addItemWithTitle:title action:@selector(orderFrontStandardAboutPanel:) keyEquivalent:@""]; - - [appleMenu addItem:[NSMenuItem separatorItem]]; - - title = [@"Hide " stringByAppendingString:appName]; - [appleMenu addItemWithTitle:title action:@selector(hide:) keyEquivalent:@"h"]; - - menuItem = (NSMenuItem *)[appleMenu addItemWithTitle:@"Hide Others" action:@selector(hideOtherApplications:) keyEquivalent:@"h"]; - [menuItem setKeyEquivalentModifierMask:(NSAlternateKeyMask|NSCommandKeyMask)]; - - [appleMenu addItemWithTitle:@"Show All" action:@selector(unhideAllApplications:) keyEquivalent:@""]; - - [appleMenu addItem:[NSMenuItem separatorItem]]; - - title = [@"Quit " stringByAppendingString:appName]; - [appleMenu addItemWithTitle:title action:@selector(terminate:) keyEquivalent:@"q"]; - - - /* Put menu into the menubar */ - menuItem = [[NSMenuItem alloc] initWithTitle:@"" action:nil keyEquivalent:@""]; - [menuItem setSubmenu:appleMenu]; - [[NSApp mainMenu] addItem:menuItem]; - - /* Tell the application object that this is now the application menu */ - [NSApp setAppleMenu:appleMenu]; - - /* Finally give up our references to the objects */ - [appleMenu release]; - [menuItem release]; -} - -/* Create a window menu */ -static void setupWindowMenu(void) -{ - NSMenu *windowMenu; - NSMenuItem *windowMenuItem; - NSMenuItem *menuItem; - - windowMenu = [[NSMenu alloc] initWithTitle:@"Window"]; - - /* "Minimize" item */ - menuItem = [[NSMenuItem alloc] initWithTitle:@"Minimize" action:@selector(performMiniaturize:) keyEquivalent:@"m"]; - [windowMenu addItem:menuItem]; - [menuItem release]; - - /* Put menu into the menubar */ - windowMenuItem = [[NSMenuItem alloc] initWithTitle:@"Window" action:nil keyEquivalent:@""]; - [windowMenuItem setSubmenu:windowMenu]; - [[NSApp mainMenu] addItem:windowMenuItem]; - - /* Tell the application object that this is now the window menu */ - [NSApp setWindowsMenu:windowMenu]; - - /* Finally give up our references to the objects */ - [windowMenu release]; - [windowMenuItem release]; -} - -/* Replacement for NSApplicationMain */ -static void CustomApplicationMain (int argc, char **argv) -{ - NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; - SDLMain *sdlMain; - - /* Ensure the application object is initialised */ - [SDLApplication sharedApplication]; - -#ifdef SDL_USE_CPS - { - CPSProcessSerNum PSN; - /* Tell the dock about us */ - if (!CPSGetCurrentProcess(&PSN)) - if (!CPSEnableForegroundOperation(&PSN,0x03,0x3C,0x2C,0x1103)) - if (!CPSSetFrontProcess(&PSN)) - [SDLApplication sharedApplication]; - } -#endif /* SDL_USE_CPS */ - - /* Set up the menubar */ - [NSApp setMainMenu:[[NSMenu alloc] init]]; - setApplicationMenu(); - setupWindowMenu(); - - /* Create SDLMain and make it the app delegate */ - sdlMain = [[SDLMain alloc] init]; - [NSApp setDelegate:sdlMain]; - - /* Start the main event loop */ - [NSApp run]; - - [sdlMain release]; - [pool release]; -} - -#endif - - -/* - * Catch document open requests...this lets us notice files when the app - * was launched by double-clicking a document, or when a document was - * dragged/dropped on the app's icon. You need to have a - * CFBundleDocumentsType section in your Info.plist to get this message, - * apparently. - * - * Files are added to gArgv, so to the app, they'll look like command line - * arguments. Previously, apps launched from the finder had nothing but - * an argv[0]. - * - * This message may be received multiple times to open several docs on launch. - * - * This message is ignored once the app's mainline has been called. - */ -- (BOOL)application:(NSApplication *)theApplication openFile:(NSString *)filename -{ - const char *temparg; - size_t arglen; - char *arg; - char **newargv; - - if (!gFinderLaunch) /* MacOS is passing command line args. */ - return FALSE; - - if (gCalledAppMainline) /* app has started, ignore this document. */ - return FALSE; - - temparg = [filename UTF8String]; - arglen = SDL_strlen(temparg) + 1; - arg = (char *) SDL_malloc(arglen); - if (arg == NULL) - return FALSE; - - newargv = (char **) realloc(gArgv, sizeof (char *) * (gArgc + 2)); - if (newargv == NULL) - { - SDL_free(arg); - return FALSE; - } - gArgv = newargv; - - SDL_strlcpy(arg, temparg, arglen); - gArgv[gArgc++] = arg; - gArgv[gArgc] = NULL; - return TRUE; -} - - -/* Called when the internal event loop has just started running */ -- (void) applicationDidFinishLaunching: (NSNotification *) note -{ - int status; - - /* Set the working directory to the .app's parent directory */ - [self setupWorkingDirectory:gFinderLaunch]; - -#if SDL_USE_NIB_FILE - /* Set the main menu to contain the real app name instead of "SDL App" */ - [self fixMenu:[NSApp mainMenu] withAppName:getApplicationName()]; -#endif - - /* Hand off to main application code */ - gCalledAppMainline = TRUE; - status = SDL_main (gArgc, gArgv); - - /* We're done, thank you for playing */ - exit(status); -} -@end - - -@implementation NSString (ReplaceSubString) - -- (NSString *)stringByReplacingRange:(NSRange)aRange with:(NSString *)aString -{ - unsigned int bufferSize; - unsigned int selfLen = [self length]; - unsigned int aStringLen = [aString length]; - unichar *buffer; - NSRange localRange; - NSString *result; - - bufferSize = selfLen + aStringLen - aRange.length; - buffer = NSAllocateMemoryPages(bufferSize*sizeof(unichar)); - - /* Get first part into buffer */ - localRange.location = 0; - localRange.length = aRange.location; - [self getCharacters:buffer range:localRange]; - - /* Get middle part into buffer */ - localRange.location = 0; - localRange.length = aStringLen; - [aString getCharacters:(buffer+aRange.location) range:localRange]; - - /* Get last part into buffer */ - localRange.location = aRange.location + aRange.length; - localRange.length = selfLen - localRange.location; - [self getCharacters:(buffer+aRange.location+aStringLen) range:localRange]; - - /* Build output string */ - result = [NSString stringWithCharacters:buffer length:bufferSize]; - - NSDeallocateMemoryPages(buffer, bufferSize); - - return result; -} - -@end - -#ifdef main -#undef main -#endif - - -/* Main entry point to executable - should *not* be SDL_main! */ -int main (int argc, char **argv) -{ - /* Copy the arguments into a global variable */ - /* This is passed if we are launched by double-clicking */ - if ( argc >= 2 && strncmp (argv[1], "-psn", 4) == 0 ) { - gArgv = (char **) SDL_malloc(sizeof (char *) * 2); - gArgv[0] = argv[0]; - gArgv[1] = NULL; - gArgc = 1; - gFinderLaunch = YES; - } else { - int i; - gArgc = argc; - gArgv = (char **) SDL_malloc(sizeof (char *) * (argc+1)); - for (i = 0; i <= argc; i++) - gArgv[i] = argv[i]; - gFinderLaunch = NO; - } - -#if SDL_USE_NIB_FILE - [SDLApplication poseAsClass:[NSApplication class]]; - NSApplicationMain (argc, argv); -#else - CustomApplicationMain (argc, argv); -#endif - - return 0; -} - diff --git a/src/osxlaunch/client.m b/src/osxlaunch/client.m new file mode 120000 index 000000000..c224081fa --- /dev/null +++ b/src/osxlaunch/client.m @@ -0,0 +1 @@ +client.mm \ No newline at end of file diff --git a/src/osxlaunch/client.mm b/src/osxlaunch/client.mm new file mode 100644 index 000000000..6de919e2a --- /dev/null +++ b/src/osxlaunch/client.mm @@ -0,0 +1,373 @@ +/* SDLMain.m - main entry point for our Cocoa-ized SDL app + Initial Version: Darrell Walisser + Non-NIB-Code & other changes: Max Horn + + Feel free to customize this file to suit your needs +*/ + +#import +#import "client.h" +#import /* for MAXPATHLEN */ +#import + +/* For some reaon, Apple removed setAppleMenu from the headers in 10.4, + but the method still is there and works. To avoid warnings, we declare + it ourselves here. */ +@interface NSApplication(SDL_Missing_Methods) +- (void)setAppleMenu:(NSMenu *)menu; +@end + +/* Use this flag to determine whether we use SDLMain.nib or not */ +#define SDL_USE_NIB_FILE 0 + +/* Use this flag to determine whether we use CPS (docking) or not */ +#define SDL_USE_CPS 1 +#ifdef SDL_USE_CPS +/* Portions of CPS.h */ +typedef struct CPSProcessSerNum +{ + UInt32 lo; + UInt32 hi; +} CPSProcessSerNum; + +extern OSErr CPSGetCurrentProcess( CPSProcessSerNum *psn); +extern OSErr CPSEnableForegroundOperation( CPSProcessSerNum *psn, UInt32 _arg2, UInt32 _arg3, UInt32 _arg4, UInt32 _arg5); +extern OSErr CPSSetFrontProcess( CPSProcessSerNum *psn); + +#endif /* SDL_USE_CPS */ + +static int gArgc; +static char **gArgv; +static BOOL gFinderLaunch; +static BOOL gCalledAppMainline = FALSE; + +static NSString *getApplicationName(void) +{ + NSDictionary *dict; + NSString *appName = 0; + + /* Determine the application name */ + dict = (NSDictionary *)CFBundleGetInfoDictionary(CFBundleGetMainBundle()); + if (dict) + appName = [dict objectForKey: @"CFBundleName"]; + + if (![appName length]) + appName = [[NSProcessInfo processInfo] processName]; + + return appName; +} + +#if SDL_USE_NIB_FILE +/* A helper category for NSString */ +@interface NSString (ReplaceSubString) +- (NSString *)stringByReplacingRange:(NSRange)aRange with:(NSString *)aString; +@end +#endif + +@interface SDLApplication : NSApplication +@end + +@implementation SDLApplication +/* Invoked from the Quit menu item */ +- (void)terminate:(id)sender +{ + /* Post a SDL_QUIT event */ + SDL_Event event; + event.type = SDL_QUIT; + SDL_PushEvent(&event); +} +@end + +/* The main class of the application, the application's delegate */ +@implementation SDLMain + +/* Set the working directory to the .app's parent directory */ +- (void) setupWorkingDirectory:(BOOL)shouldChdir +{ + NSString *resourcePath = [[NSBundle mainBundle] resourcePath]; + [[NSFileManager defaultManager] changeCurrentDirectoryPath:resourcePath]; +} + +#if SDL_USE_NIB_FILE + +/* Fix menu to contain the real app name instead of "SDL App" */ +- (void)fixMenu:(NSMenu *)aMenu withAppName:(NSString *)appName +{ + NSRange aRange; + NSEnumerator *enumerator; + NSMenuItem *menuItem; + + aRange = [[aMenu title] rangeOfString:@"SDL App"]; + if (aRange.length != 0) + [aMenu setTitle: [[aMenu title] stringByReplacingRange:aRange with:appName]]; + + enumerator = [[aMenu itemArray] objectEnumerator]; + while ((menuItem = [enumerator nextObject])) + { + aRange = [[menuItem title] rangeOfString:@"SDL App"]; + if (aRange.length != 0) + [menuItem setTitle: [[menuItem title] stringByReplacingRange:aRange with:appName]]; + if ([menuItem hasSubmenu]) + [self fixMenu:[menuItem submenu] withAppName:appName]; + } + [ aMenu sizeToFit ]; +} + +#else + +static void setApplicationMenu(void) +{ + /* warning: this code is very odd */ + NSMenu *appleMenu; + NSMenuItem *menuItem; + NSString *title; + NSString *appName; + + appName = getApplicationName(); + appleMenu = [[NSMenu alloc] initWithTitle:@""]; + + /* Add menu items */ + title = [@"About " stringByAppendingString:appName]; + [appleMenu addItemWithTitle:title action:@selector(orderFrontStandardAboutPanel:) keyEquivalent:@""]; + + [appleMenu addItem:[NSMenuItem separatorItem]]; + + title = [@"Hide " stringByAppendingString:appName]; + [appleMenu addItemWithTitle:title action:@selector(hide:) keyEquivalent:@"h"]; + + menuItem = (NSMenuItem *)[appleMenu addItemWithTitle:@"Hide Others" action:@selector(hideOtherApplications:) keyEquivalent:@"h"]; + [menuItem setKeyEquivalentModifierMask:(NSAlternateKeyMask|NSCommandKeyMask)]; + + [appleMenu addItemWithTitle:@"Show All" action:@selector(unhideAllApplications:) keyEquivalent:@""]; + + [appleMenu addItem:[NSMenuItem separatorItem]]; + + title = [@"Quit " stringByAppendingString:appName]; + [appleMenu addItemWithTitle:title action:@selector(terminate:) keyEquivalent:@"q"]; + + + /* Put menu into the menubar */ + menuItem = [[NSMenuItem alloc] initWithTitle:@"" action:nil keyEquivalent:@""]; + [menuItem setSubmenu:appleMenu]; + [[NSApp mainMenu] addItem:menuItem]; + + /* Tell the application object that this is now the application menu */ + [NSApp setAppleMenu:appleMenu]; + + /* Finally give up our references to the objects */ + [appleMenu release]; + [menuItem release]; +} + +/* Create a window menu */ +static void setupWindowMenu(void) +{ + NSMenu *windowMenu; + NSMenuItem *windowMenuItem; + NSMenuItem *menuItem; + + windowMenu = [[NSMenu alloc] initWithTitle:@"Window"]; + + /* "Minimize" item */ + menuItem = [[NSMenuItem alloc] initWithTitle:@"Minimize" action:@selector(performMiniaturize:) keyEquivalent:@"m"]; + [windowMenu addItem:menuItem]; + [menuItem release]; + + /* Put menu into the menubar */ + windowMenuItem = [[NSMenuItem alloc] initWithTitle:@"Window" action:nil keyEquivalent:@""]; + [windowMenuItem setSubmenu:windowMenu]; + [[NSApp mainMenu] addItem:windowMenuItem]; + + /* Tell the application object that this is now the window menu */ + [NSApp setWindowsMenu:windowMenu]; + + /* Finally give up our references to the objects */ + [windowMenu release]; + [windowMenuItem release]; +} + +/* Replacement for NSApplicationMain */ +static void CustomApplicationMain (int argc, char **argv) +{ + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + SDLMain *sdlMain; + + /* Ensure the application object is initialised */ + [SDLApplication sharedApplication]; + +#ifdef SDL_USE_CPS + { + CPSProcessSerNum PSN; + /* Tell the dock about us */ + if (!CPSGetCurrentProcess(&PSN)) + if (!CPSEnableForegroundOperation(&PSN,0x03,0x3C,0x2C,0x1103)) + if (!CPSSetFrontProcess(&PSN)) + [SDLApplication sharedApplication]; + } +#endif /* SDL_USE_CPS */ + + /* Set up the menubar */ + [NSApp setMainMenu:[[NSMenu alloc] init]]; + setApplicationMenu(); + setupWindowMenu(); + + /* Create SDLMain and make it the app delegate */ + sdlMain = [[SDLMain alloc] init]; + [NSApp setDelegate:sdlMain]; + + /* Start the main event loop */ + [NSApp run]; + + [sdlMain release]; + [pool release]; +} + +#endif + + +/* + * Catch document open requests...this lets us notice files when the app + * was launched by double-clicking a document, or when a document was + * dragged/dropped on the app's icon. You need to have a + * CFBundleDocumentsType section in your Info.plist to get this message, + * apparently. + * + * Files are added to gArgv, so to the app, they'll look like command line + * arguments. Previously, apps launched from the finder had nothing but + * an argv[0]. + * + * This message may be received multiple times to open several docs on launch. + * + * This message is ignored once the app's mainline has been called. + */ +- (BOOL)application:(NSApplication *)theApplication openFile:(NSString *)filename +{ + const char *temparg; + size_t arglen; + char *arg; + char **newargv; + + if (!gFinderLaunch) /* MacOS is passing command line args. */ + return FALSE; + + if (gCalledAppMainline) /* app has started, ignore this document. */ + return FALSE; + + temparg = [filename UTF8String]; + arglen = SDL_strlen(temparg) + 1; + arg = (char *) SDL_malloc(arglen); + if (arg == NULL) + return FALSE; + + newargv = (char **) realloc(gArgv, sizeof (char *) * (gArgc + 2)); + if (newargv == NULL) + { + SDL_free(arg); + return FALSE; + } + gArgv = newargv; + + SDL_strlcpy(arg, temparg, arglen); + gArgv[gArgc++] = arg; + gArgv[gArgc] = NULL; + return TRUE; +} + + +/* Called when the internal event loop has just started running */ +- (void) applicationDidFinishLaunching: (NSNotification *) note +{ + int status; + + /* Set the working directory to the .app's parent directory */ + [self setupWorkingDirectory:gFinderLaunch]; + +#if SDL_USE_NIB_FILE + /* Set the main menu to contain the real app name instead of "SDL App" */ + [self fixMenu:[NSApp mainMenu] withAppName:getApplicationName()]; +#endif + + /* Hand off to main application code */ + gCalledAppMainline = TRUE; + status = SDL_main (gArgc, gArgv); + + /* We're done, thank you for playing */ + exit(status); +} +@end + + +@implementation NSString (ReplaceSubString) + +- (NSString *)stringByReplacingRange:(NSRange)aRange with:(NSString *)aString +{ + unsigned int bufferSize; + unsigned int selfLen = [self length]; + unsigned int aStringLen = [aString length]; + unichar *buffer; + NSRange localRange; + NSString *result; + + bufferSize = selfLen + aStringLen - aRange.length; + buffer = NSAllocateMemoryPages(bufferSize*sizeof(unichar)); + + /* Get first part into buffer */ + localRange.location = 0; + localRange.length = aRange.location; + [self getCharacters:buffer range:localRange]; + + /* Get middle part into buffer */ + localRange.location = 0; + localRange.length = aStringLen; + [aString getCharacters:(buffer+aRange.location) range:localRange]; + + /* Get last part into buffer */ + localRange.location = aRange.location + aRange.length; + localRange.length = selfLen - localRange.location; + [self getCharacters:(buffer+aRange.location+aStringLen) range:localRange]; + + /* Build output string */ + result = [NSString stringWithCharacters:buffer length:bufferSize]; + + NSDeallocateMemoryPages(buffer, bufferSize); + + return result; +} + +@end + +#ifdef main +#undef main +#endif + + +/* Main entry point to executable - should *not* be SDL_main! */ +int main (int argc, char **argv) +{ + /* Copy the arguments into a global variable */ + /* This is passed if we are launched by double-clicking */ + if ( argc >= 2 && strncmp (argv[1], "-psn", 4) == 0 ) { + gArgv = (char **) SDL_malloc(sizeof (char *) * 2); + gArgv[0] = argv[0]; + gArgv[1] = NULL; + gArgc = 1; + gFinderLaunch = YES; + } else { + int i; + gArgc = argc; + gArgv = (char **) SDL_malloc(sizeof (char *) * (argc+1)); + for (i = 0; i <= argc; i++) + gArgv[i] = argv[i]; + gFinderLaunch = NO; + } + +#if SDL_USE_NIB_FILE + [SDLApplication poseAsClass:[NSApplication class]]; + NSApplicationMain (argc, argv); +#else + CustomApplicationMain (argc, argv); +#endif + + return 0; +} + diff --git a/src/osxlaunch/server.m b/src/osxlaunch/server.m deleted file mode 100644 index 5ae32c6fa..000000000 --- a/src/osxlaunch/server.m +++ /dev/null @@ -1,112 +0,0 @@ -#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: 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; -} diff --git a/src/osxlaunch/server.m b/src/osxlaunch/server.m new file mode 120000 index 000000000..9ff19d9b5 --- /dev/null +++ b/src/osxlaunch/server.m @@ -0,0 +1 @@ +server.mm \ No newline at end of file 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; +}