Skip to content

Commit

Permalink
Readme and docs
Browse files Browse the repository at this point in the history
  • Loading branch information
leonidumanskiy committed Jan 23, 2024
1 parent ea8166a commit 5c2361e
Show file tree
Hide file tree
Showing 11 changed files with 132 additions and 35 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,9 @@ Fenrir provides a great balance between performance and ease of development and
- [Serialization](docs/Serialization.md)
- [Custom Type Serialization](docs/CustomTypeSerialization.md)
- [Custom Serializer](docs/CustomSerializer.md)
- [Room Management](docs/RoomManagementBasics.md)
- [Room Management](docs/RoomManagement.md)
- [Logging](docs/Logging.md)
- [Docker Setup](docs/DockerBasics.md)
- [Docker Setup](docs/DockerSetup.md)
- [Thread Safety](docs/ThreadSafety.md)
- [Client and Server Lifecycle](docs/Lifecycle.md)
- [FAQ](docs/FAQ.md)
Expand Down
2 changes: 1 addition & 1 deletion docs/CustomSerializer.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ Plugin packages for those are coming soon!
Note: `DataContractSerializer` does not provide performance sufficient for most games. Provided only as an example.

```csharp
using Fenrir.Multiplayer.Serialization;
using Fenrir.Multiplayer;

class CustomSerializer : ITypeSerializer
{
Expand Down
2 changes: 1 addition & 1 deletion docs/CustomTypeSerialization.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ Custom serializer must implement `ITypeSerializer<T>` interface as such:

```csharp
using UnityEngine;
using Fenrir.Multiplayer.Serialization;
using Fenrir.Multiplayer;

