-
Notifications
You must be signed in to change notification settings - Fork 97
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
1a7d3ab
commit b9b0237
Showing
33 changed files
with
2,388 additions
and
278 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,11 +1,3 @@ | ||
# Quilkin Unreal Engine Plugin | ||
|
||
This is an alpha version of the Unreal Engine plugin for Quilkin. Currently it only supports adding a routing token in the following format. | ||
|
||
``` | ||
<packet> | token | version | ||
X bytes | 16 bytes | 1 bytes | ||
``` | ||
|
||
## How to install | ||
To get this client proxy installed, the SDK should be located in `Engine` path for Plugins, so copy the whole `ue4` folder (resides under `sdks` folder) in your Unreal Engine path `/[UE4 Root]/Engine/Plugins`, then you may want to rename the ue4 folder to `Quilkin`. Unreal Engine will automatically discover the plugin by searching for `.uplugin` file. | ||
{{#include ../../../sdks/ue5/README.md }} |
This file was deleted.
Oops, something went wrong.
109 changes: 0 additions & 109 deletions
109
sdks/ue4/Source/Quilkin/Private/QuilkinSocketSubsystem.cpp
This file was deleted.
Oops, something went wrong.
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
Binaries/ | ||
Intermediate/ |
File renamed without changes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
This is an unreal engine 5 plugin for Quilkin, a UDP proxy for gameservers. The plugin provides several features that you can use with Quilkin deployments, such as proxying game traffic, and latency measurement. | ||
|
||
You can also find guide level documentation on how the proxy works in the [Quilkin Book](https://googleforgames.github.io/quilkin/main/book/). | ||
|
||
### Installation | ||
|
||
Copy this plugin to your `Plugins` folder in your `Engine` directory. | ||
|
||
### Configuration | ||
Static configuration is available in the editor through `UQuilkinDeveloperSettings` in "Project Settings". | ||
|
||
Dynamic configuration is available through `UQuilkinConfigSubsystem`, it is initialised from the settings provided in `UQuilkinDeveloperSettings`, but can also be updated in code, and users can bind individual properties to delegates allowing them to dynamically set based on custom logic. | ||
|
||
- `bool Enabled` Whether the plugin will attach a versioned routing token to UDP packets to allow load balancers forward traffic to the correct gameserver. This also requires the address the clients connect to be a Quilkin load balancer, if connected directly to a gameserver the client will be rejected. | ||
- `bool EnabledInPie` By default `Enabled` is disabled in editor to prevent interfering with local clients and gameservers, you can override this behaviour by also enabling `EnabledInPie`. | ||
- `TArray<uint8> RoutingToken` The routing token representing the gameserver a client wants to reach, the token **must** be 16 bytes exactly. Currently the plugin only supports using `Enabled` with a routing token to create the following layout. It is assumed that the routing token would come from an external service, such as a matchmaking system. | ||
|
||
``` | ||
<packet> | token | version | ||
X bytes | 16 bytes | 1 byte | ||
``` | ||
|
||
- `TArray<FQuilkinEndpoint> Endpoints` A set of Quilkin load balancer endpoints that can be used for the following features. | ||
- `bool MeasureEndpoints` When enabled, the plugin will start a new `Tick` task that executes at a fixed interval (currently 30 seconds), where it will spawn a new background task that will ping each endpoint in `Endpoints`, and track its measurement in a fixed size circular buffer. | ||
Pings are handled through Quilkin Control Message Protocol, this is a bespoke protocol for UDP to be able to support situations where for example using ICMP is not possible, see the [Quilkin Book](https://googleforgames.github.io/quilkin/main/book/services/proxy/qcmp.html) for more details on the protocol data unit. | ||
**Note** `MeasureEndpoints` is orthogonal to `Enabled` and `UseEndpoints` meaning that you can use `MeasureEndpoints` for latency measurements without being required to also use Quilkin for game traffic. | ||
- `bool UseEndpoints` Whether to use `Endpoints` for game traffic. When enabled, instead of using the provided `FInternetAddr`, the plugin will choose the lowest latency endpoint available and send traffic through that endpoint to connect to the gameserver, and if the latency should exceed `JitterThreshold` then the plugin will attempt to redirect traffic to the next available endpoint with the lowest latency. | ||
|
||
### Delegates | ||
Quilkin exposes a number of delegates to be able to access certain information, they can be accessed through the `FQuilkinDelegates` class. | ||
|
||
- `GetQuilkinEndpointMeasurements` returns `TArray<EndpointPair>` representing each endpoint set in `Endpoints` with their median latency. The array will be empty if no endpoints have been set and `MeasureEndpoints` is not enabled. | ||
|
||
- `GetLowestLatencyEndpoint` returns `TOptional<EndpointPair>` is a specialisation of `GetQuilkinEndpointMeasurements` returning the lowest latency endpoint and its median latency. The delegate will return `None` if the array is empty and `MeasureEndpoints` is not enabled. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
/* | ||
* Copyright 2023 Google LLC | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
#pragma once | ||
|
||
#include "Containers/Deque.h" | ||
|
||
/* A circular first-in last-out buffer used for taking the median of measurements */ | ||
template <typename T> | ||
class CircularBuffer | ||
{ | ||
public: | ||
explicit CircularBuffer(size_t InCapacity = 50) | ||
: Capacity(InCapacity) | ||
{ | ||
} | ||
|
||
void Add(const T& value) | ||
{ | ||
if (Buffer.Num() == Capacity) | ||
{ | ||
Buffer.PopFirst(); | ||
} | ||
Buffer.PushLast(value); | ||
} | ||
|
||
bool IsEmpty() | ||
{ | ||
return Num() == 0; | ||
} | ||
|
||
size_t Num() | ||
{ | ||
return Buffer.Num(); | ||
} | ||
|
||
T Median() const | ||
{ | ||
if (Buffer.IsEmpty()) | ||
{ | ||
return T{}; // Return default value if the buffer is empty | ||
} | ||
|
||
TArray<T> Sorted; | ||
for (const auto& Item : Buffer) | ||
{ | ||
Sorted.Add(Item); | ||
} | ||
|
||
Sorted.Sort(); | ||
|
||
size_t Middle = Sorted.Num() / 2; | ||
|
||
return (Sorted.Num() % 2 == 0) ? (Sorted[Middle] + Sorted[Middle - 1]) / 2 : Sorted[Middle]; | ||
} | ||
|
||
private: | ||
size_t Capacity; | ||
TDeque<T> Buffer; | ||
}; | ||
|
Oops, something went wrong.