| Filename | Latest commit message | Latest commit date |
|---|---|---|
| .. | ||
| Samples | ||
| Client.cs | ||
| ClientSecurityOptions.cs | ||
| GameCult.Networking.csproj | ||
| Messages.cs | ||
| MessageSerialization.cs | ||
| NetPeerExtensions.cs | ||
| PlayerData.cs | ||
| README.md | ||
| Secret.cs | ||
| Server.cs | ||
| ServerSecurityOptions.cs | ||
GameCult.Networking
GameCult.Networking provides client/server messaging over LiteNetLib with encrypted credential exchange and signed session tokens.
It is intended for game or game-service scenarios where you want a compact transport layer with a small set of built-in authentication flows rather than a full HTTP stack.
The networking/auth layer is the durable organ. Some payloads in this repo are just sample application messages riding that organ.
Scope
The library currently includes:
- a shared message contract model
- a client wrapper around LiteNetLib
- a server wrapper around LiteNetLib
- encrypted login, register, and verify flows
- signed session-token generation and validation
PlayerDataintegration withCultCache- sample application payloads under
Samples/
The library is focused on the built-in authentication and session flows in this repository.
Keep the distinction clean:
- auth/session semantics belong to the core library
- application payload contracts should be explicit, versioned, and kept in sync across runtimes
- runtimes should be able to ask each other which schemas they speak before pretending a shared pipe implies shared understanding
- if multiple apps share a message contract, they should be able to talk directly without bespoke translation sludge
Main Types
Message: base type for all wire messagesClient: client connection, dispatch, reconnect, and login/register helpersServer: server dispatch, auth flow handling, rate limiting, and session refreshSecret: encryption and signed-token helper methodsPlayerData: cache-backed player record type
Sample payloads:
ChangeNameMessageChatMessageSchemaCatalogRequestMessageSchemaCatalogResponseMessage
Those now live under Samples/ to make it obvious they are example application
messages, not the entire meaning of the library.
Authentication Model
The built-in flow is:
- client connects with the shared LiteNetLib connection key
- credentials are encrypted with AES-GCM using a per-message nonce
- server validates credentials and issues a signed session token
- client stores the encrypted session token and can send
VerifyMessageon reconnect - server validates the token and re-establishes the session
The session token is signed and validated by the server.
Runtime Secrets
GameCult.Networking uses:
GAMECULT_CONNECTION_KEYGAMECULT_SESSION_SIGNING_SECRET
Production requirements:
- set both before constructing
Serverwithout explicitServerSecurityOptions - use high-entropy random values, not human-memorable strings
- keep
GAMECULT_SESSION_SIGNING_SECRETin your deployment platform's secret store rather than in source control or appsettings checked into the repo - distribute
GAMECULT_CONNECTION_KEYto clients through your build or asset pipeline, not through runtime environment variables on shipped clients - partial configuration is rejected by
ServerSecurityOptions.FromEnvironment()
Recommended format:
- 32 or more random bytes per value
- store as Base64/Base64Url text if needed
Example PowerShell generation:
[Convert]::ToBase64String((1..32 | ForEach-Object { Get-Random -Maximum 256 }))
Example environment assignment in PowerShell:
$env:GAMECULT_CONNECTION_KEY = "<random-base64-value>"
$env:GAMECULT_SESSION_SIGNING_SECRET = "<different-random-base64-value>"
Deployment model:
- the client and server must share the same
GAMECULT_CONNECTION_KEY - the server alone needs
GAMECULT_SESSION_SIGNING_SECRET GAMECULT_CONNECTION_KEYis shared protocol configuration, not a server-only secret- rotating
GAMECULT_CONNECTION_KEYrequires a coordinated client/server rollout or multi-key server support during migration GAMECULT_SESSION_SIGNING_SECRETcan be rotated server-side with the usual session invalidation tradeoffs
Strict production-style configuration:
using GameCult.Caching;
using GameCult.Networking;
var cache = new CultCache();
var security = ServerSecurityOptions.FromEnvironment();
var server = new Server(cache, security);
Explicit local-development server configuration:
using GameCult.Caching;
using GameCult.Networking;
var cache = new CultCache();
var security = ServerSecurityOptions.Development();
var server = new Server(cache, security);
Explicit client configuration:
using GameCult.Networking;
var security = new ClientSecurityOptions("<matching-connection-key>");
var client = new Client(security);
Use ServerSecurityOptions.Development() only for local development and tests. Client does not read environment variables.
Basic Server Usage
using GameCult.Caching;
using GameCult.Logging;
using GameCult.Networking;
var cache = new CultCache();
var server = new Server(cache)
{
Logger = new ConsoleLogger()
};
server.AddMessageListener<ChatMessage>(message =>
{
server.Logger.LogInfo($"Chat: {message.Text}");
});
server.Start();
Basic Client Usage
using GameCult.Logging;
using GameCult.Networking;
var client = new Client(new ClientSecurityOptions("<matching-connection-key>"))
{
Logger = new ConsoleLogger()
};
client.OnError += error => client.Logger.LogError($"Client error: {error}");
client.AddMessageListener<ChatMessage>(message => client.Logger.LogInfo($"Chat: {message.Text}"));
client.Connect("localhost", 3075);
client.Login("user@example.com", "correct horse battery staple");
Reconnect Behavior
The client:
- disposes its prior polling subscription before reconnecting
- stops the prior
NetManager - schedules reconnect with a short delay
- automatically re-verifies using the stored signed session token
Important Constraints
Servercurrently centers onPlayerDataas the built-in account model.- Message authorization is based on the built-in verify/login/register flow.
- Transport is LiteNetLib, so this is not a drop-in substitute for HTTP or WebSocket stacks.
Message Example
Messages derive from Message and are MessagePack-serializable:
using GameCult.Networking;
using MessagePack;
[MessagePackObject]
public class CustomPingMessage : Message
{
[Key(0)] public string Value = string.Empty;
}
If you extend the built-in message set, update the union and serialization model accordingly.
If you want cross-runtime compatibility with TypeScript, Rust, Python, or anything else, treat message tags and field keys like CultCache schema:
- explicit
- stable
- shared
- boring in exactly the useful way