-
-
Notifications
You must be signed in to change notification settings - Fork 94
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Tunnel autochooser #179
base: develop
Are you sure you want to change the base?
Tunnel autochooser #179
Changes from 4 commits
7fed700
be6430f
dc6b52a
e408b20
67718cf
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -18,7 +18,7 @@ public class CnCNetTunnel | |
public CnCNetTunnel() { } | ||
|
||
/// <summary> | ||
/// Parses a formatted string that contains the tunnel server's | ||
/// Parses a formatted string that contains the tunnel server's | ||
/// information into a CnCNetTunnel instance. | ||
/// </summary> | ||
/// <param name="str">The string that contains the tunnel server's information.</param> | ||
|
@@ -34,7 +34,7 @@ public static CnCNetTunnel Parse(string str) | |
|
||
string address = parts[0]; | ||
string[] detailedAddress = address.Split(new char[] { ':' }); | ||
|
||
tunnel.Address = detailedAddress[0]; | ||
tunnel.Port = int.Parse(detailedAddress[1]); | ||
tunnel.Country = parts[1]; | ||
|
@@ -85,6 +85,59 @@ public static CnCNetTunnel Parse(string str) | |
public double Distance { get; private set; } | ||
public int PingInMs { get; set; } = -1; | ||
|
||
/// <summary> | ||
/// Rating Factor: | ||
/// The latency in milleseconds that ping times are rounded off to. | ||
/// </summary> | ||
private const int LATENCY_PRECISION = 70; | ||
|
||
/// <summary> | ||
/// Rating Factor: | ||
/// The importance of latency compared to client count. | ||
/// </summary> | ||
private const int LATENCY_WEIGHT = 100000; | ||
|
||
/// <summary> | ||
/// Rating Factor: | ||
/// The value of client count compared to latency | ||
/// </summary> | ||
private const int CLIENTS_WEIGHT = 1; | ||
|
||
/// <summary> | ||
/// Rating Factor: | ||
/// Base Rating for untrusted servers and unpingable servers. | ||
/// </summary> | ||
private const int UNTRUSTED_RATING = int.MaxValue - 100000; | ||
|
||
/// <summary> | ||
/// Rating Factor: | ||
/// The amount of free client slots needed for the tunnel to be eligible for autoselection | ||
/// </summary> | ||
private const int CLIENTS_HEADROOM = 24; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why don't use some sort of a percentage instead? Hardcaps are bad in this case, imagine a tunnel with 50 players max. being filled with 26 players and stopping receiving players. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Live example: Berryville tunnel has 50 slots, so the server will be running at 26 players max. in case of autochoosing it? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The CLIENTS_HEADROOM is not for performance reasons. It's meant to make sure that when we go to use a tunnel server it has enough free slots to fill our request. The problem occurs because there is a time difference between when we select the tunnel server (game lobby creation) to when we request the user slots (game start). There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I understood that already, yet the issue I mentioned is still here. Servers with low max. player amounts would never be chosen or chosen rarely. IMO the issue of time difference should be dealt with some other sort of measure, f.ex. a task in game lobby checking for availability of the current tunnel on tunnel refresh. Ideally the players in lobby would be counted as players on servers even before starting but that would require server-side changes. |
||
|
||
public int Rating | ||
{ | ||
get | ||
{ | ||
if (Clients + CLIENTS_HEADROOM >= MaxClients) | ||
return int.MaxValue; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In my opinion it would be a lot better to use something like a quadratic or exponential function to calculate rating than hardcap at There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think a more complicated algorithm might be better in narrow cases but IMO the complexity out weighs the benefit. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I've already written a proto. algorithm, it isn't so hard, just needs adjustments to be done. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The point of this code is not to select tunnels with fewer clients (that's handled elsewhere). The point of this code comes from the fact that the tunnel chooser first runs when the game lobby is created and after each ping, there is no way to know if the selected tunnel will have enough resources to host our game when we're ready to start (ie, resource is requested/granted on game start). So we're creating some headroom that will give us a reasonable chance to get our first tunnel choice on game start. |
||
|
||
if (Official || Recommended) | ||
{ | ||
if (PingInMs <= -1) | ||
return UNTRUSTED_RATING + Clients; | ||
|
||
int latency = 1 + PingInMs / LATENCY_PRECISION; | ||
|
||
return (latency * LATENCY_WEIGHT) + (Clients * CLIENTS_WEIGHT); | ||
} | ||
else | ||
{ | ||
return UNTRUSTED_RATING + Clients; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. With this code it looks like the clients would almost never get an unofficial and non-recommended server selected. This is not the behavior I see as good, CnCNet is meant to be a community service, and IMO recommendation should boost the server, not basically "whitelist" recommended servers. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is the best case, the recommended servers have all been tested and proven to be good. The goal is for the users to never want or need to select a tunnel server themselves. When they do manually select a tunnel server it should be their own server that they want to use for personal reasons. This provides the added benefit that we can do some hacks on the master-list side to balance tunnel servers during the high load times. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I still object against verified and official tunnels being effectively whitelisted against regular ones, this is not future-proof at all. I mean the example is already at hand. I have a feeling no one actually bothered to test Berryville, yet it has very low ping for Europe and I never had issues using it. Imagine CnCNet staff going very busy all at once, then some of the verified tunnel will also go off and the players will be automatically balanced to 2-3 verified servers in USA, for example, even if they are from EU and there is regular, non-verified EU servers. This is absolutely not a desirable outcome IMO. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The reason we should never use untrusted tunnel servers is because they fail more often. When a tunnel server fails and it breaks the game for a group of players, the players don't blame the tunnel server owner they blame CnCNet, we can't stake our reputation on untrusted servers.
That's still more desirable than a broken tunnel server with low ping destroying everyone's game. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. My view of future CnCNet is as of a community service, not an organization, so I don't think this outcome is more desirable. I don't say that the system should be ditched. Per my idea verified servers would be "boosted" and chosen most of the time, but in case there's no local verified servers with low enough ping - regular one would be chosen. This would never happen in the current implementation. Again, you say that untrusted servers are bad because all good servers are made verified. Is that so? Not really. Someone has to test them manually, and as I said I don't see anyone testing Berryville server or some other EU servers which are OK despite the lack of EU tunnels. I always get Canada East chosen and I live in Europe. |
||
} | ||
} | ||
} | ||
|
||
/// <summary> | ||
/// Gets a list of player ports to use from a specific tunnel server. | ||
/// </summary> | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm against hidden changes of tunnel server, and this stuff also makes the whole following codeblock obsolete.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've added logging here so that the change is no longer hidden.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Perhaps I didn't phrase it clear enough, my bad. I meant that the user should be aware of the tunnel being chosen at least. Also the next codeblock after that still duplicates this one's functionally and won't be used in 99% cases.
The best possible solution I see is to just select the suggested tunnel server in the opened window if the previous tunnel was manually selected, and in case the previous tunnel was automatically selected add a notice to chatbox that the tunnel was changed to
TunnelName
instead.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This bit of code is designed to reduce frustration when a player wants to start a game and the tunnel server is out of resources. Manual tunnel selection is an advanced option now but it will be exclusively a power user option in the future when v3 tunnels are implemented.
The manual selection code isn't really ready to handle corner cases like this. It's a bit hacky, it should have it's own PR to handle it correctly. I don't think it's a good idea to block this PR for that reason.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The code redundancy must be fixed either way, preferably in a way I proposed - change tunnel server silently only in case the user didn't select the tunnel manually before.
PR shouldn't introduce more inoptimal solutions code-wise, in my opinion.