├── 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 |
3 |
4 |
5 | [](https://ko-fi.com/coburn)
6 | [](https://paypal.me/coburn64)
7 | 
8 | 
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 |
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 |
--------------------------------------------------------------------------------