PeersAck 0.1.0
dotnet add package PeersAck --version 0.1.0
NuGet\Install-Package PeersAck -Version 0.1.0
<PackageReference Include="PeersAck" Version="0.1.0" />
<PackageVersion Include="PeersAck" Version="0.1.0" />
<PackageReference Include="PeersAck" />
paket add PeersAck --version 0.1.0
#r "nuget: PeersAck, 0.1.0"
#:package PeersAck@0.1.0
#addin nuget:?package=PeersAck&version=0.1.0
#tool nuget:?package=PeersAck&version=0.1.0
PeersAck
A lightweight, transport-agnostic networking library for C# games with support for:
- LAN/Local connections via LiteNetLib
- Steam P2P via Facepunch.Steamworks
- Room/Lobby abstraction for multiplayer game sessions
- Fluent builder API for easy setup
- Logging integration (Microsoft.Extensions.Logging)
- Connection statistics (latency, bytes sent/received)
Requirements
- .NET 8.0+ (supports net8.0, net9.0, net10.0)
- For Steam support: Steam client must be running
- For Godot: Godot 4.3+ with .NET support
Installation
NuGet:
# Core library
dotnet add package PeersAck
# For Godot 4 integration
dotnet add package PeersAck.Godot
From source:
dotnet restore
dotnet build
Godot 4 Integration
PeersAck provides first-class Godot 4 support with Node-based wrappers and signals.
Quick Start (Godot C#)
using Godot;
using PeersAck.Godot;
public partial class Game : Node
{
[Export] public NetworkManagerNode Network { get; set; }
public override void _Ready()
{
Network.PeerConnected += OnPeerConnected;
Network.DataReceived += OnDataReceived;
Network.StartServer(7777);
}
private void OnPeerConnected(long connectionId)
{
GD.Print($"Peer connected: {connectionId}");
}
private void OnDataReceived(long connectionId, byte[] data)
{
GD.Print($"Received {data.Length} bytes");
}
}
Using from GDScript
extends Node
@onready var network = $NetworkManagerNode
func _ready():
network.peer_connected.connect(_on_peer_connected)
network.data_received.connect(_on_data_received)
network.start_server(7777)
func _on_peer_connected(connection_id: int):
print("Peer connected: ", connection_id)
func _on_data_received(connection_id: int, data: PackedByteArray):
print("Received ", data.size(), " bytes")
Available Nodes
NetworkManagerNode- Low-level transport wrapper with auto-pollingRoomManagerNode- High-level room/lobby system wrapper
See PeersAck.Godot/README.md for full documentation.
Quick Start
Using the Builder (Recommended)
using PeersAck;
using PeersAck.Rooms;
using Microsoft.Extensions.Logging;
// Server with fluent configuration
var (transport, roomServer) = new PeersAckBuilder()
.UseLanTransport()
.WithLogging(loggerFactory) // Optional: add logging
.WithConnectionKey("MyGame_v1")
.WithMaxConnections(16)
.WithMaxPlayersPerRoom(4)
.BuildServer();
await transport.StartServerAsync(7777);
// Run game loop
await transport.RunLoopAsync(tickRate: 60, onTick: () =>
{
// Your game logic here
});
// Client with fluent configuration
var (transport, roomClient) = new PeersAckBuilder()
.UseLanTransport()
.WithConnectionKey("MyGame_v1")
.WithOperationTimeout(TimeSpan.FromSeconds(10))
.BuildClient();
await roomClient.ConnectAsync("127.0.0.1", 7777);
await roomClient.JoinRoomAsync("game-room");
LAN Server (Manual Setup)
using PeersAck.Transport;
using PeersAck.Rooms;
await using var transport = new LanTransport();
using var roomServer = new RoomServer(transport);
roomServer.OnPlayerJoinedRoom += (roomId, playerId) =>
Console.WriteLine($"Player {playerId} joined {roomId}");
await transport.StartServerAsync(7777);
while (true)
{
transport.Poll();
await Task.Delay(16);
}
LAN Client (Manual Setup)
await using var transport = new LanTransport();
using var roomClient = new RoomClient(transport);
await roomClient.ConnectAsync("127.0.0.1", 7777);
await roomClient.JoinRoomAsync("game-room");
roomClient.SendToRoom("game-room", myDataBytes, DeliveryMode.Reliable);
while (roomClient.IsConnected)
{
transport.Poll();
await Task.Delay(16);
}
Steam Host
using PeersAck.Steam;
using Steamworks;
SteamClient.Init(480); // Your App ID
// Create lobby for matchmaking
using var lobbyManager = new SteamLobbyManager();
var lobby = await lobbyManager.CreateLobbyAsync(maxPlayers: 4);
lobbyManager.SetLobbyData("game", "MyGame");
// Create P2P server
var (transport, roomServer) = new PeersAckBuilder()
.UseSteamTransport()
.BuildServer();
await transport.StartServerAsync();
while (true)
{
transport.Poll();
await Task.Delay(16);
}
SteamClient.Shutdown();
Steam Client
SteamClient.Init(480);
using var lobbyManager = new SteamLobbyManager();
var lobbies = await lobbyManager.FindLobbiesAsync(
new Dictionary<string, string> { ["game"] = "MyGame" });
await lobbyManager.JoinLobbyAsync(lobbies[0]);
var hostId = lobbyManager.GetHostSteamId()!.Value;
var (transport, roomClient) = new PeersAckBuilder()
.UseSteamTransport()
.BuildClient();
await ((SteamTransport)transport).ConnectAsync(hostId);
await roomClient.JoinRoomAsync("main");
SteamClient.Shutdown();
Logging
PeersAck integrates with Microsoft.Extensions.Logging:
using Microsoft.Extensions.Logging;
// Create a logger factory (e.g., from DI container or manually)
using var loggerFactory = LoggerFactory.Create(builder =>
{
builder.AddConsole();
builder.SetMinimumLevel(LogLevel.Debug);
});
// Pass to builder
var (transport, server) = new PeersAckBuilder()
.UseLanTransport()
.WithLogging(loggerFactory)
.BuildServer();
Or pass a logger directly:
var logger = loggerFactory.CreateLogger<LanTransport>();
var transport = new LanTransport(logger);
Connection Statistics
Monitor connection health and bandwidth:
var transport = new LanTransport();
// Get stats for a specific connection
var stats = transport.GetConnectionStats(connectionId);
if (stats != null)
{
Console.WriteLine($"Latency: {stats.Latency}ms");
Console.WriteLine($"Bytes sent: {stats.BytesSent}");
Console.WriteLine($"Bytes received: {stats.BytesReceived}");
Console.WriteLine($"Packets sent: {stats.PacketsSent}");
Console.WriteLine($"Connected for: {stats.ConnectionDuration}");
}
// Get aggregate transport stats
var transportStats = transport.Stats;
Console.WriteLine($"Active connections: {transportStats.ActiveConnections}");
Console.WriteLine($"Total bytes sent: {transportStats.TotalBytesSent}");
Architecture
┌─────────────────────────────────────────────────────┐
│ Your Game │
├─────────────────────────────────────────────────────┤
│ PeersAckBuilder │
│ (Fluent configuration) │
├─────────────────────────────────────────────────────┤
│ RoomServer / RoomClient │
│ (Room management, player tracking) │
├─────────────────────────────────────────────────────┤
│ INetworkTransport │
├──────────────────────┬──────────────────────────────┤
│ LanTransport │ SteamTransport │
│ (LiteNetLib) │ (Facepunch.Steamworks) │
└──────────────────────┴──────────────────────────────┘
Key Types
Transport Layer
| Type | Description |
|---|---|
INetworkTransport |
Core transport interface |
LanTransport |
LAN/local network transport |
SteamTransport |
Steam P2P transport |
ConnectionId |
Unique connection identifier |
DeliveryMode |
Reliable or Unreliable |
IConnectionStats |
Connection statistics interface |
TransportStats |
Aggregate transport statistics |
Room Layer
| Type | Description |
|---|---|
RoomServer |
Server-side room management |
RoomClient |
Client-side room handling |
RoomId |
Room identifier (string-based) |
PlayerId |
Player identifier |
Builder & Utilities
| Type | Description |
|---|---|
PeersAckBuilder |
Fluent builder for configuration |
TransportType |
Enum: Lan or Steam |
Steam Extras
| Type | Description |
|---|---|
SteamLobbyManager |
Steam lobby create/join/search |
Builder Options
new PeersAckBuilder()
// Transport selection
.UseLanTransport() // Use LiteNetLib (default)
.UseSteamTransport() // Use Steam P2P
// Logging
.WithLogging(loggerFactory) // Add logging support
// Connection settings
.WithConnectionKey("key") // LAN connection key
.WithMaxConnections(32) // Max server connections
.WithDisconnectTimeout(5000) // Timeout in ms
.WithDisconnectTimeout(TimeSpan.FromSeconds(5))
// Room settings
.WithAutoCreateRooms(true) // Auto-create rooms on join
.WithMaxPlayersPerRoom(8) // Max players per room
// Client settings
.WithOperationTimeout(10000) // Async operation timeout
// Build
.BuildTransport() // Just the transport
.BuildServer() // (transport, roomServer)
.BuildClient() // (transport, roomClient)
Delivery Modes
- Reliable: Guaranteed delivery, ordered. Use for important events (chat, state changes).
- Unreliable: Fast, no guarantees. Use for frequently-updated data (positions, inputs).
How to Extend
Adding a New Transport
- Implement
INetworkTransport - Map your transport's connection IDs to
ConnectionId - Raise events:
OnPeerConnected,OnPeerDisconnected,OnDataReceived
public class MyTransport : INetworkTransport
{
// Implement all interface members...
}
Adding Room Features
Extend RoomServer/RoomClient or create wrapper classes:
public class GameRoomServer : RoomServer
{
public Dictionary<RoomId, GameState> RoomStates { get; } = new();
// Add game-specific room logic...
}
Custom Room Messages
Extend RoomProtocol with new message types:
public static class GameProtocol
{
public const byte SpawnPlayer = 0x20;
public const byte UpdatePosition = 0x21;
public static byte[] CreateSpawnPlayer(PlayerId id, Vector3 position) { ... }
}
Thread Safety
The library is designed to be called from a single thread (your game loop). Call Poll() regularly to process network events.
Running Tests
dotnet test PeersAck.Tests/PeersAck.Tests.csproj
License
MIT
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 is compatible. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net10.0
- Facepunch.Steamworks (>= 2.3.3)
- LiteNetLib (>= 1.3.0)
- Microsoft.Extensions.Logging.Abstractions (>= 8.0.0)
-
net8.0
- Facepunch.Steamworks (>= 2.3.3)
- LiteNetLib (>= 1.3.0)
- Microsoft.Extensions.Logging.Abstractions (>= 8.0.0)
-
net9.0
- Facepunch.Steamworks (>= 2.3.3)
- LiteNetLib (>= 1.3.0)
- Microsoft.Extensions.Logging.Abstractions (>= 8.0.0)
NuGet packages (1)
Showing the top 1 NuGet packages that depend on PeersAck:
| Package | Downloads |
|---|---|
|
PeersAck.Godot
Godot 4 integration for PeersAck networking library. Provides Node-based wrappers with signals for easy integration with GDScript and C# Godot projects. |
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 0.1.0 | 140 | 3/12/2026 |