ENet-CSharp

repository·master·Indexed 21 days ago

https://github.com/nxrighthere/enet-csharp

An independent C# implementation of the ENet networking protocol for lightweight, low-resource, and reliable UDP communication. It supports sequencing, channels, fragmentation, and dual-stack IPv4/IPv6. The library provides managed assemblies and native libraries for .NET Standard 2.1 via the ENet-CSharp NuGet package, with a dedicated ENet-Unity package for Unity engine integration.

Tokens
4.7K
Snippets
15
Records
17
Agent score
25%

What's inside ENet-CSharp

  1. Multi-threading strategy for ENet

    master

    ENet is generally not thread-safe. The recommended strategy is to run ENet in an independent I/O thread and use inter-thread messaging (like a non-blocking Ring Buffer) to transfer data between the I/O thread and your main logic/worker threads.

    Thread-safe elements:

    • Packet structures are safe as long as they are moved across threads by value and a custom memory allocator is not being used.
    • Peer.ID is cached in the Peer structure and is safe to access once obtained.
    • Library.Time uses atomic primitives and is safe to call.
  2. Install ENet-CSharp via NuGet

    master

    You can install the compiled libraries for the .NET environment using NuGet. The ENet-CSharp package contains the managed assembly and native libraries for .NET Standard 2.1.

    Note: It is highly recommended to delete the existing folder containing binaries instead of replacing it when upgrading.

    dotnet add package ENet-CSharp
  3. Use ENet in Unity

    master

    Usage in Unity is nearly identical to the standard .NET environment, with two key differences:

    1. Replace Console calls with Unity-specific logging (e.g., Debug.Log).
    2. When calling Host.Service() inside a game loop, set the timeout parameter to 0 to ensure it is non-blocking.

    Requirement: Ensure Unity is set to run in the background in the Player Settings to prevent connection timeouts when the window loses focus.

  4. Start a new ENet Server

    master

    To create a server, instantiate a Host, configure an Address with a port, and call server.Create(address, maxClients). You must then run a loop that calls server.Service() to process incoming packets and events.

    using (Host server = new Host()) {
    	Address address = new Address();
    	address.Port = port;
    	server.Create(address, maxClients);
    
    	Event netEvent;
    	while (!Console.KeyAvailable) {
    		if (server.Service(15, out netEvent) > 0) {
    			switch (netEvent.Type) {
    				case EventType.Connect:
    					Console.WriteLine("Client connected");
    					break;
    				case EventType.Receive:
    					Console.WriteLine("Packet received");
    					netEvent.Packet.Dispose();
    					break;
    				// Handle other EventTypes...
    				}
    			}
    		}
    	}
    	server.Flush();
    }
  5. Start a new ENet Client

    master

    To create a client, instantiate a Host, call client.Create(), and then use client.Connect(address) to initiate a connection to a server. Similar to the server, you must call client.Service() in a loop to handle connection events and incoming data.

    using (Host client = new Host()) {
    	Address address = new Address();
    	address.SetHost(ip);
    	address.Port = port;
    	client.Create();
    	Peer peer = client.Connect(address);
    
    	Event netEvent;
    	while (!Console.KeyAvailable) {
    		if (client.Service(15, out netEvent) > 0) {
    			switch (netEvent.Type) {
    				case EventType.Connect:
    					Console.WriteLine("Client connected to server");
    					break;
    				case EventType.Receive:
    					Console.WriteLine("Packet received");
    					netEvent.Packet.Dispose();
    					break;
    				// Handle other EventTypes...
    				}
    			}
    		}
    	}
    	client.Flush();
    }
  6. Integrate a custom memory allocator

    master

    You can provide custom memory management by passing a Callbacks object to Library.Initialize(callbacks). This requires implementing AllocCallback, FreeCallback, and NoMemoryCallback delegates.

    Warning: You must maintain a reference to these delegates to prevent them from being garbage collected.

    AllocCallback OnMemoryAllocate = (size) => {
    	return Marshal.AllocHGlobal(size);
    };
    
    FreeCallback OnMemoryFree = (memory) => {
    	Marshal.FreeHGlobal(memory);
    };
    
    NoMemoryCallback OnNoMemory = () => {
    	throw new OutOfMemoryException();
    };
    
    Callbacks callbacks = new Callbacks(OnMemoryAllocate, OnMemoryFree, OnNoMemory);
    
    if (ENet.Library.Initialize(callbacks)) {
    	Console.WriteLine("ENet successfully initialized using a custom memory allocator");
    }
  7. Initialize and Deinitialize the ENet Library

    master

    Before performing any networking operations, you must initialize the library. Once all work is completed, you must deinitialize it to clean up resources.

    Use ENet.Library.Initialize() to start and ENet.Library.Deinitialize() to shut down.

    ENet.Library.Initialize();
    
    // ... perform networking work ...
    
    ENet.Library.Deinitialize();
  8. Reference: PeerState

    master

    The current connection state of a Peer as reported by Peer.State.

    PeerState.Uninitialized: a peer not initialized.
    PeerState.Disconnected: a peer disconnected or timed out.
    PeerState.Connecting: a peer connection in-progress.
    PeerState.Connected: a peer successfully connected.
    PeerState.Disconnecting: a peer disconnection in-progress.
    PeerState.Zombie: a peer not properly disconnected.
  9. Reference: EventType

    master

    Types returned by Event.Type to identify the nature of a polled event.

    EventType.None: no event occurred within the specified time limit.
    EventType.Connect: a connection request initiated by Peer.Connect() function has completed.
    EventType.Disconnect: a peer has disconnected.
    EventType.Receive: a packet has been received from a peer. (Note: Packet must be destroyed using Event.Packet.Dispose())
    EventType.Timeout: a peer has timed out.