{"id":13662244,"url":"https://github.com/zestylife/EuNet","last_synced_at":"2025-04-25T07:30:59.665Z","repository":{"id":41575196,"uuid":"307567651","full_name":"zestylife/EuNet","owner":"zestylife","description":"Peer to peer network solution for multiplayer games.","archived":false,"fork":false,"pushed_at":"2023-03-06T01:06:49.000Z","size":20241,"stargazers_count":152,"open_issues_count":9,"forks_count":26,"subscribers_count":11,"default_branch":"main","last_synced_at":"2025-04-10T11:37:14.692Z","etag":null,"topics":["csharp","game-engine","holepunching","multiplayer","network","p2p","relay","rpc","rudp","tcp"],"latest_commit_sha":null,"homepage":"","language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/zestylife.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null}},"created_at":"2020-10-27T02:50:05.000Z","updated_at":"2025-03-27T13:47:10.000Z","dependencies_parsed_at":"2022-09-24T17:33:00.723Z","dependency_job_id":"bde7673b-81cc-4241-80c0-5167da81ee17","html_url":"https://github.com/zestylife/EuNet","commit_stats":{"total_commits":140,"total_committers":3,"mean_commits":"46.666666666666664","dds":0.09285714285714286,"last_synced_commit":"8fa3faa87f46fad5fc2e9b6f5270c3ec1774b6a6"},"previous_names":[],"tags_count":11,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zestylife%2FEuNet","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zestylife%2FEuNet/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zestylife%2FEuNet/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zestylife%2FEuNet/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/zestylife","download_url":"https://codeload.github.com/zestylife/EuNet/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":250774631,"owners_count":21485176,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["csharp","game-engine","holepunching","multiplayer","network","p2p","relay","rpc","rudp","tcp"],"created_at":"2024-08-02T05:01:53.249Z","updated_at":"2025-04-25T07:30:59.656Z","avatar_url":"https://github.com/zestylife.png","language":"C#","funding_links":[],"categories":["Open Source Repositories","NetWork","C\\#"],"sub_categories":["Networking"],"readme":"EuNet C# (.NET, .NET Core, Unity)\n===\n[![GitHub Actions](https://github.com/zestylife/EuNet/workflows/Build-Debug/badge.svg)](https://github.com/zestylife/EuNet/actions) [![GitHub Actions](https://github.com/zestylife/EuNet/workflows/Build-Release/badge.svg)](https://github.com/zestylife/EuNet/actions) [![nuget](https://img.shields.io/nuget/dt/EuNet.svg)](https://www.nuget.org/packages/EuNet/) [![Releases](https://img.shields.io/github/v/release/zestylife/EuNet)](https://github.com/zestylife/EuNet/releases)\n\nEasy Unity Network (EuNet) is a network solution for multiplayer games.\n\nSupports Server-Client, Peer to Peer communication using TCP, UDP, and RUDP protocols.\n\nIn the case of P2P (Peer to Peer), supports hole punching and tries to communicate directly as much as possible, and if it is impossible, automatically relayed through the server.\n\nGreat for developing Action MORPG, MOBA, Channel Based MMORPG, Casual Multiplayer Game (e.g. League of Legends, Among Us, Kart Rider, Diablo, etc.).\n\nProduced based on .Net Standard 2.0, multiplatform supported(Windows, Linux, Android, iOS, etc.), and is optimized for .Net Core-based servers and Unity3D-based clients.\n\nRPC(Remote procedure call) can be used to call remote functions and receive return values.  \nThere is no overhead as it serializes at high speed and calls remote functions.  \nWork efficiency increases as there is no work to create a message every time.  \n\n## Example\n| EuNet-Starter | EuNet-Tanks |  \n| :---: | :---: |\n| https://github.com/zestylife/EuNet-Starter | https://github.com/zestylife/EuNet-Tanks |\n| | [Google Play](https://play.google.com/store/apps/details?id=com.zestylife.EuNetTanks) |\n| ![image](https://github.com/zestylife/EuNet-Starter/raw/master/Starter.gif) | ![image](https://github.com/zestylife/EuNet-Tanks/raw/main/docs/images/screenshot.gif?raw=true)\n\n## Diagram\n![image](https://github.com/zestylife/EuNet/blob/main/docs/images/Network.png?raw=true)\n\n## Table of Contents\n\n- [EuNet C# (.NET, .NET Core, Unity)](#eunet-c-net-net-core-unity)\n  - [Example](#example)\n  - [Diagram](#diagram)\n  - [Table of Contents](#table-of-contents)\n  - [Features](#features)\n  - [Channels](#channels)\n  - [Installation](#installation)\n    - [Common project](#common-project)\n    - [Server project (.net core)](#server-project-net-core)\n    - [Client project (Unity3D)](#client-project-unity3d)\n    - [Install via git URL](#install-via-git-url)\n    - [Install via package file](#install-via-package-file)\n  - [RPC (Remote procedure call)](#rpc-remote-procedure-call)\n    - [Common project](#common-project-1)\n    - [Server project (.Net Core)](#server-project-net-core-1)\n    - [Client project (Unity3D)](#client-project-unity3d-1)\n  - [Quick Start](#quick-start)\n  - [Serialize](#serialize)\n    - [Using Auto-Generated formmater](#using-auto-generated-formmater)\n    - [Manualy serialize](#manualy-serialize)\n  - [Unity3D](#unity3d)\n    - [Settings](#settings)\n    - [How to use Rpc](#how-to-use-rpc)\n    - [How to use ViewRpc](#how-to-use-viewrpc)\n  - [IL2CPP issue (AOT)](#il2cpp-issue-aot)\n    - [Serialization](#serialization)\n\n## Features\n  \n* Fast network communication\n  * High speed communication using multi-thread\n  * Fast allocation using pooling buffer\n* Supported channels\n  * TCP\n  * Unreliable UDP\n  * Reliable Ordered UDP\n  * Reliable Unordered UDP\n  * Reliable Sequenced UDP\n  * Sequenced UDP\n* Supported communication\n  * Client to Server\n  * Peer to Peer\n    * Hole Punching\n    * Relay (Auto Switching)\n* RPC (Remote Procedure Call)\n* Fast packet serializer (Partial using MessagePack for C#)\n* Custom Compiler(EuNetCodeGenerator) for fast serializing and RPC\n* Automatic MTU detection\n* Automatic fragmentation of large UDP packets\n* Automatic merging small packets \n* Unity3D support\n* Supported platforms\n  * Windows / Mac / Linux (.Net Core)\n  * Android (Unity)\n  * iOS (Unity)\n\n## Channels\n\n|        Channels        |     Transmission guarantee     |   Not duplicate    |  Order guarantee   |\n| :--------------------: | :----------------------------: | :----------------: | :----------------: |\n|          TCP           |       :heavy_check_mark:       | :heavy_check_mark: | :heavy_check_mark: |\n|     Unreliable UDP     |              :x:               |        :x:         |        :x:         |\n|  Reliable Ordered UDP  |       :heavy_check_mark:       | :heavy_check_mark: | :heavy_check_mark: |\n| Reliable Unordered UDP |       :heavy_check_mark:       | :heavy_check_mark: |        :x:         |\n| Reliable Sequenced UDP | :heavy_check_mark:(Last order) | :heavy_check_mark: | :heavy_check_mark: |\n|     Sequenced UDP      |              :x:               | :heavy_check_mark: | :heavy_check_mark: |\n\n***\n\n## Installation\n\nWe need three projects\n* Common project (.Net Standard 2.0)\n  * Server, Client common use\n  * Generate code using EuNetCodeGenerator\n* Server project (.Net Core)\n* Client project (Unity3D)\n\nSee [EuNet-Starter](https://github.com/zestylife/EuNet-Starter) for an example\n\n### Common project\n\n* Create .Net Standard 2.0 based project.\n* Install nuget package.\n\n```\nPM\u003e Install-Package EuNet.CodeGenerator.Templates\n```\n* Rebuild project.\n* If you look at the project, `CodeGen/EuNet.Rpc.CodeGen.cs` file was created.\n\n### Server project (.net core)\n\n* First install the nuget package.\n```\nPM\u003e Install-Package EuNet\n```\n* Add common project to reference\n```\nSolution Explorer -\u003e [User Project] -\u003e References -\u003e Add Reference -\u003e [Add Common project]\n```\n* Write server code. [Server Code Sample](https://github.com/zestylife/EuNet/tree/main/sandbox/Dev/Server)\n* Write session code. [Session Code Sample](https://github.com/zestylife/EuNet/tree/main/sandbox/Dev/Server/Session)\n\n### Client project (Unity3D)\n\n### Install via git URL\n\nAfter Unity 2019.3.4f1, Unity 2020.1a21, that support path query parameter of git package.\nYou can add package from UPM (Unity Package Manager)\n```\nhttps://github.com/zestylife/EuNet.git?path=src/EuNet.Unity/Assets/Plugins/EuNet\n``` \nIf you want to add a specific release version, add `#version` after the url. ex) version 1.1.13\n```\nhttps://github.com/zestylife/EuNet.git?path=src/EuNet.Unity/Assets/Plugins/EuNet#1.1.13\n``` \n\n![image](https://github.com/zestylife/EuNet/blob/main/docs/images/AddPackageFromUPM.png?raw=true)\n\n### Install via package file\n* Install the unity-package. [Download here](https://github.com/zestylife/EuNet/releases)\n\n## RPC (Remote procedure call)\n\nRPC(Remote procedure call) can be used to call remote functions and receive return values.  \nThere is no overhead as it serializes at high speed and calls remote functions.  \nWork efficiency increases as there is no work to create a message every time.  \n\n![image](https://github.com/zestylife/EuNet/blob/main/docs/images/Rpc.png?raw=true)\n\n### Common project\n```csharp\n// Declaring login rpc interface\npublic interface ILoginRpc : IRpc\n{\n    Task\u003cint\u003e Login(string id, ISession session);\n    Task\u003cUserInfo\u003e GetUserInfo();\n}\n// Generate Rpc code using EuNetCodeGenerator and use it in server and client\n```\n\n### Server project (.Net Core)\n```csharp\n// User session class inherits Rpc Interface (ILoginRpc)\npublic partial class UserSession : ILoginRpc\n{\n    private UserInfo _userInfo = new UserInfo();\n    \n    // Implement Rpc Method that client calls\n    public Task\u003cint\u003e Login(string id, ISession session)\n    {\n        if (id == \"AuthedId\")\n            return Task\u003cint\u003e.FromResult(0);\n\n        return Task\u003cint\u003e.FromResult(1);\n    }\n\n    // Implement Rpc Method that client calls\n    public Task\u003cUserInfo\u003e GetUserInfo()\n    {\n        // Set user information\n        _userInfo.Name = \"abc\";\n\n        return Task\u003cUserInfo\u003e.FromResult(_userInfo);\n    }\n}\n```\n\n### Client project (Unity3D)\n```csharp\nprivate async UniTaskVoid ConnectAsync()\n{\n    var client = NetClientGlobal.Instance.Client;\n\n    // Trying to connect. Timeout is 10 seconds.\n    var result = await client.ConnectAsync(TimeSpan.FromSeconds(10));\n\n    if(result == true)\n    {\n        // Create an object for calling login Rpc\n        LoginRpc loginRpc = new LoginRpc(client);\n\n        // Call the server's login function (UserSession.Login)\n        var loginResult = await loginRpc.Login(\"AuthedId\", null);\n\n        Debug.Log($\"Login Result : {loginResult}\");\n        if (loginResult != 0)\n            return;\n        \n        // Call the server's get user information function (UserSession.GetUserInfo)\n        var userInfo = await loginRpc.GetUserInfo();\n        Debug.Log($\"UserName : {userInfo.Name}\");\n        // UserName : abc\n    }\n    else\n    {\n        // Fail to connect\n        Debug.LogError(\"Fail to connect server\");\n    }\n}\n```\n\n## Quick Start\n\n## Serialize\n\nObject serialization is required to use Rpc.\nThere are two ways to serialize objects.\n\n### Using Auto-Generated formmater\n\nDeclaring the `NetDataObject` Attribute makes the class serializable.\nAll public objects are serialized.\nDeclaring the `[IgnoreMember]` Attribute does not serialize it.\n\n```csharp\n[NetDataObject]\npublic class DataClass\n{\n    // Serializable\n    public int Int;\n\n    // Serializable\n    public int Property { get; set; }\n\n    // Ignore\n    public int PropertyOnlyGet { get; }\n\n    // Ignore\n    private int IntPrivate;\n\n    // Ignore\n    protected int IntProtected;\n    \n    // Ignore\n    [IgnoreMember]\n    public int IgnoreInt;\n\n    // Ignore\n    [IgnoreMember]\n    public int IgnoreProperty { get; set; }\n}\n```\n\n### Manualy serialize\n\nImplement serialization manually by inheriting `INetSerializable`.\nYou have to code, but it's the fastest and most flexible.\n\n```csharp\npublic class InterfaceSerializeClass : INetSerializable\n{\n    public int Value;\n    public string Name;\n\n    public void Serialize(NetDataWriter writer)\n    {\n        writer.Write(Value);\n        writer.Write(Name);\n    }\n\n    public void Deserialize(NetDataReader reader)\n    {\n        Value = reader.ReadInt32();\n        Name = reader.ReadString();\n    }\n}\n```\n\n## Unity3D\n\n* Special object NetView is supported, and synchronization and Rpc communication between NetViews are possible.   \n(NetClientP2pBehaviour required. Peer to Peer only)\n* Supported global settings with NetClientGlobal object. (Singleton)\n* Supported for communication to the server (NetClientBehaviour, NetClientP2pBehaviour)\n* Support NetClientP2pBehaviour only one.\n\n### Settings\n\n* Add an empty GameObject to the first run Scene and add a NetClientGlobal component.   \nOnly one should be made globally.\n\n![image](https://github.com/zestylife/EuNet/blob/main/docs/images/NetClientGlobal.png?raw=true)\n\n* Add NetClientP2pBehaviour component for communicate to one server (including P2p).  \nModify the options as needed.\n\n![image](https://github.com/zestylife/EuNet/blob/main/docs/images/NetClientP2pBehaviour.png?raw=true)\n\n* Add user component to receive and process events.\n\n![image](https://github.com/zestylife/EuNet/blob/main/docs/images/GameClient.png?raw=true)\n\n* `GameClient.cs` file\n```csharp\nusing Common.Resolvers;\nusing EuNet.Core;\nusing EuNet.Unity;\nusing System.Threading.Tasks;\n\npublic class GameClient : Singleton\u003cGameClient\u003e\n{\n    private NetClientP2pBehaviour _client;\n\n    public NetClientP2p Client =\u003e _client.ClientP2p;\n\n    protected override void Awake()\n    {\n        base.Awake();\n\n        _client = GetComponent\u003cNetClientP2pBehaviour\u003e();\n\n        Client.OnConnected = OnConnected;\n        Client.OnClosed = OnClosed;\n        Client.OnReceived = OnReceive;\n        \n        // Register automatically generated resolver.\n        //CustomResolver.Register(GeneratedResolver.Instance);\n\n        // If you generated RpcService, register it.\n        //Client.AddRpcService(new GameScRpcService());\n    }\n\n    public Task\u003cbool\u003e ConnectAsync()\n    {\n        // Try to connect server. All functions can be accessed with Client instance\n        return Client.ConnectAsync(TimeSpan.FromSeconds(10));\n    }\n\n    private void OnConnected()\n    {\n        // Connected\n    }\n\n    private void OnClosed()\n    {\n        // Disconnected\n\n    private Task OnReceive(NetDataReader reader)\n    {\n        // Received data. No need to use when using RPC\n        return Task.CompletedTask;\n    }\n}\n```\n\n### How to use Rpc\n\nRpc is service that can call remote procedures.   \nEuNet's Rpc is a function call service between the server and the client.   \nWhen you declare an interface that inherits the IRpc interface, calls and service codes are automatically generated.\n\n* Create Rpc Interface in `Common` project.\n* Build project.\n  \n```csharp\nusing EuNet.Rpc;\nusing System.Threading.Tasks;\n\nnamespace Common\n{\n    // Inherit IRpc for Rpc\n    public interface IGameCsRpc : IRpc\n    {\n        // Login Rpc\n        Task\u003cint\u003e Login(string id);\n    }\n}\n```\n\n* In the `Server` project, register RpcService when creating a server .\n\n```csharp\n_server.AddRpcService(new GameCsRpcServiceSession());\n```\n\n* In the `Server` project, `UserSession` class inherits from `IGameCsRpc`.\n```csharp\npublic partial class UserSession : IGameCsRpc\n{\n    public Task\u003cint\u003e Login(string id)\n    {\n        return Task.FromResult(0);\n    }\n}\n```\n\n* In the `Client` project, call Rpc.\n\n```csharp\n// Rpc callable object\nvar rpc = new GameCsRpc(_client.Client, null, TimeSpan.FromSeconds(10));\n\n// Call Rpc Login\nvar loginResult = await rpc.Login(\"MyId\");\nDebug.Log(loginResult);\n```\n\n\n### How to use ViewRpc\n\nViewRpc is a technology that makes peer-to-peer communication between NetView Components as Rpc.   \nBy adding a NetView Component to the GameObject, you can call functions of the same NetView Component (same ViewId) that exist on different clients.   \nFor example, if you shoot a cannon from a red tank, the other user's red tank will also fire.   \n1:1 or 1:N call is possible, and in case of 1:N, return value can not be received.\n\n## IL2CPP issue (AOT)\n\nSome platforms do not allow runtime code generation. Therefore, any managed code which depends upon just-in-time (JIT) compilation on the target device will fail. Instead, you need to compile all of the managed code ahead-of-time (AOT). Often, this distinction doesn’t matter, but in a few specific cases, AOT platforms require additional consideration.\n\nSee more   \nhttps://docs.unity3d.com/2019.4/Documentation/Manual/ScriptingRestrictions.html\n\n### Serialization\n\nThere is a problem when serializing generic objects as AOT cannot generate code\nSo, you need to provide a hint so that AOT can generate the code.\n\n* Class for serialize (In `Common` project)\n```csharp\n[NetDataObject]\npublic class DataClass\n{\n    public Tuple\u003cint,string\u003e TupleData;\n    public Dictionary\u003cint,string\u003e DictionaryData;\n}\n```\n\n* Hint function (In `Client` unity project)\n```csharp\nprivate void UsedOnlyForAOTCodeGeneration()\n{\n    // Hints for using \u003cint,string\u003e in TupleFormatter\u003cT,T\u003e\n    new TupleFormatter\u003cint, string\u003e();\n\n    // Hints for using \u003cint,string\u003e in DictionaryFormatter\u003cT,T\u003e\n    new DictionaryFormatter\u003cint, string\u003e();\n\n    // Exception!\n    throw new InvalidOperationException(\"This method is used for AOT code generation only. Do not call it at runtime.\");\n}\n```","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fzestylife%2FEuNet","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fzestylife%2FEuNet","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fzestylife%2FEuNet/lists"}