Skip to content

Commit

Permalink
Custom connection request data now propagates to IServerPeer.Connecti…
Browse files Browse the repository at this point in the history
…onRequestData. Added documentation
  • Loading branch information
leonidumanskiy committed Dec 7, 2021
1 parent 8d72cca commit a07262e
Show file tree
Hide file tree
Showing 19 changed files with 219 additions and 53 deletions.
42 changes: 22 additions & 20 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
![Fenrir Multiplayer](/docs/images/FenrirLogo512.png)
![Fenrir Multiplayer](/docs/images/FenrirLogo.png)

# Fenrir Multiplayer SDK

Expand All @@ -22,22 +22,26 @@ Fenrir provides a great balance between performance and ease of development and

**Table of Contents**:

- [Installation](/docs/Installation.md)
- [Quick Start](/docs/QuickStart.md)
- [Networking](/docs/NetworkingBasics.md)
- [Connection](/docs/Connection.md)
- [Peer Object](/docs/PeerObject.md)
- [Reliability](/docs/Reliability.md)
- [Serialization](/docs/Serialization.md)
- [Custom Type Serialization](/docs/CustomTypeSerialization.md)
- [Custom Serializer](/docs/CustomSerializer.md)
- [Room Management](/docs/RoomManagementBasics.md)
- [Logging](/docs/Logging.md)
- [Docker Setup](/docs/DockerBasics.md)
- [Thread Safety](/docs/ThreadSafety.md)
- [Client and Server Lifecycle](/docs/Lifecycle.md)

# Installation
- [Documentation Home](DocumentationIndex.md)
- [Installation](Installation.md)
- [Quick Start](QuickStart.md)
- [Networking](NetworkingBasics.md)
- [Connection](Connection.md)
- [Peer Object](PeerObject.md)
- [Reliability](Reliability.md)
- [Serialization](Serialization.md)
- [Custom Type Serialization](CustomTypeSerialization.md)
- [Custom Serializer](CustomSerializer.md)
- [Room Management](RoomManagementBasics.md)
- [Logging](Logging.md)
- [Docker Setup](DockerBasics.md)
- [Thread Safety](ThreadSafety.md)
- [Client and Server Lifecycle](Lifecycle.md)
- [FAQ](FAQ.md)

# Quick Start

## Installing Unity Package

This package can be installed using Unity Package from `https://upm.fenrirserver.org` registry.

Expand All @@ -46,9 +50,7 @@ This package can be installed using Unity Package from `https://upm.fenrirserver
1. In Unity, open **Edit****Project Settings****Package Manager** and add a **Scoped Registry** using URL: `https://upm.fenrirserver.org`
2. Open **Window****Package Manager** and switch to **Packages: My Registries**. Select **Fenrir Multiplayer** and click **Install**

# Quick Start

## Server Project
## Generating Server Project

Fenrir Multiplayer Unity Package comes with a server template that is recommended (but is not strictly required) to use.

Expand Down
14 changes: 13 additions & 1 deletion docs/Connection.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ Server Info endpoint is very useful for local testing and connecting to any spec

In production setups, very often the Server Info will be provided by the matchmaking server. In that case, TCP port does not need to be exposed.

** TODO: Endpoint vs UDP infographic **
![Connection Flows](images/ConnectionFlows.png)

**Example connecting via http endpoint**:

