A simple semi-reliable UDP protocol for multiplayer games
Switch branches/tags
Clone or download
bors[bot] and jstnlef Merge #130
130: Upgrade to Rust 2018 r=TimonPost,LucioFranco a=jstnlef



Co-authored-by: Justin LeFebvre <jstnlefebvre@gmail.com>
Latest commit 89424eb Dec 10, 2018

README.md

Laminar

Build Status Latest Version docs.rs Join us on Discord MIT/Apache Lines of Code Coverage

This library implements some TCP-like features on top of an UDP-socket. It will provide a lightweight message-based interface with certain guarantees like reliability, fragmentation congestion monitoring.

Laminar was designed to be used in the Amethyst game engine and is loosely based on articles from gaffer on games.

Table of contents:

Features

These are the features this crate provides:

  • UDP-based protocol
  • Connection tracking
  • Automatic Fragmentation
  • Unreliable and Reliable packets
  • Protocol versioning
  • RTT estimation
  • Link conditioner to simulate packet loss and latency
  • Well tested by integration tests and unit tests
  • Good error handling
  • Benchmarks

Getting Stated

Add the laminar package to your Cargo.toml file.

[dependencies]
laminar = "0.1"

Useful Links

Examples

These are some basic examples demonstrating how to use this crate. Please checkout our examples for more.

UDP API | see more

This is an example of how to use the UDP API.

Send packets

use laminar::{DeliveryMethod, Packet};
use laminar::net::{UdpSocket, NetworkConfig};

// Create the necessarily config, you can edit it or just use the default.
let config = NetworkConfig::default();

// Setup an udp socket and bind it to the client address.
let mut udp_socket = UdpSocket::bind("127.0.0.1:12346", config).unwrap();

// our data
let bytes = vec![...];

// Create a packet that can be send with the given destination and raw data.
let packet = Packet::new(destination, bytes, DeliveryMethod::Unreliable);

// Or we could also use the function syntax for more clarity:
let packet = Packet::unreliable(destination, bytes);
let packet = Packet::reliable_unordered(destination, bytes);

// Send the packet to the endpoint we earlier placed into the packet.
udp_socket.send(packet);

Receive Packets

use laminar::net::{UdpSocket, NetworkConfig};
use std::net::SocketAddr;
// Create the necessarily config, you can edit it or just use the default.
let config = NetworkConfig::default();

// Setup an udp socket and bind it to the client address.
let mut udp_socket = UdpSocket::bind("127.0.0.1:12345", config).unwrap();

// Start receiving (blocks the current thread), use `udp_socket.set_nonblocking()` for not blocking the current thread.
let result = udp_socket.recv();

match result {
    Ok(Some(packet)) => {
        let endpoint: SocketAddr = packet.addr();
        let received_data: &[u8] = packet.payload();

        // You can deserialize your bytes here into the data you have passed it when sending.

        println!("Received packet from: {:?} with length {}", endpoint, received_data.len());
    }
    Ok(None) => {
        println!("This could happen when we have not received all the data from this packet yet");
    }
    Err(e) => {
        // We get an error if something went wrong, like the address is already in use.
        println!("Something went wrong when receiving, error: {:?}", e);
    }
}

Authors

We want to give credit to gaffer on games as we have used his guide to building a game networking protocol to build this library.

Note

This library is not fully stable yet. Although version 0.1.0 is released we might have to change some of the existing API.
Laminar is used in Amethyst-Network, you could give that a look if you want to see some more advanced use-cases.

Contribution

Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.

License

Licensed under either of