├── CHANGES.md ├── Source ├── Native │ ├── jni │ │ ├── Application.mk │ │ └── Android.mk │ ├── CMakeLists.txt │ ├── enet.c │ └── custom │ │ └── enet_logging.h └── Managed │ ├── ENet-CSharp.csproj │ └── ENet.cs ├── .github ├── FUNDING.yml └── workflows │ └── MasterBuild.yaml ├── MSBuild ├── ENetTests │ ├── Properties │ │ └── launchSettings.json │ ├── ENetTests.csproj │ └── UnitTests.cs ├── CMake │ ├── CMake.Copy.targets │ ├── CMake.csproj │ └── CMake.Build.targets ├── Common │ ├── BannerTask.targets │ ├── BannerTask.cs │ └── Banner.txt └── ENetCSharp │ └── ENetCSharp.csproj ├── .gitignore ├── ENet-CSharp.nuspec ├── BuildScripts ├── apple-mac.command ├── ms-windows.cmd ├── linux-androidndk.sh └── apple-ios.command ├── LICENSE ├── Build-iOS ├── CMakeLists.txt └── Build-iOS.command ├── CMakeLists.txt ├── COMMON-MISTAKES.md ├── Directory.Build.props ├── QUICKSTART-EXAMPLES.md ├── ENet-CSharp.sln ├── BUILD-FOR-SWITCH.txt ├── README.md ├── DOCUMENTATION.md └── MobileToolchains └── ios.toolchain.cmake /CHANGES.md: -------------------------------------------------------------------------------- 1 | ## Changes in this fork compared to upstream's fork 2 | 3 | TODO. -------------------------------------------------------------------------------- /Source/Native/jni/Application.mk: -------------------------------------------------------------------------------- 1 | APP_PLATFORM := android-21 2 | APP_OPTIM := release 3 | APP_MODULES := libenet 4 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | ko_fi: coburn 2 | patreon: Oiran_Studio 3 | custom: [ 'https://www.paypal.com/paypalme/coburn64' ] 4 | -------------------------------------------------------------------------------- /MSBuild/ENetTests/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "profiles": { 3 | "SockLynxTests": { 4 | "commandName": "Project", 5 | "nativeDebugging": true 6 | } 7 | } 8 | } -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | README.md 2 | Source/Native/build/ 3 | build_cmake_enet/ 4 | *.bak 5 | **/bin 6 | **/obj 7 | .vs 8 | Directory.Build.rsp 9 | Unity 10 | deps/ 11 | 12 | x86_Build/ 13 | UpgradeLog.htm 14 | NEW_DO_NOT_SEND_TO_GIT/ 15 | out/ 16 | Output 17 | -------------------------------------------------------------------------------- /Source/Native/jni/Android.mk: -------------------------------------------------------------------------------- 1 | LOCAL_PATH := $(call my-dir) 2 | include $(CLEAR_VARS) 3 | 4 | LOCAL_MODULE := libenet 5 | LOCAL_SRC_FILES := ../enet.c 6 | 7 | ifdef ENET_DEBUG 8 | LOCAL_CFLAGS += -DENET_DEBUG 9 | endif 10 | 11 | ifdef ENET_STATIC 12 | include $(BUILD_STATIC_LIBRARY) 13 | else 14 | include $(BUILD_SHARED_LIBRARY) 15 | endif 16 | -------------------------------------------------------------------------------- /ENet-CSharp.nuspec: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | ENet-CSharp 5 | 2.4.5 6 | ENet-CSharp 7 | Matt Coburn 8 | coburn64 9 | false 10 | license\license.txt 11 | https://github.com/SoftwareGuy/ENet-CSharp 12 | Reliable UDP networking library extended for the .NET environment 13 | 14 | 15 | (c) 2019-2020 Matt Coburn 16 | networking udp protocol ipv4 ipv6 gamedev 17 | 18 | 19 | -------------------------------------------------------------------------------- /Source/Managed/ENet-CSharp.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Library 5 | netstandard2.1;netcoreapp3.1 6 | ENet 7 | 8 | 3 9 | 10 | 11 | 12 | false 13 | True 14 | 3 15 | 16 | 17 | 18 | true 19 | True 20 | 3 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /BuildScripts/apple-mac.command: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # MacOS flavoured version of Coburn's autobuild script, since YAML 3 | # can go suck it. 4 | 5 | # Cache variables. 6 | WORKDIR=$(pwd) 7 | 8 | # Make work directories. 9 | mkdir -p $WORKDIR/ReleaseOut 10 | mkdir -p $WORKDIR/DebugOut 11 | 12 | echo Preparing build environment... 13 | dotnet clean 14 | 15 | echo Building Debug Library... 16 | dotnet build 17 | 18 | echo Stashing... 19 | cp -v Unity/Plugins/x86_64/* $WORKDIR/DebugOut 20 | 21 | echo Cleaning up... 22 | dotnet clean 23 | rm -vf Unity/Plugins/x86_64/* 24 | 25 | echo Building Release Library... 26 | dotnet build -c Release 27 | 28 | echo Stashing 29 | cp -v Unity/Plugins/x86_64/* $WORKDIR/ReleaseOut 30 | 31 | echo Compressing... 32 | cd $WORKDIR/ReleaseOut && zip -9 Release.zip libenet.bundle 33 | cd $WORKDIR/DebugOut && zip -9 Debug.zip libenet.bundle 34 | 35 | echo End of Build Script. Have a nice day. 36 | exit $? -------------------------------------------------------------------------------- /Source/Native/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 2.6) 2 | project(enet C) 3 | 4 | set(ENET_DEBUG "0" CACHE BOOL "Enable debug functionality") 5 | set(ENET_STATIC "0" CACHE BOOL "Create a static library") 6 | set(ENET_SHARED "0" CACHE BOOL "Create a shared library") 7 | 8 | if (MSYS OR MINGW) 9 | set(CMAKE_C_FLAGS "-static") 10 | 11 | add_definitions(-DWINVER=0x0601) 12 | add_definitions(-D_WIN32_WINNT=0x0601) 13 | endif() 14 | 15 | if (ENET_DEBUG) 16 | add_definitions(-DENET_DEBUG) 17 | endif() 18 | 19 | if (ENET_STATIC) 20 | add_library(enet_static STATIC enet.c ${SOURCES}) 21 | 22 | if (NOT UNIX) 23 | target_link_libraries(enet_static winmm ws2_32) 24 | SET_TARGET_PROPERTIES(enet_static PROPERTIES PREFIX "") 25 | endif() 26 | endif() 27 | 28 | if (ENET_SHARED) 29 | add_definitions(-DENET_DLL) 30 | add_library(enet SHARED enet.c ${SOURCES}) 31 | 32 | if (NOT UNIX) 33 | target_link_libraries(enet winmm ws2_32) 34 | SET_TARGET_PROPERTIES(enet PROPERTIES PREFIX "") 35 | endif() 36 | endif() -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 - 2020 Matt Coburn (SoftwareGuy/Coburn64), Chris Burns (c6burns), et al. 4 | 5 | This library uses portions of other libraries that may be licensed under a different license. 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining a copy 8 | of this software and associated documentation files (the "Software"), to deal 9 | in the Software without restriction, including without limitation the rights 10 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | copies of the Software, and to permit persons to whom the Software is 12 | furnished to do so, subject to the following conditions: 13 | 14 | The above copyright notice and this permission notice shall be included in all 15 | copies or substantial portions of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | SOFTWARE. 24 | -------------------------------------------------------------------------------- /Build-iOS/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(ENET_LIB_NAME enet) 2 | cmake_minimum_required(VERSION 3.1) 3 | project(${ENET_LIB_NAME} LANGUAGES C) 4 | 5 | set(ENET_DEBUG OFF CACHE BOOL "Do debug things") 6 | set(ENET_PLUGIN_DIR_BASE "${CMAKE_CURRENT_SOURCE_DIR}/Unity/Plugins") 7 | set(ENET_PLUGIN_DIR_ARCH "x86_64") 8 | set(ENET_DEFINES -DENET_NO_PRAGMA_LINK -DENET_DLL) 9 | set(ENET_DEPS "") 10 | set(ENET_SRCDIR "../Source/Native") 11 | set(ENET_SRCS 12 | ${ENET_SRCDIR}/enet.c 13 | ${ENET_SRCDIR}/enet.h 14 | ${ENET_SRCDIR}/custom/enet_logging.h 15 | ${ENET_SRCDIR}/custom/enet_iosFixes.h 16 | ) 17 | 18 | if(ENET_DEBUG) 19 | list(APPEND ENET_DEFINES -DENET_DEBUG) 20 | endif() 21 | 22 | include_directories(${ENET_SRCDIR}) 23 | add_library(${ENET_LIB_NAME} STATIC ${ENET_SRCS}) 24 | target_link_libraries(${ENET_LIB_NAME} ${ENET_DEPS}) 25 | target_compile_definitions(${ENET_LIB_NAME} PRIVATE ${ENET_DEFINES}) 26 | 27 | set(ENET_PLUGIN_DIR ${ENET_PLUGIN_DIR_BASE}/${ENET_PLUGIN_DIR_ARCH}) 28 | set(ENET_LIB_PREFIX ${CMAKE_SHARED_LIBRARY_PREFIX}) 29 | string(REPLACE ".dylib" ".bundle" ENET_LIB_SUFFIX ${CMAKE_SHARED_LIBRARY_SUFFIX}) 30 | set(ENET_PLUGIN_NAME ${ENET_LIB_PREFIX}${ENET_LIB_NAME}${ENET_LIB_SUFFIX}) 31 | 32 | file(MAKE_DIRECTORY ${ENET_PLUGIN_DIR}) 33 | add_custom_command( 34 | TARGET ${ENET_LIB_NAME} 35 | POST_BUILD 36 | COMMAND ${CMAKE_COMMAND} -E copy 37 | $ 38 | ${ENET_PLUGIN_DIR}/${ENET_PLUGIN_NAME} 39 | ) 40 | 41 | -------------------------------------------------------------------------------- /Source/Native/enet.c: -------------------------------------------------------------------------------- 1 | /* 2 | * ENet reliable UDP networking library 3 | * This is a fork from upstream and is available at http://github.com/SoftwareGuy/ENet-CSharp 4 | * 5 | * Copyright (c) 2019-2020 Matt Coburn (SoftwareGuy/Coburn64), Chris Burns (c6burns) 6 | * Copyright (c) 2018 Lee Salzman, Vladyslav Hrytsenko, Dominik Madarász, Stanislav Denisov 7 | * 8 | * Permission is hereby granted, free of charge, to any person obtaining a copy 9 | * of this software and associated documentation files (the "Software"), to deal 10 | * in the Software without restriction, including without limitation the rights 11 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | * copies of the Software, and to permit persons to whom the Software is 13 | * furnished to do so, subject to the following conditions: 14 | * 15 | * The above copyright notice and this permission notice shall be included in all 16 | * copies or substantial portions of the Software. 17 | * 18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 24 | * SOFTWARE. 25 | */ 26 | 27 | #define ENET_IMPLEMENTATION 28 | #include "enet.h" -------------------------------------------------------------------------------- /BuildScripts/ms-windows.cmd: -------------------------------------------------------------------------------- 1 | @echo off 2 | rem Oh hey there. Coburn here. 3 | rem You might be thinking what's this file gotta 4 | rem do with ENet? Well, let's just say I've got 5 | rem the shits with the fucking GitHub actions 6 | rem system. Syntax error without any fucking additional 7 | rem information. No "expecting ..." or "... not allowed here", 8 | rem just fucking syntax error, lol. And there's no Github-flavoured 9 | rem YAML parsers online, so yeah. Poor 'ol me can't figure it out. 10 | rem 11 | rem Anyway, that ends here. What this script does is mainly runs 12 | rem the build process as part of the CI pipeline. Hopefully that 13 | rem means I can just use this script to run the Microsoft Windows 14 | rem builds, because I've had the shits as mentioned above trying to 15 | rem use YAML files. YAML can GTFO until further notice. 16 | set _OutputFolder=%1 17 | PATH=C:\Program Files\7-Zip;%PATH% 18 | 19 | rem Make release and debug folders. 20 | mkdir %_OutputFolder%\ReleaseOut 21 | mkdir %_OutputFolder%\DebugOut 22 | 23 | echo Preparing Debug Build 24 | dotnet clean 25 | dotnet build 26 | 27 | echo Stashing... 28 | copy Unity\Plugins\x86_64\enet.dll %_OutputFolder%\DebugOut 29 | 30 | echo Preparing Release Build 31 | dotnet clean 32 | dotnet build -c Release 33 | 34 | echo Stashing... 35 | copy Unity\Plugins\x86_64\enet.dll %_OutputFolder%\ReleaseOut 36 | 37 | echo Compressing... 38 | cd %_OutputFolder%\ReleaseOut 39 | 7z a %_OutputFolder%\DebugOut\Debug.zip %_OutputFolder%\DebugOut\enet.dll 40 | 7z a %_OutputFolder%\ReleaseOut\Release.zip %_OutputFolder%\ReleaseOut\enet.dll 41 | 42 | echo BUILD SCRIPT EXITING -------------------------------------------------------------------------------- /MSBuild/CMake/CMake.Copy.targets: -------------------------------------------------------------------------------- 1 | 22 | 23 | 24 | 25 | 26 | $(PluginDir)$(PluginArchDir)$(PluginPrefix)$(PluginBaseName).$(PluginExt) 27 | 28 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /MSBuild/Common/BannerTask.targets: -------------------------------------------------------------------------------- 1 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /MSBuild/ENetCSharp/ENetCSharp.csproj: -------------------------------------------------------------------------------- 1 | 22 | 23 | 24 | 25 | netstandard2.0 26 | True 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | false 36 | true 37 | 38 | 39 | 40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /MSBuild/ENetTests/ENetTests.csproj: -------------------------------------------------------------------------------- 1 | 22 | 23 | 24 | 25 | netcoreapp3.1 26 | 7.1 27 | false 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /BuildScripts/linux-androidndk.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | echo "Executing autobuild process for ENet-CSharp repository" 3 | echo "Script written by SoftwareGuy (https://github.com/SoftwareGuy)" 4 | 5 | echo "Retreiving paths" 6 | WORKFILEPATH=`readlink -f "${BASH_SOURCE:-$0}"` 7 | WORKPATH=`dirname "$WORKFILEPATH"` 8 | SOURCEDIR=`dirname "$WORKPATH/../Source/Native/jni"` 9 | OUTPUTDIR="$WORKPATH/Out" 10 | DUMP="$HOME/Dump" 11 | 12 | echo "" 13 | echo "Script is located at '$WORKFILEPATH'" 14 | echo "Script directory is located at '$WORKPATH'" 15 | echo "Source code should be located at '$SOURCEDIR'" 16 | echo "Grabbing tools if they don't exist already..." 17 | echo "" 18 | 19 | if [ ! -d $DUMP ]; then 20 | mkdir $DUMP 21 | fi 22 | 23 | if [ ! -f "$DUMP/android-ndk-r25c-linux.zip" ]; then 24 | wget https://dl.google.com/android/repository/android-ndk-r25c-linux.zip -O "$DUMP/android-ndk-r25c-linux.zip" 25 | 26 | if [ $? -ne 0 ]; then 27 | echo "Failure: Tools download failed. Aborting!" 28 | exit 1 29 | fi 30 | fi 31 | 32 | cd "$DUMP" 33 | 34 | if [ ! -d "$DUMP/android-ndk-r25c" ]; then 35 | echo "Unpacking tools..." 36 | unzip -o android-ndk-r25c-linux.zip 37 | 38 | if [ $? -ne 0 ]; then 39 | echo "Failure: Tools unpack failed. Aborting!" 40 | exit 1 41 | fi 42 | fi 43 | 44 | PATH="$DUMP/android-ndk-r25c:$PATH" 45 | cd $SOURCEDIR 46 | 47 | echo "Output directory is set to '$OUTPUTDIR'." 48 | echo "Compile: ENet Native (Non-debug version)" 49 | if [ ! -d "$OUTPUTDIR/Release" ]; then 50 | mkdir -p "$OUTPUTDIR/Release" 51 | fi 52 | NDK_LIBS_OUT="$OUTPUTDIR/Release" ndk-build 53 | 54 | echo "Compile: ENet Native (Debug version)" 55 | if [ ! -d "$OUTPUTDIR/Debug" ]; then 56 | mkdir -p "$OUTPUTDIR/Debug" 57 | fi 58 | NDK_LIBS_OUT="$OUTPUTDIR/Debug" ENET_DEBUG=1 ndk-build 59 | 60 | echo "" 61 | echo "Complete!" 62 | exit 0 63 | -------------------------------------------------------------------------------- /MSBuild/CMake/CMake.csproj: -------------------------------------------------------------------------------- 1 | 22 | 23 | 24 | 25 | netcoreapp3.1 26 | false 27 | false 28 | false 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /Source/Native/custom/enet_logging.h: -------------------------------------------------------------------------------- 1 | #ifndef ENET_LOGGING_H 2 | #define ENET_LOGGING_H 3 | 4 | #include 5 | #include 6 | #if __APPLE__ 7 | #include 8 | #endif 9 | 10 | // TODO: Make better filenames; ie. enet_log.pid.txt 11 | #define ENET_LOG_FILE "enet-debug.log" 12 | static FILE* enet_log_fp = NULL; 13 | 14 | enum enet_log_type 15 | { 16 | ENET_LOG_TYPE_TRACE, 17 | ENET_LOG_TYPE_ERROR, 18 | }; 19 | 20 | static const char *const enet_log_type_names[] = { 21 | [ENET_LOG_TYPE_TRACE] = "TRACE", 22 | [ENET_LOG_TYPE_ERROR] = "ERROR", 23 | }; 24 | 25 | #if ENET_DEBUG 26 | // Debug 27 | #define ENET_LOG_TRACE(...) enet_log_to_file(ENET_LOG_TYPE_TRACE, __FUNCTION__, __LINE__, __VA_ARGS__) 28 | #define ENET_LOG_ERROR(...) enet_log_to_file(ENET_LOG_TYPE_ERROR, __FUNCTION__, __LINE__, __VA_ARGS__) 29 | 30 | static inline void enet_log_to_file(enum enet_log_type type, const char *func, int line, const char *fmt, ...) 31 | { 32 | va_list args; 33 | time_t tstamp = time(NULL); 34 | struct tm *local_time = localtime(&tstamp); 35 | char time_buf[64]; 36 | 37 | time_buf[strftime(time_buf, sizeof(time_buf), "%Y-%m-%d %H:%M:%S", local_time)] = '\0'; 38 | 39 | #if __ANDROID__ || (__APPLE__ && TARGET_OS_IPHONE) 40 | // iOS Debugging - Sandboxed logging can't write file. This might extend even into Android! 41 | // Can't write to files without the file permission... so don't do that if we're on iOS/Android. 42 | // https://github.com/SoftwareGuy/ENet-CSharp/issues/15 43 | 44 | // Write the initial debug text to stdout. 45 | printf("%s [%s] [%s:%d] ", time_buf, enet_log_type_names[type], func, line); 46 | 47 | // Write our arguments and related stuff to stdout, then newline it. 48 | va_start(args, fmt); 49 | vprintf(fmt, args); 50 | va_end(args); 51 | printf("\n"); 52 | 53 | // -- End logging for Android and Apple iOS -- // 54 | #else 55 | // Open the log file, and if we can't, then short-circuit. 56 | if (!enet_log_fp) enet_log_fp = fopen(ENET_LOG_FILE, "a"); 57 | if (!enet_log_fp) return; 58 | 59 | // Write the initial debug text to buffer. 60 | fprintf(enet_log_fp, "%s [%s] [%s:%d] ", time_buf, enet_log_type_names[type], func, line); 61 | 62 | // Write our arguments and related stuff to buffer. 63 | va_start(args, fmt); 64 | vfprintf(enet_log_fp, fmt, args); 65 | va_end(args); 66 | 67 | // Write new line marker, then flush and wrap up. 68 | fprintf(enet_log_fp, "\n"); 69 | fflush(enet_log_fp); 70 | 71 | // -- End logging for other platforms -- // 72 | #endif 73 | } 74 | #else 75 | // We are not building a debug library, stub the functions. 76 | #define ENET_LOG_TRACE(...) ((void)0) 77 | #define ENET_LOG_ERROR(...) ((void)0) 78 | #endif 79 | 80 | // end ifndef 81 | #endif -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (c) 2019 Chris Burns 3 | # 4 | # Permission is hereby granted, free of charge, to any person obtaining a copy 5 | # of this software and associated documentation files (the "Software"), to deal 6 | # in the Software without restriction, including without limitation the rights 7 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | # copies of the Software, and to permit persons to whom the Software is 9 | # furnished to do so, subject to the following conditions: 10 | # 11 | # The above copyright notice and this permission notice shall be included in all 12 | # copies or substantial portions of the Software. 13 | # 14 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | # SOFTWARE. 21 | # 22 | 23 | set(ENET_LIB_NAME enet) 24 | cmake_minimum_required(VERSION 3.1) 25 | project(${ENET_LIB_NAME} LANGUAGES C) 26 | 27 | set(ENET_DEBUG OFF CACHE BOOL "Enables debug and trace logging") 28 | set(ENET_PLUGIN_DIR_BASE "${CMAKE_CURRENT_SOURCE_DIR}/Unity/Plugins") 29 | set(ENET_PLUGIN_DIR_ARCH "x86_64") 30 | set(ENET_DEFINES -DENET_NO_PRAGMA_LINK -DENET_DLL) 31 | set(ENET_DEPS "") 32 | set(ENET_SRCDIR "Source/Native") 33 | set(ENET_SRCS 34 | ${ENET_SRCDIR}/enet.c 35 | ${ENET_SRCDIR}/enet.h 36 | ${ENET_SRCDIR}/custom/enet_logging.h 37 | ) 38 | 39 | if(ENET_DEBUG) 40 | list(APPEND ENET_DEFINES -DENET_DEBUG) 41 | endif() 42 | 43 | if(MSVC) 44 | set(CompilerFlags 45 | CMAKE_C_FLAGS 46 | CMAKE_C_FLAGS_RELEASE 47 | CMAKE_C_FLAGS_DEBUG 48 | ) 49 | foreach(CompilerFlag ${CompilerFlags}) 50 | string(REPLACE "/MD" "/MT" ${CompilerFlag} "${${CompilerFlag}}") 51 | endforeach() 52 | 53 | list(APPEND ENET_DEFINES -D_CRT_SECURE_NO_WARNINGS) 54 | list(APPEND ENET_DEPS Ws2_32 Winmm) 55 | endif() 56 | 57 | include_directories(${ENET_SRCDIR}) 58 | add_library(${ENET_LIB_NAME} SHARED ${ENET_SRCS}) 59 | target_link_libraries(${ENET_LIB_NAME} ${ENET_DEPS}) 60 | target_compile_definitions(${ENET_LIB_NAME} PRIVATE ${ENET_DEFINES}) 61 | 62 | set(ENET_PLUGIN_DIR ${ENET_PLUGIN_DIR_BASE}/${ENET_PLUGIN_DIR_ARCH}) 63 | set(ENET_LIB_PREFIX ${CMAKE_SHARED_LIBRARY_PREFIX}) 64 | string(REPLACE ".dylib" ".bundle" ENET_LIB_SUFFIX ${CMAKE_SHARED_LIBRARY_SUFFIX}) 65 | set(ENET_PLUGIN_NAME ${ENET_LIB_PREFIX}${ENET_LIB_NAME}${ENET_LIB_SUFFIX}) 66 | 67 | file(MAKE_DIRECTORY ${ENET_PLUGIN_DIR}) 68 | add_custom_command( 69 | TARGET ${ENET_LIB_NAME} 70 | POST_BUILD 71 | COMMAND ${CMAKE_COMMAND} -E copy 72 | $ 73 | ${ENET_PLUGIN_DIR}/${ENET_PLUGIN_NAME} 74 | ) 75 | -------------------------------------------------------------------------------- /MSBuild/Common/BannerTask.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2019 Chris Burns 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in all 12 | * copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | * SOFTWARE. 21 | */ 22 | using System; 23 | using System.IO; 24 | using System.Threading; 25 | using Microsoft.Build.Framework; 26 | using Microsoft.Build.Utilities; 27 | 28 | public class BannerTask : Task 29 | { 30 | ITaskItem _textFileItem; 31 | FileStream _fileStream; 32 | StreamReader _filein; 33 | StreamWriter _stdout; 34 | bool _taskSucceeded; 35 | int _width; 36 | 37 | [Required] 38 | public ITaskItem TextFile { get; set; } 39 | 40 | public override bool Execute() 41 | { 42 | try 43 | { 44 | _textFileItem = TextFile; 45 | if (_textFileItem == null || _textFileItem.ItemSpec.Length <= 0) 46 | { 47 | throw new FileNotFoundException("Invalid TaskItem passed to BannerTask::TextFile"); 48 | } 49 | 50 | _taskSucceeded = true; 51 | using (_fileStream = new FileStream(_textFileItem.ItemSpec, FileMode.Open, FileAccess.Read)) 52 | using (_filein = new StreamReader(_fileStream)) 53 | using (_stdout = new StreamWriter(Console.OpenStandardOutput())) 54 | { 55 | _stdout.AutoFlush = true; 56 | _width = Console.BufferWidth; 57 | if (_width >= 80) 58 | { 59 | while (_filein.Peek() > 0) 60 | { 61 | _stdout.WriteLine(_filein.ReadLine()); 62 | Thread.Sleep(5); 63 | } 64 | } 65 | } 66 | } 67 | catch (Exception e) 68 | { 69 | Log.LogError("ENET-CSharp Build Error: " + e.Message); 70 | // c6: oh i know how to fix that; it needs to just skip the console output thing if its win7 71 | // _taskSucceeded = false; 72 | } 73 | 74 | return _taskSucceeded; 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /COMMON-MISTAKES.md: -------------------------------------------------------------------------------- 1 | ## Common Mistakes working with ENet-CSharp 2 | 3 | This file describes some mistakes that newcomers or even experienced veterans can make. Here's some that have been collected over time. 4 | 5 | ### `Packet.Dispose()` called right after sending a packet. 6 | 7 | Never dispose a packet after enqueuing it for sending, ENet does that for you automatically. Otherwise, a memory access failure will occur. 8 | 9 | ### `Packet.Dispose()` called more than once per received packet. 10 | 11 | The `Packet` structure is a value type thus internal checks will fail for two different copies of a packet and a memory access failure will occur. Try to keep processing flow under strict control. If the received packet will be sent further, you should not dispose it since ENet will use it as you normally enqueuing a packet for sending. 12 | 13 | ### Channels limit didn't match at the endpoints. 14 | 15 | Always make sure that the channel limit set to the same value at the endpoints using `Host.Create()` and `Host.Connect()` functions. Failure to do so otherwise results in packets will not be delivered on disabled channels. 16 | 17 | Example: If the server has 10 channels, but the client only has 8 specified, packets channels 9 and 10 will not be accepted. 18 | 19 | ### Round-trip time is unstable even on localhost. 20 | 21 | This is the first indication that the `Host.Service()` is not called often enough. Make sure that the service and events are processed continuously and nothing prevents the ENet to shuttle packets across peers. 22 | 23 | ### Latency gets higher relatively to a count of concurrent connections. 24 | 25 | Make sure that only the actual payload is sent and not a whole buffer, a packet should be created with the correct length using the `Packet.Create()` function. Check that the ENet is not overwhelmed with large [reliably fragmented](https://github.com/SoftwareGuy/ENet-CSharp/DOCUMENTATION.md#packetflags) packets. 26 | 27 | ### A host is unable to accept multiple connections or degrades with many packets. 28 | 29 | Make sure that the service is processing as many events as possible and not only one event per frame/iteration. Put the service into a loop even within a game loop (but without a timeout to avoid blocking). 30 | If nothing helps, you can try to increase the socket buffer size of the [host](https://github.com/SoftwareGuy/ENet-CSharp/DOCUMENTATION.md#host) up to one megabyte using the appropriate parameter at both ends. 31 | 32 | Example: If using the Unity Engine, you can carefully put ENet into it's own C# thread. This decouples Enet away from the Unity main loop. 33 | 34 | ### A host is not flushed after the service is no longer in a loop. 35 | 36 | Always flush the host before the end of a session to ensure that all queued packets and protocol commands were sent to its designated peers. 37 | 38 | ### Unreliable packets are dropped significantly under simulation of latency. 39 | 40 | If the simulated delay/ping is applied in the middle of the process but not before connection establishment, then unreliable packets will be throttled if simulated latency exceeds the threshold (40 ms by default between service updates). 41 | 42 | See the description of `Peer.ConfigureThrottle()` [here](https://github.com/SoftwareGuy/ENet-CSharp/blob/master/DOCUMENTATION.md#peer) for details and parameters tuning. 43 | 44 | This document will be updated as time goes on. 45 | -------------------------------------------------------------------------------- /Directory.Build.props: -------------------------------------------------------------------------------- 1 | 22 | 23 | 24 | 25 | $(MSBuildThisFileDirectory) 26 | $(SlnDir)\ 27 | 28 | $(SlnDir)MSBuild\ 29 | 30 | $(MSBuildExtensionsPath) 31 | $(SdkDir)\ 32 | 33 | 34 | 35 | true 36 | true 37 | true 38 | 39 | 40 | 41 | $(DefineConstants);EN_PLATFORM_WINDOWS;EN_SOCK_API_WINSOCK 42 | 43 | 44 | 45 | $(DefineConstants);EN_PLATFORM_LINUX;EN_SOCK_API_POSIX 46 | 47 | 48 | 49 | $(DefineConstants);EN_PLATFORM_OSX;EN_SOCK_API_POSIX 50 | 51 | 52 | 53 | $(SlnDir)build_cmake_enet\ 54 | $(PluginDir)$(Configuration)\ 55 | 56 | enet 57 | 58 | lib 59 | lib 60 | 61 | dll 62 | so 63 | dylib 64 | 65 | 66 | 67 | -------------------------------------------------------------------------------- /Build-iOS/Build-iOS.command: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # CMake-powered script for compiling iOS builds of ENET 3 | # Script written by Coburn (SoftwareGuy) as part of the forked 4 | # version of upstream ENET-CSharp tree. 5 | # Licensed under MIT. Don't be a code thief. 6 | 7 | OLDDIR=$(pwd) 8 | CMAKE=$(which cmake) 9 | CODE_ROOT=$(pwd) 10 | UPPER_ROOT="$(pwd)/.." 11 | DEBUG_STATUS=0 12 | 13 | # Change this to OS64 for ARM64 only builds, OS for ARMv7 + ARM64 builds 14 | DEV_TYPE="OS" 15 | # Change this for Release/Debug versions 16 | BUILD_TYPE="Release" 17 | 18 | # Banner 19 | echo "-------------" 20 | echo "iOS Build Script for ENET, by Coburn (SoftwareGuy)" 21 | echo "Make sure you get the latest from http://github.com/SoftwareGuy/ENet-CSharp" 22 | echo "This script is beta quality and may break. Fixes welcome. Report them on the git." 23 | echo "-------------" 24 | 25 | # Phase 1 26 | if [ -d build ] 27 | then 28 | echo "Removing directory contents for a clean iOS build" 29 | rm -vrf build/* 30 | else 31 | echo "Making directory for iOS Building..." 32 | mkdir build 33 | fi 34 | 35 | # Phase 2 36 | # cd build 37 | 38 | if [ -f $CMAKE ] 39 | then 40 | echo "Setting up Xcode project for building..." 41 | 42 | if [ $BUILD_TYPE == "Debug" ] 43 | then 44 | echo "*** DEBUG TARGET: RESULTING LIBRARY WILL BE A DEBUG BUILD ***" 45 | echo "" 46 | DEBUG_STATUS=1 47 | fi 48 | 49 | cmake $CODE_ROOT -B$CODE_ROOT/build -G Xcode -DCMAKE_TOOLCHAIN_FILE=$UPPER_ROOT/MobileToolchains/ios.toolchain.cmake -DPLATFORM=OS -DENABLE_ARC=0 -DENABLE_VISIBILITY=0 -DENET_DEBUG=$DEBUG_STATUS -DENET_STATIC=1 -DENET_SHARED=0 -DCMAKE_XCODE_ATTRIBUTE_CODE_SIGNING_ALLOWED=NO 50 | 51 | if [ $? -eq 0 ] 52 | then 53 | # Phase 3 54 | cd $CODE_ROOT/build 55 | 56 | if [ -f $(which xcodebuild) ] 57 | then 58 | [ ! -d Release-iphoneos ] && rm -rvf Release-iphoneos && mkdir Release-iphoneos 59 | [ ! -d Debug-iphoneos ] && rm -rvf Debug-iphoneos && mkdir Debug-iphoneos 60 | xcodebuild -configuration $BUILD_TYPE 61 | 62 | if [ $? -eq 0 ] 63 | then 64 | echo "*** SUCCESSFUL BUILD! ***" 65 | echo "" 66 | echo "Good show, good show. Nicely done." 67 | echo "You'll find the static library under the respective folder, " 68 | echo "ie. Release-iphoneos or Debug-iphoneos . You may also want " 69 | echo "to run a 'lipo -archs libenet.a' check on that file to " 70 | echo "ensure that your architecture has been compiled in. " 71 | else 72 | echo "*** ERROR: XCode Build Failed! Check the logs and " 73 | echo "make sure you have updated XCode. It might be simple " 74 | echo "fix, but it might also be something complex." 75 | fi 76 | else 77 | echo "*** ERROR: You don't seem to have XCode installed correctly!" 78 | echo "*** How do you expect this script to compile ENET?" 79 | fi 80 | 81 | else 82 | echo "*** ERROR: CMake reported a failure. Sorry, but we can't continue!" 83 | echo "*** Hint: Check the logs and see if it's an easy fix. Otherwise, " 84 | echo "*** file a bug report on the GitHub with what happened." 85 | fi 86 | else 87 | echo "*** ERROR: CMake is not present on your device!" 88 | echo "*** You probably need to install either the XCode Command Line tools, " 89 | echo "*** or grab a third party package manager like Homebrew and install " 90 | echo "*** a copy of CMake that way. Sorry, but we can't continue!" 91 | fi 92 | 93 | # Get back to the directory you were in. 94 | cd $pwd 95 | 96 | # Bye bye. 97 | echo "" 98 | echo "Thanks for using SoftwareGuy's fork of ENet-CSharp!" 99 | echo "Support the fork at http://github.com/SoftwareGuy/ENet-CSharp" 100 | -------------------------------------------------------------------------------- /QUICKSTART-EXAMPLES.md: -------------------------------------------------------------------------------- 1 | # ENet-CSharp Quickstart Examples 2 | 3 | ## A server code example: 4 | 5 | ```c# 6 | using (Host server = new Host()) { 7 | Address address = new Address(); 8 | 9 | address.Port = port; 10 | server.Create(address, maxClients); 11 | 12 | Event netEvent; 13 | 14 | while (!Console.KeyAvailable) { 15 | bool polled = false; 16 | 17 | while (!polled) { 18 | if (server.CheckEvents(out netEvent) <= 0) { 19 | if (server.Service(15, out netEvent) <= 0) 20 | break; 21 | 22 | polled = true; 23 | } 24 | 25 | switch (netEvent.Type) { 26 | case EventType.None: 27 | break; 28 | 29 | case EventType.Connect: 30 | Console.WriteLine($"Client connected - ID: {netEvent.Peer.ID}, IP: {netEvent.Peer.IP}"); 31 | break; 32 | 33 | case EventType.Disconnect: 34 | Console.WriteLine($"Client disconnected - ID: {netEvent.Peer.ID}, IP: {netEvent.Peer.IP}"); 35 | break; 36 | 37 | case EventType.Timeout: 38 | Console.WriteLine($"Client timeout - ID: {netEvent.Peer.ID}, IP: {netEvent.Peer.IP}"); 39 | break; 40 | 41 | case EventType.Receive: 42 | Console.WriteLine($"Packet received from peer ID: {netEvent.Peer.ID}, IP: {netEvent.Peer.IP}, Channel ID: {netEvent.ChannelID}, Data length: {netEvent.Packet.Length}"); 43 | netEvent.Packet.Dispose(); 44 | break; 45 | } 46 | } 47 | } 48 | 49 | server.Flush(); 50 | } 51 | ``` 52 | 53 | ## A client code sample: 54 | 55 | ```c# 56 | using (Host client = new Host()) { 57 | Address address = new Address(); 58 | 59 | address.SetHost(ip); 60 | address.Port = port; 61 | client.Create(); 62 | 63 | Peer peer = client.Connect(address); 64 | 65 | Event netEvent; 66 | 67 | while (!Console.KeyAvailable) { 68 | bool polled = false; 69 | 70 | while (!polled) { 71 | if (client.CheckEvents(out netEvent) <= 0) { 72 | if (client.Service(15, out netEvent) <= 0) 73 | break; 74 | 75 | polled = true; 76 | } 77 | 78 | switch (netEvent.Type) { 79 | case EventType.None: 80 | break; 81 | 82 | case EventType.Connect: 83 | Console.WriteLine("Client connected to server"); 84 | break; 85 | 86 | case EventType.Disconnect: 87 | Console.WriteLine("Client disconnected from server"); 88 | break; 89 | 90 | case EventType.Timeout: 91 | Console.WriteLine("Client connection timeout"); 92 | break; 93 | 94 | case EventType.Receive: 95 | Console.WriteLine($"Packet received from server - Channel ID: {netEvent.ChannelID}, Data length: {netEvent.Packet.Length}"); 96 | netEvent.Packet.Dispose(); 97 | break; 98 | } 99 | } 100 | } 101 | 102 | client.Flush(); 103 | } 104 | ``` 105 | 106 | ## Create and send a new packet: 107 | ```csharp 108 | Packet packet = default(Packet); 109 | byte[] data = new byte[64]; 110 | 111 | packet.Create(data); 112 | peer.Send(channelID, ref packet); 113 | ``` 114 | 115 | ## Copy payload from a packet: 116 | ```csharp 117 | byte[] buffer = new byte[1024]; 118 | 119 | netEvent.Packet.CopyTo(buffer); 120 | ``` 121 | 122 | ## (Pro-tier) Using a custom memory allocator: 123 | ```csharp 124 | AllocCallback OnMemoryAllocate = (size) => { 125 | return Marshal.AllocHGlobal(size); 126 | }; 127 | 128 | FreeCallback OnMemoryFree = (memory) => { 129 | Marshal.FreeHGlobal(memory); 130 | }; 131 | 132 | NoMemoryCallback OnNoMemory = () => { 133 | throw new OutOfMemoryException(); 134 | }; 135 | 136 | Callbacks callbacks = new Callbacks(OnMemoryAllocate, OnMemoryFree, OnNoMemory); 137 | 138 | if (ENet.Library.Initialize(callbacks)) 139 | Console.WriteLine("ENet successfully initialized using a custom memory allocator"); 140 | ``` 141 | -------------------------------------------------------------------------------- /ENet-CSharp.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 16 4 | VisualStudioVersion = 16.0.29209.62 5 | MinimumVisualStudioVersion = 15.0.26124.0 6 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "MSBuild", "MSBuild", "{3C9CA6C8-3AAB-4D16-BF28-E66AA81F9854}" 7 | EndProject 8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CMake", "MSBuild\CMake\CMake.csproj", "{CB21753B-56F0-46D2-8495-40CC8F5915A7}" 9 | EndProject 10 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ENetCSharp", "MSBuild\ENetCSharp\ENetCSharp.csproj", "{311EBFD0-E0DE-439E-9AE3-CBE210E1A9EF}" 11 | EndProject 12 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ENetTests", "MSBuild\ENetTests\ENetTests.csproj", "{E25F1A0A-7FCB-4CA2-9CFF-AAE6DD28EB0E}" 13 | EndProject 14 | Global 15 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 16 | Debug|Any CPU = Debug|Any CPU 17 | Debug|x64 = Debug|x64 18 | Debug|x86 = Debug|x86 19 | Release|Any CPU = Release|Any CPU 20 | Release|x64 = Release|x64 21 | Release|x86 = Release|x86 22 | EndGlobalSection 23 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 24 | {CB21753B-56F0-46D2-8495-40CC8F5915A7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 25 | {CB21753B-56F0-46D2-8495-40CC8F5915A7}.Debug|Any CPU.Build.0 = Debug|Any CPU 26 | {CB21753B-56F0-46D2-8495-40CC8F5915A7}.Debug|x64.ActiveCfg = Debug|Any CPU 27 | {CB21753B-56F0-46D2-8495-40CC8F5915A7}.Debug|x64.Build.0 = Debug|Any CPU 28 | {CB21753B-56F0-46D2-8495-40CC8F5915A7}.Debug|x86.ActiveCfg = Debug|Any CPU 29 | {CB21753B-56F0-46D2-8495-40CC8F5915A7}.Debug|x86.Build.0 = Debug|Any CPU 30 | {CB21753B-56F0-46D2-8495-40CC8F5915A7}.Release|Any CPU.ActiveCfg = Release|Any CPU 31 | {CB21753B-56F0-46D2-8495-40CC8F5915A7}.Release|Any CPU.Build.0 = Release|Any CPU 32 | {CB21753B-56F0-46D2-8495-40CC8F5915A7}.Release|x64.ActiveCfg = Release|Any CPU 33 | {CB21753B-56F0-46D2-8495-40CC8F5915A7}.Release|x64.Build.0 = Release|Any CPU 34 | {CB21753B-56F0-46D2-8495-40CC8F5915A7}.Release|x86.ActiveCfg = Release|Any CPU 35 | {CB21753B-56F0-46D2-8495-40CC8F5915A7}.Release|x86.Build.0 = Release|Any CPU 36 | {311EBFD0-E0DE-439E-9AE3-CBE210E1A9EF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 37 | {311EBFD0-E0DE-439E-9AE3-CBE210E1A9EF}.Debug|Any CPU.Build.0 = Debug|Any CPU 38 | {311EBFD0-E0DE-439E-9AE3-CBE210E1A9EF}.Debug|x64.ActiveCfg = Debug|Any CPU 39 | {311EBFD0-E0DE-439E-9AE3-CBE210E1A9EF}.Debug|x64.Build.0 = Debug|Any CPU 40 | {311EBFD0-E0DE-439E-9AE3-CBE210E1A9EF}.Debug|x86.ActiveCfg = Debug|Any CPU 41 | {311EBFD0-E0DE-439E-9AE3-CBE210E1A9EF}.Debug|x86.Build.0 = Debug|Any CPU 42 | {311EBFD0-E0DE-439E-9AE3-CBE210E1A9EF}.Release|Any CPU.ActiveCfg = Release|Any CPU 43 | {311EBFD0-E0DE-439E-9AE3-CBE210E1A9EF}.Release|Any CPU.Build.0 = Release|Any CPU 44 | {311EBFD0-E0DE-439E-9AE3-CBE210E1A9EF}.Release|x64.ActiveCfg = Release|Any CPU 45 | {311EBFD0-E0DE-439E-9AE3-CBE210E1A9EF}.Release|x64.Build.0 = Release|Any CPU 46 | {311EBFD0-E0DE-439E-9AE3-CBE210E1A9EF}.Release|x86.ActiveCfg = Release|Any CPU 47 | {311EBFD0-E0DE-439E-9AE3-CBE210E1A9EF}.Release|x86.Build.0 = Release|Any CPU 48 | {E25F1A0A-7FCB-4CA2-9CFF-AAE6DD28EB0E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 49 | {E25F1A0A-7FCB-4CA2-9CFF-AAE6DD28EB0E}.Debug|Any CPU.Build.0 = Debug|Any CPU 50 | {E25F1A0A-7FCB-4CA2-9CFF-AAE6DD28EB0E}.Debug|x64.ActiveCfg = Debug|Any CPU 51 | {E25F1A0A-7FCB-4CA2-9CFF-AAE6DD28EB0E}.Debug|x64.Build.0 = Debug|Any CPU 52 | {E25F1A0A-7FCB-4CA2-9CFF-AAE6DD28EB0E}.Debug|x86.ActiveCfg = Debug|Any CPU 53 | {E25F1A0A-7FCB-4CA2-9CFF-AAE6DD28EB0E}.Debug|x86.Build.0 = Debug|Any CPU 54 | {E25F1A0A-7FCB-4CA2-9CFF-AAE6DD28EB0E}.Release|Any CPU.ActiveCfg = Release|Any CPU 55 | {E25F1A0A-7FCB-4CA2-9CFF-AAE6DD28EB0E}.Release|Any CPU.Build.0 = Release|Any CPU 56 | {E25F1A0A-7FCB-4CA2-9CFF-AAE6DD28EB0E}.Release|x64.ActiveCfg = Release|Any CPU 57 | {E25F1A0A-7FCB-4CA2-9CFF-AAE6DD28EB0E}.Release|x64.Build.0 = Release|Any CPU 58 | {E25F1A0A-7FCB-4CA2-9CFF-AAE6DD28EB0E}.Release|x86.ActiveCfg = Release|Any CPU 59 | {E25F1A0A-7FCB-4CA2-9CFF-AAE6DD28EB0E}.Release|x86.Build.0 = Release|Any CPU 60 | EndGlobalSection 61 | GlobalSection(SolutionProperties) = preSolution 62 | HideSolutionNode = FALSE 63 | EndGlobalSection 64 | GlobalSection(NestedProjects) = preSolution 65 | {CB21753B-56F0-46D2-8495-40CC8F5915A7} = {3C9CA6C8-3AAB-4D16-BF28-E66AA81F9854} 66 | {311EBFD0-E0DE-439E-9AE3-CBE210E1A9EF} = {3C9CA6C8-3AAB-4D16-BF28-E66AA81F9854} 67 | {E25F1A0A-7FCB-4CA2-9CFF-AAE6DD28EB0E} = {3C9CA6C8-3AAB-4D16-BF28-E66AA81F9854} 68 | EndGlobalSection 69 | GlobalSection(ExtensibilityGlobals) = postSolution 70 | SolutionGuid = {F6AF2E99-F5E4-4098-9468-EA8E26ACBE57} 71 | EndGlobalSection 72 | EndGlobal 73 | -------------------------------------------------------------------------------- /BUILD-FOR-SWITCH.txt: -------------------------------------------------------------------------------- 1 | Hi all, 2 | 3 | over the last couple of days, I ported the native part of enet to the Nintendo Switch. The Switch being a platform under a strict NDA means I can't share code. But I want to help to make porting easier in the future. Also, I have not fully tested the c#-bindings with my version of enet; In general everything should work, but I will post a small update as soon as I have tried it out with a better example. 4 | 5 | First things first; 6 | * Almost everybody is using Visual Studio to develop for the Switch; 7 | * Switch has its own toolchain based on clang 8 | * Switch is not allowing every feature of c/cpp on its platform (can't go super in depth about it) 9 | 10 | Obviously, I did not have to change much to get it up and running on windows. But had to add a couple of preprocessor #ifs and #elses :) 11 | 12 | The first big change is when enet figures out the platform and compiler it is building on. 13 | The Switch is Unix based but not directly compatible with most of the Unix networking headers. In general, you can probably get it working using the standard. But during submission, you will fail due to not using the specific headers. 14 | 15 | :::Systems differences::: 16 | Old: 17 | #ifdef _WIN32 18 | //Windows stuff 19 | #else 20 | //Unix stuff 21 | #endif 22 | 23 | New: 24 | #ifdef _WIN32 25 | //Windows stuff 26 | #elif defined(unix) || defined(__unix__) || defined(__unix) //UNIX 27 | //unix stuff 28 | #elif <<>> 29 | //Nintendo stuff 30 | #endif 31 | 32 | A good thing here is that most of the things we do in Unix we can do on the Switch, but still a couple of things that are not supported. Its also good to know that the switch does not need to include all the header files we need in the Unix version. Basically, everything is combined into "a switch socket header". 33 | 34 | Things that don't work on the switch: 35 | #define ENET_HOST_ANY in6addr_any 36 | #define ENET_HOST_TO_NET_16(value) (htons(value)) 37 | #define ENET_HOST_TO_NET_32(value) (htonl(value)) 38 | #define ENET_NET_TO_HOST_16(value) (ntohs(value)) 39 | #define ENET_NET_TO_HOST_32(value) (ntohl(value)) 40 | 41 | So I wrapped those in a define and changed them to the switch version. in6addr_any is not allowed so we have to switch to the ipv4 version. htons and friends have an appropriate switch function to be used. 42 | 43 | Here we can clearly see the first big picture. Every function, every define, every typedef related to sockets has to be changed. Most of the changes are trivial and just have different naming. 44 | 45 | So for example: 46 | #if defined(ENET_WIN) || defined(ENET_UNIX) 47 | #define ENET_HOST_TO_NET_16(value) (htons(value)) 48 | #elif defined (ENET_NINTENDO) 49 | #define ENET_HOST_TO_NET_16(value) (<<>>) 50 | #else 51 | #error 52 | #endif 53 | 54 | Not being able to use in6addr_any proved to be one of the bigger challenges and so far I have not found a good solution on how to change that and still be able to use the original Enet.cs Binding file. 55 | 56 | #if defined(ENET_NINTENDO) 57 | typedef struct _ENetAddress { 58 | <<>> host; 59 | enet_uint16 port; 60 | enet_uint16 scope; 61 | } ENetAddress; 62 | 63 | #define in6_equal(in6_addr_a, in6_addr_b) (memcmp(&in6_addr_a, &in6_addr_b, sizeof(<<>>)) == 0) 64 | #else // ENET_WIN or ENET_UNIX -> breakes bindings here. 65 | typedef struct _ENetAddress { 66 | struct in6_addr host; 67 | enet_uint16 port; 68 | enet_uint16 scope; 69 | } ENetAddress; 70 | 71 | #define in6_equal(in6_addr_a, in6_addr_b) (memcmp(&in6_addr_a, &in6_addr_b, sizeof(struct in6_addr)) == 0) 72 | #endif 73 | 74 | :::Atomics::: 75 | Proved to be the other big problem. Because we have to use Visual Studio and a different (not windows based) toolchain. 76 | I changed the 77 | #ifdef _MSC_VER 78 | to 79 | #if defined(_MSC_VER) && defined(ENET_WIN) 80 | That way I can exclude windows specifics. 81 | 82 | The switch being based clang is able to use __atomic_* and the likes but when debugging via Visual Studio IntelliSense keeps reporting errors. Which is annoying. Using the __INTELLISENSE__ preprocessor helped to shut it up. 83 | 84 | In the end I defined a function for each atomic operation: 85 | #ifdef __INTELLISENSE__ 86 | int32_t enet_atomic_load32(const int32_t* ptr, int memorder); 87 | #endif 88 | 89 | #if defined(ENET_WIN) 90 | static __inline int32_t enet_atomic_load32(const int32_t* ptr, int memorder) { 91 | //.. 92 | } 93 | #elif defined(ENET_UNIX) || defined(ENET_NINTENDO) 94 | static __inline int32_t enet_atomic_load32(int32_t* ptr, int memorder) { 95 | return __atomic_load_n(ptr, memorder); 96 | } 97 | #endif 98 | 99 | That helped a lot :) 100 | 101 | :::Platform Specific (Unix)::: 102 | As I already said, each socket function has to be changed. Most of those changes are easy. Keep in mind the socket address is ipv4 instead of ipv6: 103 | For example: 104 | From: 105 | ((enet_uint32*)&address->host.s6_addr)[0] = 0; 106 | ((enet_uint32*)&address->host.s6_addr)[1] = 0; 107 | ((enet_uint32*)&address->host.s6_addr)[2] = ENET_HOST_TO_NET_32(0xFFFF); 108 | ((enet_uint32*)&address->host.s6_addr)[3] = sin->sin_addr.s_addr; 109 | 110 | To: 111 | address->host = sin->sin_addr.S_addr; 112 | 113 | pollfd is not directly usable on the switch and is wrapped via different functions. (all in all a very easy change) 114 | 115 | Other than that. The Nintendo switch requires explicit initialization of all socket buffers. It is able to do that with a simple config and function call. I've not yet fully understood the implications here because somehow I need it in a c/cpp only test application but not when I use enet via Unity, maybe the Unity SDK does something here. Could be wrapped into enet_initialize, enet_deinitialize, I suppose. 116 | 117 | I think that's "all" in a c/cpp sense. 118 | 119 | Obviously, I had to change the Enet.cs part: 120 | 121 | From: 122 | [StructLayout(LayoutKind.Sequential)] 123 | public struct ENetAddress { 124 | [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] 125 | public byte[] host; 126 | public ushort port; 127 | public ushort scope; 128 | } 129 | 130 | to 131 | 132 | [StructLayout(LayoutKind.Sequential)] 133 | public struct ENetAddress { 134 | public uint host; 135 | public ushort port; 136 | public ushort scope; 137 | } -------------------------------------------------------------------------------- /BuildScripts/apple-ios.command: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Script modified from upstream at the following URL: 3 | # https://github.com/nxrighthere/ENet-CSharp/blob/master/Source/Native/build-ios.sh 4 | # Original portions by JohannesDeml, modifications by Coburn. 5 | 6 | # Cache this for later. 7 | # Point sysdir to iOS SDK 8 | RELEASE_SDKROOT="/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS.sdk" 9 | SIMULATOR_SDKROOT="/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator.sdk" 10 | WORKSPACE="$(pwd)" 11 | OUTPUT="$WORKSPACE/Binaries" 12 | X64_SIMULATOR_STAGING="$WORKSPACE/x86_64-apple-ios-simulator" 13 | ARM64_STAGING="$WORKSPACE/arm64-apple-ios" 14 | ARMV7_STAGING="$WORKSPACE/armv7-apple-ios" 15 | 16 | # Function declaration 17 | create_enet_symlink() { 18 | # Only symlink if we don't have one already 19 | if [ ! -d "Sources" ]; then 20 | # Symlink work directory sources. 21 | ln -s "$WORKSPACE/../Source/Native" "Sources" 22 | if [ $? -ne 0 ]; then 23 | echo "ERROR: Failed to make symlink to ENet source code. Did you git pull this correctly? Build script aborted." 24 | exit $? 25 | fi 26 | fi 27 | } 28 | 29 | make_enet_directories() { 30 | # Output 31 | if [ ! -d "$OUTPUT" ]; then 32 | mkdir "$OUTPUT" 33 | 34 | if [ $? -ne 0 ]; then 35 | echo "ERROR: Failed to make staging directory for x64 Simulator. Build script aborted." 36 | exit $? 37 | fi 38 | else 39 | rm -rfv "$OUTPUT"/* 40 | 41 | if [ $? -ne 0 ]; then 42 | echo "ERROR: Failed to delete files inside output directory. Build script aborted." 43 | exit $? 44 | fi 45 | fi 46 | 47 | # Simulator 48 | if [ ! -d "$X64_SIMULATOR_STAGING" ]; then 49 | # Make it. 50 | mkdir "$X64_SIMULATOR_STAGING" 51 | 52 | if [ $? -ne 0 ]; then 53 | echo "ERROR: Failed to make staging directory for x64 Simulator. Build script aborted." 54 | exit $? 55 | fi 56 | else 57 | # Purge it. 58 | echo "Cleaning out existing x64 Simulator staging directory." 59 | rm -rfv "$X64_SIMULATOR_STAGING"/* 60 | 61 | if [ $? -ne 0 ]; then 62 | echo "ERROR: Failed to delete files inside staging directory. Build script aborted." 63 | exit $? 64 | fi 65 | fi 66 | 67 | # ARMv7 68 | if [ ! -d "$ARMV7_STAGING" ]; then 69 | # Make it. 70 | mkdir "$ARMV7_STAGING" 71 | 72 | if [ $? -ne 0 ]; then 73 | echo "ERROR: Failed to make staging directory for ARMv7. Build script aborted." 74 | exit $? 75 | fi 76 | else 77 | # Purge it. 78 | echo "Cleaning out existing ARMv7 staging directory." 79 | rm -rfv "$ARMV7_STAGING"/* 80 | 81 | if [ $? -ne 0 ]; then 82 | echo "ERROR: Failed to delete files inside staging directory. Build script aborted." 83 | exit $? 84 | fi 85 | fi 86 | 87 | # ARM64 88 | if [ ! -d "$ARM64_STAGING" ]; then 89 | # Make it. 90 | mkdir "$ARM64_STAGING" 91 | 92 | if [ $? -ne 0 ]; then 93 | echo "ERROR: Failed to make staging directory for ARM64. Build script aborted." 94 | exit $? 95 | fi 96 | else 97 | # Purge it. 98 | echo "Cleaning out existing ARM64 staging directory." 99 | rm -rfv "$ARM64_STAGING"/* 100 | 101 | if [ $? -ne 0 ]; then 102 | echo "ERROR: Failed to delete files inside staging directory. Build script aborted." 103 | exit $? 104 | fi 105 | fi 106 | } 107 | 108 | compile_enet_x64simulator () { 109 | echo "Start compiling x64 Simulator" 110 | export SDKROOT=$SIMULATOR_SDKROOT 111 | 112 | cd "$X64_SIMULATOR_STAGING" 113 | # Pre-clean 114 | rm -vf *.a *.o 115 | 116 | create_enet_symlink 117 | 118 | # Release Binaries 119 | gcc -c Sources/enet.c -fembed-bitcode -target x86_64-apple-ios-simulator 120 | if [ $? -ne 0 ]; then 121 | echo "ERROR: Compile step resulted in failure." 122 | exit $? 123 | fi 124 | 125 | # Create static library 126 | libtool -static enet.o -o libenet-release-simulator64.a 127 | if [ $? -ne 0 ]; then 128 | echo "ERROR: Libtool step resulted in failure." 129 | exit $? 130 | fi 131 | 132 | # Cleanup 133 | rm -vf *.o 134 | 135 | # Debug Binaries 136 | gcc -DENET_DEBUG=1 -c Sources/enet.c -fembed-bitcode -target x86_64-apple-ios-simulator 137 | if [ $? -ne 0 ]; then 138 | echo "ERROR: Compile step resulted in failure." 139 | exit $? 140 | fi 141 | libtool -static enet.o -o libenet-debug-simulator64.a 142 | if [ $? -ne 0 ]; then 143 | echo "ERROR: Libtool step resulted in failure." 144 | exit $? 145 | fi 146 | 147 | # Copy. 148 | cp -v *.a "$OUTPUT" 149 | } 150 | 151 | compile_enet_armv7 () { 152 | echo "Start compiling ARMv7" 153 | export SDKROOT=$RELEASE_SDKROOT 154 | cd "$ARMV7_STAGING" 155 | 156 | # Pre-clean 157 | rm -vf *.a *.o 158 | 159 | create_enet_symlink 160 | 161 | # Release Binaries 162 | gcc -c Sources/enet.c -fembed-bitcode -target armv7-apple-ios 163 | if [ $? -ne 0 ]; then 164 | echo "ERROR: Compile step resulted in failure." 165 | exit $? 166 | fi 167 | 168 | # Create static library 169 | libtool -static enet.o -o libenet-release-armv7.a 170 | if [ $? -ne 0 ]; then 171 | echo "ERROR: Libtool step resulted in failure." 172 | exit $? 173 | fi 174 | 175 | # Cleanup 176 | rm -vf *.o 177 | 178 | # Debug Binaries 179 | gcc -DENET_DEBUG=1 -c Sources/enet.c -fembed-bitcode -target armv7-apple-ios 180 | if [ $? -ne 0 ]; then 181 | echo "ERROR: Compile step resulted in failure." 182 | exit $? 183 | fi 184 | 185 | libtool -static enet.o -o libenet-debug-armv7.a 186 | if [ $? -ne 0 ]; then 187 | echo "ERROR: Libtool step resulted in failure." 188 | exit $? 189 | fi 190 | 191 | # Copy. 192 | cp -v *.a "$OUTPUT" 193 | } 194 | 195 | compile_enet_arm64 () { 196 | echo "Start compiling ARM64" 197 | export SDKROOT=$RELEASE_SDKROOT 198 | cd "$ARM64_STAGING" 199 | 200 | # Pre-clean 201 | rm -vf *.a *.o 202 | 203 | create_enet_symlink 204 | 205 | # Release Binaries 206 | gcc -c Sources/enet.c -fembed-bitcode -target arm64-apple-ios 207 | if [ $? -ne 0 ]; then 208 | echo "ERROR: Compile step resulted in failure." 209 | exit $? 210 | fi 211 | 212 | # Create static library 213 | libtool -static enet.o -o libenet-release-arm64.a 214 | if [ $? -ne 0 ]; then 215 | echo "ERROR: Libtool step resulted in failure." 216 | exit $? 217 | fi 218 | 219 | # Cleanup 220 | rm -v *.o 221 | 222 | # Debug Binaries 223 | gcc -DENET_DEBUG=1 -c Sources/enet.c -fembed-bitcode -target arm64-apple-ios 224 | if [ $? -ne 0 ]; then 225 | echo "ERROR: Compile step resulted in failure." 226 | exit $? 227 | fi 228 | 229 | libtool -static enet.o -o libenet-debug-arm64.a 230 | if [ $? -ne 0 ]; then 231 | echo "ERROR: Libtool step resulted in failure." 232 | exit $? 233 | fi 234 | 235 | # Copy. 236 | cp -v *.a "$OUTPUT" 237 | } 238 | 239 | compress_and_exfil() { 240 | # Good 'ol Zip. 241 | cd $OUTPUT 242 | 243 | if [ $? -ne 0 ]; then 244 | echo "WARNING: Looks like we can't enter the output directory, skipping compression phase" 245 | return 246 | fi 247 | 248 | echo "About to compress compiled binaries." 249 | zip -v -9 -j "libenet-combo-iOS.zip" *.a 250 | 251 | if [ $? -ne 0 ]; then 252 | echo "WARNING: Looks like the compression step failed, continuing as this is not fatal" 253 | fi 254 | } 255 | 256 | # Make staging directories and build. 257 | make_enet_directories 258 | compile_enet_x64simulator 259 | compile_enet_arm64 260 | compile_enet_armv7 261 | 262 | # Compress the goods. 263 | compress_and_exfil 264 | 265 | FINAL_STAND=$? 266 | 267 | echo "Build script has finished." 268 | exit $FINAL_STAND 269 | -------------------------------------------------------------------------------- /MSBuild/CMake/CMake.Build.targets: -------------------------------------------------------------------------------- 1 | 36 | 37 | 38 | 39 | enet 40 | $(SlnDir) 41 | $(SlnDir)build_cmake_enet 42 | Debug 43 | Release 44 | https://github.com/SoftwareGuy/ENet-CSharp 45 | $(CMakeOpts) -DENET_DEBUG=ON 46 | 47 | 48 | 49 | -DCMAKE_BUILD_TYPE=$(CMakeBuildType) 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | $(VisualStudioVersion.Substring(0, 2)) 63 | 64 | 65 | 66 | 67 | 14.1 68 | 14.2 69 | $(VCToolsVersion.Substring(0, 2)) 70 | $(VCToolsVersion.Substring(3, 1)) 71 | 2017 72 | 2019 73 | $(VisualStudioVersionMajor) $(CMakeVSYear) 74 | -Tv$(VCToolsVersionMajor)$(VCToolsVersionMinor) 75 | $(CMakeVSToolset) 76 | $(Platform) 77 | x64 78 | 79 | 80 | 81 | Win64 82 | $(CMakeVSArch) 83 | -G"Visual Studio $(CMakeVSGenVer)$(CMakeVSArch)"$(CMakeVSToolset) 84 | 85 | 86 | 87 | -AWin32 88 | $(CMakeVSArch) 89 | -G"Visual Studio $(CMakeVSGenVer)"$(CMakeVSArch)$(CMakeVSToolset) 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | -------------------------------------------------------------------------------- /MSBuild/ENetTests/UnitTests.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2019 Chris Burns 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in all 12 | * copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | * SOFTWARE. 21 | */ 22 | using NUnit.Framework; 23 | using System; 24 | using System.Net; 25 | using System.Diagnostics; 26 | using ENet; 27 | 28 | public class UnitTests 29 | { 30 | enum ClientState 31 | { 32 | None, 33 | Connecting, 34 | Connected, 35 | SendData, 36 | RecvData, 37 | Disconnecting, 38 | Disconnected, 39 | } 40 | 41 | [OneTimeSetUp] 42 | public void FixtureSetup() 43 | { 44 | } 45 | 46 | [OneTimeTearDown] 47 | public void FixtureCleanup() 48 | { 49 | } 50 | 51 | [SetUp] 52 | public void TestSetup() 53 | { 54 | } 55 | 56 | [TearDown] 57 | public void TestCleanup() 58 | { 59 | } 60 | 61 | [Test] 62 | public void InitAndUninit() 63 | { 64 | using (Host host = new Host()) 65 | { 66 | } 67 | } 68 | 69 | [Test] 70 | public void SendAndRecv() 71 | { 72 | const ushort port = 7777; 73 | const int maxClients = 1; 74 | const byte dataVal = 42; 75 | 76 | int clientEvents = 0; 77 | int clientConnected = 0; 78 | int clientDisconnected = 0; 79 | int clientTimeout = 0; 80 | int clientNone = 0; 81 | int clientRecvData = 0; 82 | int serverEvents = 0; 83 | int serverConnected = 0; 84 | int serverDisconnected = 0; 85 | int serverRecvData = 0; 86 | int serverTimeout = 0; 87 | int serverNone = 0; 88 | 89 | ClientState clientState = ClientState.None; 90 | 91 | using (Host client = new Host()) 92 | using (Host server = new Host()) 93 | { 94 | Address address = new Address(); 95 | address.Port = port; 96 | server.Create(address, maxClients); 97 | 98 | address.SetIP("127.0.0.1"); 99 | client.Create(); 100 | 101 | Peer clientPeer = default; 102 | Stopwatch sw = Stopwatch.StartNew(); 103 | while (clientState != ClientState.Disconnected && sw.ElapsedMilliseconds < 10000) 104 | { 105 | while (server.Service(15, out Event netEvent) > 0) 106 | { 107 | serverEvents++; 108 | switch (netEvent.Type) 109 | { 110 | case EventType.None: 111 | serverNone++; 112 | break; 113 | case EventType.Connect: 114 | serverConnected++; 115 | break; 116 | case EventType.Disconnect: 117 | serverDisconnected++; 118 | clientState = ClientState.Disconnected; 119 | break; 120 | case EventType.Timeout: 121 | serverTimeout++; 122 | break; 123 | case EventType.Receive: 124 | serverRecvData++; 125 | Packet packet = default(Packet); 126 | byte[] data = new byte[64]; 127 | netEvent.Packet.CopyTo(data); 128 | 129 | for (int i = 0; i < data.Length; i++) Assert.True(data[i] == dataVal); 130 | 131 | packet.Create(data); 132 | netEvent.Peer.Send(0, ref packet); 133 | netEvent.Packet.Dispose(); 134 | break; 135 | } 136 | } 137 | server.Flush(); 138 | 139 | while (client.Service(15, out Event netEvent) > 0) 140 | { 141 | clientEvents++; 142 | switch (netEvent.Type) 143 | { 144 | case EventType.None: 145 | clientNone++; 146 | break; 147 | case EventType.Connect: 148 | clientConnected++; 149 | clientState = ClientState.Connected; 150 | break; 151 | case EventType.Disconnect: 152 | clientDisconnected++; 153 | clientState = ClientState.Disconnected; 154 | break; 155 | case EventType.Timeout: 156 | clientTimeout++; 157 | break; 158 | case EventType.Receive: 159 | clientRecvData++; 160 | byte[] data = new byte[64]; 161 | Packet packet = netEvent.Packet; 162 | packet.CopyTo(data); 163 | for (int i = 0; i < data.Length; i++) Assert.True(data[i] == dataVal); 164 | netEvent.Packet.Dispose(); 165 | 166 | clientState = ClientState.RecvData; 167 | break; 168 | } 169 | } 170 | client.Flush(); 171 | 172 | if (clientState == ClientState.None) 173 | { 174 | clientState = ClientState.Connecting; 175 | clientPeer = client.Connect(address); 176 | } 177 | else if (clientState == ClientState.Connected) 178 | { 179 | Packet packet = default(Packet); 180 | byte[] data = new byte[64]; 181 | for (int i = 0; i < data.Length; i++) data[i] = dataVal; 182 | 183 | packet.Create(data); 184 | clientPeer.Send(0, ref packet); 185 | 186 | clientState = ClientState.SendData; 187 | } 188 | else if (clientState == ClientState.RecvData) 189 | { 190 | clientPeer.DisconnectNow(0); 191 | clientState = ClientState.Disconnecting; 192 | } 193 | } 194 | } 195 | 196 | Assert.True(clientEvents != 0, "client host never generated an event"); 197 | Assert.True(serverEvents != 0, "server host never generated an event"); 198 | 199 | Assert.True(clientState == ClientState.Disconnected, "client didn't fully disconnect"); 200 | 201 | Assert.AreEqual(1, clientConnected, "client should have connected once"); 202 | Assert.AreEqual(1, serverConnected, "server should have had one inbound connect"); 203 | 204 | Assert.AreEqual(1, clientRecvData, "client should have recvd once"); 205 | Assert.AreEqual(1, serverRecvData, "server should have recvd once"); 206 | 207 | Assert.AreEqual(0, clientTimeout, "client had timeout events"); 208 | Assert.AreEqual(0, serverTimeout, "server had timeout events"); 209 | 210 | Assert.AreEqual(0, clientNone, "client had none events"); 211 | Assert.AreEqual(0, serverNone, "server had none events"); 212 | 213 | Assert.AreEqual(1, serverDisconnected, "server should have had one client disconnect"); 214 | } 215 | } 216 | -------------------------------------------------------------------------------- /.github/workflows/MasterBuild.yaml: -------------------------------------------------------------------------------- 1 | name: Master Build 2 | 3 | on: 4 | push: 5 | tags: 6 | - 'v2.*' 7 | jobs: 8 | create_release: 9 | name: Prepare a new release 10 | runs-on: ubuntu-latest 11 | outputs: 12 | create_release_url: ${{ steps.create_release.outputs.upload_url }} 13 | 14 | steps: 15 | - name: Get the commit hash. 16 | id: commit 17 | uses: prompt/actions-commit-hash@v3 18 | 19 | - name: Create release on repository 20 | id: create_release 21 | uses: actions/create-release@master 22 | env: 23 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 24 | with: 25 | tag_name: "autobuild-${{ steps.commit.outputs.short }}" 26 | release_name: "Native Libraries (Autobuild ${{ steps.commit.outputs.short }})" 27 | body: "Automated build of the ENet native libraries, up to date with the latest commits. The attached per-platform archives contain ENet for use in both production and debugging environments." 28 | draft: false 29 | prerelease: false 30 | 31 | # START LINUX BUILD JOB 32 | build_linux64: 33 | name: Linux x86_64 34 | needs: create_release 35 | runs-on: ubuntu-latest 36 | steps: 37 | - name: Checkout 38 | uses: actions/checkout@v2 39 | 40 | - name: Create temporary staging directories 41 | run: | 42 | mkdir -p ${{ runner.workspace }}/Staging 43 | mkdir -p ${{ runner.workspace }}/Work/ReleaseBuild 44 | mkdir -p ${{ runner.workspace }}/Work/DebugBuild 45 | 46 | - name: Compile ENet (non-debug) 47 | uses: ashutoshvarma/action-cmake-build@master 48 | with: 49 | build-dir: ${{ runner.workspace }}/Work/ReleaseBuild 50 | cc: gcc 51 | cxx: g++ 52 | build-type: Release 53 | configure-options: -DENET_DEBUG=0 54 | 55 | - name: Stash and compress production library 56 | run: | 57 | zip -j -9 ${{ runner.workspace }}/Staging/Release.zip ${{ runner.workspace }}/Work/ReleaseBuild/libenet.so 58 | 59 | - name: Compile ENet (debug) 60 | uses: ashutoshvarma/action-cmake-build@master 61 | with: 62 | build-dir: ${{ runner.workspace }}/Work/DebugBuild 63 | cc: gcc 64 | cxx: g++ 65 | build-type: Debug 66 | configure-options: -DENET_DEBUG=1 67 | 68 | - name: Stash compiled libraries 69 | run: | 70 | zip -j -9 ${{ runner.workspace }}/Staging/Debug.zip ${{ runner.workspace }}/Work/DebugBuild/libenet.so 71 | 72 | - name: Upload non-debug library 73 | id: upload-release-asset 74 | uses: actions/upload-release-asset@master 75 | env: 76 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 77 | with: 78 | upload_url: ${{ needs.create_release.outputs.create_release_url }} 79 | asset_path: ${{ runner.workspace }}/Staging/Release.zip 80 | asset_name: libenet-release-linux-x86_64.zip 81 | asset_content_type: application/zip 82 | 83 | - name: Upload debug library 84 | id: upload-debug-asset 85 | uses: actions/upload-release-asset@master 86 | env: 87 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 88 | with: 89 | upload_url: ${{ needs.create_release.outputs.create_release_url }} 90 | asset_path: ${{ runner.workspace }}/Staging/Debug.zip 91 | asset_name: libenet-debug-linux-x86_64.zip 92 | asset_content_type: application/zip 93 | # END LINUX BUILD JOB 94 | 95 | # START APPLE MACOS BUILD JOB 96 | # Need to revise this - future Coburn job. 97 | # build_apple_64: 98 | # name: MacOS 99 | # needs: create_release 100 | # runs-on: macos-latest 101 | # steps: 102 | # - name: Setup XCode 103 | # uses: maxim-lobanov/setup-xcode@v1 104 | # with: 105 | # xcode-version: latest-stable 106 | # 107 | # - name: Grab the latest copy of the repository. 108 | # uses: actions/checkout@v2 109 | # 110 | # - name: Run automated build script. 111 | # run: | 112 | # cd "${{ runner.workspace }}/ENet-CSharp" && bash BuildScripts/apple-mac.command 113 | # 114 | # - name: Upload release library 115 | # id: upload-release-asset 116 | # uses: actions/upload-release-asset@master 117 | # env: 118 | # GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 119 | # with: 120 | # upload_url: ${{ needs.create_release.outputs.create_release_url }} 121 | # asset_path: ${{ runner.workspace }}/ENet-CSharp/ReleaseOut/Release.zip 122 | # asset_name: libenet-release-macOS.zip 123 | # asset_content_type: application/zip 124 | # 125 | # - name: Upload debug library 126 | # id: upload-debug-asset 127 | # uses: actions/upload-release-asset@master 128 | # env: 129 | # GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 130 | # with: 131 | # upload_url: ${{ needs.create_release.outputs.create_release_url }} 132 | # asset_path: ${{ runner.workspace }}/ENet-CSharp/DebugOut/Debug.zip 133 | # asset_name: libenet-debug-macOS.zip 134 | # asset_content_type: application/zip 135 | # 136 | # END APPLE MACOS BUILD JOB 137 | 138 | build_windows_64: 139 | name: Windows x86_64 140 | needs: create_release 141 | runs-on: windows-latest 142 | steps: 143 | - name: Checkout 144 | uses: actions/checkout@v2 145 | 146 | - name: Compile ENet (non-debug) 147 | uses: ashutoshvarma/action-cmake-build@master 148 | with: 149 | build-dir: ${{ runner.workspace }}/ReleaseBuild 150 | build-type: Release 151 | configure-options: -DENET_DEBUG=0 152 | 153 | - name: List release build directory 154 | run: | 155 | dir "${{ runner.workspace }}/ReleaseBuild/Release" 156 | 157 | - name: Compile ENet (debug) 158 | uses: ashutoshvarma/action-cmake-build@master 159 | with: 160 | build-dir: ${{ runner.workspace }}/DebugBuild 161 | build-type: Debug 162 | configure-options: -DENET_DEBUG=1 163 | 164 | - name: List debug build directory 165 | run: | 166 | dir "${{ runner.workspace }}/DebugBuild/Debug" 167 | 168 | - name: Archive release library 169 | uses: thedoctor0/zip-release@0.7.5 170 | with: 171 | type: 'zip' 172 | directory: '${{ runner.workspace }}' 173 | path: '${{ runner.workspace }}/ReleaseBuild/Release' 174 | filename: 'Release.zip' 175 | exclusions: '*.exp *.lib *.pdb' 176 | 177 | - name: Archive debug library 178 | uses: thedoctor0/zip-release@0.7.5 179 | with: 180 | type: 'zip' 181 | directory: '${{ runner.workspace }}' 182 | path: '${{ runner.workspace }}/DebugBuild/Debug' 183 | filename: 'Debug.zip' 184 | exclusions: 'enet.exp enet.lib enet.pdb' 185 | 186 | - name: Upload release library 187 | id: upload-release-asset 188 | uses: actions/upload-release-asset@master 189 | env: 190 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 191 | with: 192 | upload_url: ${{ needs.create_release.outputs.create_release_url }} 193 | asset_path: ${{ runner.workspace }}/Release.zip 194 | asset_name: libenet-release-win64.zip 195 | asset_content_type: application/zip 196 | 197 | - name: Upload debug library 198 | id: upload-debug-asset 199 | uses: actions/upload-debug-asset@master 200 | env: 201 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 202 | with: 203 | upload_url: ${{ needs.create_release.outputs.create_release_url }} 204 | asset_path: ${{ runner.workspace }}/Debug.zip 205 | asset_name: libenet-debug-win64.zip 206 | asset_content_type: application/zip 207 | 208 | 209 | # START APPLE IOS BUILD JOB 210 | build_apple_mobile: 211 | name: Build for Apple iOS 212 | needs: create_release 213 | runs-on: macos-latest 214 | steps: 215 | 216 | - name: Setup XCode 217 | uses: maxim-lobanov/setup-xcode@master 218 | with: 219 | xcode-version: latest-stable 220 | 221 | - name: Grab the latest copy of the repository. 222 | uses: actions/checkout@v2 223 | 224 | - name: Run the iOS build script 225 | run: | 226 | cd "$GITHUB_WORKSPACE/BuildScripts" && bash ./apple-ios.command 227 | 228 | - name: Upload release library 229 | id: upload-release-asset 230 | uses: actions/upload-release-asset@master 231 | env: 232 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 233 | with: 234 | upload_url: ${{ needs.create_release.outputs.create_release_url }} 235 | asset_path: ${{ runner.workspace }}/ENet-CSharp/BuildScripts/Binaries/libenet-combo-iOS.zip 236 | asset_name: libenet-combo-iOS.zip 237 | asset_content_type: application/zip 238 | # END APPLE IOS BUILD JOB 239 | 240 | # START ANDROID BUILD JOB 241 | # build_android: 242 | # name: Build for Android 243 | # needs: create_release 244 | # runs-on: ubuntu-latest 245 | # steps: 246 | # - name: Grab the latest copy of the repository. 247 | # uses: actions/checkout@v2 248 | # Stubbed! 249 | # END ANDROID BUILD JOB 250 | 251 | # end of build jobs. 252 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 | alt logo 3 |