Expand Down Expand Up @@ -142,5 +142,17 @@ using var networkClient = new NetworkClient();
var connectionResponse = await networkClient.Connect("http://127.0.0.1:27016", connectionRequest);
```

Once the peer is connected, you can also access connection request data using `IServerPeer.ConnectionRequestData` object, througuout the Peer lifecycle.
For example, you can access it in `PeerConnected` event or any of your Request Handlers.

```csharp
networkServer.PeerConnected += (sender, e) =>
{
IServerPeer peer = e.Peer;
var requestData = (MyConnectionRequestData)peer.ConnectionRequestData;
Console.WriteLine("Player connected, name = " + requestData.Name);
};
```

Next Section: [Peer Object](PeerObject.md)
Table of Contents: [Documentation Home](DocumentationIndex.md)
1 change: 1 addition & 0 deletions docs/DocumentationIndex.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

This section contains Table of Contents for the Fenrir Multiplayer SDK documentation.

- [Documentation Home](DocumentationIndex.md)
- [Installation](Installation.md)
- [Quick Start](QuickStart.md)
- [Networking](NetworkingBasics.md)
Expand Down
25 changes: 24 additions & 1 deletion docs/PeerObject.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,30 @@ Previous Section: [Connection](Connection.md)

## Identifying Server Peer

There are two main ways of uniquely identifying each Peer.
There are several ways of uniquely identifying each Peer.

## Connection Request Data

If you set up a custom Connection Request Handler, you can validate custom Connection Request Data object and access it later using `IServerPeer.ConnectionRequestData` property:

```csharp
// Use with NetworkServer.SetConnectionRequestHandler<>
class MyConnectionRequestData
{
public string Name;

...
}

...

