Add Android build scripts

This commit is contained in:
Jupeyy 2021-08-24 12:18:20 +02:00
parent acb87171a9
commit b216b6744a
41 changed files with 1617 additions and 207 deletions

1
.gitignore vendored
View file

@ -38,6 +38,7 @@ testrunner\[1\]_include.cmake
# Ignore all the generated executables without extensions (for non-Windows
# systems).
DDNet
!DDNet/
DDNet-Server
DDNet-Server-Launcher
libsteam_api.a

View file

@ -54,6 +54,22 @@ else()
set(TARGET_BITS "64")
endif()
if(${CMAKE_SYSTEM_PROCESSOR} MATCHES "arm" OR ${CMAKE_SYSTEM_PROCESSOR} MATCHES "aarch64")
if(TARGET_BITS STREQUAL "32")
set(TARGET_CPU_ARCHITECTURE "arm")
else()
set(TARGET_CPU_ARCHITECTURE "arm64")
endif()
else()
if(TARGET_BITS STREQUAL "32")
set(TARGET_CPU_ARCHITECTURE "x86")
else()
set(TARGET_CPU_ARCHITECTURE "x86_64")
endif()
endif()
if(CMAKE_SYSTEM_NAME STREQUAL "Windows")
set(TARGET_OS "windows")
elseif(CMAKE_SYSTEM_NAME STREQUAL "Linux")
@ -62,6 +78,8 @@ elseif(CMAKE_SYSTEM_NAME STREQUAL "Darwin")
set(TARGET_OS "mac")
elseif(CMAKE_SYSTEM_NAME STREQUAL "Haiku")
set(TARGET_OS "haiku")
elseif(CMAKE_SYSTEM_NAME STREQUAL "Android")
set(TARGET_OS "android")
endif()
include(CheckCCompilerFlag)
@ -89,6 +107,8 @@ option(VIDEORECORDER "Enable video recording support via FFmpeg" OFF)
option(UPNP "Enable UPnP support" OFF)
option(ANTIBOT "Enable support for a dynamic anticheat library" OFF)
option(CLIENT "Compile client" ON)
option(SERVER "Compile server" ON)
option(TOOLS "Compile tools" ON)
option(DOWNLOAD_GTEST "Download and compile GTest" ${AUTO_DEPENDENCIES_DEFAULT})
option(STEAM "Build the Steam release version" OFF)
option(DISCORD "Enable Discord rich presence support" OFF)
@ -307,7 +327,11 @@ function(set_extra_dirs_lib VARIABLE NAME)
set(TYPE PATHS)
endif()
if(TARGET_BITS AND TARGET_OS)
set(DIR "ddnet-libs/${NAME}/${TARGET_OS}/lib${TARGET_BITS}")
if(TARGET_CPU_ARCHITECTURE STREQUAL "arm" OR TARGET_CPU_ARCHITECTURE STREQUAL "arm64")
set(DIR "ddnet-libs/${NAME}/${TARGET_OS}/lib${TARGET_CPU_ARCHITECTURE}")
else()
set(DIR "ddnet-libs/${NAME}/${TARGET_OS}/lib${TARGET_BITS}")
endif()
set("${TYPE}_${VARIABLE}_LIBDIR" "${DIR}" PARENT_SCOPE)
set("EXTRA_${VARIABLE}_LIBDIR" "${DIR}" PARENT_SCOPE)
endif()
@ -323,7 +347,12 @@ function(set_extra_dirs_include VARIABLE NAME LIBRARY)
endfunction()
if(CMAKE_CROSSCOMPILING)
set(CROSSCOMPILING_NO_CMAKE_SYSTEM_PATH NO_CMAKE_SYSTEM_PATH)
if(TARGET_OS STREQUAL "android")
# be more aggressive with android toolchain
set(CROSSCOMPILING_NO_CMAKE_SYSTEM_PATH NO_CMAKE_SYSTEM_PATH NO_DEFAULT_PATH NO_CMAKE_FIND_ROOT_PATH)
else()
set(CROSSCOMPILING_NO_CMAKE_SYSTEM_PATH NO_CMAKE_SYSTEM_PATH)
endif()
else()
set(CROSSCOMPILING_NO_CMAKE_SYSTEM_PATH)
endif()
@ -346,6 +375,9 @@ if(NOT CMAKE_CROSSCOMPILING)
# quietly.
find_package(PkgConfig)
endif()
if(TARGET_OS STREQUAL "android")
find_package(Android)
endif()
find_package(ZLIB)
find_package(Crypto)
find_package(Curl)
@ -356,7 +388,9 @@ find_package(Freetype)
if(DOWNLOAD_GTEST)
find_package(Git)
endif()
find_package(GLEW)
if(NOT(TARGET_OS STREQUAL "android"))
find_package(GLEW)
endif()
find_package(GTest)
if(UPNP)
find_package(Miniupnpc)
@ -517,6 +551,9 @@ endif()
if(CLIENT AND NOT(SDL2_FOUND))
message(SEND_ERROR "You must install SDL2 to compile the DDNet client")
endif()
if(TARGET_OS STREQUAL "android" AND CLIENT AND NOT(CRYPTO_FOUND))
message(SEND_ERROR "You must install OpenSSL to compile the DDNet client")
endif()
if(NOT(GTEST_FOUND))
if(DOWNLOAD_GTEST)
if(GIT_FOUND)
@ -551,6 +588,13 @@ elseif(TARGET_OS STREQUAL "haiku")
set(PLATFORM_LIBS GL network)
set(PLATFORM_CLIENT_LIBS ${OPENGL_gl_LIBRARY})
set(PLATFORM_CLIENT_INCLUDE_DIRS ${OPENGL_INCLUDE_DIR})
elseif(TARGET_OS STREQUAL "android")
set(PLATFORM_CLIENT
src/android/android_main.cpp
)
set(PLATFORM_LIBS ${TW_ANDROID_LIBS})
set(PLATFORM_CLIENT_LIBS ${PLATFORM_LIBS})
set(PLATFORM_CLIENT_INCLUDE_DIRS)
else()
find_package(Notify)
find_package(OpenGL)
@ -1923,14 +1967,26 @@ if(CLIENT)
# Target
set(TARGET_CLIENT ${CLIENT_EXECUTABLE})
add_executable(${TARGET_CLIENT} WIN32
${CLIENT_SRC}
${CLIENT_ICON}
${CLIENT_MANIFEST}
${DEPS_CLIENT}
$<TARGET_OBJECTS:engine-shared>
$<TARGET_OBJECTS:game-shared>
)
if(TARGET_OS STREQUAL "android")
add_library(${TARGET_CLIENT} SHARED
${CLIENT_SRC}
${CLIENT_ICON}
${CLIENT_MANIFEST}
${DEPS_CLIENT}
$<TARGET_OBJECTS:engine-shared>
$<TARGET_OBJECTS:game-shared>
)
else()
add_executable(${TARGET_CLIENT} WIN32
${CLIENT_SRC}
${CLIENT_ICON}
${CLIENT_MANIFEST}
${DEPS_CLIENT}
$<TARGET_OBJECTS:engine-shared>
$<TARGET_OBJECTS:game-shared>
)
endif()
target_link_libraries(${TARGET_CLIENT} ${LIBS_CLIENT})
if(MSVC)
@ -1987,208 +2043,212 @@ endif()
# SERVER
########################################################################
# Sources
set_src(ANTIBOT_SRC GLOB src/antibot
antibot_data.h
antibot_interface.h
antibot_null.cpp
)
if(SERVER)
# Sources
set_src(ANTIBOT_SRC GLOB src/antibot
antibot_data.h
antibot_interface.h
antibot_null.cpp
)
set_src(ENGINE_SERVER GLOB_RECURSE src/engine/server
antibot.cpp
antibot.h
authmanager.cpp
authmanager.h
databases/connection.cpp
databases/connection.h
databases/connection_pool.cpp
databases/connection_pool.h
databases/mysql.cpp
databases/sqlite.cpp
name_ban.cpp
name_ban.h
register.cpp
register.h
server.cpp
server.h
sql_string_helpers.cpp
sql_string_helpers.h
upnp.cpp
upnp.h
)
set_src(GAME_SERVER GLOB_RECURSE src/game/server
alloc.h
ddracechat.cpp
ddracecommands.cpp
entities/character.cpp
entities/character.h
entities/door.cpp
entities/door.h
entities/dragger.cpp
entities/dragger.h
entities/flag.cpp
entities/flag.h
entities/gun.cpp
entities/gun.h
entities/laser.cpp
entities/laser.h
entities/light.cpp
entities/light.h
entities/pickup.cpp
entities/pickup.h
entities/plasma.cpp
entities/plasma.h
entities/projectile.cpp
entities/projectile.h
entity.cpp
entity.h
eventhandler.cpp
eventhandler.h
gamecontext.cpp
gamecontext.h
gamecontroller.cpp
gamecontroller.h
gamemodes/DDRace.cpp
gamemodes/DDRace.h
gameworld.cpp
gameworld.h
player.cpp
player.h
save.cpp
save.h
score.cpp
score.h
teams.cpp
teams.h
teehistorian.cpp
teehistorian.h
teeinfo.cpp
teeinfo.h
)
set(GAME_GENERATED_SERVER
"src/game/generated/server_data.cpp"
"src/game/generated/server_data.h"
"src/game/generated/wordlist.h"
)
set(SERVER_SRC ${ENGINE_SERVER} ${GAME_SERVER} ${GAME_GENERATED_SERVER})
if(TARGET_OS STREQUAL "windows")
set(SERVER_ICON "other/icons/DDNet-Server.rc")
else()
set(SERVER_ICON)
endif()
set_src(ENGINE_SERVER GLOB_RECURSE src/engine/server
antibot.cpp
antibot.h
authmanager.cpp
authmanager.h
databases/connection.cpp
databases/connection.h
databases/connection_pool.cpp
databases/connection_pool.h
databases/mysql.cpp
databases/sqlite.cpp
name_ban.cpp
name_ban.h
register.cpp
register.h
server.cpp
server.h
sql_string_helpers.cpp
sql_string_helpers.h
upnp.cpp
upnp.h
)
set_src(GAME_SERVER GLOB_RECURSE src/game/server
alloc.h
ddracechat.cpp
ddracecommands.cpp
entities/character.cpp
entities/character.h
entities/door.cpp
entities/door.h
entities/dragger.cpp
entities/dragger.h
entities/flag.cpp
entities/flag.h
entities/gun.cpp
entities/gun.h
entities/laser.cpp
entities/laser.h
entities/light.cpp
entities/light.h
entities/pickup.cpp
entities/pickup.h
entities/plasma.cpp
entities/plasma.h
entities/projectile.cpp
entities/projectile.h
entity.cpp
entity.h
eventhandler.cpp
eventhandler.h
gamecontext.cpp
gamecontext.h
gamecontroller.cpp
gamecontroller.h
gamemodes/DDRace.cpp
gamemodes/DDRace.h
gameworld.cpp
gameworld.h
player.cpp
player.h
save.cpp
save.h
score.cpp
score.h
teams.cpp
teams.h
teehistorian.cpp
teehistorian.h
teeinfo.cpp
teeinfo.h
)
set(GAME_GENERATED_SERVER
"src/game/generated/server_data.cpp"
"src/game/generated/server_data.h"
"src/game/generated/wordlist.h"
)
set(SERVER_SRC ${ENGINE_SERVER} ${GAME_SERVER} ${GAME_GENERATED_SERVER})
if(TARGET_OS STREQUAL "windows")
set(SERVER_ICON "other/icons/DDNet-Server.rc")
else()
set(SERVER_ICON)
endif()
# Antibot
if(ANTIBOT)
set(TARGET_ANTIBOT antibot)
add_library(${TARGET_ANTIBOT} SHARED ${ANTIBOT_SRC})
list(APPEND TARGETS_OWN ${TARGET_ANTIBOT})
endif()
# Antibot
if(ANTIBOT)
set(TARGET_ANTIBOT antibot)
add_library(${TARGET_ANTIBOT} SHARED ${ANTIBOT_SRC})
list(APPEND TARGETS_OWN ${TARGET_ANTIBOT})
endif()
# Libraries
set(LIBS_SERVER
${LIBS}
${MYSQL_LIBRARIES}
${TARGET_ANTIBOT}
${MINIUPNPC_LIBRARIES}
# Add pthreads (on non-Windows) at the end, so that other libraries can depend
# on it.
${CMAKE_THREAD_LIBS_INIT}
)
# Libraries
set(LIBS_SERVER
${LIBS}
${MYSQL_LIBRARIES}
${TARGET_ANTIBOT}
${MINIUPNPC_LIBRARIES}
# Add pthreads (on non-Windows) at the end, so that other libraries can depend
# on it.
${CMAKE_THREAD_LIBS_INIT}
)
# Target
set(TARGET_SERVER ${SERVER_EXECUTABLE})
add_executable(${TARGET_SERVER}
${DEPS}
${SERVER_SRC}
${SERVER_ICON}
$<TARGET_OBJECTS:engine-shared>
$<TARGET_OBJECTS:game-shared>
)
target_link_libraries(${TARGET_SERVER} ${LIBS_SERVER})
list(APPEND TARGETS_OWN ${TARGET_SERVER})
list(APPEND TARGETS_LINK ${TARGET_SERVER})
# Target
set(TARGET_SERVER ${SERVER_EXECUTABLE})
add_executable(${TARGET_SERVER}
${DEPS}
${SERVER_SRC}
${SERVER_ICON}
$<TARGET_OBJECTS:engine-shared>
$<TARGET_OBJECTS:game-shared>
)
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/macoslaunch/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})
if(TARGET_OS AND TARGET_OS STREQUAL "mac")
set(SERVER_LAUNCHER_SRC src/macoslaunch/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()
endif()
########################################################################
# VARIOUS TARGETS
########################################################################
set_src(MASTERSRV_SRC GLOB src/mastersrv mastersrv.cpp mastersrv.h)
set_src(TWPING_SRC GLOB src/twping twping.cpp)
if(TOOLS)
set_src(MASTERSRV_SRC GLOB src/mastersrv mastersrv.cpp mastersrv.h)
set_src(TWPING_SRC GLOB src/twping twping.cpp)
set(TARGET_MASTERSRV mastersrv)
set(TARGET_TWPING twping)
set(TARGET_MASTERSRV mastersrv)
set(TARGET_TWPING twping)
add_executable(${TARGET_MASTERSRV} EXCLUDE_FROM_ALL ${MASTERSRV_SRC} $<TARGET_OBJECTS:engine-shared> ${DEPS})
add_executable(${TARGET_TWPING} EXCLUDE_FROM_ALL ${TWPING_SRC} $<TARGET_OBJECTS:engine-shared> ${DEPS})
add_executable(${TARGET_MASTERSRV} EXCLUDE_FROM_ALL ${MASTERSRV_SRC} $<TARGET_OBJECTS:engine-shared> ${DEPS})
add_executable(${TARGET_TWPING} EXCLUDE_FROM_ALL ${TWPING_SRC} $<TARGET_OBJECTS:engine-shared> ${DEPS})
target_link_libraries(${TARGET_MASTERSRV} ${LIBS})
target_link_libraries(${TARGET_TWPING} ${LIBS})
target_link_libraries(${TARGET_MASTERSRV} ${LIBS})
target_link_libraries(${TARGET_TWPING} ${LIBS})
list(APPEND TARGETS_OWN ${TARGET_MASTERSRV} ${TARGET_TWPING})
list(APPEND TARGETS_LINK ${TARGET_MASTERSRV} ${TARGET_TWPING})
list(APPEND TARGETS_OWN ${TARGET_MASTERSRV} ${TARGET_TWPING})
list(APPEND TARGETS_LINK ${TARGET_MASTERSRV} ${TARGET_TWPING})
set(TARGETS_TOOLS)
set_src(TOOLS GLOB src/tools
config_common.h
config_retrieve.cpp
config_store.cpp
crapnet.cpp
dilate.cpp
dummy_map.cpp
fake_server.cpp
map_convert_07.cpp
map_diff.cpp
map_extract.cpp
map_optimize.cpp
map_replace_image.cpp
map_resave.cpp
packetgen.cpp
unicode_confusables.cpp
uuid.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 "^(dilate|map_convert_07|map_optimize|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})
set(TARGETS_TOOLS)
set_src(TOOLS GLOB src/tools
config_common.h
config_retrieve.cpp
config_store.cpp
crapnet.cpp
dilate.cpp
dummy_map.cpp
fake_server.cpp
map_convert_07.cpp
map_diff.cpp
map_extract.cpp
map_optimize.cpp
map_replace_image.cpp
map_resave.cpp
packetgen.cpp
unicode_confusables.cpp
uuid.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 "^(dilate|map_convert_07|map_optimize|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()
if(TOOL MATCHES "^config_")
list(APPEND EXTRA_TOOL_SRC "src/tools/config_common.h")
endif()
set(EXCLUDE_FROM_ALL)
if(DEV)
set(EXCLUDE_FROM_ALL EXCLUDE_FROM_ALL)
endif()
add_executable(${TOOL} ${EXCLUDE_FROM_ALL}
${TOOL_DEPS}
src/tools/${TOOL}.cpp
${EXTRA_TOOL_SRC}
$<TARGET_OBJECTS:engine-shared>
)
target_include_directories(${TOOL} PRIVATE ${TOOL_INCLUDE_DIRS})
target_link_libraries(${TOOL} ${TOOL_LIBS})
list(APPEND TARGETS_TOOLS ${TOOL})
endif()
if(TOOL MATCHES "^config_")
list(APPEND EXTRA_TOOL_SRC "src/tools/config_common.h")
endif()
set(EXCLUDE_FROM_ALL)
if(DEV)
set(EXCLUDE_FROM_ALL EXCLUDE_FROM_ALL)
endif()
add_executable(${TOOL} ${EXCLUDE_FROM_ALL}
${TOOL_DEPS}
src/tools/${TOOL}.cpp
${EXTRA_TOOL_SRC}
$<TARGET_OBJECTS:engine-shared>
)
target_include_directories(${TOOL} PRIVATE ${TOOL_INCLUDE_DIRS})
target_link_libraries(${TOOL} ${TOOL_LIBS})
list(APPEND TARGETS_TOOLS ${TOOL})
endif()
endforeach()
endforeach()
list(APPEND TARGETS_OWN ${TARGETS_TOOLS})
list(APPEND TARGETS_LINK ${TARGETS_TOOLS})
list(APPEND TARGETS_OWN ${TARGETS_TOOLS})
list(APPEND TARGETS_LINK ${TARGETS_TOOLS})
add_custom_target(tools DEPENDS ${TARGETS_TOOLS})
add_custom_target(tools DEPENDS ${TARGETS_TOOLS})
endif()
add_custom_target(everything DEPENDS ${TARGETS_OWN})
########################################################################
@ -2408,15 +2468,23 @@ endforeach()
set(CMAKE_INSTALL_DEFAULT_COMPONENT_NAME ${PROJECT_NAME})
if(TOOLS)
set(TARGET_TOOLS
config_retrieve
config_store
dilate
map_convert_07
map_diff
map_extract
)
else()
set(TARGET_TOOLS)
endif()
set(CPACK_TARGETS
${TARGET_CLIENT}
${TARGET_SERVER}
config_retrieve
config_store
dilate
map_convert_07
map_diff
map_extract
${TARGET_TOOLS}
)
if(STEAMAPI_KIND STREQUAL SHARED)
list(APPEND CPACK_TARGETS ${TARGET_STEAMAPI})

30
cmake/FindAndroid.cmake Normal file
View file

@ -0,0 +1,30 @@
# the android toolchain sets the paths right
FIND_LIBRARY(ANDROID_LIBRARY_EGL
EGL
)
FIND_LIBRARY(ANDROID_LIBRARY_GLES1
GLESv1_CM
)
FIND_LIBRARY(ANDROID_LIBRARY_GLES2
GLESv2
)
FIND_LIBRARY(ANDROID_LIBRARY_GLES3
GLESv3
)
FIND_LIBRARY(ANDROID_LIBRARY_LOG
log
)
FIND_LIBRARY(ANDROID_LIBRARY_ANDROID
android
)
FIND_LIBRARY(ANDROID_LIBRARY_OPENSLES
OpenSLES
)
set(TW_ANDROID_LIBS ${ANDROID_LIBRARY_EGL} ${ANDROID_LIBRARY_GLES1} ${ANDROID_LIBRARY_GLES2} ${ANDROID_LIBRARY_GLES3} ${ANDROID_LIBRARY_LOG} ${ANDROID_LIBRARY_ANDROID} ${ANDROID_LIBRARY_OPENSLES})

View file

@ -8,6 +8,39 @@ if(NOT PREFER_BUNDLED_LIBS)
endif()
endif()
if(PREFER_BUNDLED_LIBS AND TARGET_OS STREQUAL "android")
set_extra_dirs_lib(CRYPTO openssl)
find_library(CRYPTO_LIBRARY1
NAMES crypto
HINTS ${HINTS_CRYPTO_LIBDIR} ${PC_CRYPTO_LIBDIR} ${PC_CRYPTO_LIBRARY_DIRS}
PATHS ${PATHS_CRYPTO_LIBDIR}
${CROSSCOMPILING_NO_CMAKE_SYSTEM_PATH}
)
find_library(CRYPTO_LIBRARY2
NAMES ssl
HINTS ${HINTS_CRYPTO_LIBDIR} ${PC_CRYPTO_LIBDIR} ${PC_CRYPTO_LIBRARY_DIRS}
PATHS ${PATHS_CRYPTO_LIBDIR}
${CROSSCOMPILING_NO_CMAKE_SYSTEM_PATH}
)
set(CRYPTO_LIBRARY ${CRYPTO_LIBRARY1} ${CRYPTO_LIBRARY2})
set(CMAKE_FIND_FRAMEWORK FIRST)
set_extra_dirs_include(CRYPTO openssl "${CRYPTO_LIBRARY}")
find_path(CRYPTO_INCLUDEDIR1 openssl/opensslconf.h
PATH_SUFFIXES CRYPTO
HINTS ${HINTS_CRYPTO_INCLUDEDIR} ${PC_CRYPTO_INCLUDEDIR} ${PC_CRYPTO_INCLUDE_DIRS}
PATHS ${PATHS_CRYPTO_INCLUDEDIR}
${CROSSCOMPILING_NO_CMAKE_SYSTEM_PATH}
)
find_path(CRYPTO_INCLUDEDIR2 openssl/configuration.h
PATH_SUFFIXES CRYPTO
HINTS ${HINTS_CRYPTO_INCLUDEDIR} ${PC_CRYPTO_INCLUDEDIR} ${PC_CRYPTO_INCLUDE_DIRS}
PATHS ${PATHS_CRYPTO_INCLUDEDIR}
${CROSSCOMPILING_NO_CMAKE_SYSTEM_PATH}
)
set(CRYPTO_INCLUDEDIR ${CRYPTO_INCLUDEDIR1} ${CRYPTO_INCLUDEDIR2})
endif()
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(Crypto DEFAULT_MSG CRYPTO_LIBRARY CRYPTO_INCLUDEDIR)

View file

@ -18,6 +18,7 @@ find_path(SDL2_INCLUDEDIR SDL_assert.h
PATH_SUFFIXES SDL2
HINTS ${HINTS_SDL2_INCLUDEDIR} ${PC_SDL2_INCLUDEDIR} ${PC_SDL2_INCLUDE_DIRS}
PATHS ${PATHS_SDL2_INCLUDEDIR}
${CROSSCOMPILING_NO_CMAKE_SYSTEM_PATH}
)
include(FindPackageHandleStandardArgs)

53
scripts/android/README.md Normal file
View file

@ -0,0 +1,53 @@
Requirements for building:
==========================
- Android NDK (tested with NDK 23), must be in the same location in which Android studio would unpack it (~/Android/Sdk/ndk/)
atleast version 23
- Android SDK build tools
version 30.0.3
- ddnet-libs with Android libs
- Java -- JDK 11+
- 7zip (for ddnet-libs building)
- ninja
- curl runtime
How to build:
=============
- run a terminal inside the source directory:
`scripts/android/cmake_android.sh <x86/x86_64/arm/arm64/all> <Game name> <Debug/Release>`
where the first parameter is the arch (all for all arches), the second is the apk name, which must be equal to the library name (if you want to rename the APK do it after the build)
and the third parameter which simply defines the build type
- if you build with a signing key for the APK
Generate one with
`keytool -genkey -v -keystore my-release-key.jks -keyalg RSA -keysize 2048 -validity 10000 -alias my-alias`
export environment variables for the script
```
export TW_KEY_NAME=<key name>
export TW_KEY_PW=<key password>
export TW_KEY_ALIAS=<key alias>
```
so for example:
```
keytool -genkey -v -keystore Teeworlds.jks -keyalg RSA -keysize 2048 -validity 10000 -alias Teeworlds-Key
(it will prompt an input:)
Input keystore-password: mypassword
export TW_KEY_NAME=Teeworlds.jks
export TW_KEY_PW=mypassword
export TW_KEY_ALIAS=Teeworlds-Key
scripts/android/cmake_android.sh all DDNet Release
```
You can also specify the build version code and build version string before running the build script, e.g.:
```
export TW_VERSION_CODE=20210819
export TW_VERSION_NAME="1.0"
```
How to build the ddnet-libs for Android:
========================================
- There is a script to automatically download and build all repositories, this requires an active internet connection:
`scripts/android/gen_android_libs.sh <directory to build in>`
Warning!: DO NOT CHOOSE A DIRECTORY INSIDE THE SOURCE TREE
After the script finished executing it should have created a ddnet-libs directory which created all libs in the right directory format and can be merged with ddnet-libs in the source directory

233
scripts/android/cmake_android.sh Executable file
View file

@ -0,0 +1,233 @@
#!/bin/bash
export ANDROID_HOME=~/Android/Sdk
export MAKEFLAGS=-j32
ANDROID_NDK_VERSION="$(cd "$ANDROID_HOME/ndk" && find . -maxdepth 1 | sort -n | tail -1)"
ANDROID_NDK_VERSION="${ANDROID_NDK_VERSION:2}"
export ANDROID_NDK_VERSION
ANDROID_NDK="$ANDROID_HOME/ndk/$ANDROID_NDK_VERSION"
_DEFAULT_ANDROID_BUILD=x86
_DEFAULT_GAME_NAME=DDNet
_DEFAULT_BUILD_TYPE=Debug
_ANDROID_API_LEVEL=android-24
_ANDROID_SUB_BUILD_DIR=build_arch
_SHOW_USAGE_INFO=0
if [ -z ${1+x} ]; then
printf "\e[31m%s\e[30m\n" "Did not pass android build type, using default: ${_DEFAULT_ANDROID_BUILD}"
_SHOW_USAGE_INFO=1
else
_DEFAULT_ANDROID_BUILD=$1
fi
if [ -z ${2+x} ]; then
printf "\e[31m%s\e[30m\n" "Did not pass game name, using default: ${_DEFAULT_GAME_NAME}"
_SHOW_USAGE_INFO=1
else
_DEFAULT_GAME_NAME=$2
fi
if [ -z ${3+x} ]; then
printf "\e[31m%s\e[30m\n" "Did not pass build type, using default: ${_DEFAULT_BUILD_TYPE}"
_SHOW_USAGE_INFO=1
else
_DEFAULT_BUILD_TYPE=$3
fi
_ANDROID_JAR_KEY_NAME=~/.android/debug.keystore
_ANDROID_JAR_KEY_PW=android
_ANDROID_JAR_KEY_ALIAS=androiddebugkey
if [ -z ${TW_KEY_NAME+x} ]; then
printf "\e[31m%s\e[30m\n" "Did not pass a key for the jar signer, using default: ${_ANDROID_JAR_KEY_NAME}"
else
_ANDROID_JAR_KEY_NAME=$TW_KEY_NAME
fi
if [ -z ${TW_KEY_PW+x} ]; then
printf "\e[31m%s\e[30m\n" "Did not pass a key pw for the jar signer, using default: ${_ANDROID_JAR_KEY_PW}"
else
_ANDROID_JAR_KEY_PW=$TW_KEY_PW
fi
if [ -z ${TW_KEY_ALIAS+x} ]; then
printf "\e[31m%s\e[30m\n" "Did not pass a key alias for the jar signer, using default: ${_ANDROID_JAR_KEY_ALIAS}"
else
_ANDROID_JAR_KEY_ALIAS=$TW_KEY_ALIAS
fi
export TW_KEY_NAME="${_ANDROID_JAR_KEY_NAME}"
export TW_KEY_PW=$_ANDROID_JAR_KEY_PW
export TW_KEY_ALIAS=$_ANDROID_JAR_KEY_ALIAS
_ANDROID_VERSION_CODE=1
if [ -z ${TW_VERSION_CODE+x} ]; then
printf "\e[31m%s\e[30m\n" "Did not pass a version code, using default: ${_ANDROID_VERSION_CODE}"
else
_ANDROID_VERSION_CODE=$TW_VERSION_CODE
fi
export TW_VERSION_CODE=$_ANDROID_VERSION_CODE
_ANDROID_VERSION_NAME="1.0"
if [ -z ${TW_VERSION_NAME+x} ]; then
printf "\e[31m%s\e[30m\n" "Did not pass a version name, using default: ${_ANDROID_VERSION_NAME}"
else
_ANDROID_VERSION_NAME=$TW_VERSION_NAME
fi
export TW_VERSION_NAME=$_ANDROID_VERSION_NAME
printf "\e[31m%s\e[1m\n" "Building with setting, for arch: ${_DEFAULT_ANDROID_BUILD}, with build type: ${_DEFAULT_BUILD_TYPE}, with name: ${_DEFAULT_GAME_NAME}"
if [ $_SHOW_USAGE_INFO == 1 ]; then
printf "\e[31m%s\e[1m\n" "Usage: ./cmake_android.sh <x86/x86_64/arm/arm64/all> <Game name> <Debug/Release>"
fi
printf "\e[33mBuilding cmake\e[0m\n"
function build_for_type() {
cmake \
-H. \
-G "Ninja" \
-DPREFER_BUNDLED_LIBS=ON \
-DCMAKE_BUILD_TYPE="${_DEFAULT_BUILD_TYPE}" \
-DANDROID_NATIVE_API_LEVEL="$_ANDROID_API_LEVEL" \
-DCMAKE_TOOLCHAIN_FILE="$ANDROID_NDK/build/cmake/android.toolchain.cmake" \
-DANDROID_NDK="$ANDROID_NDK" \
-DANDROID_ABI="${2}" \
-DANDROID_ARM_NEON=TRUE \
-Bbuild_android/"$_ANDROID_SUB_BUILD_DIR/$1" \
-DSERVER=OFF \
-DTOOLS=OFF \
-DDEV=TRUE \
-DCMAKE_CROSSCOMPILING=ON \
-DPREFER_BUNDLED_LIBS=ON
(
cd "build_android/$_ANDROID_SUB_BUILD_DIR/$1" || exit 1
cmake --build . --target DDNet
)
}
mkdir build_android
if [[ "${_DEFAULT_ANDROID_BUILD}" == "arm" || "${_DEFAULT_ANDROID_BUILD}" == "all" ]]; then
build_for_type arm armeabi-v7a arm eabi &
fi
if [[ "${_DEFAULT_ANDROID_BUILD}" == "arm64" || "${_DEFAULT_ANDROID_BUILD}" == "all" ]]; then
build_for_type arm64 arm64-v8a aarch64 &
fi
if [[ "${_DEFAULT_ANDROID_BUILD}" == "x86" || "${_DEFAULT_ANDROID_BUILD}" == "all" ]]; then
build_for_type x86 x86 i686 &
fi
if [[ "${_DEFAULT_ANDROID_BUILD}" == "x86_64" || "${_DEFAULT_ANDROID_BUILD}" == "x64" || "${_DEFAULT_ANDROID_BUILD}" == "all" ]]; then
build_for_type x86_64 x86_64 x86_64 &
fi
wait
printf "\e[36mPreparing gradle build\n"
cd build_android || exit 1
mkdir -p src/main
mkdir -p src/main/res/mipmap
function copy_dummy_files() {
rm ./"$2"
cp ../"$1" "$2"
}
function copy_dummy_files_rec() {
rm -R ./"$2"/"$1"
cp -R ../"$1" "$2"
}
copy_dummy_files scripts/android/files/build.sh build.sh
copy_dummy_files scripts/android/files/gradle-wrapper.jar gradle-wrapper.jar
copy_dummy_files scripts/android/files/build.gradle build.gradle
copy_dummy_files scripts/android/files/gradle-wrapper.properties gradle-wrapper.properties
copy_dummy_files scripts/android/files/gradle.properties gradle.properties
copy_dummy_files scripts/android/files/local.properties local.properties
copy_dummy_files scripts/android/files/proguard-rules.pro proguard-rules.pro
copy_dummy_files scripts/android/files/settings.gradle settings.gradle
copy_dummy_files scripts/android/files/AndroidManifest.xml src/main/AndroidManifest.xml
copy_dummy_files_rec scripts/android/files/res src/main
copy_dummy_files other/icons/DDNet_512x512x32.png src/main/res/mipmap/ic_launcher.png
copy_dummy_files other/icons/DDNet_512x512x32.png src/main/res/mipmap/ic_launcher_round.png
function copy_libs() {
mkdir -p "lib/$2"
cp "$_ANDROID_SUB_BUILD_DIR/$1/libDDNet.so" "lib/$2"
cp "$_ANDROID_SUB_BUILD_DIR/$1/libs/libSDL2.so" "lib/$2"
cp "$_ANDROID_SUB_BUILD_DIR/$1/libs/libhidapi.so" "lib/$2"
}
if [[ "${_DEFAULT_ANDROID_BUILD}" == "arm" || "${_DEFAULT_ANDROID_BUILD}" == "all" ]]; then
copy_libs arm armeabi-v7a arm eabi
fi
if [[ "${_DEFAULT_ANDROID_BUILD}" == "arm64" || "${_DEFAULT_ANDROID_BUILD}" == "all" ]]; then
copy_libs arm64 arm64-v8a aarch64
fi
if [[ "${_DEFAULT_ANDROID_BUILD}" == "x86" || "${_DEFAULT_ANDROID_BUILD}" == "all" ]]; then
copy_libs x86 x86 i686
fi
if [[ "${_DEFAULT_ANDROID_BUILD}" == "x86_64" || "${_DEFAULT_ANDROID_BUILD}" == "x64" || "${_DEFAULT_ANDROID_BUILD}" == "all" ]]; then
copy_libs x86_64 x86_64 x86_64
fi
_DEFAULT_ANDROID_BUILD_DUMMY=$_DEFAULT_ANDROID_BUILD
if [[ "${_DEFAULT_ANDROID_BUILD}" == "all" ]]; then
_DEFAULT_ANDROID_BUILD_DUMMY=arm
fi
mkdir -p assets/asset_integrity_files
cp -R "$_ANDROID_SUB_BUILD_DIR/$_DEFAULT_ANDROID_BUILD_DUMMY/data" ./assets/asset_integrity_files
curl --remote-name --time-cond cacert.pem https://curl.se/ca/cacert.pem
cp ./cacert.pem ./assets/asset_integrity_files/data/cacert.pem
# create integrity file for extracting assets
(
cd assets/asset_integrity_files || exit 1
tmpfile="$(mktemp /tmp/hash_strings.XXX)"
find data -iname "*" -type f -print0 | while IFS= read -r -d $'\0' file; do
sha_hash=$(sha256sum "$file" | cut -d' ' -f 1)
echo "$file $sha_hash" >> "$tmpfile"
done
full_hash="$(sha256sum "$tmpfile" | cut -d' ' -f 1)"
rm "integrity.txt"
{
echo "$full_hash"
cat "$tmpfile"
} > "integrity.txt"
)
printf "\e[0m"
echo "Building..."
rm -R src/main/java/tw
mkdir -p src/main/java/tw/DDNet
cp ../scripts/android/files/java/tw/DDNet/NativeMain.java src/main/java/tw/DDNet/NativeMain.java
rm -R src/main/java/org
cp -R ../scripts/android/files/java/org src/main/java/
cp -R ../ddnet-libs/sdl/java/org src/main/java/
# shellcheck disable=SC1091
source ./build.sh "$ANDROID_HOME" "$_DEFAULT_GAME_NAME" "$_DEFAULT_BUILD_TYPE"
cd ..

View file

@ -0,0 +1,41 @@
#!/bin/bash
ANDROID_HOME=~/Android/Sdk
ANDROID_NDK="$(find "$ANDROID_HOME/ndk" -maxdepth 1 | sort -n | tail -1)"
echo "$ANDROID_NDK"
export MAKEFLAGS=-j32
function compile_source() {
cmake \
-H. \
-G "Unix Makefiles" \
-DCMAKE_BUILD_TYPE=Release \
-DANDROID_NATIVE_API_LEVEL="android-$1" \
-DCMAKE_TOOLCHAIN_FILE="$ANDROID_NDK/build/cmake/android.toolchain.cmake" \
-DANDROID_ABI="${3}" \
-DANDROID_ARM_NEON=TRUE \
-B"$2" \
-DBUILD_SHARED_LIBS=OFF \
-DHIDAPI_SKIP_LIBUSB=TRUE \
-DCMAKE_USE_OPENSSL=ON \
-DHIDAPI=OFF \
-DOP_DISABLE_HTTP=ON \
-DOP_DISABLE_EXAMPLES=ON \
-DOP_DISABLE_DOCS=ON \
-DOPENSSL_ROOT_DIR="$PWD"/../openssl/"$2" \
-DOPENSSL_CRYPTO_LIBRARY="$PWD"/../openssl/"$2"/libcrypto.a \
-DOPENSSL_SSL_LIBRARY="$PWD"/../openssl/"$2"/libssl.a \
-DOPENSSL_INCLUDE_DIR="${PWD}/../openssl/include;${PWD}/../openssl/${2}/include"
(
cd "$2" || exit 1
cmake --build .
)
}
compile_source "$1" build_android_arm armeabi-v7a &
compile_source "$1" build_android_arm64 arm64-v8a &
compile_source "$1" build_android_x86 x86 &
compile_source "$1" build_android_x86_64 x86_64 &
wait

View file

@ -0,0 +1,41 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="tw.DDNet">
<uses-feature
android:glEsVersion="0x00030000" />
<!-- Teeworlds does broadcasts over local networks -->
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
<uses-permission android:name="android.permission.CHANGE_WIFI_MULTICAST_STATE"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.INTERNET" />
<!-- usesCleartextTraffic because unencrypted UDP packets -->
<application
android:usesCleartextTraffic="true"
android:label="@string/app_name"
android:hasCode="true"
android:extractNativeLibs="true"
android:supportsRtl="true"
android:isGame="true"
android:icon="@mipmap/ic_launcher"
android:roundIcon="@mipmap/ic_launcher_round"
>
<activity
android:name=".NativeMain"
android:configChanges="orientation|screenSize|screenLayout|keyboardHidden">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<meta-data android:name="android.app.lib_name"
android:value="DDNet" />
</activity>
</application>
</manifest>

View file

@ -0,0 +1,80 @@
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
buildscript {
ext.kotlin_version = '+'
repositories {
google()
mavenCentral()
}
dependencies {
classpath 'com.android.tools.build:gradle:4.2.0'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
}
}
android {
compileSdkVersion 30
buildToolsVersion "30.0.3"
ndkVersion "TW_NDK_VERSION"
defaultConfig {
applicationId "tw.DDNet"
minSdkVersion 24
targetSdkVersion 30
versionCode TW_VERSION_CODE
versionName "TW_VERSION_NAME"
}
signingConfigs {
release {
storeFile file("TW_KEY_NAME")
storePassword "TW_KEY_PW"
keyAlias "TW_KEY_ALIAS"
keyPassword "TW_KEY_PW"
}
}
buildTypes {
release {
signingConfig signingConfigs.release
minifyEnabled true
shrinkResources true
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
debug {
minifyEnabled false
shrinkResources false
}
}
sourceSets {
main {
assets.srcDirs = ['assets']
jniLibs.srcDirs = ['lib']
//TW_ENABLE_RESOURCESresources.srcDirs = ['resources']
}
}
lintOptions {
abortOnError false
}
}
allprojects {
repositories {
google()
mavenCentral()
}
gradle.projectsEvaluated {
tasks.withType(JavaCompile) {
options.compilerArgs << "-Xlint:unchecked" << "-Xlint:deprecation"
}
}
}
dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
implementation 'androidx.appcompat:appcompat:1.1.0'
implementation 'androidx.core:core-ktx:1.3.0'
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
}

View file

@ -0,0 +1,88 @@
#!/bin/bash
[ x"$1" == x ] && {
printf '\e[31mDid not pass ANDROID_SDK_ROOT to build script\e[30m\n'
exit 1
}
[ x"$2" == x ] && {
printf '\e[31mDid not pass APK name to build script\e[30m\n'
exit 1
}
[ x"$3" == x ] && {
printf '\e[31mDid not pass build type to build script\e[30m\n'
exit 1
}
_APK_BASENAME="$2"
sed -i "s/DDNet/${2}/g" settings.gradle
_REPLACE_PACKAGE_NAME_STR="tw.${2,,}"
sed -i "s/tw.DDNet/${_REPLACE_PACKAGE_NAME_STR}/g" build.gradle
TW_KEY_NAME_ESCAPED=$(echo "$TW_KEY_NAME"|sed 's/\//\\\//g')
TW_KEY_PW_ESCAPED=$(echo "$TW_KEY_PW"|sed 's/\//\\\//g')
TW_KEY_ALIAS_ESCAPED=$(echo "$TW_KEY_ALIAS"|sed 's/\//\\\//g')
sed -i "s/TW_KEY_NAME/${TW_KEY_NAME_ESCAPED}/g" build.gradle
sed -i "s/TW_KEY_PW/${TW_KEY_PW_ESCAPED}/g" build.gradle
sed -i "s/TW_KEY_ALIAS/${TW_KEY_ALIAS_ESCAPED}/g" build.gradle
sed -i "s/DDNet/${2}/g" src/main/res/values/strings.xml
sed -i "s/\"DDNet\"/\"${2}\"/g" src/main/AndroidManifest.xml
sed -i "s/tw.DDNet/${_REPLACE_PACKAGE_NAME_STR}/g" src/main/AndroidManifest.xml
__TW_HOME_DIR=$(echo "$HOME"|sed 's/\//\\\//g')
sed -i "s/TW_HOME_DIR/${__TW_HOME_DIR}/g" local.properties
sed -i "s/TW_NDK_VERSION/${ANDROID_NDK_VERSION}/g" build.gradle
sed -i "s/TW_VERSION_CODE/${TW_VERSION_CODE}/g" build.gradle
sed -i "s/TW_VERSION_NAME/${TW_VERSION_NAME}/g" build.gradle
mv src/main/java/tw/DDNet src/main/java/tw/"${2}"
sed -i "s/tw.DDNet/${_REPLACE_PACKAGE_NAME_STR}/g" src/main/java/tw/"${2}"/NativeMain.java
sed -i "s/tw.DDNet/${_REPLACE_PACKAGE_NAME_STR}/g" proguard-rules.pro
# disable hid manager for now
sed -i "s/mHIDDeviceManager = HIDDeviceManager.acquire(this);/mHIDDeviceManager=null;/g" src/main/java/org/libsdl/app/SDLActivity.java
if [[ "${3}" == "Debug" ]]; then
sed -i "s/android.enableR8.fullMode=true/android.enableR8.fullMode=false/g" gradle.properties
fi
if [[ -z ${GE_NO_APK_BUILD} || "${GE_NO_APK_BUILD}" != "1" ]]; then
_RELEASE_TYPE_NAME=debug
_RELEASE_TYPE_APK_NAME=
if [[ "${3}" == "Debug" ]]; then
_RELEASE_TYPE_NAME=debug
fi
if [[ "${3}" == "Release" ]]; then
_RELEASE_TYPE_NAME=release
_RELEASE_TYPE_APK_NAME=
fi
APP_BASE_NAME=Gradle
CLASSPATH=gradle-wrapper.jar
java "-Dorg.gradle.appname=${APP_BASE_NAME}" -classpath "${CLASSPATH}" org.gradle.wrapper.GradleWrapperMain --warning-mode all
if [[ "${3}" == "Debug" ]]; then
java "-Dorg.gradle.appname=${APP_BASE_NAME}" -classpath "${CLASSPATH}" org.gradle.wrapper.GradleWrapperMain --warning-mode all builddebug
java "-Dorg.gradle.appname=${APP_BASE_NAME}" -classpath "${CLASSPATH}" org.gradle.wrapper.GradleWrapperMain --warning-mode all assembleDebug
else
java "-Dorg.gradle.appname=${APP_BASE_NAME}" -classpath "${CLASSPATH}" org.gradle.wrapper.GradleWrapperMain --warning-mode all buildrelease
java "-Dorg.gradle.appname=${APP_BASE_NAME}" -classpath "${CLASSPATH}" org.gradle.wrapper.GradleWrapperMain --warning-mode all assembleRelease
fi
cp build/outputs/apk/"$_RELEASE_TYPE_NAME"/"$_APK_BASENAME"-"$_RELEASE_TYPE_NAME""$_RELEASE_TYPE_APK_NAME".apk "$_APK_BASENAME".apk
if [[ "${3}" == "Release" ]]; then
java "-Dorg.gradle.appname=${APP_BASE_NAME}" -classpath "${CLASSPATH}" org.gradle.wrapper.GradleWrapperMain --warning-mode all bundleRelease
cp build/outputs/bundle/"$_RELEASE_TYPE_NAME"/"$_APK_BASENAME"-"$_RELEASE_TYPE_NAME""$_RELEASE_TYPE_APK_NAME".aab "$_APK_BASENAME".aab
fi
fi

Binary file not shown.

View file

@ -0,0 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-7.2-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists

View file

@ -0,0 +1,22 @@
# Project-wide Gradle settings.
# IDE (e.g. Android Studio) users:
# Gradle settings configured through the IDE *will override*
# any settings specified in this file.
# For more details on how to configure your build environment visit
# http://www.gradle.org/docs/current/userguide/build_environment.html
# Specifies the JVM arguments used for the daemon process.
# The setting is particularly useful for tweaking memory settings.
org.gradle.jvmargs=-Xmx3536m
# When configured, Gradle will run in incubating parallel mode.
# This option should only be used with decoupled projects. More details, visit
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
# org.gradle.parallel=true
# AndroidX package structure to make it clearer which packages are bundled with the
# Android operating system, and which are packaged with your app's APK
# https://developer.android.com/topic/libraries/support-library/androidx-rn
android.useAndroidX=true
# Automatically convert third-party libraries to use AndroidX
android.enableJetifier=true
# Kotlin code style for this project: "official" or "obsolete":
kotlin.code.style=official
android.enableR8.fullMode=true

View file

@ -0,0 +1,27 @@
package tw.DDNet;
import android.app.NativeActivity;
import org.libsdl.app.SDLActivity;
import android.os.Bundle;
import android.content.pm.ActivityInfo;
public class NativeMain extends SDLActivity {
static {
System.loadLibrary("DDNet");
}
@Override
protected String[] getLibraries() {
return new String[] {
// disable hid API for now
// "hidapi",
// "SDL2",
"DDNet",
};
}
@Override
public void onCreate(Bundle SavedInstanceState) {
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
super.onCreate(SavedInstanceState);
}
}

View file

@ -0,0 +1,10 @@
## This file is automatically generated by Android Studio.
# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
#
# This file should *NOT* be checked into Version Control Systems,
# as it contains information specific to your local configuration.
#
# Location of the SDK. This is only used by Gradle.
# For customization when using a Version Control System, please read the
# header note.
sdk.dir="TW_HOME_DIR/Android/Sdk"

View file

@ -0,0 +1,35 @@
# Add project specific ProGuard rules here.
# You can control the set of applied configuration files using the
# proguardFiles setting in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable
-keepclassmembers, allowoptimization public class tw.DDNet.NativeMain {
*;
}
-keepclassmembers, allowoptimization public class org.libsdl.app.* {
*;
}
# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile
############################################
## OUR
############################################
############################################
## OTHER
############################################

View file

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name">DDNet</string>
</resources>

View file

@ -0,0 +1 @@
rootProject.name='DDNet'

View file

@ -0,0 +1,179 @@
#!/bin/bash
CURDIR="$PWD"
if [ -z ${1+x} ]; then
echo "Give a destination path where to run this script, please choose a path other than in the source directory"
exit 1
fi
mkdir -p "$1"
cd "$1" || exit 1
function build_cmake_lib() {
if [ ! -d "${1}" ]; then
git clone "${2}" "${1}"
fi
(
cd "${1}" || exit 1
cp "${CURDIR}"/scripts/android/cmake_lib_compile.sh cmake_lib_compile.sh
./cmake_lib_compile.sh "$_ANDROID_ABI_LEVEL"
)
}
_ANDROID_ABI_LEVEL=24
mkdir -p android_libs
cd android_libs || exit 1
# start with openssl
(
_WAS_THERE_SSLFILE=1
if [ ! -d "openssl" ]; then
git clone https://github.com/openssl/openssl openssl
_WAS_THERE_SSLFILE=0
fi
(
cd openssl || exit 1
if [[ "$_WAS_THERE_SSLFILE" == 0 ]]; then
./autogen.sh
fi
cp "${CURDIR}"/scripts/android/make_android_openssl.sh make_android_openssl.sh
./make_android_openssl.sh "$_ANDROID_ABI_LEVEL"
)
)
build_cmake_lib curl https://github.com/curl/curl
build_cmake_lib freetype2 https://gitlab.freedesktop.org/freetype/freetype
build_cmake_lib sdl https://github.com/libsdl-org/SDL
build_cmake_lib ogg https://github.com/xiph/ogg
build_cmake_lib opus https://github.com/xiph/opus
(
_WAS_THERE_OPUSFILE=1
if [ ! -d "opusfile" ]; then
git clone https://github.com/xiph/opusfile opusfile
_WAS_THERE_OPUSFILE=0
fi
cd opusfile || exit 1
if [[ "$_WAS_THERE_OPUSFILE" == 0 ]]; then
./autogen.sh
fi
cp "${CURDIR}"/scripts/android/make_android_opusfile.sh make_android_opusfile.sh
./make_android_opusfile.sh "$_ANDROID_ABI_LEVEL"
)
# SQLite, just download and built by hand
if [ ! -d "sqlite3" ]; then
wget https://www.sqlite.org/2021/sqlite-amalgamation-3360000.zip
7z e sqlite-amalgamation-3360000.zip -osqlite3
fi
(
cd sqlite3 || exit 1
cp "${CURDIR}"/scripts/android/make_android_sqlite3.sh make_android_sqlite3.sh
./make_android_sqlite3.sh "$_ANDROID_ABI_LEVEL"
)
cd ..
mkdir ddnet-libs
function _copy_curl() {
mkdir -p ddnet-libs/curl/android/lib"$2"
cp android_libs/curl/build_android_"$1"/lib/libcurl.a ddnet-libs/curl/android/lib"$2"/libcurl.a
}
_copy_curl arm arm
_copy_curl arm64 arm64
_copy_curl x86 32
_copy_curl x86_64 64
mkdir ddnet-libs
function _copy_freetype2() {
mkdir -p ddnet-libs/freetype/android/lib"$2"
cp android_libs/freetype2/build_android_"$1"/libfreetype.a ddnet-libs/freetype/android/lib"$2"/libfreetype.a
}
_copy_freetype2 arm arm
_copy_freetype2 arm64 arm64
_copy_freetype2 x86 32
_copy_freetype2 x86_64 64
mkdir ddnet-libs
function _copy_sdl() {
mkdir -p ddnet-libs/sdl/android/lib"$2"
cp android_libs/sdl/build_android_"$1"/libSDL2.a ddnet-libs/sdl/android/lib"$2"/libSDL2.a
cp android_libs/sdl/build_android_"$1"/libSDL2main.a ddnet-libs/sdl/android/lib"$2"/libSDL2main.a
if [ ! -d "ddnet-libs/sdl/include/android" ]; then
mkdir -p ddnet-libs/sdl/include/android
fi
cp -R android_libs/sdl/include/* ddnet-libs/sdl/include/android
}
_copy_sdl arm arm
_copy_sdl arm64 arm64
_copy_sdl x86 32
_copy_sdl x86_64 64
# copy java code from SDL2
rm -R ddnet-libs/sdl/java
mkdir -p ddnet-libs/sdl/java
cp -R android_libs/sdl/android-project/app/src/main/java/org ddnet-libs/sdl/java/
mkdir ddnet-libs
function _copy_ogg() {
mkdir -p ddnet-libs/opus/android/lib"$2"
cp android_libs/ogg/build_android_"$1"/libogg.a ddnet-libs/opus/android/lib"$2"/libogg.a
}
_copy_ogg arm arm
_copy_ogg arm64 arm64
_copy_ogg x86 32
_copy_ogg x86_64 64
mkdir ddnet-libs
function _copy_opus() {
mkdir -p ddnet-libs/opus/android/lib"$2"
cp android_libs/opus/build_android_"$1"/libopus.a ddnet-libs/opus/android/lib"$2"/libopus.a
}
_copy_opus arm arm
_copy_opus arm64 arm64
_copy_opus x86 32
_copy_opus x86_64 64
mkdir ddnet-libs
function _copy_opusfile() {
mkdir -p ddnet-libs/opus/android/lib"$2"
cp android_libs/opusfile/build_"$1"/libopusfile.a ddnet-libs/opus/android/lib"$2"/libopusfile.a
}
_copy_opusfile arm arm
_copy_opusfile arm64 arm64
_copy_opusfile x86 32
_copy_opusfile x86_64 64
mkdir ddnet-libs
function _copy_sqlite3() {
mkdir -p ddnet-libs/sqlite3/android/lib"$2"
cp android_libs/sqlite3/build_"$1"/sqlite3.a ddnet-libs/sqlite3/android/lib"$2"/libsqlite3.a
}
_copy_sqlite3 arm arm
_copy_sqlite3 arm64 arm64
_copy_sqlite3 x86 32
_copy_sqlite3 x86_64 64
mkdir ddnet-libs
function _copy_openssl() {
mkdir -p ddnet-libs/openssl/android/lib"$2"
mkdir -p ddnet-libs/openssl/include
mkdir -p ddnet-libs/openssl/include/android
cp android_libs/openssl/build_android_"$1"/libcrypto.a ddnet-libs/openssl/android/lib"$2"/libcrypto.a
cp android_libs/openssl/build_android_"$1"/libssl.a ddnet-libs/openssl/android/lib"$2"/libssl.a
cp -R android_libs/openssl/build_android_"$1"/include/* ddnet-libs/openssl/include/android
cp -R android_libs/openssl/include/* ddnet-libs/openssl/include
}
_copy_openssl arm arm
_copy_openssl arm64 arm64
_copy_openssl x86 32
_copy_openssl x86_64 64

View file

@ -0,0 +1,33 @@
#!/bin/bash
ANDROID_HOME=~/Android/Sdk
ANDROID_NDK="$(find "$ANDROID_HOME/ndk" -maxdepth 1 | sort -n | tail -1)"
export MAKEFLAGS=-j32
export ANDROID_NDK_ROOT=$ANDROID_NDK
PATH=$ANDROID_NDK_ROOT/toolchains/llvm/prebuilt/linux-x86_64/bin:$ANDROID_NDK_ROOT/toolchains/arm-linux-androideabi-4.9/prebuilt/linux-x86_64/bin:$PATH
function buid_openssl() {
_EXISTS_PROJECT=0
if [ -d "$1" ]; then
_EXISTS_PROJECT=1
else
mkdir "$1"
fi
(
cd "$1" || exit 1
if [[ "$_EXISTS_PROJECT" == "0" ]]; then
../Configure "$2" no-asm no-shared
fi
make $MAKEFLAGS build_generated
make $MAKEFLAGS libcrypto.a
make $MAKEFLAGS libssl.a
cd ..
)
}
buid_openssl build_android_arm android-arm "$1"
buid_openssl build_android_arm64 android-arm64 "$1"
buid_openssl build_android_x86 android-x86 "$1"
buid_openssl build_android_x86_64 android-x86_64 "$1"

View file

@ -0,0 +1,62 @@
#!/bin/bash
ANDROID_HOME=~/Android/Sdk
ANDROID_NDK="$(find "$ANDROID_HOME/ndk" -maxdepth 1 | sort -n | tail -1)"
export MAKEFLAGS=-j32
export ANDROID_NDK_ROOT="$ANDROID_NDK"
function make_opusfile() {
_EXISTS_PROJECT=0
if [ -d "$1" ]; then
_EXISTS_PROJECT=1
else
mkdir "$1"
fi
(
cd "$1" || exit 1
if [[ "$_EXISTS_PROJECT" == 0 ]]; then
#not nice but doesnt matter
cp -R ../../ogg/include .
cp -R ../../opus/include .
cp -R ../../ogg/"$2"/include/ogg/* include/ogg/
cp ../../ogg/"$2"/libogg.a libogg.a
cp ../../opus/"$2"/libopus.a libopus.a
fi
"$ANDROID_NDK_ROOT/toolchains/llvm/prebuilt/linux-x86_64/bin/$3$4-clang" \
-c \
-fPIC \
-I"${PWD}"/../include \
-I"${PWD}"/include \
../src/opusfile.c \
../src/info.c \
../src/internal.c
"$ANDROID_NDK_ROOT/toolchains/llvm/prebuilt/linux-x86_64/bin/$3$4-clang" \
-c \
-fPIC \
-I"${PWD}"/../include \
-I"${PWD}"/include \
-include stdio.h \
-Dftello=ftell \
-Dfseek=fseek \
../src/stream.c
"$ANDROID_NDK_ROOT/toolchains/llvm/prebuilt/linux-x86_64/bin/llvm-ar" \
rvs \
libopusfile.a \
opusfile.o \
info.o \
stream.o \
internal.o
)
}
function compile_all_opusfile() {
make_opusfile build_arm build_android_arm armv7a-linux-androideabi "$1"
make_opusfile build_arm64 build_android_arm64 aarch64-linux-android "$1"
make_opusfile build_x86 build_android_x86 i686-linux-android "$1"
make_opusfile build_x86_64 build_android_x86_64 x86_64-linux-android "$1"
}
compile_all_opusfile "$1"

View file

@ -0,0 +1,41 @@
#!/bin/bash
ANDROID_HOME=~/Android/Sdk
ANDROID_NDK="$(find "$ANDROID_HOME/ndk" -maxdepth 1 | sort -n | tail -1)"
export MAKEFLAGS=-j32
export ANDROID_NDK_ROOT="$ANDROID_NDK"
PATH="$ANDROID_NDK_ROOT/toolchains/llvm/prebuilt/linux-x86_64/bin:$ANDROID_NDK_ROOT/toolchains/arm-linux-androideabi-4.9/prebuilt/linux-x86_64/bin:$PATH"
_LD_LIBRARY_PATH=".:$ANDROID_NDK_ROOT/toolchains/llvm/prebuilt/linux-x86_64/bin:$ANDROID_NDK_ROOT/toolchains/arm-linux-androideabi-4.9/prebuilt/linux-x86_64/bin:$LD_LIBRARY_PATH"
function make_sqlite3() {
(
mkdir -p "$1"
cd "$1" || exit 1
LDFLAGS="-L./" \
LD_LIBRARY_PATH="$_LD_LIBRARY_PATH" \
"$ANDROID_NDK_ROOT/toolchains/llvm/prebuilt/linux-x86_64/bin/$3$4-clang" \
-c \
-fPIC \
../sqlite3.c \
-o sqlite3.o
LDFLAGS="-L./" \
LD_LIBRARY_PATH="$_LD_LIBRARY_PATH" \
"$ANDROID_NDK_ROOT/toolchains/llvm/prebuilt/linux-x86_64/bin/llvm-ar" \
rvs \
sqlite3.a \
sqlite3.o
)
}
function compile_all_sqlite3() {
make_sqlite3 build_arm build_android_arm armv7a-linux-androideabi "$1"
make_sqlite3 build_arm64 build_android_arm64 aarch64-linux-android "$1"
make_sqlite3 build_x86 build_android_x86 i686-linux-android "$1"
make_sqlite3 build_x86_64 build_android_x86_64 x86_64-linux-android "$1"
}
compile_all_sqlite3 "$1"

View file

@ -0,0 +1,159 @@
#include <base/detect.h>
#ifdef CONF_PLATFORM_ANDROID
#include <sys/stat.h>
#include <unistd.h>
#include <SDL.h>
#include <base/hash.h>
#include <base/system.h>
#include <engine/shared/linereader.h>
#include <string>
#include <vector>
extern "C" __attribute__((visibility("default"))) void InitAndroid();
static int gs_AndroidStarted = false;
void InitAndroid()
{
if(gs_AndroidStarted)
{
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "DDNet", "The app was started, but not closed properly, this causes bugs. Please restart or manually delete this task.", SDL_GL_GetCurrentWindow());
std::exit(0);
}
gs_AndroidStarted = true;
// change current path to a writable directory
const char *pPath = SDL_AndroidGetExternalStoragePath();
chdir(pPath);
dbg_msg("client", "changed path to %s", pPath);
// copy integrity files
{
SDL_RWops *pF = SDL_RWFromFile("asset_integrity_files/integrity.txt", "rb");
if(!pF)
{
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "DDNet", "integrity.txt not found, consider reinstalling", SDL_GL_GetCurrentWindow());
std::exit(0);
}
long int length;
SDL_RWseek(pF, 0, RW_SEEK_END);
length = SDL_RWtell(pF);
SDL_RWseek(pF, 0, RW_SEEK_SET);
char *pAl = (char *)malloc(length);
SDL_RWread(pF, pAl, 1, length);
SDL_RWclose(pF);
mkdir("data", 0755);
dbg_msg("integrity", "copying integrity.txt with size: %ld", length);
IOHANDLE pIO = io_open("integrity.txt", IOFLAG_WRITE);
io_write(pIO, pAl, length);
io_close(pIO);
free(pAl);
}
IOHANDLE pIO = io_open("integrity.txt", IOFLAG_READ);
CLineReader LineReader;
LineReader.Init(pIO);
const char *pReadLine = NULL;
std::vector<std::string> Lines;
while((pReadLine = LineReader.Get()))
{
Lines.push_back(pReadLine);
}
io_close(pIO);
// first line is the whole hash
std::string AllAsOne;
for(size_t i = 1; i < Lines.size(); ++i)
{
AllAsOne.append(Lines[i]);
AllAsOne.append("\n");
}
SHA256_DIGEST ShaAll;
bool GotSHA = false;
{
IOHANDLE pIOR = io_open("integrity_save.txt", IOFLAG_READ);
if(pIOR != NULL)
{
CLineReader LineReader;
LineReader.Init(pIOR);
const char *pLine = LineReader.Get();
if(pLine != NULL)
{
sha256_from_str(&ShaAll, pLine);
GotSHA = true;
}
}
}
SHA256_DIGEST ShaAllFile;
sha256_from_str(&ShaAllFile, Lines[0].c_str());
// TODO: check files individually
if(!GotSHA || sha256_comp(ShaAllFile, ShaAll) != 0)
{
// then the files
for(size_t i = 1; i < Lines.size(); ++i)
{
std::string FileName, Hash;
std::string::size_type n = 0;
std::string::size_type c = 0;
while((c = Lines[i].find(' ', n)) != std::string::npos)
n = c + 1;
FileName = Lines[i].substr(0, n - 1);
Hash = Lines[i].substr(n + 1);
std::string AssetFileName = std::string("asset_integrity_files/") + FileName;
SDL_RWops *pF = SDL_RWFromFile(AssetFileName.c_str(), "rb");
dbg_msg("Integrity", "Copying from assets: %s", FileName.c_str());
std::string FileNamePath = FileName;
std::string FileNamePathSub;
c = 0;
while((c = FileNamePath.find('/', c)) != std::string::npos)
{
FileNamePathSub = FileNamePath.substr(0, c);
fs_makedir(FileNamePathSub.c_str());
++c;
}
long int length;
SDL_RWseek(pF, 0, RW_SEEK_END);
length = SDL_RWtell(pF);
SDL_RWseek(pF, 0, RW_SEEK_SET);
char *pAl = (char *)malloc(length);
SDL_RWread(pF, pAl, 1, length);
SDL_RWclose(pF);
IOHANDLE pIO = io_open(FileName.c_str(), IOFLAG_WRITE);
io_write(pIO, pAl, length);
io_close(pIO);
free(pAl);
}
IOHANDLE pIOR = io_open("integrity_save.txt", IOFLAG_WRITE);
if(pIOR != NULL)
{
char aFileSHA[SHA256_MAXSTRSIZE];
sha256_str(ShaAllFile, aFileSHA, SHA256_MAXSTRSIZE);
io_write(pIOR, aFileSHA, SHA256_MAXSTRSIZE - 1);
io_close(pIOR);
}
}
}
#endif

View file

@ -46,7 +46,7 @@
#define PLATFORM_STRING "openbsd"
#endif
#if defined(__LINUX__) || defined(__linux__)
#if(defined(__LINUX__) || defined(__linux__)) && !defined(__ANDROID__)
#define CONF_FAMILY_UNIX 1
#define CONF_FAMILY_STRING "unix"
#define CONF_PLATFORM_LINUX 1
@ -54,6 +54,15 @@
#define CONF_BACKEND_OPENGL_ES3 1
#endif
#if defined(__ANDROID__)
#define CONF_FAMILY_UNIX 1
#define CONF_FAMILY_STRING "unix"
#define CONF_PLATFORM_ANDROID 1
#define PLATFORM_STRING "android"
#define CONF_BACKEND_OPENGL_ES 1
#define CONF_BACKEND_OPENGL_ES3 1
#endif
#if defined(__GNU__) || defined(__gnu__)
#define CONF_FAMILY_UNIX 1
#define CONF_FAMILY_STRING "unix"

View file

@ -50,6 +50,10 @@
#include <mach/mach_time.h>
#endif
#ifdef CONF_PLATFORM_ANDROID
#include <android/log.h>
#endif
#elif defined(CONF_FAMILY_WINDOWS)
#define WIN32_LEAN_AND_MEAN
#undef _WIN32_WINNT
@ -135,9 +139,12 @@ void dbg_msg(const char *sys, const char *fmt, ...)
va_start(args, fmt);
#if defined(CONF_FAMILY_WINDOWS)
_vsnprintf(msg, sizeof(str) - len, fmt, args);
#elif defined(CONF_PLATFORM_ANDROID)
__android_log_vprint(ANDROID_LOG_DEBUG, sys, fmt, args);
#else
vsnprintf(msg, sizeof(str) - len, fmt, args);
#endif
va_end(args);
for(i = 0; i < num_loggers; i++)
@ -2098,6 +2105,9 @@ int fs_storage_path(const char *appname, char *path, int max)
return -1;
_snprintf(path, max, "%s/%s", home, appname);
return 0;
#elif defined(CONF_PLATFORM_ANDROID)
// just use the data directory
return -1;
#else
char *home = getenv("HOME");
#if !defined(CONF_PLATFORM_MACOS)

View file

@ -2,6 +2,8 @@
#include <base/detect.h>
#if defined(BACKEND_AS_OPENGL_ES) || !defined(CONF_BACKEND_OPENGL_ES)
#include <engine/client/backend/opengl/opengl_sl.h>
#include <engine/client/backend/opengl/opengl_sl_program.h>
@ -2332,3 +2334,5 @@ void CCommandProcessorFragment_OpenGL2::Cmd_RenderTileLayer(const CCommandBuffer
#endif
#endif
#endif

View file

@ -2,6 +2,8 @@
#include <base/detect.h>
#if defined(BACKEND_AS_OPENGL_ES) || !defined(CONF_BACKEND_OPENGL_ES)
#ifndef BACKEND_AS_OPENGL_ES
#include <GL/glew.h>
#else
@ -1569,3 +1571,5 @@ void CCommandProcessorFragment_OpenGL3_3::Cmd_RenderQuadContainerAsSpriteMultipl
DrawCount -= RSPCount;
}
}
#endif

View file

@ -14,7 +14,7 @@
#include "backend_opengl.h"
#define MAX_STREAM_BUFFER_COUNT 30
#define MAX_STREAM_BUFFER_COUNT 10
// takes care of opengl 3.3+ related rendering
class CCommandProcessorFragment_OpenGL3_3 : public CCommandProcessorFragment_OpenGL3

View file

@ -1,4 +1,9 @@
#include "opengl_sl.h"
#include <base/detect.h>
#if defined(BACKEND_AS_OPENGL_ES) || !defined(CONF_BACKEND_OPENGL_ES)
#include <engine/shared/linereader.h>
#include <engine/storage.h>
#include <stdio.h>
@ -157,3 +162,5 @@ CGLSL::~CGLSL()
{
DeleteShader();
}
#endif

View file

@ -2,6 +2,10 @@
#include "opengl_sl.h"
#include <base/system.h>
#include <base/detect.h>
#if defined(BACKEND_AS_OPENGL_ES) || !defined(CONF_BACKEND_OPENGL_ES)
#ifndef BACKEND_AS_OPENGL_ES
#include <GL/glew.h>
#else
@ -140,3 +144,5 @@ CGLSLProgram::~CGLSLProgram()
{
DeleteProgram();
}
#endif

View file

@ -188,6 +188,26 @@ void CCommandProcessorFragment_SDL::Cmd_VSync(const CCommandBuffer::SCommand_VSy
*pCommand->m_pRetOk = SDL_GL_SetSwapInterval(pCommand->m_VSync) == 0;
}
void CCommandProcessorFragment_SDL::Cmd_WindowCreateNtf(const CCommandBuffer::SCommand_WindowCreateNtf *pCommand)
{
m_pWindow = SDL_GetWindowFromID(pCommand->m_WindowID);
// Android destroys windows when they are not visible, so we get the new one and work with that
// The graphic context does not need to be recreated, just unbound see @see SCommand_WindowDestroyNtf
#ifdef CONF_PLATFORM_ANDROID
SDL_GL_MakeCurrent(m_pWindow, m_GLContext);
dbg_msg("gfx", "render surface created.");
#endif
}
void CCommandProcessorFragment_SDL::Cmd_WindowDestroyNtf(const CCommandBuffer::SCommand_WindowDestroyNtf *pCommand)
{
// Unbind the graphic context from the window, so it does not get destroyed
#ifdef CONF_PLATFORM_ANDROID
dbg_msg("gfx", "render surface destroyed.");
SDL_GL_MakeCurrent(NULL, NULL);
#endif
}
CCommandProcessorFragment_SDL::CCommandProcessorFragment_SDL()
{
}
@ -196,6 +216,8 @@ bool CCommandProcessorFragment_SDL::RunCommand(const CCommandBuffer::SCommand *p
{
switch(pBaseCommand->m_Cmd)
{
case CCommandBuffer::CMD_WINDOW_CREATE_NTF: Cmd_WindowCreateNtf(static_cast<const CCommandBuffer::SCommand_WindowCreateNtf *>(pBaseCommand)); break;
case CCommandBuffer::CMD_WINDOW_DESTROY_NTF: Cmd_WindowDestroyNtf(static_cast<const CCommandBuffer::SCommand_WindowDestroyNtf *>(pBaseCommand)); break;
case CCommandBuffer::CMD_SWAP: Cmd_Swap(static_cast<const CCommandBuffer::SCommand_Swap *>(pBaseCommand)); break;
case CCommandBuffer::CMD_VSYNC: Cmd_VSync(static_cast<const CCommandBuffer::SCommand_VSync *>(pBaseCommand)); break;
case CMD_INIT: Cmd_Init(static_cast<const SCommand_Init *>(pBaseCommand)); break;

View file

@ -141,6 +141,8 @@ private:
void Cmd_Shutdown(const SCommand_Shutdown *pCommand);
void Cmd_Swap(const CCommandBuffer::SCommand_Swap *pCommand);
void Cmd_VSync(const CCommandBuffer::SCommand_VSync *pCommand);
void Cmd_WindowCreateNtf(const CCommandBuffer::SCommand_WindowCreateNtf *pCommand);
void Cmd_WindowDestroyNtf(const CCommandBuffer::SCommand_WindowDestroyNtf *pCommand);
public:
CCommandProcessorFragment_SDL();

View file

@ -76,6 +76,10 @@
#undef main
#endif
// for android
#include "SDL_rwops.h"
#include "base/hash.h"
static const ColorRGBA ClientNetworkPrintColor{0.7f, 1, 0.7f, 1.0f};
static const ColorRGBA ClientNetworkErrPrintColor{1.0f, 0.25f, 0.25f, 1.0f};
@ -3031,7 +3035,9 @@ void CClient::Run()
return;
}
#ifndef CONF_PLATFORM_ANDROID
atexit(SDL_Quit); // ignore_convention
#endif
}
// init graphics
@ -4275,6 +4281,11 @@ void CClient::HandleMapPath(const char *pPath)
#if defined(CONF_PLATFORM_MACOS)
extern "C" int TWMain(int argc, const char **argv) // ignore_convention
#elif defined(CONF_PLATFORM_ANDROID)
extern "C" __attribute__((visibility("default"))) int SDL_main(int argc, char *argv[]);
extern "C" void InitAndroid();
int SDL_main(int argc, char *argv[])
#else
int main(int argc, const char **argv) // ignore_convention
#endif
@ -4296,6 +4307,10 @@ int main(int argc, const char **argv) // ignore_convention
}
}
#if defined(CONF_PLATFORM_ANDROID)
InitAndroid();
#endif
if(secure_random_init() != 0)
{
RandInitFailed = true;
@ -4311,7 +4326,7 @@ int main(int argc, const char **argv) // ignore_convention
// create the components
IEngine *pEngine = CreateEngine("DDNet", Silent, 2);
IConsole *pConsole = CreateConsole(CFGFLAG_CLIENT);
IStorage *pStorage = CreateStorage("Teeworlds", IStorage::STORAGETYPE_CLIENT, argc, argv); // ignore_convention
IStorage *pStorage = CreateStorage("Teeworlds", IStorage::STORAGETYPE_CLIENT, argc, (const char **)argv); // ignore_convention
IConfigManager *pConfigManager = CreateConfigManager();
IEngineSound *pEngineSound = CreateEngineSound();
IEngineInput *pEngineInput = CreateEngineInput();
@ -4423,7 +4438,7 @@ int main(int argc, const char **argv) // ignore_convention
else if(argc == 2 && str_endswith(argv[1], ".map"))
pClient->HandleMapPath(argv[1]);
else if(argc > 1) // ignore_convention
pConsole->ParseArguments(argc - 1, &argv[1]); // ignore_convention
pConsole->ParseArguments(argc - 1, (const char **)&argv[1]); // ignore_convention
if(pSteam->GetConnectAddress())
{
@ -4451,6 +4466,12 @@ int main(int argc, const char **argv) // ignore_convention
}
delete pKernel;
#ifdef CONF_PLATFORM_ANDROID
// properly close this native thread, so globals are destructed
std::exit(0);
#endif
return 0;
}

View file

@ -2376,6 +2376,30 @@ int CGraphics_Threaded::GetWindowScreen()
return m_pBackend->GetWindowScreen();
}
void CGraphics_Threaded::WindowDestroyNtf(uint32_t WindowID)
{
CCommandBuffer::SCommand_WindowDestroyNtf Cmd;
Cmd.m_WindowID = WindowID;
if(!AddCmd(
Cmd, [] { return true; }, "failed to add window destroy notify command"))
{
return;
}
}
void CGraphics_Threaded::WindowCreateNtf(uint32_t WindowID)
{
CCommandBuffer::SCommand_WindowCreateNtf Cmd;
Cmd.m_WindowID = WindowID;
if(!AddCmd(
Cmd, [] { return true; }, "failed to add window create notify command"))
{
return;
}
}
int CGraphics_Threaded::WindowActive()
{
return m_pBackend->WindowActive();

View file

@ -126,6 +126,9 @@ public:
CMD_SCREENSHOT,
CMD_UPDATE_VIEWPORT,
// in Android a window that minimizes gets destroyed
CMD_WINDOW_CREATE_NTF,
CMD_WINDOW_DESTROY_NTF,
};
enum
@ -562,6 +565,22 @@ public:
int m_Slot;
};
struct SCommand_WindowCreateNtf : public CCommandBuffer::SCommand
{
SCommand_WindowCreateNtf() :
SCommand(CMD_WINDOW_CREATE_NTF) {}
uint32_t m_WindowID;
};
struct SCommand_WindowDestroyNtf : public CCommandBuffer::SCommand
{
SCommand_WindowDestroyNtf() :
SCommand(CMD_WINDOW_DESTROY_NTF) {}
uint32_t m_WindowID;
};
//
CCommandBuffer(unsigned CmdBufferSize, unsigned DataBufferSize) :
m_CmdBuffer(CmdBufferSize), m_DataBuffer(DataBufferSize), m_pCmdBufferHead(nullptr), m_pCmdBufferTail(nullptr)
@ -1137,6 +1156,9 @@ public:
void AddWindowResizeListener(WINDOW_RESIZE_FUNC pFunc, void *pUser) override;
int GetWindowScreen() override;
void WindowDestroyNtf(uint32_t WindowID) override;
void WindowCreateNtf(uint32_t WindowID) override;
int WindowActive() override;
int WindowOpen() override;

View file

@ -148,6 +148,10 @@ int CRequest::RunImpl(CURL *pHandle)
curl_easy_setopt(pHandle, CURLOPT_PROGRESSDATA, this);
curl_easy_setopt(pHandle, CURLOPT_PROGRESSFUNCTION, ProgressCallback);
#ifdef CONF_PLATFORM_ANDROID
curl_easy_setopt(pHandle, CURLOPT_CAINFO, "data/cacert.pem");
#endif
if(!AfterInit(pHandle))
{
return HTTP_ERROR;

View file

@ -52,6 +52,9 @@ CInput::CInput()
m_NumTextInputInstances = 0;
m_EditingTextLen = -1;
m_aEditingText[0] = 0;
m_LastX = 0;
m_LastY = 0;
}
void CInput::Init()
@ -71,7 +74,18 @@ void CInput::MouseRelative(float *x, float *y)
int nx = 0, ny = 0;
float Sens = g_Config.m_InpMousesens / 100.0f;
#if defined(CONF_PLATFORM_ANDROID) // No relative mouse on Android
SDL_GetMouseState(&nx, &ny);
int XTmp = nx - m_LastX;
int YTmp = ny - m_LastY;
m_LastX = nx;
m_LastY = ny;
nx = XTmp;
ny = YTmp;
Sens = 1;
#else
SDL_GetRelativeMouseState(&nx, &ny);
#endif
*x = nx * Sens;
*y = ny * Sens;
@ -87,7 +101,9 @@ void CInput::MouseModeAbsolute()
void CInput::MouseModeRelative()
{
m_InputGrabbed = 1;
#if !defined(CONF_PLATFORM_ANDROID) // No relative mouse on Android
SDL_SetRelativeMouseMode(SDL_TRUE);
#endif
Graphics()->SetWindowGrab(true);
// Clear pending relative mouse motion
SDL_GetRelativeMouseState(0x0, 0x0);
@ -347,12 +363,18 @@ int CInput::Update()
m_InputGrabbed = true;
}
break;
#if defined(CONF_PLATFORM_MACOS) // Todo: remove this when fixed in SDL
case SDL_WINDOWEVENT_MINIMIZED:
Graphics()->WindowDestroyNtf(Event.window.windowID);
break;
case SDL_WINDOWEVENT_MAXIMIZED:
#if defined(CONF_PLATFORM_MACOS) // Todo: remove this when fixed in SDL
MouseModeAbsolute();
MouseModeRelative();
break;
#endif
// fallthrough
case SDL_WINDOWEVENT_RESTORED:
Graphics()->WindowCreateNtf(Event.window.windowID);
break;
}
break;

View file

@ -12,6 +12,9 @@ class CInput : public IEngineInput
{
IEngineGraphics *m_pGraphics;
int m_LastX;
int m_LastY;
int m_InputGrabbed;
char *m_pClipboardText;

View file

@ -4,7 +4,7 @@
#if defined(CONF_PLATFORM_MACOS)
// Code is in src/macos/notification.mm.
#elif defined(CONF_FAMILY_UNIX)
#elif defined(CONF_FAMILY_UNIX) && !defined(CONF_PLATFORM_ANDROID)
#include <libnotify/notify.h>
void NotificationsInit()
{

View file

@ -215,6 +215,9 @@ public:
virtual void Resize(int w, int h, int RefreshRate, bool SetWindowSize = false, bool ForceResizeEvent = false) = 0;
virtual void AddWindowResizeListener(WINDOW_RESIZE_FUNC pFunc, void *pUser) = 0;
virtual void WindowDestroyNtf(uint32_t WindowID) = 0;
virtual void WindowCreateNtf(uint32_t WindowID) = 0;
virtual void Clear(float r, float g, float b) = 0;
virtual void ClipEnable(int x, int y, int w, int h) = 0;