class Vector3Serializer : ITypeSerializer<Vector3>
{
Expand Down
18 changes: 17 additions & 1 deletion docs/DockerSetup.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,22 @@ This section explains how to run Fenrir Server using Docker

Previous Section: [Logging](/Logging.md)

TODO: Docker setup
## Building Server solution with Docker

Fenrir Server is a standalone .NET application that supports Docker out of the box.

When using built-in template, you can navigate to the `Server` folder and build it using provided dockerfile:

```bash
cd Server
docker build . -t example:latest
```

**Note**: When running docker, make sure to bind both **TCP** and **UDP** ports:

```bash
docker run -p 27016:27016/tcp -p 27016:27016/udp example:latest
```


Next Section: [Thread Safety](/ThreadSafety.md)
4 changes: 2 additions & 2 deletions docs/DocumentationIndex.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@ This section contains Table of Contents for the Fenrir Multiplayer SDK documenta
- [Serialization](Serialization.md)
- [Custom Type Serialization](CustomTypeSerialization.md)
- [Custom Serializer](CustomSerializer.md)
- [Room Management](RoomManagementBasics.md)
- [Room Management](RoomManagement.md)
- [Logging](Logging.md)
- [Docker Setup](DockerBasics.md)
- [Docker Setup](DockerSetup.md)
- [Thread Safety](ThreadSafety.md)
- [Client and Server Lifecycle](Lifecycle.md)
- [FAQ](FAQ.md)
50 changes: 48 additions & 2 deletions docs/LifeCycle.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,54 @@ Previous Section: [Thread Safety](/ThreadSafety.md)

## Server and Client Lifecycle

TODO
Both `NetworkClient` and `NetworkServer` implement `IDisposable` and should be used within the `using` statement`, or be disposed properly.

⚠️ Failure to dispose a NetworkClient properly could lead to issues such as unclosed socket.

Unity Example:

```csharp
class MyBehaviour : MonoBehaviour
{
private NetworkClient _client;

public void Start()
{
_client = new NetworkClient();
}

...

public void Destroy()
{
_client.Dispose();
}
}
```

## Server Shutdown event

TODO
Built-in server template includes a Shutdown mechanism that can be used for server draining / rolling updates.

Example server with draining:

```csharp
// Listen for SIGTERM - invoked when Docker container is shutting down
AppDomain.CurrentDomain.ProcessExit += (_, _) => application.Shutdown(0).Wait();

class Application
{
public async Task Shutdown(int exitCode)
{
// Notify players they have to leave...
...

// Wait for all peers to disconnect
while(_peers.Count > 0)
{
await Task.Delay(1000); // wait 1 seconds
_logger.Info($"Waiting for players to leave: " + DateTime.UtcNow);
}
}
}
```
27 changes: 9 additions & 18 deletions docs/NetworkingBasics.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,7 @@ In order to do that, you can define a Request Handler or Event Handler.
**Example Request** (client+server shared code):

```csharp
using Fenrir.Multiplayer.Network;
using Fenrir.Multiplayer.Serialization;
using Fenrir.Multiplayer;

class HelloRequest : IRequest, IByteStreamSerializable
{
Expand All @@ -58,8 +57,7 @@ class HelloRequest : IRequest, IByteStreamSerializable
**Example server Request handler** (server code)

```csharp
using Fenrir.Multiplayer.Network;
using Fenrir.Multiplayer.Server;
using Fenrir.Multiplayer;

// Request Handler
class HelloRequestHandler : IRequestHandler<HelloRequest>
Expand All @@ -81,8 +79,7 @@ networkServer.Start();
**Example client sending a Request** (client code):

```csharp
using Fenrir.Multiplayer.Network;
using Fenrir.Multiplayer.Client;
using Fenrir.Multiplayer;

using var networkClient = new NetworkClient();
var connectionResponse = await networkClient.Connect("http://127.0.0.1:27016");
Expand All @@ -98,8 +95,7 @@ networkClient.Peer.SendRequest(new HelloRequest() { Name = "World" });
**Example Request with Response** (client+server shared code):

```csharp
using Fenrir.Multiplayer.Network;
using Fenrir.Multiplayer.Serialization;
using Fenrir.Multiplayer;

class PingResponse : IResponse, IByteStreamSerializable
{
Expand Down Expand Up @@ -135,8 +131,7 @@ class PingRequest : IRequest<PingResponse>, IByteStreamSerializable
**Example server Request handler with Response** (server code):

```csharp
using Fenrir.Multiplayer.Network;
using Fenrir.Multiplayer.Server;
using Fenrir.Multiplayer;

// Request Handler
class PingRequestHandler : IRequestHandler<PingRequest, PingResponse>
Expand All @@ -158,8 +153,7 @@ networkServer.Start();
**Example client sending a Request with a Response** (client code):

```csharp
using Fenrir.Multiplayer.Network;
using Fenrir.Multiplayer.Client;
using Fenrir.Multiplayer;

using var networkClient = new NetworkClient();
await networkClient.Connect("http://127.0.0.1:27016");
Expand All @@ -174,8 +168,7 @@ Debug.Log(response.ResponseText); // prints "Hello, World"
**Example Event** (client+server shared code):

```csharp
using Fenrir.Multiplayer.Network;
using Fenrir.Multiplayer.Serialization;
using Fenrir.Multiplayer;

class PingEvent : IEvent, IByteStreamSerializable
{
Expand All @@ -196,8 +189,7 @@ class PingEvent : IEvent, IByteStreamSerializable
**Example server sending Event** (server code):

```csharp
using Fenrir.Multiplayer.Network;
using Fenrir.Multiplayer.Server;
using Fenrir.Multiplayer;

using var networkServer = new NetworkServer();
networkServer.PeerConnected += (sender, e) =>
Expand All @@ -211,8 +203,7 @@ networkServer.Start();
**Example client Event Handler** (client code):

```csharp
using Fenrir.Multiplayer.Network;
using Fenrir.Multiplayer.Client;
using Fenrir.Multiplayer;

class PingEventHandler : IEventHandler<PingEvent>
{
Expand Down
17 changes: 16 additions & 1 deletion docs/Reliability.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,24 @@

This section explains the concept of "Reliable UDP".


Previous Section: [Peer Object](/PeerObject.md)

TODO: Reliability and Channels
## Message reliability and channels

Fenrir Multiplayer supports both reliable and unreliable communication.

When sending Requests or Events, optional **Channel** and **Message Delivery** parameters can be set:

```csharp

// Send realiable message using the 1st channel. Packets won't be dropped, won't be duplicated, will arrive in order.
networkClient.Peer.SendRequest(new PingRequest(), channel: 1, deliveryMethod: MessageDeliveryMethod.ReliableOrdered);

// Send unreliable message using 2nd channel. Packets can be dropped, can be duplicated, can arrive in no specific order.
networkClient.Peer.SendRequest(new PingRequest(), channel: 2, deliveryMethod: MessageDeliveryMethod.Unreliable);
```


Next Section: [Serialization](/Serialization.md)

6 changes: 3 additions & 3 deletions docs/RoomManagement.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ Each room has a unique id and is **created when first user joins**, and is **des
**Basic room example:**

```csharp
using Fenrir.Multiplayer.Network;
using Fenrir.Multiplayer;
using Fenrir.Multiplayer.Rooms;

class MyRoom : ServerRoom
Expand Down Expand Up @@ -54,7 +54,7 @@ class MyRoom : ServerRoom
In order to use the room management, you can use the extension method:

```csharp
using Fenrir.Multiplayer.Server;
using Fenrir.Multiplayer;
using Fenrir.Multiplayer.Rooms;

...
Expand All @@ -74,7 +74,7 @@ networkServer.AddRooms(CreateMyRoom);
**Client Room Management:**

```csharp
using Fenrir.Multiplayer.Client;
using Fenrir.Multiplayer;
using Fenrir.Multiplayer.Rooms;

...
Expand Down
3 changes: 1 addition & 2 deletions docs/Serialization.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,7 @@ It is simple but powerful: it allows explicitly serializing messages into direct
In order to use byte stream serializables, your messages should implement `IByteStreamSerializable`:

```csharp
using Fenrir.Multiplayer.Serialization;
using Fenrir.Multiplayer.Network;
using Fenrir.Multiplayer;

class MyEvent : IEvent, IByteStreamSerializable
{
Expand Down
34 changes: 32 additions & 2 deletions docs/ThreadSafety.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,41 @@ Previous Section: [Docker Setup](/DockerSetup.md)

## Multithreading Basics

TODO
Fenrir allows to build high-performance multi-threaded applications with very basic understanding of multi-threading.

### Fenrir SDK methods are thread-safe, unless specified otherwise

You can call any regular operations such as `peer.SendRequest`, `peer.SendEvent` from any thread.

### Network Client SDK is single-threaded

`NetworClient` events will be invoked from a single thread, running on a default Synchronization Context:

1. In Unity, it will be invoked on Unity main thread.
2. In a standalone .NET app, it will be invoked on a thread pool.

You can also set `NetworkClient.AutoPollEvents` to `false` and invoke `NetworkClient.PollEvents` manually. This allows you to trigger NetworkClient events from any thread/whenever you want.

### Network Server Threading Model

Each Connection Handler / Request Handler invocation happens on a separate thread, specific to a Server Peer.

### Room Threading Model

Room SDK simplifies multiplayer development. Each Room has it's own event loop baked by a single thread.

However, incoming requests handlers must still be scheduled to be run on a room.

Please refer to [Room Management](/RoomManagement.md) for the further details.

**⚠️ In other words, Request Handlers are multi-threaded, and Rooms are single-threaded. ⚠️**

## Asynchronous Methods

TODO
Request handlers can be synchronous and asynchronous. Asynchronous request handlers will use default Synchronization Context.

Please refer to [Networking Basics](/NetworkingBasics.md) for further details.



Next Section: [Life Cycle](/LifeCycle.md)

0 comments on commit 5c2361e

Please sign in to comment.