4 | 5 | [![Ko-Fi](https://img.shields.io/badge/Donate-Ko--Fi-red)](https://ko-fi.com/coburn) 6 | [![PayPal](https://img.shields.io/badge/Donate-PayPal-blue)](https://paypal.me/coburn64) 7 | ![MIT Licensed](https://img.shields.io/badge/license-MIT-green.svg) 8 | ![Master Build](https://github.com/SoftwareGuy/ENet-CSharp/workflows/Master%20Build/badge.svg) 9 | 10 | _**Please consider a donation (see the Ko-Fi button above) if this project is useful to you.**_ 11 | 12 | ## What's this? 13 | 14 | In short, this is an independent ENet native implementation with a modified protocol for C, C++, C#, and other languages. 15 | The native C library code (although condensed) included in both this fork and upstream uses is located [here](https://github.com/lsalzman/enet). 16 | 17 | ### Why another fork? 18 | This fork started since *nxrighthere*'s repository was originally archived, disabling the ability to report issues and submit pull requests. 19 | 20 | Due to this, I forked his repository manually and this is the result. As a result, developers can ask questions about Enet, get answers and submit pull requests to improve the implementation. 21 | 22 | This repository might not always have the latest version of the implementation from upstream, as careful integration of fork-specific features needs to be taken. However, I will try to keep it in sync with upstream as much as possible. 23 | 24 | ## Native Library Features 25 | 26 | - Enhanced debugging functionality, including piping messages to console or log file (default behaviour) 27 | - Lightweight and straightforward 28 | - Low resource consumption 29 | - Dual-stack IPv4/IPv6 support 30 | - Connection management, Sequencing, Channels, Reliability, Fragmentation, Reassembly 31 | - Aggregation 32 | - Adaptability and portability 33 | 34 | ## Upstream Compatibility 35 | In theory, upstream binaries can be used with this fork unless things change dramatically. To err on the safe side, use the automatic builds located on the release page. 36 | 37 | In short: just use the automatic build binaries in [Releases](https://github.com/SoftwareGuy/ENet-CSharp/releases). 38 | 39 | ## Obtaining Native Libraries 40 | 41 | ### Easy Mode 42 | 43 | You can get precompiled binaries for use with this fork by checking out the [Releases](https://github.com/SoftwareGuy/ENet-CSharp/releases) page. 44 | 45 | ### Hard Mode 46 | 47 | If you don't want to take the automatically built libraries in the releases section, you can use the Visual Studio MS Build engine to build a binary for your platform(s). 48 | 49 | However the following will be oriented for power users and command line heroes, and requires NET Core SDK 2.2 to work correctly. 50 | 51 | #### Desktop Compiling 52 | 53 | - **Windows:** Make sure you have Visual Studio 2017 or newer installed with C++ Development Support, a recent Windows SDK and CMake. You may need to install [CMake 3.16+ from Kitware](https://cmake.org/download/) as it *sometimes* doesn't get automatically installed with Visual Studio. 54 | 55 | - **MacOS:** You'll need Xcode, which is available from the Mac App Store or the Apple Developer Portal. Make sure you also have the Apple Xcode CLI Tools installed. 56 | 57 | - **Linux:** Make sure you have your repositories' `build-essential` and `cmake` package installed. On Debian and Ubuntu-based distros, you can do `sudo apt -y build-essential cmake` to install the required packages. 58 | 59 | #### Mobile Compiling 60 | 61 | - **Android:** Ensure you have the Android NDK installed. Easiest way to do this to go into `Sources/Native` and run when `ndk-build`. A fresh batch of ENET binaries should then be spat out, which can be used in your project. 62 | 63 | - **Apple iOS:** Using **Terminal.app** on your MacOS device, navigate to the `Build-iOS` directory and run the command file found inside. You might need to make it executable, however. It will try to auto-pilot a build for you, just make sure you have CMake installed for MacOS and a recent Xcode installation. Library code signing will be disabled for the build. 64 | 65 | #### Console Compiling 66 | 67 | - **Microsoft Xbox One:** Limited testing says the Windows library should work fine, unless the Windows-based Xbox OS uses a different SDK. However, I do not have access to an XB1 Developer Kit. 68 | 69 | - **Nintendo Switch:** A old guide is available [here](https://github.com/SoftwareGuy/ENet-CSharp/blob/master/BUILD-FOR-SWITCH.txt). However, it will require patches to work with the Switch SDK. Since said SDK is under NDA, limited public info can be provided. 70 | 71 | - **Playstation 4/Vita:** I am not planning to add support for the PS4/PSVita to this repository. The native layer will most likely require patches to use on Sony's BSD-based PlayStation OS. 72 | 73 | - **Other console not listed:** Open a issue ticket and I'll gladly add your steps for your platform here. 74 | 75 | #### Recipe for victory 76 | 77 | - Clone a fresh copy of this Git Repo somewhere on your workstation's filesystem. 78 | - Open a command prompt/terminal and change directory into the newly cloned git repository. 79 | - Run `dotnet build`. A **Debug** release will be generated, unless you read the next dot point. 80 | - **Protip:** You can append `-c Release` or `-c Debug` to your `dotnet build` command to build a release binary or a debug binary of ENet. At the moment, the default build is a Debug build. 81 | 82 | You will see a [Ignorance](https://github.com/SoftwareGuy/Ignorance) banner fly by and the compile will start. CMake will then be invoked and configure the build after inspecting your environment. If all is well, a binary blob inside the `Unity/Plugins` directory will be generated. 83 | 84 | If it does not compile successfully, read the error messages it provides and file an issue ticket if you are not able to solve it yourself. 85 | 86 | On Windows, this freshly baked library will be called `enet.dll` DLL, on Mac it will be `libenet.bundle` and on Linux it will be a shared object (`libenet.so`). This can be used with Unity or other applications like a C# NET Core application or C/C++ apps. 87 | Unity users should take note that you may need to rename `libenet.bundle` to `libenet.dylib` for Unity to load the plugin at runtime. 88 | 89 | #### Rebuilding the native binaries 90 | 91 | Inside the directory that you cloned the repo to, run: 92 | 93 | - `dotnet clean` 94 | - `dotnet build` (don't forget about the `-c Release/Debug` argument as mentioned earlier!) 95 | 96 | It is recommended to clean the repository work space before building. 97 | 98 | ### Testing 99 | 100 | - `dotnet test` will run some sanity checks and make sure ENet initializes, data is received and sent correctly, etc. Right now tests are limited, but eventually will hopefully test the basics of ENet to ensure nothing is broken. 101 | 102 | ## Usage 103 | 104 | - Please make sure you initialize ENet first before doing anything by calling the `ENet.Library.Initialize();` function. 105 | - This returns **true** if successful, if not it will return **false**. 106 | - You can use this to gracefully quit your application should it fail to initialize, for example. 107 | - Once you are done with Enet, deinitialize the library using `ENet.Library.Deinitialize();` function to ensure a clean shutdown. 108 | - Using Enet-CSharp inside the Unity Engine is almost the same as in the standard .NET environment, except that the console functions must be replaced with functions provided by Unity. 109 | - If the `Host.Service()` will be called in a game loop, then make sure that the timeout parameter set to 0 which means non-blocking. 110 | - Also make sure Unity runs in the background by enabling the ***Run in Background*** player setting. 111 | 112 | ### Code Examples/Quick Start 113 | 114 | - A good idea is to check out the [common mistakes during integration](https://github.com/SoftwareGuy/ENet-CSharp/blob/master/COMMON-MISTAKES.md) documentation. 115 | - There's also some [quickstart examples](https://github.com/SoftwareGuy/ENet-CSharp/blob/master/QUICKSTART-EXAMPLES.md) to make your Enet life easier. 116 | 117 | ## API Documentation 118 | 119 | - Read [DOCUMENTATION.md](https://github.com/SoftwareGuy/ENet-CSharp/blob/master/DOCUMENTATION.md) as it is quite detailed. 120 | 121 | ## Multi-threaded Enet Implementation 122 | 123 | ### Strategy 124 | The best-known strategy is to use ENet in an independent I/O thread. This can be achieved by using Threads as well as ConcurrentQueues, RingBuffers and Disruptors, for example. 125 | 126 | You can use whatever system you are comfortable with, just make sure you keep ENet pumping as fast as possible in your application. Not pumping fast enough will cause Enet to become backlogged/congested, and this will hurt performance and network throughput. 127 | 128 | A real world example is Oiran Studio's [Ignorance](https://github.com/SoftwareGuy/Ignorance) transport which uses ConcurrentQueues for high performance transport I/O. 129 | 130 | ### Thread Safety 131 | In general, ENet is not thread-safe, but some of its functions can be used safely if the user is careful enough: 132 | 133 | - The `Packet` structure and its functions are safe until a packet is only moving across threads by value and a custom memory allocator is not used. 134 | 135 | - `Peer.ID`: As soon as a pointer to a peer was obtained from the native side, the ID will be cached in the `Peer` structure for further actions with objects that assigned to that ID. The `Peer` structure can be moved across threads by value, but its functions are not thread-safe because data in memory may change by the servicing functions in another thread. 136 | 137 | - `Library.Time`: utilizes atomic primitives internally for managing local monotonic time. 138 | 139 | 140 | ## Supporters 141 | 142 | Enet-CSharp is supported by, used internally and mantained by [Oiran Studio](http://www.oiran.studio). 143 | 144 |

145 | Oiran Studio Logo 146 |

147 | 148 | ## Credits 149 | 150 | - Coburn, c6burns, Katori, Mirror development team and discord members, repository contributors and coffee donators 151 | - Vincenzo from Flying Squirrel Entertainment ("resident enet guy"), lsalzman for the original Enet native repository 152 | - nxrighthere for the upstream Enet-CSharp repository in which this fork started from -------------------------------------------------------------------------------- /MSBuild/Common/Banner.txt: -------------------------------------------------------------------------------- 1 | ..---..._ 2 | ..--"" "-. 3 | ..-""" ". 4 | ..-"" " 5 | .-" 6 | .-" ... -_ 7 | .=" _..-" F .-"-.....___-.. 8 | "L_ _-' ." j" .-": /"-._ "- 9 | " : ." j" : : |"" ". 10 | ......---------"""""""""""-:_ | |\ 11 | ...---"""" -. f | " 12 | ...---"" . ..----"""""""".. ".-... f ". 13 | ..---""" ..---""""""""-..--"""""""""^^:: |. "-. . 14 | .--" .mm::::::::::::::::::::::::::... ""L |x ". 15 | -" mm;;;;;;;;;;XXXXXXXXXXXXX:::::::::::.. | |x. - 16 | xF -._ .mF;;;;;;XXXXXXXXXXXXXXXXXXXXXXXXXX:::::::| |X:. " 17 | j | j;;;;;XXX#############################::::::| XX:::: 18 | | |.#;::XXX##################################::::| |XX::: 19 | | j#::XXX#######################################:: XXX:: 20 | | .#:XXX########################################### |XX:: 21 | | #XXX##############################XX############Fl XXX: 22 | | .XXX###################XX#######X##XXX###########Fl lXX: 23 | | #XX##################XXX######XXXXXXX###########F j lXXX 24 | | #X#########X#X#####XXX#######XXXXXX#######XXX##F jl XXXX 25 | | #X#######XX#" V###XX#' ####XXXXXX##F"T##XXXXXX. V / . .#XXXX 26 | | #########" V#XX#' "####XXXX##.---.##XXXXXX. / / / .##XXXX 27 | | "######X' .--"" "V##L #####XXX#" "###XXXX. ." / / .###XXXX 28 | | #####X " .m###m##L ####XX# m###m"###XX# / / .#####XXX 29 | | "###X .mF"" "y ##### mX" "Y#"^####X / .######XXX 30 | | "T# #" # #### X" "F""###XX"###########XX 31 | | L d" dXX xm "^##L mx dXX YL-"##XX"S""########## 32 | | xL J Xd% T "" T XdX L. "##XS.f |######### 33 | | BL X## X X## X T#SS" |######### 34 | | #L X%##X X%##X| j#SSS /########## 35 | | #L ._ TXXX-" "-._ XXXF.- ###SS\########### 36 | | ## """"" """""" ##DS.\########### 37 | | TF ##BBS.T#########F 38 | | #L --- ###BBS.T########' 39 | | '## "" jL|###BSSS.T####### 40 | | '#### ______ .:#|##WWBBBSS.T####F 41 | J L '######. \___/ _c::#|###WWWBSSS|#### 42 | J ;; '########m \_/ c:::'#|###WWWBBSS.T##" 43 | J ;;;L :########.:m. _ _cf:::'.L|####WWWWSSS|#" 44 | .J ;;;;B ########B....:m.. _,c%%%:::'...L####WWWBBSSj 45 | x ;;;;dB #######BB.......##m...___..cc%%%%%::::'....|#####WWBBDS.| 46 | " ;;;;;ABB# #######BB........##j%%%%%%%%%%%%%%:::'..... #####WWWWDDS| 47 | .;;;;;dBBB# #######BB.........%%%%%%%%%%%%%%%:::'... j####WWWWWBDF 48 | ;;;;;BBB#### ######BBB.........%%%%%%%%%%%%%%:::'.. #####WWWWWWS 49 | ;;;;dBBB#### ######BBB..........^%%%%%%%%%%:::" #####WWWWWWB 50 | ;;;:BBB###### X#####BBB"..........."^YYYYY::" #####WWWWWWW 51 | ;;.BB######### X######BBB........:'' #####WWWWWWW 52 | ;;BB##########L X######BBB.......mmmm.. ..x#####WWWWWWB. 53 | ;dBB########### X#######BB..... "-._ x"" #####WWWWWWBL 54 | ;BBB###########L X######BB... "- ######WWWWBBBL 55 | BBB#############. ######BBB. #####WWWWBBBB 56 | BBB############## X#####BBB #####WWWWWBBB 57 | BBB############### T#####BB #####WWWBBB : 58 | BB################# T###BBP #####WWBB" .# 59 | BB##################..W##P ###BBB" .## 60 | BB###################..l "WW" ### 61 | BB####################j ___ " l j### 62 | BBB##################J_- """-.. ':::' .-""""""""""-. l .#### 63 | BBB######B##########J######## "-. ::' -" ..mmm####mm.."-.< ##### 64 | MCL-5/7/88 BBB#####J############ "-_ :| " .###############mmLlR#### 65 | BBBBBBBBBBBBBBB###/ ####### -. .:| ".#####F^^^P^^"""^^^Y#lT#### 66 | BBBBBBBBBBBBBBBBBj|####mm ######xx-...:::|" ###f ..... "#T### 67 | BBBBBBBBBBBBBBBBjj##########mm.. ":::."j##F .mm#########mmm.. Yj### 68 | BBBBBBBBBBBBBBBB|^WWWSRR############mmmmm xx """mjF.mm####################j### 69 | BBBBBBBBBBBBBBBB| ######mmmmmm#######################j### 70 | BBBBBBBBBBBBBBBBY#m... ..mmm##########PPPPP#####m.. lj### 71 | BBBBBBBBBBBBBBBBB2##############^^"" ..umF^^^Tx ^##mmmm........mmmmmmlj### 72 | BBBBBBBBBBBBBBBBBJT######^^^"" .mm##PPPF"...."m. "^^###############lj#### 73 | BBBBBBBBBBBBBBBBB##^L .mmm###PPP............"m.. """"^^^^^"" lj#### 74 | BBBBBBBBBBBBBBBB#####Y#mmx#########P.................."^:muuuummmmmm###^.##### 75 | BBBBBBBBBBBBBBBB#####::Y##mPPPPF^".......|.............. ""^^######^^"...##### 76 | BBBBBBBBBBBBBB########..................F............ \ ........##### 77 | BBBBBBBBBBBBB#########.................|.......... : ....l##### 78 | BBBBBBBBBBBB###########...............F......... \ ..###### 79 | BBBBBBBBBBB#############.............|........ : dA#### 80 | BBBBBBBBBB##############..................... kM#### 81 | BBBBBBBBB################.................. k##### 82 | BBBBBBB##################................ k##### 83 | BBBBB#####################............. t##### 84 | BB########################............ "E#### 85 | B########################F............ . "#### 86 | #########################............' | .. "L## 87 | ########################F............ ... "L# 88 | #######################F............' ..... "# 89 | ######################F............. ....... " 90 | #####################$.............. ......... 91 | #####################lmmm............. ........... ..m# 92 | ####################j########mmmm............. ......mmmmmm######## 93 | ###################j###::::;:::::########mmmmmmm############################## 94 | ##################j:::::::;:::::::;;::##############################^^^"""" 95 | ##################.mm:::mmm######mmmm:::' ^^^^^^""#######^^"""" 96 | #################F...^m::;::################mmm .mm""" 97 | #################.......m;::::::::::::#########^" 98 | ################F.........###mmm::::;' .##^""" 99 | ##############F...........:#######m.m#" 100 | ############..............':#### 101 | #########F............mm^"" 102 | #######..........m^"" 103 | ####.......%^" 104 | #.....x" 105 | |.x"" 106 | .-" 107 | .- 108 | .- 109 | .- 110 | - 111 | -" 112 | -" 113 | " 114 | x 115 | xx 116 | xx 117 | xxx" 118 | xxx" 119 | .xxxx" 120 | ___xxx"" 121 | .xxxx""....F 122 | """"mmxxxxx ___xxx^^^..........' 123 | .xx^^^^YYYY###xxx^^.................| 124 | .xx^" #######x..................| 125 | .xx" ###########mx..............f 126 | .x^ ##############xx............| 127 | j" ############## x..........; 128 | .........# ############ #x.........| 129 | x.......j" ########## ####x.......f 130 | xxx....#.. ######## #######x......| 131 | xxxx.#.... ####### ##########x.....| 132 | xxx...... ##### ######### x....| 133 | xxx...... ### ####### #m...| 134 | xxx...... ## ###### ####..| 135 | xxx......#. ##### ######m| 136 | xxxx....... ### #######Fx 137 | xxx...... # j##### m 138 | xx...... #### Jxm 139 | xxx...... #### j###Km 140 | xxx..... ### j####F m 141 | xx...... # ###F .m 142 | xxx .... j##F .###m 143 | m..xx..... ##F j#####K^mm. 144 | m...xx...... ## #####F ####mm 145 | m .....x...... F j####F ######## 146 | m ......x..... ###F J########## 147 | "m ........x.... .#F #########^^| 148 | "......mmF^^^x.... ## ###### | 149 | lL..jF x.... .F #### | 150 | lTLJF x.... #### | 151 | l::|. ".... j### ## 152 | l.... L.... ###F x## 153 | l.... ..m##L... ##F j### 154 | l:... #####L... #F j#### 155 | l.... #### ... ##### 156 | ".... ... ####F | 157 | l.... ... j###F | 158 | #... .... ###F | 159 | "#.. .jL.... ##F | 160 | ##. .m###L....#F | 161 | "## ..mm###### .... | 162 | | |... | 163 | k |... | 164 | l |... k 165 | k .m#L... Jk 166 | ## ..mm####L... k 167 | ### d########' L.... | 168 | l | "-.__-" 169 | l | 170 | l j# 171 | : j## 172 | k j##' 173 | l .m###k 174 | l ###^^"| 175 | | | 176 | j .## 177 | | ###### 178 | |== ##### #### 179 | .k #####" #### 180 | l #####^ #### 181 | l ### ####' 182 | ! m###F 183 | | ###### 184 | | mm##m###' 185 | |. m########F 186 | |. m#######F" # 187 | d. ### # 188 | |.. .' 189 | |.. | 190 | k.. : 191 | \... F 192 | |... #d 193 | |... ### 194 | L... ####. 195 | |... j### | 196 | ___ L... ### | 197 | |_ _|__ _ _ __ ___ _ __ __ _ _ __ ___ ___ .. j## k 198 | | |/ _` | '_ \ / _ \| '__/ _` | '_ \ / __/ _ \... ## | 199 | | | (_| | | | | (_) | | | (_| | | | | (_| __/ \... . 200 | |___\__, |_| |_|\___/|_| \__,_|_| |_|\___\___| "^-____- 201 | |___/ Mothers, hide your daughters! 202 | ------------------------------------------------------------------------------ 203 | 204 | -------------------------------------------------------------------------------- /DOCUMENTATION.md: -------------------------------------------------------------------------------- 1 | API Reference Documentation 2 | ----- 3 | ### Enumerations 4 | 5 | #### PacketFlags 6 | Definitions of a flags for `Peer.Send()` function: 7 | 8 | `PacketFlags.None` unreliable sequenced, delivery of packet is not guaranteed. 9 | 10 | `PacketFlags.Reliable` reliable sequenced, a packet must be received by the target peer and resend attempts should be made until the packet is delivered. 11 | 12 | `PacketFlags.Unsequenced` a packet will not be sequenced with other packets and may be delivered out of order. This flag makes delivery unreliable. 13 | 14 | `PacketFlags.NoAllocate` a packet will not allocate data, and the user must supply it instead. Packet lifetime should be tracked using the `PacketFreeCallback` callback. 15 | 16 | `PacketFlags.UnreliableFragmented` a packet will be unreliably fragmented if it exceeds the MTU. By default, unreliable packets that exceed the MTU are fragmented and transmitted reliably. This flag should be used to explicitly indicate packets that should remain unreliable. 17 | 18 | `PacketFlags.Instant` a packet will not be bundled with other packets at a next service iteration and sent instantly instead. This delivery type trades multiplexing efficiency in favor of latency. The same packet can't be used for multiple `Peer.Send()` calls. 19 | 20 | `PacketFlags.Unthrottled` a packet that was enqueued for sending unreliably should not be dropped due to throttling and sent if possible. 21 | 22 | `PacketFlags.Sent` a packet was sent from all queues it has entered. 23 | 24 | #### EventType 25 | Definitions of event types for `Event.Type` property: 26 | 27 | `EventType.None` no event occurred within the specified time limit. 28 | 29 | `EventType.Connect` a connection request initiated by `Peer.Connect()` function has completed. `Event.Peer` returns a peer which successfully connected. `Event.Data` returns the user-supplied data describing the connection or 0 if none is available. 30 | 31 | `EventType.Disconnect` a peer has disconnected. This event is generated on a successful completion of a disconnect initiated by `Peer.Disconnect()` function. `Event.Peer` returns a peer which disconnected. `Event.Data` returns the user-supplied data describing the disconnection or 0 if none is available. 32 | 33 | `EventType.Receive` a packet has been received from a peer. `Event.Peer` returns a peer which sent the packet. `Event.ChannelID` specifies the channel number upon which the packet was received. `Event.Packet` returns a packet that was received, and this packet must be destroyed using `Event.Packet.Dispose()` function after use. 34 | 35 | `EventType.Timeout` a peer has timed out. This event occurs if a peer has timed out or if a connection request initialized by `Peer.Connect()` has timed out. `Event.Peer` returns a peer which timed out. 36 | 37 | #### PeerState 38 | Definitions of peer states for `Peer.State` property: 39 | 40 | `PeerState.Uninitialized` a peer not initialized. 41 | 42 | `PeerState.Disconnected` a peer disconnected or timed out. 43 | 44 | `PeerState.Connecting` a peer connection in-progress. 45 | 46 | `PeerState.Connected` a peer successfully connected. 47 | 48 | `PeerState.Disconnecting` a peer disconnection in-progress. 49 | 50 | `PeerState.Zombie` a peer not properly disconnected. 51 | 52 | ### Delegates 53 | #### Memory callbacks 54 | 55 | `AllocCallback(IntPtr size)` notifies when a memory is requested for allocation. Expects pointer to the newly allocated memory. A reference to the delegate should be preserved from being garbage collected. 56 | 57 | `FreeCallback(IntPtr memory)` notifies when the memory can be freed. A reference to the delegate should be preserved from being garbage collected. 58 | 59 | `NoMemoryCallback()` notifies when memory is not enough. A reference to the delegate should be preserved from being garbage collected. 60 | 61 | #### Packet callbacks 62 | 63 | `PacketFreeCallback(Packet packet)` notifies when a packet is being destroyed. Indicates if a reliable packet was acknowledged. A reference to the delegate should be preserved from being garbage collected. 64 | 65 | #### Host callbacks 66 | Provides per host events. 67 | 68 | `InterceptCallback(ref Event @event, ref Address address, IntPtr receivedData, int receivedDataLength)` notifies when a raw UDP packet is intercepted. Status code returned from this callback instructs ENet how the set event should be handled. Returning 1 indicates dispatching of the set event by the service. Returning 0 indicates that ENet subsystems should handle received data. Returning -1 indicates an error. A reference to the delegate should be preserved from being garbage collected. 69 | 70 | ### Structures 71 | #### Address 72 | Contains structure with anonymous host data and port number. 73 | 74 | `Address.Port` gets or sets a port number. 75 | 76 | `Address.GetIP()` gets an IP address. 77 | 78 | `Address.SetIP(string ip)` sets an IP address. To use IPv4 broadcast in the local network the address can be set to _255.255.255.255_ for a client. ENet will automatically respond to the broadcast and update the address to a server's actual IP. 79 | 80 | `Address.GetHost()` attempts to do a reverse lookup from the address. Returns a string with a resolved name or an IP address. 81 | 82 | `Address.SetHost(string hostName)` sets host name or an IP address. Should be used for binding to a network interface or for connection to a foreign host. Returns true on success or false on failure. 83 | 84 | #### Event 85 | Contains structure with the event type, managed pointer to the peer, channel ID, the user-supplied data, and managed pointer to the packet. 86 | 87 | `Event.Type` returns a type of the event. 88 | 89 | `Event.Peer` returns a peer that generated a connect, disconnect, receive or a timeout event. 90 | 91 | `Event.ChannelID` returns a channel ID on the peer that generated the event, if appropriate. 92 | 93 | `Event.Data` returns the user-supplied data, if appropriate. 94 | 95 | `Event.Packet` returns a packet associated with the event, if appropriate. 96 | 97 | #### Packet 98 | Contains a managed pointer to the packet. 99 | 100 | `Packet.Dispose()` destroys the packet. Should be called only when the packet was obtained from `EventType.Receive` event. 101 | 102 | `Packet.IsSet` returns a state of the managed pointer. 103 | 104 | `Packet.Data` returns a managed pointer to the packet data. 105 | 106 | `Packet.UserData` gets or sets the user-supplied data. 107 | 108 | `Packet.Length` returns a length of payload in the packet. 109 | 110 | `Packet.HasReferences` checks references to the packet. 111 | 112 | `Packet.SetFreeCallback(PacketFreeCallback callback)` sets callback to notify when an appropriate packet is being destroyed. A pointer `IntPtr` to a callback can be used instead of a reference to a delegate. 113 | 114 | `Packet.Create(byte[] data, int offset, int length, PacketFlags flags)` creates a packet that may be sent to a peer. The offset parameter indicates the starting point of data in an array, the length is the ending point of data in an array. All parameters are optional. Multiple packet flags can be specified at once. A pointer `IntPtr` to a native buffer can be used instead of a reference to a byte array. 115 | 116 | `Packet.CopyTo(byte[] destination)` copies payload from the packet to the destination array. 117 | 118 | #### Peer 119 | Contains a managed pointer to the peer and cached ID. 120 | 121 | `Peer.IsSet` returns a state of the managed pointer. 122 | 123 | `Peer.ID` returns a peer ID. It's always zero on the client side. 124 | 125 | `Peer.IP` returns an IP address in a printable form. 126 | 127 | `Peer.Port` returns a port number. 128 | 129 | `Peer.MTU` returns an MTU. 130 | 131 | `Peer.State` returns a peer state described in the `PeerState` enumeration. 132 | 133 | `Peer.RoundTripTime` returns a round-trip time in milliseconds. 134 | 135 | `Peer.LastRoundTripTime` returns a round-trip time since the last acknowledgment in milliseconds. 136 | 137 | `Peer.LastSendTime` returns a last packet send time in milliseconds. 138 | 139 | `Peer.LastReceiveTime` returns a last packet receive time in milliseconds. 140 | 141 | `Peer.PacketsSent` returns a total number of packets sent during the connection. 142 | 143 | `Peer.PacketsLost` returns a total number of lost packets during the connection. 144 | 145 | `Peer.PacketsThrottle` returns a ratio of packets throttle depending on conditions of the connection to the peer. 146 | 147 | `Peer.BytesSent` returns a total number of bytes sent during the connection. 148 | 149 | `Peer.BytesReceived` returns a total number of bytes received during the connection. 150 | 151 | `Peer.Data` gets or sets the user-supplied data. Should be used with an explicit cast to appropriate data type. 152 | 153 | `Peer.ConfigureThrottle(uint interval, uint acceleration, uint deceleration, uint threshold)` configures throttle parameter for a peer. Unreliable packets are dropped by ENet in response to the varying conditions of the connection to the peer. The throttle represents a probability that an unreliable packet should not be dropped and thus sent by ENet to the peer. The lowest mean round-trip time from the sending of a reliable packet to the receipt of its acknowledgment is measured over an amount of time specified by the interval parameter in milliseconds. If a measured round-trip time happens to be significantly less than the mean round-trip time measured over the interval, then the throttle probability is increased to allow more traffic by an amount specified in the acceleration parameter, which is a ratio to the `Library.throttleScale` constant. 154 | 155 | If a measured round-trip time happens to be significantly greater than the mean round-trip time measured over the interval, then the throttle probability is decreased to limit traffic by an amount specified in the deceleration parameter, which is a ratio to the `Library.throttleScale` constant. When the throttle has a value of `Library.throttleScale`, no unreliable packets are dropped by ENet, and so 100% of all unreliable packets will be sent. When the throttle has a value of 0, all unreliable packets are dropped by ENet, and so 0% of all unreliable packets will be sent. Intermediate values for the throttle represent intermediate probabilities between 0% and 100% of unreliable packets being sent. 156 | 157 | The bandwidth limits of the local and foreign hosts are taken into account to determine a sensible limit for the throttle probability above which it should not raise even in the best of conditions. To disable throttling the deceleration parameter should be set to zero. The threshold parameter can be used to reduce packet throttling relative to measured round-trip time in unstable network environments with high jitter and low average latency which is a common condition for Wi-Fi networks in crowded places. By default the threshold parameter set to `Library.throttleThreshold` in milliseconds. 158 | 159 | `Peer.Send(byte channelID, ref Packet packet)` queues a packet to be sent. Returns true on success or false on failure. 160 | 161 | `Peer.Receive(out byte channelID, out Packet packet)` attempts to dequeue any incoming queued packet. Returns true if a packet was dequeued or false if no packets available. 162 | 163 | `Peer.Ping()` sends a ping request to a peer. ENet automatically pings all connected peers at regular intervals, however, this function may be called to ensure more frequent ping requests. 164 | 165 | `Peer.PingInterval(uint interval)` sets an interval at which pings will be sent to a peer. Pings are used both to monitor the liveness of the connection and also to dynamically adjust the throttle during periods of low traffic so that the throttle has reasonable responsiveness during traffic spikes. 166 | 167 | `Peer.Timeout(uint timeoutLimit, uint timeoutMinimum, uint timeoutMaximum)` sets a timeout parameters for a peer. The timeout parameters control how and when a peer will timeout from a failure to acknowledge reliable traffic. Timeout values used in the semi-linear mechanism, where if a reliable packet is not acknowledged within an average round-trip time plus a variance tolerance until timeout reaches a set limit. If the timeout is thus at this limit and reliable packets have been sent but not acknowledged within a certain minimum time period, the peer will be disconnected. Alternatively, if reliable packets have been sent but not acknowledged for a certain maximum time period, the peer will be disconnected regardless of the current timeout limit value. 168 | 169 | `Peer.Disconnect(uint data)` requests a disconnection from a peer. 170 | 171 | `Peer.DisconnectNow(uint data)` forces an immediate disconnection from a peer. 172 | 173 | `Peer.DisconnectLater(uint data)` requests a disconnection from a peer, but only after all queued outgoing packets are sent. 174 | 175 | `Peer.Reset()` forcefully disconnects a peer. The foreign host represented by the peer is not notified of the disconnection and will timeout on its connection to the local host. 176 | 177 | ### Classes 178 | #### Host 179 | Contains a managed pointer to the host. 180 | 181 | `Host.Dispose()` destroys the host. 182 | 183 | `Host.IsSet` returns a state of the managed pointer. 184 | 185 | `Host.PeersCount` returns a number of connected peers. 186 | 187 | `Host.PacketsSent` returns a total number of packets sent during the session. 188 | 189 | `Host.PacketsReceived` returns a total number of packets received during the session. 190 | 191 | `Host.BytesSent` returns a total number of bytes sent during the session. 192 | 193 | `Host.BytesReceived` returns a total number of bytes received during the session. 194 | 195 | `Host.Create(Address? address, int peerLimit, int channelLimit, uint incomingBandwidth, uint outgoingBandwidth, int bufferSize)` creates a host for communicating with peers. The bandwidth parameters determine the window size of a connection which limits the number of reliable packets that may be in transit at any given time. ENet will strategically drop packets on specific sides of a connection between hosts to ensure the host's bandwidth is not overwhelmed. The buffer size parameter is used to set the socket buffer size for sending and receiving datagrams. All the parameters are optional except the address and peer limit in cases where the function is used to create a host which will listen for incoming connections. 196 | 197 | `Host.PreventConnections(bool state)` prevents access to the host for new incoming connections. This function makes the host completely invisible from outside, any peer that attempts to connect to it will be timed out. 198 | 199 | `Host.Broadcast(byte channelID, ref Packet packet, Peer[] peers)` queues a packet to be sent to a range of peers or to all peers associated with the host if the optional peers parameter is not used. Any zeroed `Peer` structure in an array will be excluded from the broadcast. Instead of an array, a single `Peer` can be passed to function which will be excluded from the broadcast. 200 | 201 | `Host.CheckEvents(out Event @event)` checks for any queued events on the host and dispatches one if available. Returns > 0 if an event was dispatched, 0 if no events are available, < 0 on failure. 202 | 203 | `Host.Connect(Address address, int channelLimit, uint data)` initiates a connection to a foreign host. Returns a peer representing the foreign host on success or throws an exception on failure. The peer returned will not have completed the connection until `Host.Service()` notifies of an `EventType.Connect` event. The channel limit and the user-supplied data parameters are optional. 204 | 205 | `Host.Service(int timeout, out Event @event)` waits for events on the specified host and shuttles packets between the host and its peers. ENet uses a polled event model to notify the user of significant events. ENet hosts are polled for events with this function, where an optional timeout value in milliseconds may be specified to control how long ENet will poll. If a timeout of 0 is specified, this function will return immediately if there are no events to dispatch. Otherwise, it will return 1 if an event was dispatched within the specified timeout. This function should be regularly called to ensure packets are sent and received, otherwise, traffic spikes will occur leading to increased latency. The timeout parameter set to 0 means non-blocking which required for cases where the function is called in a game loop. 206 | 207 | `Host.SetBandwidthLimit(uint incomingBandwidth, uint outgoingBandwidth)` adjusts the bandwidth limits of a host in bytes per second. 208 | 209 | `Host.SetChannelLimit(int channelLimit)` limits the maximum allowed channels of future incoming connections. 210 | 211 | `Host.SetInterceptCallback(InterceptCallback callback)` sets callback to notify when a raw UDP packet is interecepted. A pointer `IntPtr` to a callback can be used instead of a reference to a delegate. 212 | 213 | `Host.Flush()` sends any queued packets on the specified host to its designated peers. 214 | 215 | #### Library 216 | Contains constant fields. 217 | 218 | `Library.maxChannelCount` the maximum possible number of channels. 219 | 220 | `Library.maxPeers` the maximum possible number of peers. 221 | 222 | `Library.maxPacketSize` the maximum size of a packet. 223 | 224 | `Library.version` the current compatibility version relative to the native library. 225 | 226 | `Library.Initialize(Callbacks callbacks)` initializes the native library. Callbacks parameter is optional and should be used only with a custom memory allocator. Should be called before starting the work. Returns true on success or false on failure. 227 | 228 | `Library.Deinitialize()` deinitializes the native library. Should be called after the work is done. 229 | 230 | `Library.Time` returns a current local monotonic time in milliseconds. It never reset while the application remains alive. 231 | -------------------------------------------------------------------------------- /MobileToolchains/ios.toolchain.cmake: -------------------------------------------------------------------------------- 1 | # This file is part of the ios-cmake project. It was retrieved from 2 | # https://github.com/cristeab/ios-cmake.git, which is a fork of 3 | # https://code.google.com/p/ios-cmake/. Which in turn is based off of 4 | # the Platform/Darwin.cmake and Platform/UnixPaths.cmake files which 5 | # are included with CMake 2.8.4 6 | # 7 | # The ios-cmake project is licensed under the new BSD license. 8 | # 9 | # Copyright (c) 2014, Bogdan Cristea and LTE Engineering Software, 10 | # Kitware, Inc., Insight Software Consortium. All rights reserved. 11 | # Redistribution and use in source and binary forms, with or without 12 | # modification, are permitted provided that the following conditions 13 | # are met: 14 | # 1. Redistributions of source code must retain the above copyright 15 | # notice, this list of conditions and the following disclaimer. 16 | # 17 | # 2. Redistributions in binary form must reproduce the above copyright 18 | # notice, this list of conditions and the following disclaimer in the 19 | # documentation and/or other materials provided with the distribution. 20 | # 21 | # 3. Neither the name of the copyright holder nor the names of its 22 | # contributors may be used to endorse or promote products derived from 23 | # this software without specific prior written permission. 24 | # 25 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 26 | # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 27 | # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 28 | # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 29 | # COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 30 | # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 31 | # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 32 | # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 33 | # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 34 | # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 35 | # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 36 | # POSSIBILITY OF SUCH DAMAGE. 37 | # 38 | # This file is based off of the Platform/Darwin.cmake and 39 | # Platform/UnixPaths.cmake files which are included with CMake 2.8.4 40 | # It has been altered for iOS development. 41 | # 42 | # Updated by Alex Stewart (alexs.mac@gmail.com) 43 | # 44 | # ***************************************************************************** 45 | # Now maintained by Alexander Widerberg (widerbergaren [at] gmail.com) 46 | # under the BSD-3-Clause license 47 | # https://github.com/leetal/ios-cmake 48 | # ***************************************************************************** 49 | # 50 | # INFORMATION / HELP 51 | # 52 | # The following arguments control the behaviour of this toolchain: 53 | # 54 | # PLATFORM: (default "OS") 55 | # OS = Build for iPhoneOS. 56 | # OS64 = Build for arm64 iphoneOS. 57 | # OS64COMBINED = Build for arm64 x86_64 iphoneOS. Combined into FAT STATIC lib (supported on 3.14+ of CMakewith "-G Xcode" argument ONLY) 58 | # SIMULATOR = Build for x86 i386 iphoneOS Simulator. 59 | # SIMULATOR64 = Build for x86_64 iphoneOS Simulator. 60 | # TVOS = Build for arm64 tvOS. 61 | # TVOSCOMBINED = Build for arm64 x86_64 tvOS. Combined into FAT STATIC lib (supported on 3.14+ of CMake with "-G Xcode" argument ONLY) 62 | # SIMULATOR_TVOS = Build for x86_64 tvOS Simulator. 63 | # WATCHOS = Build for armv7k arm64_32 for watchOS. 64 | # WATCHOSCOMBINED = Build for armv7k arm64_32 x86_64 watchOS. Combined into FAT STATIC lib (supported on 3.14+ of CMake with "-G Xcode" argument ONLY) 65 | # SIMULATOR_WATCHOS = Build for x86_64 for watchOS Simulator. 66 | # 67 | # CMAKE_OSX_SYSROOT: Path to the SDK to use. By default this is 68 | # automatically determined from PLATFORM and xcodebuild, but 69 | # can also be manually specified (although this should not be required). 70 | # 71 | # CMAKE_DEVELOPER_ROOT: Path to the Developer directory for the platform 72 | # being compiled for. By default this is automatically determined from 73 | # CMAKE_OSX_SYSROOT, but can also be manually specified (although this should 74 | # not be required). 75 | # 76 | # DEPLOYMENT_TARGET: Minimum SDK version to target. Default 2.0 on watchOS and 9.0 on tvOS+iOS 77 | # 78 | # ENABLE_BITCODE: (1|0) Enables or disables bitcode support. Default 1 (true) 79 | # 80 | # ENABLE_ARC: (1|0) Enables or disables ARC support. Default 1 (true, ARC enabled by default) 81 | # 82 | # ENABLE_VISIBILITY: (1|0) Enables or disables symbol visibility support. Default 0 (false, visibility hidden by default) 83 | # 84 | # ENABLE_STRICT_TRY_COMPILE: (1|0) Enables or disables strict try_compile() on all Check* directives (will run linker 85 | # to actually check if linking is possible). Default 0 (false, will set CMAKE_TRY_COMPILE_TARGET_TYPE to STATIC_LIBRARY) 86 | # 87 | # ARCHS: (armv7 armv7s armv7k arm64 arm64_32 i386 x86_64) If specified, will override the default architectures for the given PLATFORM 88 | # OS = armv7 armv7s arm64 (if applicable) 89 | # OS64 = arm64 (if applicable) 90 | # SIMULATOR = i386 91 | # SIMULATOR64 = x86_64 92 | # TVOS = arm64 93 | # SIMULATOR_TVOS = x86_64 (i386 has since long been deprecated) 94 | # WATCHOS = armv7k arm64_32 (if applicable) 95 | # SIMULATOR_WATCHOS = x86_64 (i386 has since long been deprecated) 96 | # 97 | # This toolchain defines the following variables for use externally: 98 | # 99 | # XCODE_VERSION: Version number (not including Build version) of Xcode detected. 100 | # SDK_VERSION: Version of SDK being used. 101 | # CMAKE_OSX_ARCHITECTURES: Architectures being compiled for (generated from PLATFORM). 102 | # APPLE_TARGET_TRIPLE: Used by autoconf build systems. NOTE: If "ARCHS" are overridden, this will *NOT* be set! 103 | # 104 | # This toolchain defines the following macros for use externally: 105 | # 106 | # set_xcode_property (TARGET XCODE_PROPERTY XCODE_VALUE XCODE_VARIANT) 107 | # A convenience macro for setting xcode specific properties on targets. 108 | # Available variants are: All, Release, RelWithDebInfo, Debug, MinSizeRel 109 | # example: set_xcode_property (myioslib IPHONEOS_DEPLOYMENT_TARGET "3.1" "all"). 110 | # 111 | # find_host_package (PROGRAM ARGS) 112 | # A macro used to find executable programs on the host system, not within the 113 | # environment. Thanks to the android-cmake project for providing the 114 | # command. 115 | # 116 | # ******************************** DEPRECATIONS ******************************* 117 | # 118 | # IOS_DEPLOYMENT_TARGET: (Deprecated) Alias to DEPLOYMENT_TARGET 119 | # CMAKE_IOS_DEVELOPER_ROOT: (Deprecated) Alias to CMAKE_DEVELOPER_ROOT 120 | # IOS_PLATFORM: (Deprecated) Alias to PLATFORM 121 | # IOS_ARCH: (Deprecated) Alias to ARCHS 122 | # 123 | # ***************************************************************************** 124 | # 125 | 126 | # Fix for PThread library not in path 127 | set(CMAKE_THREAD_LIBS_INIT "-lpthread") 128 | set(CMAKE_HAVE_THREADS_LIBRARY 1) 129 | set(CMAKE_USE_WIN32_THREADS_INIT 0) 130 | set(CMAKE_USE_PTHREADS_INIT 1) 131 | 132 | # Cache what generator is used 133 | set(USED_CMAKE_GENERATOR "${CMAKE_GENERATOR}" CACHE STRING "Expose CMAKE_GENERATOR" FORCE) 134 | 135 | if(${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.14") 136 | set(MODERN_CMAKE YES) 137 | endif() 138 | 139 | # Get the Xcode version being used. 140 | execute_process(COMMAND xcodebuild -version 141 | OUTPUT_VARIABLE XCODE_VERSION 142 | ERROR_QUIET 143 | OUTPUT_STRIP_TRAILING_WHITESPACE) 144 | string(REGEX MATCH "Xcode [0-9\\.]+" XCODE_VERSION "${XCODE_VERSION}") 145 | string(REGEX REPLACE "Xcode ([0-9\\.]+)" "\\1" XCODE_VERSION "${XCODE_VERSION}") 146 | 147 | ######## ALIASES (DEPRECATION WARNINGS) 148 | 149 | if(DEFINED IOS_PLATFORM) 150 | set(PLATFORM ${IOS_PLATFORM}) 151 | message(DEPRECATION "IOS_PLATFORM argument is DEPRECATED. Consider using the new PLATFORM argument instead.") 152 | endif() 153 | 154 | if(DEFINED IOS_DEPLOYMENT_TARGET) 155 | set(DEPLOYMENT_TARGET ${IOS_DEPLOYMENT_TARGET}) 156 | message(DEPRECATION "IOS_DEPLOYMENT_TARGET argument is DEPRECATED. Consider using the new DEPLOYMENT_TARGET argument instead.") 157 | endif() 158 | 159 | if(DEFINED CMAKE_IOS_DEVELOPER_ROOT) 160 | set(CMAKE_DEVELOPER_ROOT ${CMAKE_IOS_DEVELOPER_ROOT}) 161 | message(DEPRECATION "CMAKE_IOS_DEVELOPER_ROOT argument is DEPRECATED. Consider using the new CMAKE_DEVELOPER_ROOT argument instead.") 162 | endif() 163 | 164 | if(DEFINED IOS_ARCH) 165 | set(ARCHS ${IOS_ARCH}) 166 | message(DEPRECATION "IOS_ARCH argument is DEPRECATED. Consider using the new ARCHS argument instead.") 167 | endif() 168 | 169 | ######## END ALIASES 170 | 171 | # Unset the FORCE on cache variables if in try_compile() 172 | set(FORCE_CACHE FORCE) 173 | get_property(_CMAKE_IN_TRY_COMPILE GLOBAL PROPERTY IN_TRY_COMPILE) 174 | if(_CMAKE_IN_TRY_COMPILE) 175 | unset(FORCE_CACHE) 176 | endif() 177 | 178 | # Default to building for iPhoneOS if not specified otherwise, and we cannot 179 | # determine the platform from the CMAKE_OSX_ARCHITECTURES variable. The use 180 | # of CMAKE_OSX_ARCHITECTURES is such that try_compile() projects can correctly 181 | # determine the value of PLATFORM from the root project, as 182 | # CMAKE_OSX_ARCHITECTURES is propagated to them by CMake. 183 | if(NOT DEFINED PLATFORM) 184 | if (CMAKE_OSX_ARCHITECTURES) 185 | if(CMAKE_OSX_ARCHITECTURES MATCHES ".*arm.*" AND CMAKE_OSX_SYSROOT MATCHES ".*iphoneos.*") 186 | set(PLATFORM "OS") 187 | elseif(CMAKE_OSX_ARCHITECTURES MATCHES "i386" AND CMAKE_OSX_SYSROOT MATCHES ".*iphonesimulator.*") 188 | set(PLATFORM "SIMULATOR") 189 | elseif(CMAKE_OSX_ARCHITECTURES MATCHES "x86_64" AND CMAKE_OSX_SYSROOT MATCHES ".*iphonesimulator.*") 190 | set(PLATFORM "SIMULATOR64") 191 | elseif(CMAKE_OSX_ARCHITECTURES MATCHES "arm64" AND CMAKE_OSX_SYSROOT MATCHES ".*appletvos.*") 192 | set(PLATFORM "TVOS") 193 | elseif(CMAKE_OSX_ARCHITECTURES MATCHES "x86_64" AND CMAKE_OSX_SYSROOT MATCHES ".*appletvsimulator.*") 194 | set(PLATFORM "SIMULATOR_TVOS") 195 | elseif(CMAKE_OSX_ARCHITECTURES MATCHES ".*armv7k.*" AND CMAKE_OSX_SYSROOT MATCHES ".*watchos.*") 196 | set(PLATFORM "WATCHOS") 197 | elseif(CMAKE_OSX_ARCHITECTURES MATCHES "i386" AND CMAKE_OSX_SYSROOT MATCHES ".*watchsimulator.*") 198 | set(PLATFORM "SIMULATOR_WATCHOS") 199 | endif() 200 | endif() 201 | if (NOT PLATFORM) 202 | set(PLATFORM "OS") 203 | endif() 204 | endif() 205 | 206 | set(PLATFORM_INT "${PLATFORM}" CACHE STRING "Type of platform for which the build targets.") 207 | 208 | # Handle the case where we are targeting iOS and a version above 10.3.4 (32-bit support dropped officially) 209 | if(PLATFORM_INT STREQUAL "OS" AND DEPLOYMENT_TARGET VERSION_GREATER_EQUAL 10.3.4) 210 | set(PLATFORM_INT "OS64") 211 | message(STATUS "Targeting minimum SDK version ${DEPLOYMENT_TARGET}. Dropping 32-bit support.") 212 | elseif(PLATFORM_INT STREQUAL "SIMULATOR" AND DEPLOYMENT_TARGET VERSION_GREATER_EQUAL 10.3.4) 213 | set(PLATFORM_INT "SIMULATOR64") 214 | message(STATUS "Targeting minimum SDK version ${DEPLOYMENT_TARGET}. Dropping 32-bit support.") 215 | endif() 216 | 217 | # Determine the platform name and architectures for use in xcodebuild commands 218 | # from the specified PLATFORM name. 219 | if(PLATFORM_INT STREQUAL "OS") 220 | set(SDK_NAME iphoneos) 221 | if(NOT ARCHS) 222 | set(ARCHS armv7 armv7s arm64) 223 | set(APPLE_TARGET_TRIPLE_INT arm-apple-ios) 224 | endif() 225 | elseif(PLATFORM_INT STREQUAL "OS64") 226 | set(SDK_NAME iphoneos) 227 | if(NOT ARCHS) 228 | if (XCODE_VERSION VERSION_GREATER 10.0) 229 | set(ARCHS arm64) # Add arm64e when Apple have fixed the integration issues with it, libarclite_iphoneos.a is currently missung bitcode markers for example 230 | else() 231 | set(ARCHS arm64) 232 | endif() 233 | set(APPLE_TARGET_TRIPLE_INT aarch64-apple-ios) 234 | endif() 235 | elseif(PLATFORM_INT STREQUAL "OS64COMBINED") 236 | set(SDK_NAME iphoneos) 237 | if(MODERN_CMAKE) 238 | if(NOT ARCHS) 239 | if (XCODE_VERSION VERSION_GREATER 10.0) 240 | set(ARCHS arm64 x86_64) # Add arm64e when Apple have fixed the integration issues with it, libarclite_iphoneos.a is currently missung bitcode markers for example 241 | else() 242 | set(ARCHS arm64 x86_64) 243 | endif() 244 | set(APPLE_TARGET_TRIPLE_INT aarch64-x86_64-apple-ios) 245 | endif() 246 | else() 247 | message(FATAL_ERROR "Please make sure that you are running CMake 3.14+ to make the OS64COMBINED setting work") 248 | endif() 249 | elseif(PLATFORM_INT STREQUAL "SIMULATOR") 250 | set(SDK_NAME iphonesimulator) 251 | if(NOT ARCHS) 252 | set(ARCHS i386) 253 | set(APPLE_TARGET_TRIPLE_INT i386-apple-ios) 254 | endif() 255 | message(DEPRECATION "SIMULATOR IS DEPRECATED. Consider using SIMULATOR64 instead.") 256 | elseif(PLATFORM_INT STREQUAL "SIMULATOR64") 257 | set(SDK_NAME iphonesimulator) 258 | if(NOT ARCHS) 259 | set(ARCHS x86_64) 260 | set(APPLE_TARGET_TRIPLE_INT x86_64-apple-ios) 261 | endif() 262 | elseif(PLATFORM_INT STREQUAL "TVOS") 263 | set(SDK_NAME appletvos) 264 | if(NOT ARCHS) 265 | set(ARCHS arm64) 266 | set(APPLE_TARGET_TRIPLE_INT aarch64-apple-tvos) 267 | endif() 268 | elseif (PLATFORM_INT STREQUAL "TVOSCOMBINED") 269 | set(SDK_NAME appletvos) 270 | if(MODERN_CMAKE) 271 | if(NOT ARCHS) 272 | set(ARCHS arm64 x86_64) 273 | set(APPLE_TARGET_TRIPLE_INT aarch64-x86_64-apple-tvos) 274 | endif() 275 | else() 276 | message(FATAL_ERROR "Please make sure that you are running CMake 3.14+ to make the TVOSCOMBINED setting work") 277 | endif() 278 | elseif(PLATFORM_INT STREQUAL "SIMULATOR_TVOS") 279 | set(SDK_NAME appletvsimulator) 280 | if(NOT ARCHS) 281 | set(ARCHS x86_64) 282 | set(APPLE_TARGET_TRIPLE_INT x86_64-apple-tvos) 283 | endif() 284 | elseif(PLATFORM_INT STREQUAL "WATCHOS") 285 | set(SDK_NAME watchos) 286 | if(NOT ARCHS) 287 | if (XCODE_VERSION VERSION_GREATER 10.0) 288 | set(ARCHS armv7k arm64_32) 289 | set(APPLE_TARGET_TRIPLE_INT aarch64_32-apple-watchos) 290 | else() 291 | set(ARCHS armv7k) 292 | set(APPLE_TARGET_TRIPLE_INT arm-apple-watchos) 293 | endif() 294 | endif() 295 | elseif(PLATFORM_INT STREQUAL "WATCHOSCOMBINED") 296 | set(SDK_NAME watchos) 297 | if(MODERN_CMAKE) 298 | if(NOT ARCHS) 299 | if (XCODE_VERSION VERSION_GREATER 10.0) 300 | set(ARCHS armv7k arm64_32 i386) 301 | set(APPLE_TARGET_TRIPLE_INT aarch64_32-i386-apple-watchos) 302 | else() 303 | set(ARCHS armv7k i386) 304 | set(APPLE_TARGET_TRIPLE_INT arm-i386-apple-watchos) 305 | endif() 306 | endif() 307 | else() 308 | message(FATAL_ERROR "Please make sure that you are running CMake 3.14+ to make the WATCHOSCOMBINED setting work") 309 | endif() 310 | elseif(PLATFORM_INT STREQUAL "SIMULATOR_WATCHOS") 311 | set(SDK_NAME watchsimulator) 312 | if(NOT ARCHS) 313 | set(ARCHS i386) 314 | set(APPLE_TARGET_TRIPLE_INT i386-apple-watchos) 315 | endif() 316 | else() 317 | message(FATAL_ERROR "Invalid PLATFORM: ${PLATFORM_INT}") 318 | endif() 319 | 320 | if(MODERN_CMAKE AND PLATFORM_INT MATCHES ".*COMBINED" AND NOT USED_CMAKE_GENERATOR MATCHES "Xcode") 321 | message(FATAL_ERROR "The COMBINED options only work with Xcode generator, -G Xcode") 322 | endif() 323 | 324 | # If user did not specify the SDK root to use, then query xcodebuild for it. 325 | execute_process(COMMAND xcodebuild -version -sdk ${SDK_NAME} Path 326 | OUTPUT_VARIABLE CMAKE_OSX_SYSROOT_INT 327 | ERROR_QUIET 328 | OUTPUT_STRIP_TRAILING_WHITESPACE) 329 | if (NOT DEFINED CMAKE_OSX_SYSROOT_INT AND NOT DEFINED CMAKE_OSX_SYSROOT) 330 | message(SEND_ERROR "Please make sure that Xcode is installed and that the toolchain" 331 | "is pointing to the correct path. Please run:" 332 | "sudo xcode-select -s /Applications/Xcode.app/Contents/Developer" 333 | "and see if that fixes the problem for you.") 334 | message(FATAL_ERROR "Invalid CMAKE_OSX_SYSROOT: ${CMAKE_OSX_SYSROOT} " 335 | "does not exist.") 336 | elseif(DEFINED CMAKE_OSX_SYSROOT_INT) 337 | set(CMAKE_OSX_SYSROOT "${CMAKE_OSX_SYSROOT_INT}" CACHE INTERNAL "") 338 | endif() 339 | 340 | # Set Xcode property for SDKROOT as well if Xcode generator is used 341 | if(USED_CMAKE_GENERATOR MATCHES "Xcode") 342 | set(CMAKE_OSX_SYSROOT "${SDK_NAME}" CACHE INTERNAL "") 343 | if(NOT DEFINED CMAKE_XCODE_ATTRIBUTE_DEVELOPMENT_TEAM) 344 | set(CMAKE_XCODE_ATTRIBUTE_DEVELOPMENT_TEAM "123456789A" CACHE INTERNAL "") 345 | endif() 346 | endif() 347 | 348 | # Specify minimum version of deployment target. 349 | if(NOT DEFINED DEPLOYMENT_TARGET) 350 | if (PLATFORM_INT STREQUAL "WATCHOS" OR PLATFORM_INT STREQUAL "SIMULATOR_WATCHOS") 351 | # Unless specified, SDK version 2.0 is used by default as minimum target version (watchOS). 352 | set(DEPLOYMENT_TARGET "2.0" 353 | CACHE STRING "Minimum SDK version to build for." ) 354 | else() 355 | # Unless specified, SDK version 9.0 is used by default as minimum target version (iOS, tvOS). 356 | set(DEPLOYMENT_TARGET "9.0" 357 | CACHE STRING "Minimum SDK version to build for." ) 358 | endif() 359 | message(STATUS "Using the default min-version since DEPLOYMENT_TARGET not provided!") 360 | endif() 361 | 362 | # Use bitcode or not 363 | if(NOT DEFINED ENABLE_BITCODE AND NOT ARCHS MATCHES "((^|;|, )(i386|x86_64))+") 364 | # Unless specified, enable bitcode support by default 365 | message(STATUS "Enabling bitcode support by default. ENABLE_BITCODE not provided!") 366 | set(ENABLE_BITCODE TRUE) 367 | elseif(NOT DEFINED ENABLE_BITCODE) 368 | message(STATUS "Disabling bitcode support by default on simulators. ENABLE_BITCODE not provided for override!") 369 | set(ENABLE_BITCODE FALSE) 370 | endif() 371 | set(ENABLE_BITCODE_INT ${ENABLE_BITCODE} CACHE BOOL "Whether or not to enable bitcode" ${FORCE_CACHE}) 372 | # Use ARC or not 373 | if(NOT DEFINED ENABLE_ARC) 374 | # Unless specified, enable ARC support by default 375 | set(ENABLE_ARC TRUE) 376 | message(STATUS "Enabling ARC support by default. ENABLE_ARC not provided!") 377 | endif() 378 | set(ENABLE_ARC_INT ${ENABLE_ARC} CACHE BOOL "Whether or not to enable ARC" ${FORCE_CACHE}) 379 | # Use hidden visibility or not 380 | if(NOT DEFINED ENABLE_VISIBILITY) 381 | # Unless specified, disable symbols visibility by default 382 | set(ENABLE_VISIBILITY FALSE) 383 | message(STATUS "Hiding symbols visibility by default. ENABLE_VISIBILITY not provided!") 384 | endif() 385 | set(ENABLE_VISIBILITY_INT ${ENABLE_VISIBILITY} CACHE BOOL "Whether or not to hide symbols (-fvisibility=hidden)" ${FORCE_CACHE}) 386 | # Set strict compiler checks or not 387 | if(NOT DEFINED ENABLE_STRICT_TRY_COMPILE) 388 | # Unless specified, disable strict try_compile() 389 | set(ENABLE_STRICT_TRY_COMPILE FALSE) 390 | message(STATUS "Using NON-strict compiler checks by default. ENABLE_STRICT_TRY_COMPILE not provided!") 391 | endif() 392 | set(ENABLE_STRICT_TRY_COMPILE_INT ${ENABLE_STRICT_TRY_COMPILE} CACHE BOOL "Whether or not to use strict compiler checks" ${FORCE_CACHE}) 393 | # Get the SDK version information. 394 | execute_process(COMMAND xcodebuild -sdk ${CMAKE_OSX_SYSROOT} -version SDKVersion 395 | OUTPUT_VARIABLE SDK_VERSION 396 | ERROR_QUIET 397 | OUTPUT_STRIP_TRAILING_WHITESPACE) 398 | 399 | # Find the Developer root for the specific iOS platform being compiled for 400 | # from CMAKE_OSX_SYSROOT. Should be ../../ from SDK specified in 401 | # CMAKE_OSX_SYSROOT. There does not appear to be a direct way to obtain 402 | # this information from xcrun or xcodebuild. 403 | if (NOT DEFINED CMAKE_DEVELOPER_ROOT AND NOT USED_CMAKE_GENERATOR MATCHES "Xcode") 404 | get_filename_component(PLATFORM_SDK_DIR ${CMAKE_OSX_SYSROOT} PATH) 405 | get_filename_component(CMAKE_DEVELOPER_ROOT ${PLATFORM_SDK_DIR} PATH) 406 | if (NOT DEFINED CMAKE_DEVELOPER_ROOT) 407 | message(FATAL_ERROR "Invalid CMAKE_DEVELOPER_ROOT: " 408 | "${CMAKE_DEVELOPER_ROOT} does not exist.") 409 | endif() 410 | endif() 411 | # Find the C & C++ compilers for the specified SDK. 412 | if(NOT CMAKE_C_COMPILER) 413 | execute_process(COMMAND xcrun -sdk ${CMAKE_OSX_SYSROOT} -find clang 414 | OUTPUT_VARIABLE CMAKE_C_COMPILER 415 | ERROR_QUIET 416 | OUTPUT_STRIP_TRAILING_WHITESPACE) 417 | message(STATUS "Using C compiler: ${CMAKE_C_COMPILER}") 418 | endif() 419 | if(NOT CMAKE_CXX_COMPILER) 420 | execute_process(COMMAND xcrun -sdk ${CMAKE_OSX_SYSROOT} -find clang++ 421 | OUTPUT_VARIABLE CMAKE_CXX_COMPILER 422 | ERROR_QUIET 423 | OUTPUT_STRIP_TRAILING_WHITESPACE) 424 | message(STATUS "Using CXX compiler: ${CMAKE_CXX_COMPILER}") 425 | endif() 426 | # Find (Apple's) libtool. 427 | execute_process(COMMAND xcrun -sdk ${CMAKE_OSX_SYSROOT} -find libtool 428 | OUTPUT_VARIABLE BUILD_LIBTOOL 429 | ERROR_QUIET 430 | OUTPUT_STRIP_TRAILING_WHITESPACE) 431 | message(STATUS "Using libtool: ${BUILD_LIBTOOL}") 432 | # Configure libtool to be used instead of ar + ranlib to build static libraries. 433 | # This is required on Xcode 7+, but should also work on previous versions of 434 | # Xcode. 435 | set(CMAKE_C_CREATE_STATIC_LIBRARY 436 | "${BUILD_LIBTOOL} -static -o ") 437 | set(CMAKE_CXX_CREATE_STATIC_LIBRARY 438 | "${BUILD_LIBTOOL} -static -o ") 439 | # Find the toolchain's provided install_name_tool if none is found on the host 440 | if(NOT CMAKE_INSTALL_NAME_TOOL) 441 | execute_process(COMMAND xcrun -sdk ${CMAKE_OSX_SYSROOT} -find install_name_tool 442 | OUTPUT_VARIABLE CMAKE_INSTALL_NAME_TOOL_INT 443 | ERROR_QUIET 444 | OUTPUT_STRIP_TRAILING_WHITESPACE) 445 | set(CMAKE_INSTALL_NAME_TOOL ${CMAKE_INSTALL_NAME_TOOL_INT} CACHE STRING "" ${FORCE_CACHE}) 446 | endif() 447 | # Get the version of Darwin (OS X) of the host. 448 | execute_process(COMMAND uname -r 449 | OUTPUT_VARIABLE CMAKE_HOST_SYSTEM_VERSION 450 | ERROR_QUIET 451 | OUTPUT_STRIP_TRAILING_WHITESPACE) 452 | if(SDK_NAME MATCHES "iphone") 453 | set(CMAKE_SYSTEM_NAME iOS CACHE INTERNAL "" ${FORCE_CACHE}) 454 | endif() 455 | # CMake 3.14+ support building for iOS, watchOS and tvOS out of the box. 456 | if(MODERN_CMAKE) 457 | if(SDK_NAME MATCHES "appletv") 458 | set(CMAKE_SYSTEM_NAME tvOS CACHE INTERNAL "" ${FORCE_CACHE}) 459 | elseif(SDK_NAME MATCHES "watch") 460 | set(CMAKE_SYSTEM_NAME watchOS CACHE INTERNAL "" ${FORCE_CACHE}) 461 | endif() 462 | # Provide flags for a combined FAT library build on newer CMake versions 463 | if(PLATFORM_INT MATCHES ".*COMBINED") 464 | set(CMAKE_XCODE_ATTRIBUTE_ONLY_ACTIVE_ARCH "NO" CACHE INTERNAL "" ${FORCE_CACHE}) 465 | set(CMAKE_IOS_INSTALL_COMBINED YES CACHE INTERNAL "" ${FORCE_CACHE}) 466 | message(STATUS "Will combine built (static) artifacts into FAT lib...") 467 | endif() 468 | elseif(${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.10") 469 | # Legacy code path prior to CMake 3.14 or fallback if no SDK_NAME specified 470 | set(CMAKE_SYSTEM_NAME iOS CACHE INTERNAL "" ${FORCE_CACHE}) 471 | else() 472 | # Legacy code path prior to CMake 3.14 or fallback if no SDK_NAME specified 473 | set(CMAKE_SYSTEM_NAME Darwin CACHE INTERNAL "" ${FORCE_CACHE}) 474 | endif() 475 | # Standard settings. 476 | set(CMAKE_SYSTEM_VERSION ${SDK_VERSION} CACHE INTERNAL "") 477 | set(UNIX TRUE CACHE BOOL "") 478 | set(APPLE TRUE CACHE BOOL "") 479 | set(IOS TRUE CACHE BOOL "") 480 | set(CMAKE_AR ar CACHE FILEPATH "" FORCE) 481 | set(CMAKE_RANLIB ranlib CACHE FILEPATH "" FORCE) 482 | set(CMAKE_STRIP strip CACHE FILEPATH "" FORCE) 483 | # Set the architectures for which to build. 484 | set(CMAKE_OSX_ARCHITECTURES ${ARCHS} CACHE STRING "Build architecture for iOS") 485 | # Change the type of target generated for try_compile() so it'll work when cross-compiling, weak compiler checks 486 | if(ENABLE_STRICT_TRY_COMPILE_INT) 487 | message(STATUS "Using strict compiler checks (default in CMake).") 488 | else() 489 | set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY) 490 | endif() 491 | # All iOS/Darwin specific settings - some may be redundant. 492 | set(CMAKE_MACOSX_BUNDLE YES) 493 | set(CMAKE_XCODE_ATTRIBUTE_CODE_SIGNING_REQUIRED "NO") 494 | set(CMAKE_SHARED_LIBRARY_PREFIX "lib") 495 | set(CMAKE_SHARED_LIBRARY_SUFFIX ".dylib") 496 | set(CMAKE_SHARED_MODULE_PREFIX "lib") 497 | set(CMAKE_SHARED_MODULE_SUFFIX ".so") 498 | set(CMAKE_C_COMPILER_ABI ELF) 499 | set(CMAKE_CXX_COMPILER_ABI ELF) 500 | set(CMAKE_C_HAS_ISYSROOT 1) 501 | set(CMAKE_CXX_HAS_ISYSROOT 1) 502 | set(CMAKE_MODULE_EXISTS 1) 503 | set(CMAKE_DL_LIBS "") 504 | set(CMAKE_C_OSX_COMPATIBILITY_VERSION_FLAG "-compatibility_version ") 505 | set(CMAKE_C_OSX_CURRENT_VERSION_FLAG "-current_version ") 506 | set(CMAKE_CXX_OSX_COMPATIBILITY_VERSION_FLAG "${CMAKE_C_OSX_COMPATIBILITY_VERSION_FLAG}") 507 | set(CMAKE_CXX_OSX_CURRENT_VERSION_FLAG "${CMAKE_C_OSX_CURRENT_VERSION_FLAG}") 508 | 509 | if(ARCHS MATCHES "((^|;|, )(arm64|arm64e|x86_64))+") 510 | set(CMAKE_C_SIZEOF_DATA_PTR 8) 511 | set(CMAKE_CXX_SIZEOF_DATA_PTR 8) 512 | if(ARCHS MATCHES "((^|;|, )(arm64|arm64e))+") 513 | set(CMAKE_SYSTEM_PROCESSOR "aarch64") 514 | else() 515 | set(CMAKE_SYSTEM_PROCESSOR "x86_64") 516 | endif() 517 | else() 518 | set(CMAKE_C_SIZEOF_DATA_PTR 4) 519 | set(CMAKE_CXX_SIZEOF_DATA_PTR 4) 520 | set(CMAKE_SYSTEM_PROCESSOR "arm") 521 | endif() 522 | 523 | # Note that only Xcode 7+ supports the newer more specific: 524 | # -m${SDK_NAME}-version-min flags, older versions of Xcode use: 525 | # -m(ios/ios-simulator)-version-min instead. 526 | if(${CMAKE_VERSION} VERSION_LESS "3.11") 527 | if(PLATFORM_INT STREQUAL "OS" OR PLATFORM_INT STREQUAL "OS64") 528 | if(XCODE_VERSION VERSION_LESS 7.0) 529 | set(SDK_NAME_VERSION_FLAGS 530 | "-mios-version-min=${DEPLOYMENT_TARGET}") 531 | else() 532 | # Xcode 7.0+ uses flags we can build directly from SDK_NAME. 533 | set(SDK_NAME_VERSION_FLAGS 534 | "-m${SDK_NAME}-version-min=${DEPLOYMENT_TARGET}") 535 | endif() 536 | elseif(PLATFORM_INT STREQUAL "TVOS") 537 | set(SDK_NAME_VERSION_FLAGS 538 | "-mtvos-version-min=${DEPLOYMENT_TARGET}") 539 | elseif(PLATFORM_INT STREQUAL "SIMULATOR_TVOS") 540 | set(SDK_NAME_VERSION_FLAGS 541 | "-mtvos-simulator-version-min=${DEPLOYMENT_TARGET}") 542 | elseif(PLATFORM_INT STREQUAL "WATCHOS") 543 | set(SDK_NAME_VERSION_FLAGS 544 | "-mwatchos-version-min=${DEPLOYMENT_TARGET}") 545 | elseif(PLATFORM_INT STREQUAL "SIMULATOR_WATCHOS") 546 | set(SDK_NAME_VERSION_FLAGS 547 | "-mwatchos-simulator-version-min=${DEPLOYMENT_TARGET}") 548 | else() 549 | # SIMULATOR or SIMULATOR64 both use -mios-simulator-version-min. 550 | set(SDK_NAME_VERSION_FLAGS 551 | "-mios-simulator-version-min=${DEPLOYMENT_TARGET}") 552 | endif() 553 | else() 554 | # Newer versions of CMake sets the version min flags correctly 555 | set(CMAKE_OSX_DEPLOYMENT_TARGET ${DEPLOYMENT_TARGET} CACHE STRING 556 | "Set CMake deployment target" ${FORCE_CACHE}) 557 | endif() 558 | 559 | if(DEFINED APPLE_TARGET_TRIPLE_INT) 560 | set(APPLE_TARGET_TRIPLE ${APPLE_TARGET_TRIPLE_INT} CACHE STRING 561 | "Autoconf target triple compatible variable" ${FORCE_CACHE}) 562 | endif() 563 | 564 | if(ENABLE_BITCODE_INT) 565 | set(BITCODE "-fembed-bitcode") 566 | set(CMAKE_XCODE_ATTRIBUTE_BITCODE_GENERATION_MODE "bitcode" CACHE INTERNAL "") 567 | set(CMAKE_XCODE_ATTRIBUTE_ENABLE_BITCODE "YES" CACHE INTERNAL "") 568 | else() 569 | set(BITCODE "") 570 | set(CMAKE_XCODE_ATTRIBUTE_ENABLE_BITCODE "NO" CACHE INTERNAL "") 571 | endif() 572 | 573 | if(ENABLE_ARC_INT) 574 | set(FOBJC_ARC "-fobjc-arc") 575 | set(CMAKE_XCODE_ATTRIBUTE_CLANG_ENABLE_OBJC_ARC "YES" CACHE INTERNAL "") 576 | else() 577 | set(FOBJC_ARC "-fno-objc-arc") 578 | set(CMAKE_XCODE_ATTRIBUTE_CLANG_ENABLE_OBJC_ARC "NO" CACHE INTERNAL "") 579 | endif() 580 | 581 | if(NOT ENABLE_VISIBILITY_INT) 582 | set(VISIBILITY "-fvisibility=hidden") 583 | set(CMAKE_XCODE_ATTRIBUTE_GCC_SYMBOLS_PRIVATE_EXTERN "YES" CACHE INTERNAL "") 584 | else() 585 | set(VISIBILITY "") 586 | set(CMAKE_XCODE_ATTRIBUTE_GCC_SYMBOLS_PRIVATE_EXTERN "NO" CACHE INTERNAL "") 587 | endif() 588 | 589 | if(NOT IOS_TOOLCHAIN_HAS_RUN) 590 | #Check if Xcode generator is used, since that will handle these flags automagically 591 | if(USED_CMAKE_GENERATOR MATCHES "Xcode") 592 | message(STATUS "Not setting any manual command-line buildflags, since Xcode is selected as generator.") 593 | else() 594 | set(CMAKE_C_FLAGS 595 | "${SDK_NAME_VERSION_FLAGS} ${BITCODE} -fobjc-abi-version=2 ${FOBJC_ARC} ${CMAKE_C_FLAGS}") 596 | # Hidden visibilty is required for C++ on iOS. 597 | set(CMAKE_CXX_FLAGS 598 | "${SDK_NAME_VERSION_FLAGS} ${BITCODE} ${VISIBILITY} -fvisibility-inlines-hidden -fobjc-abi-version=2 ${FOBJC_ARC} ${CMAKE_CXX_FLAGS}") 599 | set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS} -O0 -g ${CMAKE_CXX_FLAGS_DEBUG}") 600 | set(CMAKE_CXX_FLAGS_MINSIZEREL "${CMAKE_CXX_FLAGS} -DNDEBUG -Os -ffast-math ${CMAKE_CXX_FLAGS_MINSIZEREL}") 601 | set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS} -DNDEBUG -O2 -g -ffast-math ${CMAKE_CXX_FLAGS_RELWITHDEBINFO}") 602 | set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS} -DNDEBUG -O3 -ffast-math ${CMAKE_CXX_FLAGS_RELEASE}") 603 | set(CMAKE_C_LINK_FLAGS "${SDK_NAME_VERSION_FLAGS} -Wl,-search_paths_first ${CMAKE_C_LINK_FLAGS}") 604 | set(CMAKE_CXX_LINK_FLAGS "${SDK_NAME_VERSION_FLAGS} -Wl,-search_paths_first ${CMAKE_CXX_LINK_FLAGS}") 605 | set(CMAKE_ASM_FLAGS "${CFLAGS} -x assembler-with-cpp") 606 | 607 | # In order to ensure that the updated compiler flags are used in try_compile() 608 | # tests, we have to forcibly set them in the CMake cache, not merely set them 609 | # in the local scope. 610 | set(VARS_TO_FORCE_IN_CACHE 611 | CMAKE_C_FLAGS 612 | CMAKE_CXX_FLAGS 613 | CMAKE_CXX_FLAGS_DEBUG 614 | CMAKE_CXX_FLAGS_RELWITHDEBINFO 615 | CMAKE_CXX_FLAGS_MINSIZEREL 616 | CMAKE_CXX_FLAGS_RELEASE 617 | CMAKE_C_LINK_FLAGS 618 | CMAKE_CXX_LINK_FLAGS) 619 | foreach(VAR_TO_FORCE ${VARS_TO_FORCE_IN_CACHE}) 620 | set(${VAR_TO_FORCE} "${${VAR_TO_FORCE}}" CACHE STRING "" ${FORCE_CACHE}) 621 | endforeach() 622 | endif() 623 | 624 | ## Print status messages to inform of the current state 625 | message(STATUS "Configuring ${SDK_NAME} build for platform: ${PLATFORM_INT}, architecture(s): ${ARCHS}") 626 | message(STATUS "Using SDK: ${CMAKE_OSX_SYSROOT_INT}") 627 | if(DEFINED APPLE_TARGET_TRIPLE) 628 | message(STATUS "Autoconf target triple: ${APPLE_TARGET_TRIPLE}") 629 | endif() 630 | message(STATUS "Using minimum deployment version: ${DEPLOYMENT_TARGET}" 631 | " (SDK version: ${SDK_VERSION})") 632 | if(MODERN_CMAKE) 633 | message(STATUS "Merging integrated CMake 3.14+ iOS,tvOS,watchOS,macOS toolchain(s) with this toolchain!") 634 | endif() 635 | if(USED_CMAKE_GENERATOR MATCHES "Xcode") 636 | message(STATUS "Using Xcode version: ${XCODE_VERSION}") 637 | endif() 638 | if(DEFINED SDK_NAME_VERSION_FLAGS) 639 | message(STATUS "Using version flags: ${SDK_NAME_VERSION_FLAGS}") 640 | endif() 641 | message(STATUS "Using a data_ptr size of: ${CMAKE_CXX_SIZEOF_DATA_PTR}") 642 | message(STATUS "Using install_name_tool: ${CMAKE_INSTALL_NAME_TOOL}") 643 | if(ENABLE_BITCODE_INT) 644 | message(STATUS "Enabling bitcode support.") 645 | else() 646 | message(STATUS "Disabling bitcode support.") 647 | endif() 648 | 649 | if(ENABLE_ARC_INT) 650 | message(STATUS "Enabling ARC support.") 651 | else() 652 | message(STATUS "Disabling ARC support.") 653 | endif() 654 | 655 | if(NOT ENABLE_VISIBILITY_INT) 656 | message(STATUS "Hiding symbols (-fvisibility=hidden).") 657 | endif() 658 | endif() 659 | 660 | set(CMAKE_PLATFORM_HAS_INSTALLNAME 1) 661 | set(CMAKE_SHARED_LINKER_FLAGS "-rpath @executable_path/Frameworks -rpath @loader_path/Frameworks") 662 | set(CMAKE_SHARED_LIBRARY_CREATE_C_FLAGS "-dynamiclib -Wl,-headerpad_max_install_names") 663 | set(CMAKE_SHARED_MODULE_CREATE_C_FLAGS "-bundle -Wl,-headerpad_max_install_names") 664 | set(CMAKE_SHARED_MODULE_LOADER_C_FLAG "-Wl,-bundle_loader,") 665 | set(CMAKE_SHARED_MODULE_LOADER_CXX_FLAG "-Wl,-bundle_loader,") 666 | set(CMAKE_FIND_LIBRARY_SUFFIXES ".tbd" ".dylib" ".so" ".a") 667 | set(CMAKE_SHARED_LIBRARY_SONAME_C_FLAG "-install_name") 668 | 669 | # Set the find root to the iOS developer roots and to user defined paths. 670 | set(CMAKE_FIND_ROOT_PATH ${CMAKE_OSX_SYSROOT_INT} ${CMAKE_PREFIX_PATH} CACHE STRING "Root path that will be prepended 671 | to all search paths") 672 | # Default to searching for frameworks first. 673 | set(CMAKE_FIND_FRAMEWORK FIRST) 674 | # Set up the default search directories for frameworks. 675 | set(CMAKE_FRAMEWORK_PATH 676 | ${CMAKE_DEVELOPER_ROOT}/Library/PrivateFrameworks 677 | ${CMAKE_OSX_SYSROOT_INT}/System/Library/Frameworks 678 | ${CMAKE_FRAMEWORK_PATH} CACHE STRING "Frameworks search paths" ${FORCE_CACHE}) 679 | 680 | set(IOS_TOOLCHAIN_HAS_RUN TRUE CACHE BOOL "Has the CMake toolchain run already?" ${FORCE_CACHE}) 681 | 682 | # By default, search both the specified iOS SDK and the remainder of the host filesystem. 683 | if(NOT CMAKE_FIND_ROOT_PATH_MODE_PROGRAM) 684 | set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM BOTH CACHE STRING "" ${FORCE_CACHE}) 685 | endif() 686 | if(NOT CMAKE_FIND_ROOT_PATH_MODE_LIBRARY) 687 | set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY BOTH CACHE STRING "" ${FORCE_CACHE}) 688 | endif() 689 | if(NOT CMAKE_FIND_ROOT_PATH_MODE_INCLUDE) 690 | set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE BOTH CACHE STRING "" ${FORCE_CACHE}) 691 | endif() 692 | if(NOT CMAKE_FIND_ROOT_PATH_MODE_PACKAGE) 693 | set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE BOTH CACHE STRING "" ${FORCE_CACHE}) 694 | endif() 695 | 696 | # 697 | # Some helper-macros below to simplify and beautify the CMakeFile 698 | # 699 | 700 | # This little macro lets you set any Xcode specific property. 701 | macro(set_xcode_property TARGET XCODE_PROPERTY XCODE_VALUE XCODE_RELVERSION) 702 | set(XCODE_RELVERSION_I "${XCODE_RELVERSION}") 703 | if(XCODE_RELVERSION_I STREQUAL "All") 704 | set_property(TARGET ${TARGET} PROPERTY 705 | XCODE_ATTRIBUTE_${XCODE_PROPERTY} "${XCODE_VALUE}") 706 | else() 707 | set_property(TARGET ${TARGET} PROPERTY 708 | XCODE_ATTRIBUTE_${XCODE_PROPERTY}[variant=${XCODE_RELVERSION_I}] "${XCODE_VALUE}") 709 | endif() 710 | endmacro(set_xcode_property) 711 | 712 | # This macro lets you find executable programs on the host system. 713 | macro(find_host_package) 714 | set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) 715 | set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY NEVER) 716 | set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE NEVER) 717 | set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE NEVER) 718 | set(IOS FALSE) 719 | find_package(${ARGN}) 720 | set(IOS TRUE) 721 | set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM BOTH) 722 | set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY BOTH) 723 | set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE BOTH) 724 | set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE BOTH) 725 | endmacro(find_host_package) 726 | -------------------------------------------------------------------------------- /Source/Managed/ENet.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * Managed C# wrapper for an extended version of ENet 3 | * This is a fork from upstream and is available at http://github.com/SoftwareGuy/ENet-CSharp 4 | * 5 | * Copyright (c) 2019-2023 Matt Coburn (SoftwareGuy/Coburn64), Chris Burns (c6burns) 6 | * Copyright (c) 2013 James Bellinger, 2016 Nate Shoffner, 2018 Stanislav Denisov 7 | * 8 | * Permission is hereby granted, free of charge, to any person obtaining a copy 9 | * of this software and associated documentation files (the "Software"), to deal 10 | * in the Software without restriction, including without limitation the rights 11 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | * copies of the Software, and to permit persons to whom the Software is 13 | * furnished to do so, subject to the following conditions: 14 | * 15 | * The above copyright notice and this permission notice shall be included in all 16 | * copies or substantial portions of the Software. 17 | * 18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 24 | * SOFTWARE. 25 | */ 26 | 27 | using System; 28 | using System.Runtime.InteropServices; 29 | using System.Security; 30 | using System.Text; 31 | 32 | namespace ENet 33 | { 34 | [Flags] 35 | public enum PacketFlags 36 | { 37 | None = 0, 38 | Reliable = 1 << 0, 39 | Unsequenced = 1 << 1, 40 | NoAllocate = 1 << 2, 41 | UnreliableFragmented = 1 << 3, 42 | Instant = 1 << 4, 43 | Unthrottled = 1 << 5, 44 | Sent = 1 << 8 45 | } 46 | 47 | public enum EventType 48 | { 49 | None = 0, 50 | Connect = 1, 51 | Disconnect = 2, 52 | Receive = 3, 53 | Timeout = 4 54 | } 55 | 56 | public enum PeerState 57 | { 58 | Uninitialized = -1, 59 | Disconnected = 0, 60 | Connecting = 1, 61 | AcknowledgingConnect = 2, 62 | ConnectionPending = 3, 63 | ConnectionSucceeded = 4, 64 | Connected = 5, 65 | DisconnectLater = 6, 66 | Disconnecting = 7, 67 | AcknowledgingDisconnect = 8, 68 | Zombie = 9 69 | } 70 | 71 | [StructLayout(LayoutKind.Explicit, Size = 18)] 72 | internal struct ENetAddress 73 | { 74 | [FieldOffset(16)] 75 | public ushort port; 76 | } 77 | 78 | [StructLayout(LayoutKind.Sequential)] 79 | internal struct ENetEvent 80 | { 81 | public EventType type; 82 | public IntPtr peer; 83 | public byte channelID; 84 | public uint data; 85 | public IntPtr packet; 86 | } 87 | 88 | [StructLayout(LayoutKind.Sequential)] 89 | internal struct ENetCallbacks 90 | { 91 | public AllocCallback malloc; 92 | public FreeCallback free; 93 | public NoMemoryCallback noMemory; 94 | } 95 | 96 | public delegate IntPtr AllocCallback(IntPtr size); 97 | public delegate void FreeCallback(IntPtr memory); 98 | public delegate void NoMemoryCallback(); 99 | public delegate void PacketFreeCallback(Packet packet); 100 | public delegate int InterceptCallback(ref Event @event, ref Address address, IntPtr receivedData, int receivedDataLength); 101 | public delegate ulong ChecksumCallback(IntPtr buffers, int bufferCount); 102 | 103 | internal static class ArrayPool 104 | { 105 | [ThreadStatic] 106 | private static byte[] byteBuffer; 107 | [ThreadStatic] 108 | private static IntPtr[] pointerBuffer; 109 | 110 | public static byte[] GetByteBuffer() 111 | { 112 | if (byteBuffer == null) 113 | byteBuffer = new byte[64]; 114 | 115 | return byteBuffer; 116 | } 117 | 118 | public static IntPtr[] GetPointerBuffer() 119 | { 120 | if (pointerBuffer == null) 121 | pointerBuffer = new IntPtr[Library.maxPeers]; 122 | 123 | return pointerBuffer; 124 | } 125 | } 126 | 127 | public struct Address 128 | { 129 | private ENetAddress nativeAddress; 130 | 131 | internal ENetAddress NativeData 132 | { 133 | get 134 | { 135 | return nativeAddress; 136 | } 137 | 138 | set 139 | { 140 | nativeAddress = value; 141 | } 142 | } 143 | 144 | internal Address(ENetAddress address) 145 | { 146 | nativeAddress = address; 147 | } 148 | 149 | public ushort Port 150 | { 151 | get 152 | { 153 | return nativeAddress.port; 154 | } 155 | 156 | set 157 | { 158 | nativeAddress.port = value; 159 | } 160 | } 161 | 162 | public string GetIP() 163 | { 164 | StringBuilder ip = new StringBuilder(1025); 165 | 166 | if (Native.enet_address_get_ip(ref nativeAddress, ip, (IntPtr)ip.Capacity) != 0) 167 | return String.Empty; 168 | 169 | return ip.ToString(); 170 | } 171 | 172 | public bool SetIP(string ip) 173 | { 174 | if (ip == null) 175 | throw new ArgumentNullException("ip"); 176 | 177 | return Native.enet_address_set_ip(ref nativeAddress, ip) == 0; 178 | } 179 | 180 | public string GetHost() 181 | { 182 | StringBuilder hostName = new StringBuilder(1025); 183 | 184 | if (Native.enet_address_get_hostname(ref nativeAddress, hostName, (IntPtr)hostName.Capacity) != 0) 185 | return String.Empty; 186 | 187 | return hostName.ToString(); 188 | } 189 | 190 | public bool SetHost(string hostName) 191 | { 192 | if (hostName == null) 193 | throw new ArgumentNullException("hostName"); 194 | 195 | return Native.enet_address_set_hostname(ref nativeAddress, hostName) == 0; 196 | } 197 | } 198 | 199 | public struct Event 200 | { 201 | private ENetEvent nativeEvent; 202 | 203 | internal ENetEvent NativeData 204 | { 205 | get 206 | { 207 | return nativeEvent; 208 | } 209 | 210 | set 211 | { 212 | nativeEvent = value; 213 | } 214 | } 215 | 216 | internal Event(ENetEvent @event) 217 | { 218 | nativeEvent = @event; 219 | } 220 | 221 | public EventType Type 222 | { 223 | get 224 | { 225 | return nativeEvent.type; 226 | } 227 | } 228 | 229 | public Peer Peer 230 | { 231 | get 232 | { 233 | return new Peer(nativeEvent.peer); 234 | } 235 | } 236 | 237 | public byte ChannelID 238 | { 239 | get 240 | { 241 | return nativeEvent.channelID; 242 | } 243 | } 244 | 245 | public uint Data 246 | { 247 | get 248 | { 249 | return nativeEvent.data; 250 | } 251 | } 252 | 253 | public Packet Packet 254 | { 255 | get 256 | { 257 | return new Packet(nativeEvent.packet); 258 | } 259 | } 260 | } 261 | 262 | public class Callbacks 263 | { 264 | private ENetCallbacks nativeCallbacks; 265 | 266 | internal ENetCallbacks NativeData 267 | { 268 | get 269 | { 270 | return nativeCallbacks; 271 | } 272 | 273 | set 274 | { 275 | nativeCallbacks = value; 276 | } 277 | } 278 | 279 | public Callbacks(AllocCallback allocCallback, FreeCallback freeCallback, NoMemoryCallback noMemoryCallback) 280 | { 281 | nativeCallbacks.malloc = allocCallback; 282 | nativeCallbacks.free = freeCallback; 283 | nativeCallbacks.noMemory = noMemoryCallback; 284 | } 285 | } 286 | 287 | public struct Packet : IDisposable 288 | { 289 | private IntPtr nativePacket; 290 | 291 | internal IntPtr NativeData 292 | { 293 | get 294 | { 295 | return nativePacket; 296 | } 297 | 298 | set 299 | { 300 | nativePacket = value; 301 | } 302 | } 303 | 304 | internal Packet(IntPtr packet) 305 | { 306 | nativePacket = packet; 307 | } 308 | 309 | public void Dispose() 310 | { 311 | if (nativePacket != IntPtr.Zero) 312 | { 313 | Native.enet_packet_dispose(nativePacket); 314 | nativePacket = IntPtr.Zero; 315 | } 316 | } 317 | 318 | public bool IsSet 319 | { 320 | get 321 | { 322 | return nativePacket != IntPtr.Zero; 323 | } 324 | } 325 | 326 | public IntPtr Data 327 | { 328 | get 329 | { 330 | ThrowIfNotCreated(); 331 | 332 | return Native.enet_packet_get_data(nativePacket); 333 | } 334 | } 335 | 336 | public IntPtr UserData 337 | { 338 | get 339 | { 340 | ThrowIfNotCreated(); 341 | 342 | return Native.enet_packet_get_user_data(nativePacket); 343 | } 344 | 345 | set 346 | { 347 | ThrowIfNotCreated(); 348 | 349 | Native.enet_packet_set_user_data(nativePacket, value); 350 | } 351 | } 352 | 353 | public int Length 354 | { 355 | get 356 | { 357 | ThrowIfNotCreated(); 358 | 359 | return Native.enet_packet_get_length(nativePacket); 360 | } 361 | } 362 | 363 | public bool HasReferences 364 | { 365 | get 366 | { 367 | ThrowIfNotCreated(); 368 | 369 | return Native.enet_packet_check_references(nativePacket) != 0; 370 | } 371 | } 372 | 373 | internal void ThrowIfNotCreated() 374 | { 375 | if (nativePacket == IntPtr.Zero) 376 | throw new InvalidOperationException("Packet not created"); 377 | } 378 | 379 | public void SetFreeCallback(IntPtr callback) 380 | { 381 | ThrowIfNotCreated(); 382 | 383 | Native.enet_packet_set_free_callback(nativePacket, callback); 384 | } 385 | 386 | public void SetFreeCallback(PacketFreeCallback callback) 387 | { 388 | ThrowIfNotCreated(); 389 | 390 | Native.enet_packet_set_free_callback(nativePacket, Marshal.GetFunctionPointerForDelegate(callback)); 391 | } 392 | 393 | public void Create(byte[] data) 394 | { 395 | if (data == null) 396 | throw new ArgumentNullException("data"); 397 | 398 | Create(data, data.Length); 399 | } 400 | 401 | public void Create(byte[] data, int length) 402 | { 403 | Create(data, length, PacketFlags.None); 404 | } 405 | 406 | public void Create(byte[] data, PacketFlags flags) 407 | { 408 | Create(data, data.Length, flags); 409 | } 410 | 411 | public void Create(byte[] data, int length, PacketFlags flags) 412 | { 413 | if (data == null) 414 | throw new ArgumentNullException("data"); 415 | 416 | if (length < 0 || length > data.Length) 417 | throw new ArgumentOutOfRangeException("length"); 418 | 419 | nativePacket = Native.enet_packet_create(data, (IntPtr)length, flags); 420 | } 421 | 422 | public void Create(IntPtr data, int length, PacketFlags flags) 423 | { 424 | if (data == IntPtr.Zero) 425 | throw new ArgumentNullException("data"); 426 | 427 | if (length < 0) 428 | throw new ArgumentOutOfRangeException("length"); 429 | 430 | nativePacket = Native.enet_packet_create(data, (IntPtr)length, flags); 431 | } 432 | 433 | public void Create(byte[] data, int offset, int length, PacketFlags flags) 434 | { 435 | if (data == null) 436 | throw new ArgumentNullException("data"); 437 | 438 | if (offset < 0) 439 | throw new ArgumentOutOfRangeException("offset"); 440 | 441 | if (length < 0 || length > data.Length) 442 | throw new ArgumentOutOfRangeException("length"); 443 | 444 | nativePacket = Native.enet_packet_create_offset(data, (IntPtr)length, (IntPtr)offset, flags); 445 | } 446 | 447 | public void Create(IntPtr data, int offset, int length, PacketFlags flags) 448 | { 449 | if (data == IntPtr.Zero) 450 | throw new ArgumentNullException("data"); 451 | 452 | if (offset < 0) 453 | throw new ArgumentOutOfRangeException("offset"); 454 | 455 | if (length < 0) 456 | throw new ArgumentOutOfRangeException("length"); 457 | 458 | nativePacket = Native.enet_packet_create_offset(data, (IntPtr)length, (IntPtr)offset, flags); 459 | } 460 | 461 | public void CopyTo(byte[] destination, int startPos = 0) 462 | { 463 | if (destination == null) 464 | throw new ArgumentNullException("destination"); 465 | 466 | // Fix by katori, prevents trying to copy a NULL 467 | // from native world (ie. disconnect a client) 468 | if (Data == null) 469 | { 470 | return; 471 | } 472 | 473 | Marshal.Copy(Data, destination, startPos, Length); 474 | } 475 | } 476 | 477 | public class Host : IDisposable 478 | { 479 | private IntPtr nativeHost; 480 | 481 | internal IntPtr NativeData 482 | { 483 | get 484 | { 485 | return nativeHost; 486 | } 487 | 488 | set 489 | { 490 | nativeHost = value; 491 | } 492 | } 493 | 494 | public void Dispose() 495 | { 496 | Dispose(true); 497 | GC.SuppressFinalize(this); 498 | } 499 | 500 | protected virtual void Dispose(bool disposing) 501 | { 502 | if (nativeHost != IntPtr.Zero) 503 | { 504 | Native.enet_host_destroy(nativeHost); 505 | nativeHost = IntPtr.Zero; 506 | } 507 | } 508 | 509 | ~Host() 510 | { 511 | Dispose(false); 512 | } 513 | 514 | public bool IsSet 515 | { 516 | get 517 | { 518 | return nativeHost != IntPtr.Zero; 519 | } 520 | } 521 | 522 | public uint PeersCount 523 | { 524 | get 525 | { 526 | ThrowIfNotCreated(); 527 | 528 | return Native.enet_host_get_peers_count(nativeHost); 529 | } 530 | } 531 | 532 | public uint PacketsSent 533 | { 534 | get 535 | { 536 | ThrowIfNotCreated(); 537 | 538 | return Native.enet_host_get_packets_sent(nativeHost); 539 | } 540 | } 541 | 542 | public uint PacketsReceived 543 | { 544 | get 545 | { 546 | ThrowIfNotCreated(); 547 | 548 | return Native.enet_host_get_packets_received(nativeHost); 549 | } 550 | } 551 | 552 | public uint BytesSent 553 | { 554 | get 555 | { 556 | ThrowIfNotCreated(); 557 | 558 | return Native.enet_host_get_bytes_sent(nativeHost); 559 | } 560 | } 561 | 562 | public uint BytesReceived 563 | { 564 | get 565 | { 566 | ThrowIfNotCreated(); 567 | 568 | return Native.enet_host_get_bytes_received(nativeHost); 569 | } 570 | } 571 | 572 | internal void ThrowIfNotCreated() 573 | { 574 | if (nativeHost == IntPtr.Zero) 575 | throw new InvalidOperationException("Host not created"); 576 | } 577 | 578 | private static void ThrowIfChannelsExceeded(int channelLimit) 579 | { 580 | if (channelLimit < 0 || channelLimit > Library.maxChannelCount) 581 | throw new ArgumentOutOfRangeException("channelLimit"); 582 | } 583 | 584 | public void Create() 585 | { 586 | Create(null, 1, 0); 587 | } 588 | 589 | public void Create(int bufferSize) 590 | { 591 | Create(null, 1, 0, 0, 0, bufferSize); 592 | } 593 | 594 | public void Create(Address? address, int peerLimit) 595 | { 596 | Create(address, peerLimit, 0); 597 | } 598 | 599 | public void Create(Address? address, int peerLimit, int channelLimit) 600 | { 601 | Create(address, peerLimit, channelLimit, 0, 0, 0); 602 | } 603 | 604 | public void Create(int peerLimit, int channelLimit) 605 | { 606 | Create(null, peerLimit, channelLimit, 0, 0, 0); 607 | } 608 | 609 | public void Create(int peerLimit, int channelLimit, uint incomingBandwidth, uint outgoingBandwidth) 610 | { 611 | Create(null, peerLimit, channelLimit, incomingBandwidth, outgoingBandwidth, 0); 612 | } 613 | 614 | public void Create(Address? address, int peerLimit, int channelLimit, uint incomingBandwidth, uint outgoingBandwidth) 615 | { 616 | Create(address, peerLimit, channelLimit, incomingBandwidth, outgoingBandwidth, 0); 617 | } 618 | 619 | public void Create(Address? address, int peerLimit, int channelLimit, uint incomingBandwidth, uint outgoingBandwidth, int bufferSize) 620 | { 621 | if (nativeHost != IntPtr.Zero) 622 | throw new InvalidOperationException("Host already created"); 623 | 624 | if (peerLimit < 0 || peerLimit > Library.maxPeers) 625 | throw new ArgumentOutOfRangeException("peerLimit"); 626 | 627 | ThrowIfChannelsExceeded(channelLimit); 628 | 629 | if (address != null) 630 | { 631 | var nativeAddress = address.Value.NativeData; 632 | 633 | nativeHost = Native.enet_host_create(ref nativeAddress, (IntPtr)peerLimit, (IntPtr)channelLimit, incomingBandwidth, outgoingBandwidth, bufferSize); 634 | } 635 | else 636 | { 637 | nativeHost = Native.enet_host_create(IntPtr.Zero, (IntPtr)peerLimit, (IntPtr)channelLimit, incomingBandwidth, outgoingBandwidth, bufferSize); 638 | } 639 | 640 | if (nativeHost == IntPtr.Zero) 641 | throw new InvalidOperationException("Host creation call failed"); 642 | } 643 | 644 | public void PreventConnections(bool state) 645 | { 646 | ThrowIfNotCreated(); 647 | 648 | Native.enet_host_prevent_connections(nativeHost, (byte)(state ? 1 : 0)); 649 | } 650 | 651 | public void Broadcast(byte channelID, ref Packet packet) 652 | { 653 | ThrowIfNotCreated(); 654 | 655 | packet.ThrowIfNotCreated(); 656 | Native.enet_host_broadcast(nativeHost, channelID, packet.NativeData); 657 | packet.NativeData = IntPtr.Zero; 658 | } 659 | 660 | public void Broadcast(byte channelID, ref Packet packet, Peer excludedPeer) 661 | { 662 | ThrowIfNotCreated(); 663 | 664 | packet.ThrowIfNotCreated(); 665 | Native.enet_host_broadcast_exclude(nativeHost, channelID, packet.NativeData, excludedPeer.NativeData); 666 | packet.NativeData = IntPtr.Zero; 667 | } 668 | 669 | public void Broadcast(byte channelID, ref Packet packet, Peer[] peers) 670 | { 671 | if (peers == null) 672 | throw new ArgumentNullException("peers"); 673 | 674 | ThrowIfNotCreated(); 675 | 676 | packet.ThrowIfNotCreated(); 677 | 678 | if (peers.Length > 0) 679 | { 680 | IntPtr[] nativePeers = ArrayPool.GetPointerBuffer(); 681 | int nativeCount = 0; 682 | 683 | for (int i = 0; i < peers.Length; i++) 684 | { 685 | if (peers[i].NativeData != IntPtr.Zero) 686 | { 687 | nativePeers[nativeCount] = peers[i].NativeData; 688 | nativeCount++; 689 | } 690 | } 691 | 692 | Native.enet_host_broadcast_selective(nativeHost, channelID, packet.NativeData, nativePeers, (IntPtr)nativeCount); 693 | } 694 | 695 | packet.NativeData = IntPtr.Zero; 696 | } 697 | 698 | public int CheckEvents(out Event @event) 699 | { 700 | ThrowIfNotCreated(); 701 | 702 | ENetEvent nativeEvent; 703 | 704 | var result = Native.enet_host_check_events(nativeHost, out nativeEvent); 705 | 706 | if (result <= 0) 707 | { 708 | @event = default(Event); 709 | 710 | return result; 711 | } 712 | 713 | @event = new Event(nativeEvent); 714 | 715 | return result; 716 | } 717 | 718 | public Peer Connect(Address address) 719 | { 720 | return Connect(address, 0, 0); 721 | } 722 | 723 | public Peer Connect(Address address, int channelLimit) 724 | { 725 | return Connect(address, channelLimit, 0); 726 | } 727 | 728 | public Peer Connect(Address address, int channelLimit, uint data) 729 | { 730 | ThrowIfNotCreated(); 731 | ThrowIfChannelsExceeded(channelLimit); 732 | 733 | var nativeAddress = address.NativeData; 734 | var peer = new Peer(Native.enet_host_connect(nativeHost, ref nativeAddress, (IntPtr)channelLimit, data)); 735 | 736 | if (peer.NativeData == IntPtr.Zero) 737 | throw new InvalidOperationException("Host connect call failed"); 738 | 739 | return peer; 740 | } 741 | 742 | public int Service(int timeout, out Event @event) 743 | { 744 | if (timeout < 0) 745 | throw new ArgumentOutOfRangeException("timeout"); 746 | 747 | ThrowIfNotCreated(); 748 | 749 | ENetEvent nativeEvent; 750 | 751 | var result = Native.enet_host_service(nativeHost, out nativeEvent, (uint)timeout); 752 | 753 | if (result <= 0) 754 | { 755 | @event = default(Event); 756 | 757 | return result; 758 | } 759 | 760 | @event = new Event(nativeEvent); 761 | 762 | return result; 763 | } 764 | 765 | public void SetBandwidthLimit(uint incomingBandwidth, uint outgoingBandwidth) 766 | { 767 | ThrowIfNotCreated(); 768 | 769 | Native.enet_host_bandwidth_limit(nativeHost, incomingBandwidth, outgoingBandwidth); 770 | } 771 | 772 | public void SetChannelLimit(int channelLimit) 773 | { 774 | ThrowIfNotCreated(); 775 | ThrowIfChannelsExceeded(channelLimit); 776 | 777 | Native.enet_host_channel_limit(nativeHost, (IntPtr)channelLimit); 778 | } 779 | 780 | public void SetMaxDuplicatePeers(ushort number) 781 | { 782 | ThrowIfNotCreated(); 783 | 784 | Native.enet_host_set_max_duplicate_peers(nativeHost, number); 785 | } 786 | 787 | public void SetInterceptCallback(IntPtr callback) 788 | { 789 | ThrowIfNotCreated(); 790 | 791 | Native.enet_host_set_intercept_callback(nativeHost, callback); 792 | } 793 | 794 | public void SetInterceptCallback(InterceptCallback callback) 795 | { 796 | ThrowIfNotCreated(); 797 | 798 | Native.enet_host_set_intercept_callback(nativeHost, Marshal.GetFunctionPointerForDelegate(callback)); 799 | } 800 | 801 | public void SetChecksumCallback(IntPtr callback) 802 | { 803 | ThrowIfNotCreated(); 804 | 805 | Native.enet_host_set_checksum_callback(nativeHost, callback); 806 | } 807 | 808 | public void SetChecksumCallback(ChecksumCallback callback) 809 | { 810 | ThrowIfNotCreated(); 811 | 812 | Native.enet_host_set_checksum_callback(nativeHost, Marshal.GetFunctionPointerForDelegate(callback)); 813 | } 814 | 815 | public void Flush() 816 | { 817 | ThrowIfNotCreated(); 818 | 819 | Native.enet_host_flush(nativeHost); 820 | } 821 | } 822 | 823 | public struct Peer 824 | { 825 | private IntPtr nativePeer; 826 | private uint nativeID; 827 | 828 | internal IntPtr NativeData 829 | { 830 | get 831 | { 832 | return nativePeer; 833 | } 834 | 835 | set 836 | { 837 | nativePeer = value; 838 | } 839 | } 840 | 841 | internal Peer(IntPtr peer) 842 | { 843 | nativePeer = peer; 844 | nativeID = nativePeer != IntPtr.Zero ? Native.enet_peer_get_id(nativePeer) : 0; 845 | } 846 | 847 | public bool IsSet 848 | { 849 | get 850 | { 851 | return nativePeer != IntPtr.Zero; 852 | } 853 | } 854 | 855 | public uint ID 856 | { 857 | get 858 | { 859 | return nativeID; 860 | } 861 | } 862 | 863 | public string IP 864 | { 865 | get 866 | { 867 | ThrowIfNotCreated(); 868 | 869 | byte[] ip = ArrayPool.GetByteBuffer(); 870 | 871 | if (Native.enet_peer_get_ip(nativePeer, ip, (IntPtr)ip.Length) == 0) 872 | return Encoding.ASCII.GetString(ip, 0, ip.StringLength()); 873 | else 874 | return String.Empty; 875 | } 876 | } 877 | 878 | public ushort Port 879 | { 880 | get 881 | { 882 | ThrowIfNotCreated(); 883 | 884 | return Native.enet_peer_get_port(nativePeer); 885 | } 886 | } 887 | 888 | public uint MTU 889 | { 890 | get 891 | { 892 | ThrowIfNotCreated(); 893 | 894 | return Native.enet_peer_get_mtu(nativePeer); 895 | } 896 | } 897 | 898 | public PeerState State 899 | { 900 | get 901 | { 902 | return nativePeer == IntPtr.Zero ? PeerState.Uninitialized : Native.enet_peer_get_state(nativePeer); 903 | } 904 | } 905 | 906 | public uint RoundTripTime 907 | { 908 | get 909 | { 910 | ThrowIfNotCreated(); 911 | 912 | return Native.enet_peer_get_rtt(nativePeer); 913 | } 914 | } 915 | 916 | public uint LastRoundTripTime 917 | { 918 | get 919 | { 920 | ThrowIfNotCreated(); 921 | 922 | return Native.enet_peer_get_last_rtt(nativePeer); 923 | } 924 | } 925 | 926 | public uint LastSendTime 927 | { 928 | get 929 | { 930 | ThrowIfNotCreated(); 931 | 932 | return Native.enet_peer_get_lastsendtime(nativePeer); 933 | } 934 | } 935 | 936 | public uint LastReceiveTime 937 | { 938 | get 939 | { 940 | ThrowIfNotCreated(); 941 | 942 | return Native.enet_peer_get_lastreceivetime(nativePeer); 943 | } 944 | } 945 | 946 | public ulong PacketsSent 947 | { 948 | get 949 | { 950 | ThrowIfNotCreated(); 951 | 952 | return Native.enet_peer_get_packets_sent(nativePeer); 953 | } 954 | } 955 | 956 | public ulong PacketsLost 957 | { 958 | get 959 | { 960 | ThrowIfNotCreated(); 961 | 962 | return Native.enet_peer_get_packets_lost(nativePeer); 963 | } 964 | } 965 | 966 | public float PacketsThrottle 967 | { 968 | get 969 | { 970 | ThrowIfNotCreated(); 971 | 972 | return Native.enet_peer_get_packets_throttle(nativePeer); 973 | } 974 | } 975 | 976 | public ulong BytesSent 977 | { 978 | get 979 | { 980 | ThrowIfNotCreated(); 981 | 982 | return Native.enet_peer_get_bytes_sent(nativePeer); 983 | } 984 | } 985 | 986 | public ulong BytesReceived 987 | { 988 | get 989 | { 990 | ThrowIfNotCreated(); 991 | 992 | return Native.enet_peer_get_bytes_received(nativePeer); 993 | } 994 | } 995 | 996 | public IntPtr Data 997 | { 998 | get 999 | { 1000 | ThrowIfNotCreated(); 1001 | 1002 | return Native.enet_peer_get_data(nativePeer); 1003 | } 1004 | 1005 | set 1006 | { 1007 | ThrowIfNotCreated(); 1008 | 1009 | Native.enet_peer_set_data(nativePeer, value); 1010 | } 1011 | } 1012 | 1013 | internal void ThrowIfNotCreated() 1014 | { 1015 | if (nativePeer == IntPtr.Zero) 1016 | throw new InvalidOperationException("Peer not created"); 1017 | } 1018 | 1019 | public void ConfigureThrottle(uint interval, uint acceleration, uint deceleration, uint threshold) 1020 | { 1021 | ThrowIfNotCreated(); 1022 | 1023 | Native.enet_peer_throttle_configure(nativePeer, interval, acceleration, deceleration, threshold); 1024 | } 1025 | 1026 | public int Send(byte channelID, ref Packet packet) 1027 | { 1028 | ThrowIfNotCreated(); 1029 | 1030 | packet.ThrowIfNotCreated(); 1031 | 1032 | return Native.enet_peer_send(nativePeer, channelID, packet.NativeData); 1033 | } 1034 | 1035 | public bool Receive(out byte channelID, out Packet packet) 1036 | { 1037 | ThrowIfNotCreated(); 1038 | 1039 | IntPtr nativePacket = Native.enet_peer_receive(nativePeer, out channelID); 1040 | 1041 | if (nativePacket != IntPtr.Zero) 1042 | { 1043 | packet = new Packet(nativePacket); 1044 | 1045 | return true; 1046 | } 1047 | 1048 | packet = default(Packet); 1049 | 1050 | return false; 1051 | } 1052 | 1053 | public void Ping() 1054 | { 1055 | ThrowIfNotCreated(); 1056 | 1057 | Native.enet_peer_ping(nativePeer); 1058 | } 1059 | 1060 | public void PingInterval(uint interval) 1061 | { 1062 | ThrowIfNotCreated(); 1063 | 1064 | Native.enet_peer_ping_interval(nativePeer, interval); 1065 | } 1066 | 1067 | public void Timeout(uint timeoutLimit, uint timeoutMinimum, uint timeoutMaximum) 1068 | { 1069 | ThrowIfNotCreated(); 1070 | 1071 | Native.enet_peer_timeout(nativePeer, timeoutLimit, timeoutMinimum, timeoutMaximum); 1072 | } 1073 | 1074 | public void Disconnect(uint data) 1075 | { 1076 | ThrowIfNotCreated(); 1077 | 1078 | Native.enet_peer_disconnect(nativePeer, data); 1079 | } 1080 | 1081 | public void DisconnectNow(uint data) 1082 | { 1083 | ThrowIfNotCreated(); 1084 | 1085 | Native.enet_peer_disconnect_now(nativePeer, data); 1086 | } 1087 | 1088 | public void DisconnectLater(uint data) 1089 | { 1090 | ThrowIfNotCreated(); 1091 | 1092 | Native.enet_peer_disconnect_later(nativePeer, data); 1093 | } 1094 | 1095 | public void Reset() 1096 | { 1097 | ThrowIfNotCreated(); 1098 | 1099 | Native.enet_peer_reset(nativePeer); 1100 | } 1101 | } 1102 | 1103 | public static class Extensions 1104 | { 1105 | public static int StringLength(this byte[] data) 1106 | { 1107 | if (data == null) 1108 | throw new ArgumentNullException("data"); 1109 | 1110 | int i; 1111 | 1112 | for (i = 0; i < data.Length && data[i] != 0; i++) ; 1113 | 1114 | return i; 1115 | } 1116 | } 1117 | 1118 | public static class Library 1119 | { 1120 | public const uint maxChannelCount = 0xFF; 1121 | public const uint maxPeers = 0xFFF; 1122 | public const uint maxPacketSize = 32 * 1024 * 1024; 1123 | public const uint throttleThreshold = 40; 1124 | public const uint throttleScale = 32; 1125 | public const uint throttleAcceleration = 2; 1126 | public const uint throttleDeceleration = 2; 1127 | public const uint throttleInterval = 5000; 1128 | public const uint timeoutLimit = 32; 1129 | public const uint timeoutMinimum = 5000; 1130 | public const uint timeoutMaximum = 30000; 1131 | public const uint version = (2 << 16) | (4 << 8) | (9); 1132 | 1133 | public static uint Time 1134 | { 1135 | get 1136 | { 1137 | return Native.enet_time_get(); 1138 | } 1139 | } 1140 | 1141 | public static bool Initialize() 1142 | { 1143 | if (Native.enet_linked_version() != version) 1144 | throw new InvalidOperationException("ENet native library is out of date, please download the latest release from https://github.com/SoftwareGuy/ENet-CSharp/releases"); 1145 | 1146 | return Native.enet_initialize() == 0; 1147 | } 1148 | 1149 | public static bool Initialize(Callbacks callbacks) 1150 | { 1151 | if (callbacks == null) 1152 | throw new ArgumentNullException("callbacks"); 1153 | 1154 | if (Native.enet_linked_version() != version) 1155 | throw new InvalidOperationException("ENet native library is out of date, please download the latest release from https://github.com/SoftwareGuy/ENet-CSharp/releases"); 1156 | 1157 | ENetCallbacks nativeCallbacks = callbacks.NativeData; 1158 | 1159 | return Native.enet_initialize_with_callbacks(version, ref nativeCallbacks) == 0; 1160 | } 1161 | 1162 | public static void Deinitialize() 1163 | { 1164 | Native.enet_deinitialize(); 1165 | } 1166 | 1167 | public static ulong CRC64(IntPtr buffers, int bufferCount) 1168 | { 1169 | return Native.enet_crc64(buffers, bufferCount); 1170 | } 1171 | } 1172 | 1173 | [SuppressUnmanagedCodeSecurity] 1174 | internal static class Native 1175 | { 1176 | // This should address Unity usage and bug #66: Platform specific Enet / libenet 1177 | // https://github.com/SoftwareGuy/Ignorance/issues/66 1178 | #if UNITY_EDITOR 1179 | // We are inside the Unity Editor. 1180 | #if UNITY_EDITOR_OSX 1181 | // Unity Editor on macOS needs to use libenet. 1182 | private const string nativeLibrary = "libenet"; 1183 | #else 1184 | private const string nativeLibrary = "enet"; 1185 | #endif 1186 | #endif 1187 | 1188 | #if !UNITY_EDITOR 1189 | // We're not inside the Unity Editor. 1190 | #if __APPLE__ && !(__IOS__ || UNITY_IOS) 1191 | // Use libenet on macOS. 1192 | private const string nativeLibrary = "libenet"; 1193 | #elif __IOS__ || UNITY_IOS 1194 | // We're building for a certain mobile fruity OS. 1195 | private const string nativeLibrary = "__Internal"; 1196 | #else 1197 | // Assume everything else, Windows et al. 1198 | private const string nativeLibrary = "enet"; 1199 | #endif 1200 | #endif 1201 | 1202 | [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] 1203 | internal static extern int enet_initialize(); 1204 | 1205 | [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] 1206 | internal static extern int enet_initialize_with_callbacks(uint version, ref ENetCallbacks inits); 1207 | 1208 | [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] 1209 | internal static extern void enet_deinitialize(); 1210 | 1211 | [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] 1212 | internal static extern uint enet_linked_version(); 1213 | 1214 | [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] 1215 | internal static extern uint enet_time_get(); 1216 | 1217 | [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] 1218 | internal static extern ulong enet_crc64(IntPtr buffers, int bufferCount); 1219 | 1220 | [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] 1221 | internal static extern int enet_address_set_ip(ref ENetAddress address, string ip); 1222 | 1223 | [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] 1224 | internal static extern int enet_address_set_hostname(ref ENetAddress address, string hostName); 1225 | 1226 | [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] 1227 | internal static extern int enet_address_get_ip(ref ENetAddress address, StringBuilder ip, IntPtr ipLength); 1228 | 1229 | [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] 1230 | internal static extern int enet_address_get_hostname(ref ENetAddress address, StringBuilder hostName, IntPtr nameLength); 1231 | 1232 | [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] 1233 | internal static extern IntPtr enet_packet_create(byte[] data, IntPtr dataLength, PacketFlags flags); 1234 | 1235 | [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] 1236 | internal static extern IntPtr enet_packet_create(IntPtr data, IntPtr dataLength, PacketFlags flags); 1237 | 1238 | [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] 1239 | internal static extern IntPtr enet_packet_create_offset(byte[] data, IntPtr dataLength, IntPtr dataOffset, PacketFlags flags); 1240 | 1241 | [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] 1242 | internal static extern IntPtr enet_packet_create_offset(IntPtr data, IntPtr dataLength, IntPtr dataOffset, PacketFlags flags); 1243 | 1244 | [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] 1245 | internal static extern int enet_packet_check_references(IntPtr packet); 1246 | 1247 | [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] 1248 | internal static extern IntPtr enet_packet_get_data(IntPtr packet); 1249 | 1250 | [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] 1251 | internal static extern IntPtr enet_packet_get_user_data(IntPtr packet); 1252 | 1253 | [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] 1254 | internal static extern IntPtr enet_packet_set_user_data(IntPtr packet, IntPtr userData); 1255 | 1256 | [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] 1257 | internal static extern int enet_packet_get_length(IntPtr packet); 1258 | 1259 | [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] 1260 | internal static extern void enet_packet_set_free_callback(IntPtr packet, IntPtr callback); 1261 | 1262 | [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] 1263 | internal static extern void enet_packet_dispose(IntPtr packet); 1264 | 1265 | [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] 1266 | internal static extern IntPtr enet_host_create(ref ENetAddress address, IntPtr peerLimit, IntPtr channelLimit, uint incomingBandwidth, uint outgoingBandwidth, int bufferSize); 1267 | 1268 | [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] 1269 | internal static extern IntPtr enet_host_create(IntPtr address, IntPtr peerLimit, IntPtr channelLimit, uint incomingBandwidth, uint outgoingBandwidth, int bufferSize); 1270 | 1271 | [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] 1272 | internal static extern IntPtr enet_host_connect(IntPtr host, ref ENetAddress address, IntPtr channelCount, uint data); 1273 | 1274 | [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] 1275 | internal static extern void enet_host_broadcast(IntPtr host, byte channelID, IntPtr packet); 1276 | 1277 | [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] 1278 | internal static extern void enet_host_broadcast_exclude(IntPtr host, byte channelID, IntPtr packet, IntPtr excludedPeer); 1279 | 1280 | [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] 1281 | internal static extern void enet_host_broadcast_selective(IntPtr host, byte channelID, IntPtr packet, IntPtr[] peers, IntPtr peersLength); 1282 | 1283 | [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] 1284 | internal static extern int enet_host_service(IntPtr host, out ENetEvent @event, uint timeout); 1285 | 1286 | [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] 1287 | internal static extern int enet_host_check_events(IntPtr host, out ENetEvent @event); 1288 | 1289 | [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] 1290 | internal static extern void enet_host_channel_limit(IntPtr host, IntPtr channelLimit); 1291 | 1292 | [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] 1293 | internal static extern void enet_host_bandwidth_limit(IntPtr host, uint incomingBandwidth, uint outgoingBandwidth); 1294 | 1295 | [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] 1296 | internal static extern uint enet_host_get_peers_count(IntPtr host); 1297 | 1298 | [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] 1299 | internal static extern uint enet_host_get_packets_sent(IntPtr host); 1300 | 1301 | [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] 1302 | internal static extern uint enet_host_get_packets_received(IntPtr host); 1303 | 1304 | [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] 1305 | internal static extern uint enet_host_get_bytes_sent(IntPtr host); 1306 | 1307 | [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] 1308 | internal static extern uint enet_host_get_bytes_received(IntPtr host); 1309 | 1310 | [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] 1311 | internal static extern void enet_host_set_max_duplicate_peers(IntPtr host, ushort number); 1312 | 1313 | [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] 1314 | internal static extern void enet_host_set_intercept_callback(IntPtr host, IntPtr callback); 1315 | 1316 | [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] 1317 | internal static extern void enet_host_set_checksum_callback(IntPtr host, IntPtr callback); 1318 | 1319 | [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] 1320 | internal static extern void enet_host_flush(IntPtr host); 1321 | 1322 | [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] 1323 | internal static extern void enet_host_destroy(IntPtr host); 1324 | 1325 | [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] 1326 | internal static extern void enet_host_prevent_connections(IntPtr host, byte state); 1327 | 1328 | [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] 1329 | internal static extern void enet_peer_throttle_configure(IntPtr peer, uint interval, uint acceleration, uint deceleration, uint threshold); 1330 | 1331 | [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] 1332 | internal static extern uint enet_peer_get_id(IntPtr peer); 1333 | 1334 | [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] 1335 | internal static extern int enet_peer_get_ip(IntPtr peer, byte[] ip, IntPtr ipLength); 1336 | 1337 | [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] 1338 | internal static extern ushort enet_peer_get_port(IntPtr peer); 1339 | 1340 | [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] 1341 | internal static extern uint enet_peer_get_mtu(IntPtr peer); 1342 | 1343 | [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] 1344 | internal static extern PeerState enet_peer_get_state(IntPtr peer); 1345 | 1346 | [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] 1347 | internal static extern uint enet_peer_get_rtt(IntPtr peer); 1348 | 1349 | [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] 1350 | internal static extern uint enet_peer_get_last_rtt(IntPtr peer); 1351 | 1352 | [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] 1353 | internal static extern uint enet_peer_get_lastsendtime(IntPtr peer); 1354 | 1355 | [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] 1356 | internal static extern uint enet_peer_get_lastreceivetime(IntPtr peer); 1357 | 1358 | [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] 1359 | internal static extern ulong enet_peer_get_packets_sent(IntPtr peer); 1360 | 1361 | [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] 1362 | internal static extern ulong enet_peer_get_packets_lost(IntPtr peer); 1363 | 1364 | [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] 1365 | internal static extern float enet_peer_get_packets_throttle(IntPtr peer); 1366 | 1367 | [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] 1368 | internal static extern ulong enet_peer_get_bytes_sent(IntPtr peer); 1369 | 1370 | [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] 1371 | internal static extern ulong enet_peer_get_bytes_received(IntPtr peer); 1372 | 1373 | [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] 1374 | internal static extern IntPtr enet_peer_get_data(IntPtr peer); 1375 | 1376 | [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] 1377 | internal static extern void enet_peer_set_data(IntPtr peer, IntPtr data); 1378 | 1379 | [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] 1380 | internal static extern int enet_peer_send(IntPtr peer, byte channelID, IntPtr packet); 1381 | 1382 | [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] 1383 | internal static extern IntPtr enet_peer_receive(IntPtr peer, out byte channelID); 1384 | 1385 | [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] 1386 | internal static extern void enet_peer_ping(IntPtr peer); 1387 | 1388 | [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] 1389 | internal static extern void enet_peer_ping_interval(IntPtr peer, uint pingInterval); 1390 | 1391 | [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] 1392 | internal static extern void enet_peer_timeout(IntPtr peer, uint timeoutLimit, uint timeoutMinimum, uint timeoutMaximum); 1393 | 1394 | [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] 1395 | internal static extern void enet_peer_disconnect(IntPtr peer, uint data); 1396 | 1397 | [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] 1398 | internal static extern void enet_peer_disconnect_now(IntPtr peer, uint data); 1399 | 1400 | [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] 1401 | internal static extern void enet_peer_disconnect_later(IntPtr peer, uint data); 1402 | 1403 | [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] 1404 | internal static extern void enet_peer_reset(IntPtr peer); 1405 | } 1406 | } 1407 | --------------------------------------------------------------------------------