void HandleRequest(PlayerMoveRequest request, IServerPeer peer)
{
string name = peer.ConnectionRequestData.Name;
}
```

See also: [Using Custom Connection Request Handler](Connection.md#custom-connection-request)

## Server Peer Data

Expand Down
Binary file added docs/images/ConnectionFlows.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/images/FenrirLogo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file removed docs/images/FenrirLogo512.png
Binary file not shown.
Binary file modified docs/images/RequestResponseEvent.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docs/images/ServerRooms.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
48 changes: 43 additions & 5 deletions source/Fenrir.Multiplayer.Tests/Integration/IntegrationTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -130,11 +130,49 @@ public async Task NetworkClient_ConnectsToNetworkServer_WithCustomClientId()
[TestMethod, Timeout(TestTimeout)]
public async Task NetworkClient_ConnectsToNetworkServer_WithCustomConnectionRequestHandler()
{
TaskCompletionSource<CustomConnectionRequestData> peerConnectionRequestDataTcs = new TaskCompletionSource<CustomConnectionRequestData>();

using var logger = new TestLogger();
using var networkServer = new NetworkServer(logger);
networkServer.PeerConnected += (sender, e) =>
{
var requestData = (CustomConnectionRequestData)e.Peer.ConnectionRequestData;
peerConnectionRequestDataTcs.SetResult(requestData);
};

TaskCompletionSource<object> connectionRequestTcs = new TaskCompletionSource<object>();
networkServer.SetConnectionRequestHandler<CustomConnectionRequestData>(connectionRequest =>
{
Assert.AreEqual("test", connectionRequest.Data.Token);
connectionRequestTcs.SetResult(true);
return new ConnectionResponse(true);
});
networkServer.Start();

Assert.AreEqual(ServerStatus.Running, networkServer.Status, "server is not running");

using var networkClient = new NetworkClient(logger);
var connectionResponse = await networkClient.Connect("http://127.0.0.1:27016", new CustomConnectionRequestData() { Token = "test" });

Assert.AreEqual(ConnectionState.Connected, networkClient.State, "client is not connected");
Assert.IsTrue(connectionResponse.Success, "connection rejected");

await connectionRequestTcs.Task;

CustomConnectionRequestData peerConnectionRequestData = await peerConnectionRequestDataTcs.Task;

Assert.IsNotNull(peerConnectionRequestData);
Assert.AreEqual("test", peerConnectionRequestData.Token);
}

[TestMethod, Timeout(TestTimeout)]
public async Task NetworkClient_ConnectsToNetworkServer_WithCustomConnectionRequestHandlerAsync()
{
using var logger = new TestLogger();
using var networkServer = new NetworkServer(logger);

TaskCompletionSource<object> connectionRequestTcs = new TaskCompletionSource<object>();
networkServer.SetConnectionRequestHandlerAsync<CustomConnectionRequestData>(connectionRequest =>
{
Assert.AreEqual("test", connectionRequest.Data.Token);
connectionRequestTcs.SetResult(true);
Expand All @@ -154,12 +192,12 @@ public async Task NetworkClient_ConnectsToNetworkServer_WithCustomConnectionRequ
}

[TestMethod, Timeout(TestTimeout)]
public async Task NetworkClient_FailsToConnectToNetworkServer_WhenCustomConnectionRequestHandlerRejects()
public async Task NetworkClient_FailsToConnectToNetworkServer_WhenCustomConnectionRequestHandlerAsyncRejects()
{
using var logger = new TestLogger();
using var networkServer = new NetworkServer(logger);

networkServer.SetConnectionRequestHandler<CustomConnectionRequestData>(connectionRequest =>
networkServer.SetConnectionRequestHandlerAsync<CustomConnectionRequestData>(connectionRequest =>
{
Assert.AreEqual("test", connectionRequest.Data.Token);
return Task.FromResult(new ConnectionResponse(false, "test_reason"));
Expand All @@ -179,13 +217,13 @@ public async Task NetworkClient_FailsToConnectToNetworkServer_WhenCustomConnecti


[TestMethod, Timeout(TestTimeout)]
public async Task NetworkClient_FailsToConnectToNetworkServer_WhenCustomConnectionRequestHandlerThrowsException()
public async Task NetworkClient_FailsToConnectToNetworkServer_WhenCustomConnectionRequestHandlerAsyncThrowsException()
{
using var logger = new TestLogger();
using var networkServer = new NetworkServer(logger);


networkServer.SetConnectionRequestHandler<CustomConnectionRequestData>(connectionRequest =>
networkServer.SetConnectionRequestHandlerAsync<CustomConnectionRequestData>(connectionRequest =>
{
throw new InvalidOperationException("test_exception");
});
Expand All @@ -209,7 +247,7 @@ public async Task NetworkClient_FailsToConnectToNetworkServer_WhenRequestDataSer
using var networkServer = new NetworkServer(logger);


networkServer.SetConnectionRequestHandler<RequestDataFailingToDeserialize>(connectionRequest =>
networkServer.SetConnectionRequestHandlerAsync<RequestDataFailingToDeserialize>(connectionRequest =>
{
return Task.FromResult(ConnectionResponse.Successful);
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,7 @@ public int SimulationMaxLatency
/// <summary>
/// Creates <see cref="LiteNetProtocolConnector"/>
/// </summary>
/// <param name="clientEventListener">Client event listener</param>
/// <param name="serializer">Serializer</param>
/// <param name="typeHashMap">Type Hash Map</param>
/// <param name="logger">Logger</param>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -280,10 +280,10 @@ private async Task HandleConnectionRequestAsync(ConnectionRequest connectionRequ
}

// Invoke connection request handler
ConnectionResponse response;
ConnectionHandlerResult connectionHandlerResult;
try
{
response = await _serverEventListener.HandleConnectionRequest(protocolVersion, clientId, connectionRequest.RemoteEndPoint, connectionRequestDataReader);
connectionHandlerResult = await _serverEventListener.HandleConnectionRequest(protocolVersion, clientId, connectionRequest.RemoteEndPoint, connectionRequestDataReader);
}
finally
{
Expand All @@ -293,25 +293,25 @@ private async Task HandleConnectionRequestAsync(ConnectionRequest connectionRequ
}
}

if(response.Success)
if(connectionHandlerResult.Response.Success)
{
AcceptConnectionRequest(connectionRequest, protocolVersion, clientId);
AcceptConnectionRequest(connectionRequest, protocolVersion, clientId, connectionHandlerResult.ConnectionRequestData);
}
else
{
RejectConnectionRequest(connectionRequest, response.Reason);
RejectConnectionRequest(connectionRequest, connectionHandlerResult.Response.Reason);
}
}

private void AcceptConnectionRequest(ConnectionRequest liteNetConnectionRequest, int protocolVersion, string clientId)
private void AcceptConnectionRequest(ConnectionRequest liteNetConnectionRequest, int protocolVersion, string clientId, object connectionRequestData)
{
_logger.Trace("Accepting connection request from {0}", liteNetConnectionRequest.RemoteEndPoint);

NetPeer netPeer = liteNetConnectionRequest.Accept();

// Create server peer
var messageWriter = new MessageWriter(_serializer, _typeHashMap, _logger);
netPeer.Tag = new LiteNetServerPeer(clientId, protocolVersion, netPeer, messageWriter, _byteStreamWriterPool);
netPeer.Tag = new LiteNetServerPeer(clientId, protocolVersion, connectionRequestData, netPeer, messageWriter, _byteStreamWriterPool);
}

private void RejectConnectionRequest(ConnectionRequest connectionRequest, string reason)
Expand Down
10 changes: 9 additions & 1 deletion source/UnityPackage/Assets/Runtime/LiteNet/LiteNetServerPeer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -32,18 +32,26 @@ class LiteNetServerPeer : LiteNetBasePeer, IServerPeer
/// </summary>
public object PeerData { get; set; }

/// <summary>
/// Connection request data
/// </summary>
public object ConnectionRequestData { get; set; }


/// <summary>
/// Default constructor
/// </summary>
/// <param name="peerId">Unique id of the client</param>
/// <param name="protocolVersion">Peer protocol version</param>
/// <param name="connectionRequestData">Custom connection request data. If no Connection Request Handler is set, always null</param>
/// <param name="netPeer">LiteNet NetPeer</param>
/// <param name="messageWriter">Message Writer</param>
/// <param name="byteStreamWriterPool">Byte Stream Writer Object Pool</param>
public LiteNetServerPeer(string peerId, int protocolVersion, NetPeer netPeer, MessageWriter messageWriter, RecyclableObjectPool<ByteStreamWriter> byteStreamWriterPool)
public LiteNetServerPeer(string peerId, int protocolVersion, object connectionRequestData, NetPeer netPeer, MessageWriter messageWriter, RecyclableObjectPool<ByteStreamWriter> byteStreamWriterPool)
: base(peerId, netPeer, messageWriter, byteStreamWriterPool)
{
ProtocolVersion = protocolVersion;
ConnectionRequestData = connectionRequestData;
}

/// <inheritdoc/>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
namespace Fenrir.Multiplayer.Network
{
/// <summary>
/// Internal class to pass the result of user connection
/// </summary>
class ConnectionHandlerResult
{
/// <summary>
/// Connection response
/// </summary>
public ConnectionResponse Response { get; set; }

/// <summary>
/// Custom connection request data.
/// If no custom connection request handler is set, always null
/// </summary>
public object ConnectionRequestData { get; set; }

/// <summary>
/// Creates empty connection handler result
/// </summary>
public ConnectionHandlerResult()
{
}

/// <summary>
/// Default constructor
/// </summary>
/// <param name="response">Connection Response</param>
/// <param name="connectionRequestData">Connection Request Data</param>
public ConnectionHandlerResult(ConnectionResponse response, object connectionRequestData)
{
Response = response;
ConnectionRequestData = connectionRequestData;
}
}
}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

9 changes: 8 additions & 1 deletion source/UnityPackage/Assets/Runtime/Network/IServerPeer.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using Fenrir.Multiplayer.Server.Events;
using Fenrir.Multiplayer.Server;
using Fenrir.Multiplayer.Server.Events;
using System;

namespace Fenrir.Multiplayer.Network
Expand All @@ -23,6 +24,12 @@ public interface IServerPeer : IPeer
/// </summary>
object PeerData { get; set; }

/// <summary>
/// Custom connection request data.
/// Set only if custom Connection Request Handler is set on the <seealso cref="NetworkServer"/>.
/// </summary>
object ConnectionRequestData { get; }

/// <summary>
/// Notifies client of the event.
/// All events are encrypted by default.
Expand Down
Loading

0 comments on commit a07262e

Please sign in to comment.