Networking logic and server runtimes for YARG online multiplayer. This repo hosts the future transport/runtime stack that both the Unity client and the dedicated server consume.
| Project | Target | Purpose |
|---|---|---|
YARG.Net |
netstandard2.1 |
Shared abstractions plus the concrete LiteNetLib transport that Unity and server hosts reference. |
YARG.ServerHost |
net8.0 |
Console application that boots the LiteNetLib transport via the default server runtime. |
YARG.LobbyServer |
net8.0 |
Lobby directory, NAT punch coordination, and relay server for multiplayer connections. |
YARG.Net.Tests |
net8.0 |
xUnit test suite that exercises the shared library with transport shims. |
The root YARG.Networking.sln loads all of the projects above. Shared SDK settings live in Directory.Build.props.
dotnet restore YARG.Networking.sln
dotnet build YARG.Networking.sln --configuration Release
dotnet test YARG.Networking.sln --configuration ReleaseThe GitHub Actions workflow (.github/workflows/dotnet.yml) runs the same restore/build/test sequence on every PR and push.
YARG.Net now ships two transports:
NullTransportkeeps unit tests fast by providing a no-op loopback implementation.LiteNetLibTransportwraps the upstream LiteNetLib stack and is the default choice for gameplay and server runtimes. It already supports server/client start, connection events, and payload forwarding; higher level runtimes will eventually own the polling cadence.
DefaultServerRuntime(inYARG.Net.Runtime) drives a configuredINetTransportwith a simple polling loop, exposingConfigure,StartAsync, andStopAsyncfor dedicated hosts.DefaultClientRuntime(also underYARG.Net.Runtime) manages client connections by registering a transport, issuingConnectAsync/DisconnectAsync, and internally running the polling loop needed by LiteNetLib on the Unity player.YARG.ServerHostwires the server runtime toLiteNetLibTransport, hosts the sharedPacketDispatcher, and now bootstraps theServerHandshakeHandler/LobbyStateManagerpipeline. The CLI supports--port <value>(default7777),--nat,--max-players <value>, and--password <value>to gate access. PressCtrl+Cto request shutdown at runtime.- Both runtimes can now forward transport payloads into a shared
IPacketDispatcher, allowing Unity and the dedicated host to share the same packet-handling logic fromYARG.Net.
INetSerializerabstracts payload encoding.JsonNetSerializerprovides the default implementation backed bySystem.Text.Json.NetSerializerOptions.CreateDefault()centralizes the JSON configuration (camelCase, enum-as-string, ignore nulls) so Unity clients and dedicated servers produce identical payloads.- Higher-level packets can depend on
INetSerializerto remain agnostic of the underlying transport wire format.
PacketTypelists the current protocol messages (HandshakeRequest,HandshakeResponse,Heartbeat,LobbyState,LobbyInvite,SongSelection,GameplayCountdown,GameplayInputFrame).- Each payload implements the
IPacketPayloadmarker record (see the files undersrc/YARG.Net/Packets/). PacketEnvelope<TPayload>wraps the payload withTypemetadata and theProtocolVersion.Currentstring so routers can inspect and dispatch without deserializing blindly.- As we add more gameplay/session packets, update
PacketTypeand create new payload records that serialize through the sharedINetSerializer.
PacketDispatcher+IPacketDispatcherlive inYARG.Net.Packets.Dispatchand provide a registry for mappingPacketTypevalues to strongly-typed handlers.- Handlers receive a
PacketContext(connection, channel, endpoint role) and the fully deserializedPacketEnvelope<T>. - Hosts simply plug the dispatcher into the runtimes; the shared library owns packet parsing, keeping Unity and the server thin.
ServerHandshakeHandlervalidates protocol versions, player names, and optional passwords before mintingSessionRecordentries insideSessionManager.LobbyStateManagerandServerLobbyCoordinatorsubscribe to those session events to keep lobby membership, roles, song selection, and readiness synchronized across every peer.- When any lobby event fires, the coordinator emits a fresh
LobbyStatePacketvia the shared dispatcher so Unity and dedicated-host clients receive identical snapshots. - On the client,
ClientLobbyStateHandlerlistens forLobbyStatePacketdispatches, caches the latest snapshot, and raisesLobbyStateChangedevents that UI layers can bind to without touching transport state. ClientLobbyCommandSenderserializes ready-state toggles and song selection commands, whileServerLobbyCommandHandlervalidates them againstSessionManager/LobbyStateManagerbefore mutating lobby state.
dotnet run --project src/YARG.ServerHost -- \
--port 7779 \
--nat \
--max-players 12 \
--password supersecretUse only the flags you need; unspecified values fall back to the defaults listed above.
var serializer = new JsonNetSerializer();
var dispatcher = new PacketDispatcher(serializer);
var lobbyHandler = new ClientLobbyStateHandler();
lobbyHandler.Register(dispatcher);
var clientRuntime = new DefaultClientRuntime();
clientRuntime.RegisterTransport(liteNetLibTransport);
clientRuntime.RegisterPacketDispatcher(dispatcher);
lobbyHandler.LobbyStateChanged += (_, args) =>
{
Debug.Log($"Lobby status: {args.Snapshot.Status}");
};
var commandSender = new ClientLobbyCommandSender(serializer);
Guid sessionId = Guid.Empty;
runtime.Connected += (_, args) =>
{
// Cache the remote connection when the handshake finishes so we can send commands later.
sessionId = /* populate from HandshakeResponsePacket */;
};
runtime.Disconnected += (_, _) => sessionId = Guid.Empty;
void ToggleReady(bool ready)
{
var connection = runtime.ActiveConnection;
if (connection is null || sessionId == Guid.Empty)
{
return;
}
commandSender.SendReadyState(connection, sessionId, ready);
}Once registered, any lobby broadcast from the server automatically updates the handler’s snapshot and fires the event.
- Build gameplay/session orchestration layers on top of the new client/server runtime pair.
- Implement serialization helpers so packets can be defined once and shared across platforms.
- Publish
YARG.Netas a NuGet package so the Unity repo can reference it viaPackages/manifest.jsonor assembly definition references.