LiteNetLib Documentation

repository·master·Indexed 25 days ago

https://github.com/revenantx/litenetlib

A lightweight, reliable UDP library for .NET Standard 2.0 and 2.1, designed for high-performance networking in games and real-time applications. It features the NetPacketProcessor for fast serialization of classes and structs, support for Unity 2021.2+, and configurable NetManager settings for connection timing, NAT punching, and network simulation.

Tokens
2.6K
Snippets
3
Records
10
Agent score
86%

What's inside LiteNetLib

  1. Use NetPacketProcessor for fast serialization

    master

    The NetPacketProcessor is a high-performance serializer specialized for network communication. It supports two types of data structures:

    1. Classes with public properties: Must have both get and set methods.
    2. Classes or structs implementing INetSerializable.

    Note on Overhead: The serializer adds an 8-byte overhead (a 64-bit hash of the class name and namespace) to each packet. All other fields are serialized with minimal overhead.

  2. Send and receive packets using NetPacketProcessor

    master

    To use NetPacketProcessor in a network loop, follow these steps:

    Sending (Client side)

    1. Create a NetPacketProcessor instance.
    2. Use _netPacketProcessor.Write(packet) to serialize the object into a NetPacketReader (or use the helper _netPacketProcessor.Send(...)).
    3. Send via the NetPeer.

    Receiving (Server side)

    1. Subscribe to the packet type using SubscribeReusable<TPacket, TPeer>(handler) in your constructor.
    2. In your OnNetworkReceive event handler, call _netPacketProcessor.ReadAllPackets(reader, peer) to deserialize the incoming data and trigger the subscribed handler.

    Note: SubscribeReusable is recommended for performance to avoid allocations.

  3. Integrate LiteNetLib with Unity

    master

    When using LiteNetLib in Unity, follow these requirements and best practices:

    • Minimum Version: Use Unity 2021.2 or newer. For older versions, you must use the 1.x branch of the library.
    • Installation Method: Do not use precompiled DLL files. Instead, always use the library source code or the OpenUPM package. This is necessary because the library contains platform-specific #ifdef directives and workarounds for Unity-specific bugs.
  4. Configure NetManager settings

    master

    The NetManager class provides several configuration properties to tune network behavior.

    Connection & Timing

    • UpdateTime: Library logic update and send period in milliseconds (Default: 15 msec).
    • PingInterval: Interval for latency detection and connection checking (Default: 1000 msec).
    • DisconnectTimeout: Time before a connection is closed due to inactivity (Default: 5000 msec).
    • ReconnectDelay: Delay between connection attempts (Default: 500 msec).
    • MaxConnectAttempts: Maximum connection attempts before calling disconnect event (Default: 10).

    Features

    • UnconnectedMessagesEnabled: Enables receiving messages without a connection (Default: false).
    • NatPunchEnabled: Enables NAT punch messages (Default: false).
    • BroadcastEnabled: Allows receiving Broadcast packets (Default: false).
    • UnsyncedEvents: Experimental feature; events are called from another thread without calling PollEvents() (Default: false).

    Network Simulation (Requires DEBUG build or SIMULATE_NETWORK defined)

    • SimulatePacketLoss: Enables random packet dropping (Default: false).
    • SimulateLatency: Enables random packet holding (Default: false).
    • SimulationPacketLossChance: Percentage chance of packet loss (Default: 10).
    • SimulationMinLatency: Minimum simulated latency in msec (Default: 30 msec).
    • SimulationMaxLatency: Maximum simulated latency in msec (Default: 100 msec).
  5. Troubleshoot 'Undefined packet in NetDataReader' error

    master

    If NetPacketProcessor throws the error "Undefined packet in NetDataReader" even though all packets are registered, it is likely due to a namespace mismatch.

    Ensure that the registered packet classes/structs reside in the exact same namespace on both the client and the server. The best practice to avoid this is to use a shared assembly or shared code for your packet definitions.

  6. Implement a LiteNetLib Server

    master

    To create a server, instantiate an EventBasedNetListener and pass it to a NetManager. Call Start(port) to begin listening on a specific port. You must handle ConnectionRequestEvent to accept or reject incoming connections and call PollEvents() in a loop. Use PeerConnectedEvent to interact with newly connected peers.

    EventBasedNetListener listener = new EventBasedNetListener();
    NetManager server = new NetManager(listener);
    server.Start(9050 /* port */);
    
    listener.ConnectionRequestEvent += request =>
    {
        if(server.PeersCount < 10 /* max connections */)
            request.AcceptIfKey("SomeConnectionKey");
        else
            request.Reject();
    };
    
    listener.PeerConnectedEvent += peer =>
    {
        Console.WriteLine("We got connection: {0}", peer.EndPoint); // Show peer ip
        NetDataWriter writer = new NetDataWriter();                 // Create writer class
        writer.Put("Hello client!");                                // Put some string
        peer.Send(writer, DeliveryMethod.ReliableOrdered);             // Send with reliability
    };
    
    while (!Console.KeyAvailable)
    {
        server.PollEvents();
        Thread.Sleep(15);
    }
    server.Stop();
  7. Implement a LiteNetLib Client

    master

    To create a client, instantiate an EventBasedNetListener and pass it to a new NetManager. Call Start() to initialize the manager, then use Connect() to connect to a host. You must call PollEvents() in a loop to process network events. Use the NetworkReceiveEvent on the listener to handle incoming data.

    EventBasedNetListener listener = new EventBasedNetListener();
    NetManager client = new NetManager(listener);
    client.Start();
    client.Connect("localhost" /* host ip or name */, 9050 /* port */, "SomeConnectionKey" /* text key or NetDataWriter */);
    listener.NetworkReceiveEvent += (fromPeer, dataReader, deliveryMethod) =>
    {
        Console.WriteLine("We got: {0}", dataReader.GetString(100 /* max length of string */));
        dataReader.Recycle();
    };
    
    while (!Console.KeyAvailable)
    {
        client.PollEvents();
        Thread.Sleep(15);
    }
    
    client.Stop();
  8. Register custom types with NetPacketProcessor

    master

    Since NetPacketProcessor does not support nested structs or classes by default, you must register custom type processors using RegisterNestedType. There are three ways to handle this:

    1. Using static Serialize/Deserialize methods

    For basic structs, provide static methods that use NetDataWriter and NetDataReader.

    struct MyType {
        public int Value1;
        public static void Serialize(NetDataWriter writer, MyType mytype) => writer.Put(mytype.Value1);
        public static MyType Deserialize(NetDataReader reader) => new MyType { Value1 = reader.GetInt() };
    }
    // Registration:
    netPacketProcessor.RegisterNestedType(MyType.Serialize, MyType.Deserialize);

    2. Implementing INetSerializable

    For structs or classes, implement the INetSerializable interface. This is the most automated way.

    struct MyType : INetSerializable {
        public int Value1;
        public void Serialize(NetDataWriter writer) => writer.Put(Value1);
        public void Deserialize(NetDataReader reader) => Value1 = reader.GetInt();
    }
    // Registration:
    netPacketProcessor.RegisterNestedType<MyType>();

    3. Registering Classes with Constructors

    If using a class instead of a struct, you must implement INetSerializable and provide a constructor factory to the registration method.

    class MyType : INetSerializable {
        public int Value1;
        public void Serialize(NetDataWriter writer) => writer.Put(Value1);
        public void Deserialize(NetDataReader reader) => Value1 = reader.GetInt();
    }
    // Registration (must provide constructor factory):
    netPacketProcessor.RegisterNestedType<MyType>(() => new MyType());
    // Example of Registering a custom type via static methods
    struct MyType
    {
        public int Value1;
        public string Value2;
    
        public static void Serialize(NetDataWriter writer, MyType mytype)
        {
            writer.Put(mytype.Value1);
            writer.Put(mytype.Value2);
        }
    
        public static MyType Deserialize(NetDataReader reader)
        {
            MyType res = new MyType();
            res.Value1 = reader.GetInt();
            res.Value2 = reader.GetString();
            return res;
        }
    }
    
    netPacketProcessor = new NetPacketProcessor();
    netPacketProcessor.RegisterNestedType( MyType.Serialize, MyType.Deserialize );