Skip to content
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

Quakenet test #422

Draft
wants to merge 72 commits into
base: develop
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
72 commits
Select commit Hold shift + click to select a range
930fbf8
Start work on version 3 tunnel support
Rampastring Jun 22, 2019
4752ca5
Update TunnelHandler, add TunneledPlayerConnection
Rampastring Jun 23, 2019
972fd8c
Add GameTunnelHandler
Rampastring Jun 23, 2019
5f03b38
Implement starting games with V3 tunnels, testing TODO
Rampastring Jun 23, 2019
6869e46
Fix CTCP string command handler not properly checking that the messag…
Rampastring Jun 24, 2019
6bf23f6
Fix bugs related to starting games with v3 tunnel connections, send t…
Rampastring Jun 24, 2019
29bc63e
Improve format of "total time played" and "average game length" in th…
Rampastring Jun 24, 2019
b2fb00f
Fix a bunch of issues related to starting games using v3 tunnels
Rampastring Jun 25, 2019
69780ca
Fix more v3 tunnel issues
Rampastring Jun 25, 2019
cd19c6c
Rebase fix
Rans4ckeR Aug 14, 2022
f2b51e1
Rebase cleanup, remove V3 tunnel login logic
Rans4ckeR Aug 14, 2022
2583ebe
Fix V3 tunnel player port assignment
Rans4ckeR Aug 15, 2022
a8746f7
Logging
Rans4ckeR Aug 15, 2022
0d038a6
Parse IPv6 & IPv4 tunnel addresses from master server, support IPv6 &…
Rans4ckeR Aug 15, 2022
95a7673
V3 tunnel fixes
Rans4ckeR Aug 16, 2022
1246f2e
Cleanup
Rans4ckeR Aug 17, 2022
c9c7297
Ignore socket error when game not loaded yet
Rans4ckeR Aug 19, 2022
e5bfeaf
Use game DualMode socket
Rans4ckeR Aug 19, 2022
abbf016
Fix tunnel selection window
Rans4ckeR Aug 21, 2022
ec6d4ff
Replace obsolete WebClient with HttpClient, IRC & LAN IPv6 support wi…
Rans4ckeR Aug 20, 2022
18d8b50
LAN connection fixes
Rans4ckeR Aug 20, 2022
84cafe9
Fix LAN game connections
Rans4ckeR Aug 21, 2022
6c11499
Prevent possible runtime errors with missing callback arguments
Rans4ckeR Aug 21, 2022
9bdaed8
Cleanup
Rans4ckeR Aug 23, 2022
34a9ead
Use Task.Run()
Rans4ckeR Aug 26, 2022
9cc4b7e
Use https requests (HTTP/2)
Rans4ckeR Sep 2, 2022
fa84349
Tunnel IPv6/IPv4 selection
Rans4ckeR Sep 12, 2022
b68e98c
Fix IRC Exception when user *.GameSurge.net sets MODE
Rans4ckeR Sep 13, 2022
b715f7f
Fix IRC disconnect
Rans4ckeR Sep 13, 2022
da18df3
Update IRC server selection
Rans4ckeR Sep 13, 2022
33dd426
Fix LAN lobby crash when no map selected
Rans4ckeR Sep 23, 2022
c37d70f
Don't send LAN host player joined using UI thread
Rans4ckeR Sep 23, 2022
7e7c8e0
Fix net48 build
Rans4ckeR Sep 23, 2022
17cfd77
Rebase fix
Rans4ckeR Nov 22, 2022
969d30c
Remove net48 code after net7 rebase
Rans4ckeR Nov 25, 2022
45219f8
Use SocketsHttpHandler instead of HttpClientHandler
Rans4ckeR Nov 26, 2022
3a9f325
Clean up Task Exception handling
Rans4ckeR Nov 26, 2022
2d2d8b5
Update Task exception handling
Rans4ckeR Nov 26, 2022
c4b6301
Update tunnel api url
Rans4ckeR Nov 26, 2022
0b89cc5
Saved game constants
Rans4ckeR Nov 26, 2022
32cf9ef
Exception logging
Rans4ckeR Nov 26, 2022
9a3cd02
Group network commands
Rans4ckeR Nov 27, 2022
a1b1706
Dynamic V3 tunnel selection
Rans4ckeR Nov 29, 2022
9a29aef
Add chat command for dynamic tunnels
Rans4ckeR Nov 29, 2022
e41bdc8
Tunnel switching and matching
Rans4ckeR Nov 29, 2022
9e8c40d
Fix LAN lobbies broadcast/discovery with multiple network interfaces
Rans4ckeR Dec 2, 2022
7483b44
Support P2P and UPnP port forwarding
Rans4ckeR Dec 3, 2022
8cf8641
Fix after rebase
Rans4ckeR Dec 3, 2022
ef73586
Cleanup
Rans4ckeR Dec 3, 2022
1049bfd
Rebase fix
Rans4ckeR Dec 3, 2022
6d3f118
Update P2P connection handling, use ValueTasks
Rans4ckeR Dec 6, 2022
0066afb
CnCNetGameLobby Dispose
Rans4ckeR Dec 6, 2022
d762991
Use Tasks instead of Threads
Rans4ckeR Dec 7, 2022
594b2ba
Use Tasks instead of Threads
Rans4ckeR Dec 7, 2022
600a03b
Update P2P handling
Rans4ckeR Dec 7, 2022
4e8f3d2
Handle remote player disconnects
Rans4ckeR Dec 10, 2022
bbd4c23
Handle P2P direct public IP to public IP connections
Rans4ckeR Dec 10, 2022
c828b10
P2P ping cleanup
Rans4ckeR Dec 11, 2022
1bdcab1
Add P2P STUN
Rans4ckeR Dec 11, 2022
1ca032f
P2P STUN port mapping and keep alive
Rans4ckeR Dec 11, 2022
c969a23
Cleanup
Rans4ckeR Dec 12, 2022
2986b51
Refactor
Rans4ckeR Dec 13, 2022
dc4195e
HttpClient handling
Rans4ckeR Dec 13, 2022
12409e0
Apply ConfigureAwait()
Rans4ckeR Dec 14, 2022
13fd239
Async file I/O, stream V3 replay data to disk
Rans4ckeR Dec 18, 2022
5a1ca8b
Game recording cleanup
Rans4ckeR Dec 18, 2022
7cc06e4
Don't parse statistics on UI thread
Rans4ckeR Dec 20, 2022
11af8fb
Prevent some exceptions
Rans4ckeR Dec 21, 2022
0aa7fec
Quakenet test
GrantBartlett Dec 21, 2022
527da28
P2P: don't fail on UPnP device unavailable services
Rans4ckeR Dec 21, 2022
8a8279f
P2P logging
Rans4ckeR Dec 21, 2022
80169e5
Merge branch 'networkstack' into quakenet-test
GrantBartlett Dec 27, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .editorconfig
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ csharp_style_prefer_range_operator = true:warning
csharp_style_prefer_tuple_swap = true:warning
csharp_style_throw_expression = true:warning
csharp_style_unused_value_assignment_preference = discard_variable:warning
csharp_style_unused_value_expression_statement_preference = discard_variable:warning
csharp_style_unused_value_expression_statement_preference = discard_variable:suggestion

# 'using' directive preferences
csharp_using_directive_placement = outside_namespace:warning
Expand Down Expand Up @@ -279,7 +279,7 @@ dotnet_diagnostic.IDE0055.severity = warning
dotnet_diagnostic.IDE0054.severity = warning
dotnet_diagnostic.IDE0056.severity = warning
dotnet_diagnostic.IDE0057.severity = warning
dotnet_diagnostic.IDE0058.severity = warning
dotnet_diagnostic.IDE0058.severity = suggestion
dotnet_diagnostic.IDE0060.severity = warning
dotnet_diagnostic.IDE0066.severity = warning
dotnet_diagnostic.IDE0059.severity = warning
Expand Down
4 changes: 2 additions & 2 deletions BuildScripts/Common.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,10 @@ $EngineMap = @{
function Build-Project($Configuration, $Game, $Engine, $Framework) {
$Output = Join-Path $CompiledRoot $Game $Output Resources Binaries ($EngineMap[$Engine])
if ($Engine -EQ 'WindowsXNA') {
dotnet publish $ProjectPath --configuration=$Configuration -property:GAME=$Game -property:ENGINE=$Engine --framework=$Framework --output=$Output --arch=x86
dotnet publish $ProjectPath -c $Configuration -p:GAME=$Game -p:ENGINE=$Engine -f $Framework -o $Output -p:SatelliteResourceLanguages=en -a x86
}
else {
dotnet publish $ProjectPath --configuration=$Configuration -property:GAME=$Game -property:ENGINE=$Engine --framework=$Framework --output=$Output
dotnet publish $ProjectPath -c $Configuration -p:GAME=$Game -p:ENGINE=$Engine -f $Framework -o $Output -p:SatelliteResourceLanguages=en
}
if ($LASTEXITCODE) {
throw "Build failed for $Game $Engine $Framework $Configuration"
Expand Down
19 changes: 6 additions & 13 deletions ClientCore/ClientConfiguration.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ public class ClientConfiguration
private const string GENERAL = "General";
private const string AUDIO = "Audio";
private const string SETTINGS = "Settings";
private const string LINKS = "Links";

private const string CLIENT_SETTINGS = "DTACnCNetClient.ini";
private const string GAME_OPTIONS = "GameOptions.ini";
Expand Down Expand Up @@ -47,14 +46,7 @@ protected ClientConfiguration()
/// <returns>The object of the ClientConfiguration class.</returns>
public static ClientConfiguration Instance
{
get
{
if (_instance == null)
{
_instance = new ClientConfiguration();
}
return _instance;
}
get { return _instance ??= new ClientConfiguration(); }
}

public void RefreshSettings()
Expand Down Expand Up @@ -202,13 +194,13 @@ public void RefreshSettings()

public string LongGameName => clientDefinitionsIni.GetStringValue(SETTINGS, "LongGameName", "Tiberian Sun");

public string LongSupportURL => clientDefinitionsIni.GetStringValue(SETTINGS, "LongSupportURL", "http://www.moddb.com/members/rampastring");
public string LongSupportURL => clientDefinitionsIni.GetStringValue(SETTINGS, "LongSupportURL", $"{Uri.UriSchemeHttps}://www.moddb.com/members/rampastring");

public string ShortSupportURL => clientDefinitionsIni.GetStringValue(SETTINGS, "ShortSupportURL", "www.moddb.com/members/rampastring");

public string ChangelogURL => clientDefinitionsIni.GetStringValue(SETTINGS, "ChangelogURL", "http://www.moddb.com/mods/the-dawn-of-the-tiberium-age/tutorials/change-log");
public string ChangelogURL => clientDefinitionsIni.GetStringValue(SETTINGS, "ChangelogURL", $"{Uri.UriSchemeHttps}://www.moddb.com/mods/the-dawn-of-the-tiberium-age/tutorials/change-log");

public string CreditsURL => clientDefinitionsIni.GetStringValue(SETTINGS, "CreditsURL", "http://www.moddb.com/mods/the-dawn-of-the-tiberium-age/tutorials/credits#Rampastring");
public string CreditsURL => clientDefinitionsIni.GetStringValue(SETTINGS, "CreditsURL", $"{Uri.UriSchemeHttps}://www.moddb.com/mods/the-dawn-of-the-tiberium-age/tutorials/credits#Rampastring");

public string ManualDownloadURL => clientDefinitionsIni.GetStringValue(SETTINGS, "ManualDownloadURL", string.Empty);

Expand Down Expand Up @@ -339,7 +331,8 @@ public OSVersion GetOperatingSystemVersion()
/// </summary>
public class ClientConfigurationException : Exception
{
public ClientConfigurationException(string message) : base(message)
public ClientConfigurationException(string message, Exception ex = null)
: base(message, ex)
{
}
}
Expand Down
4 changes: 2 additions & 2 deletions ClientCore/ClientCore.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,8 @@
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Rampastring.XNAUI.$(Engine)" Version="2.2.10" Condition="'!$(Configuration.Contains(Debug))'" />
<PackageReference Include="Rampastring.XNAUI.$(Engine).Debug" Version="2.2.10" Condition="'$(Configuration.Contains(Debug))'" />
<PackageReference Include="Rampastring.XNAUI.$(Engine)" Version="2.2.11" Condition="'!$(Configuration.Contains(Debug))'" />
<PackageReference Include="Rampastring.XNAUI.$(Engine).Debug" Version="2.2.11" Condition="'$(Configuration.Contains(Debug))'" />
<PackageReference Include="System.Text.Encoding.CodePages" Version="7.0.0" />
</ItemGroup>
<ItemGroup>
Expand Down
4 changes: 2 additions & 2 deletions ClientCore/CnCNet5/NameValidator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ public static string IsNameValid(string name)
if (profanityFilter.IsOffensive(name))
return "Please enter a name that is less offensive.".L10N("UI:ClientCore:NameOffensive");

if (int.TryParse(name.Substring(0, 1), out _))
if (int.TryParse(name[..1], out _))
return "The first character in the player name cannot be a number.".L10N("UI:ClientCore:NameFirstIsNumber");

if (name[0] == '-')
Expand Down Expand Up @@ -59,7 +59,7 @@ public static string GetValidOfflineName(string name)
string validName = new string(name.Trim().Where(c => !disallowedCharacters.Contains(c)).ToArray());

if (validName.Length > ClientConfiguration.Instance.MaxNameLength)
return validName.Substring(0, ClientConfiguration.Instance.MaxNameLength);
return validName[..ClientConfiguration.Instance.MaxNameLength];

return validName;
}
Expand Down
19 changes: 8 additions & 11 deletions ClientCore/Extensions/EnumExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,18 @@ namespace ClientCore.Extensions
{
public static class EnumExtensions
{
public static T Next<T>(this T src) where T : Enum
public static T Next<T>(this T src)
where T : Enum
{
T[] Arr = GetValues(src);
int nextIndex = Array.IndexOf(Arr, src) + 1;
return Arr.Length == nextIndex ? Arr[0] : Arr[nextIndex];
T[] values = GetValues(src);
int nextIndex = Array.IndexOf(values, src) + 1;
return values.Length == nextIndex ? values[0] : values[nextIndex];
}

public static T First<T>(this T src) where T : Enum
{
return GetValues(src)[0];
}

private static T[] GetValues<T>(T src) where T : Enum
private static T[] GetValues<T>(T src)
where T : Enum
{
return (T[])Enum.GetValues(src.GetType());
}
}
}
}
8 changes: 4 additions & 4 deletions ClientCore/Extensions/StringExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,16 @@ public static string GetLink(this string text)
if (string.IsNullOrWhiteSpace(text))
return null;

int index = text.IndexOf("http://", StringComparison.Ordinal);
int index = text.IndexOf($"{Uri.UriSchemeHttp}://", StringComparison.Ordinal);
if (index == -1)
index = text.IndexOf("ftp://", StringComparison.Ordinal);
index = text.IndexOf($"{Uri.UriSchemeFtp}://", StringComparison.Ordinal);
if (index == -1)
index = text.IndexOf("https://", StringComparison.Ordinal);
index = text.IndexOf($"{Uri.UriSchemeHttps}://", StringComparison.Ordinal);

if (index == -1)
return null; // No link found

string link = text.Substring(index);
string link = text[index..];
return link.Split(' ')[0]; // Nuke any words coming after the link
}
}
Expand Down
113 changes: 113 additions & 0 deletions ClientCore/Extensions/TaskExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;

namespace ClientCore.Extensions;

public static class TaskExtensions
{
/// <summary>
/// Runs a <see cref="Task"/> and guarantees all exceptions are caught and handled even when the <see cref="Task"/> is not directly awaited.
/// </summary>
/// <param name="task">The <see cref="Task"/> who's exceptions will be handled.</param>
/// <param name="continueOnCapturedContext">true to attempt to marshal the continuation back to the original context captured; otherwise, false.</param>
/// <returns>Returns a <see cref="Task"/> that awaited and handled the original <paramref name="task"/>.</returns>
public static async Task HandleTask(this Task task, bool continueOnCapturedContext = false)
{
try
{
await task.ConfigureAwait(continueOnCapturedContext);
}
catch (Exception ex)
{
ProgramConstants.HandleException(ex);
}
}

/// <summary>
/// Runs a <see cref="Task"/> and guarantees all exceptions are caught and handled even when the <see cref="Task"/> is not directly awaited.
/// </summary>
/// <typeparam name="T">The type of <paramref name="task"/>'s return value.</typeparam>
/// <param name="task">The <see cref="Task"/> who's exceptions will be handled.</param>
/// <param name="continueOnCapturedContext">true to attempt to marshal the continuation back to the original context captured; otherwise, false.</param>
/// <returns>Returns a <see cref="Task"/> that awaited and handled the original <paramref name="task"/>.</returns>
public static async Task<T> HandleTask<T>(this Task<T> task, bool continueOnCapturedContext = false)
{
try
{
return await task.ConfigureAwait(continueOnCapturedContext);
}
catch (Exception ex)
{
ProgramConstants.HandleException(ex);
}

return default;
}

/// <summary>
/// Executes a list of tasks and waits for all of them to complete and throws an <see cref="AggregateException"/> containing all exceptions from all tasks.
/// When using <see cref="Task.WhenAll(IEnumerable{Task})"/> only the first thrown exception from a single <see cref="Task"/> may be observed.
/// </summary>
/// <typeparam name="T">The type of <paramref name="tasks"/>'s return value.</typeparam>
/// <param name="tasks">The list of <see cref="Task"/>s who's exceptions will be handled.</param>
/// <param name="continueOnCapturedContext">true to attempt to marshal the continuation back to the original context captured; otherwise, false.</param>
/// <returns>Returns a <see cref="Task"/> that awaited and handled the original <paramref name="tasks"/>.</returns>
public static async Task<T[]> WhenAllSafe<T>(IEnumerable<Task<T>> tasks, bool continueOnCapturedContext = false)
{
var whenAllTask = Task.WhenAll(tasks);

try
{
return await whenAllTask.ConfigureAwait(continueOnCapturedContext);
}
catch
{
if (whenAllTask.Exception is null)
throw;

throw whenAllTask.Exception;
}
}

/// <summary>
/// Executes a list of tasks and waits for all of them to complete and throws an <see cref="AggregateException"/> containing all exceptions from all tasks.
/// When using <see cref="Task.WhenAll(IEnumerable{Task})"/> only the first thrown exception from a single <see cref="Task"/> may be observed.
/// </summary>
/// <param name="tasks">The list of <see cref="Task"/>s who's exceptions will be handled.</param>
/// <param name="continueOnCapturedContext">true to attempt to marshal the continuation back to the original context captured; otherwise, false.</param>
/// <returns>Returns a <see cref="Task"/> that awaited and handled the original <paramref name="tasks"/>.</returns>
public static async Task WhenAllSafe(IEnumerable<Task> tasks, bool continueOnCapturedContext = false)
{
var whenAllTask = Task.WhenAll(tasks);

try
{
await whenAllTask.ConfigureAwait(continueOnCapturedContext);
}
catch
{
if (whenAllTask.Exception is null)
throw;

throw whenAllTask.Exception;
}
}

/// <summary>
/// Runs a <see cref="ValueTask"/> and guarantees all exceptions are caught and handled even when the <see cref="ValueTask"/> is not directly awaited.
/// </summary>
/// <param name="task">The <see cref="ValueTask"/> who's exceptions will be handled.</param>
/// <param name="continueOnCapturedContext">true to attempt to marshal the continuation back to the original context captured; otherwise, false.</param>
public static async void HandleTask(this ValueTask task, bool continueOnCapturedContext = false)
{
try
{
await task.ConfigureAwait(continueOnCapturedContext);
}
catch (Exception ex)
{
ProgramConstants.HandleException(ex);
}
}
}
3 changes: 2 additions & 1 deletion ClientCore/INIProcessing/PreprocessorBackgroundTask.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using System.IO;
using System.Threading.Tasks;
using System.Collections.Generic;
using ClientCore.Extensions;

namespace ClientCore.INIProcessing
{
Expand Down Expand Up @@ -33,7 +34,7 @@ public static PreprocessorBackgroundTask Instance

public void Run()
{
task = Task.Factory.StartNew(CheckFiles);
task = Task.Run(CheckFiles).HandleTask();
}

private static void CheckFiles()
Expand Down
2 changes: 1 addition & 1 deletion ClientCore/ProfanityFilter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ private string ToRegexPattern(string wildcardSearch)
regexPattern = regexPattern.Replace(@"\?", ".");
if (regexPattern.StartsWith(".*?"))
{
regexPattern = regexPattern.Substring(3);
regexPattern = regexPattern[3..];
regexPattern = @"(^\b)*?" + regexPattern;
}
regexPattern = @"\b" + regexPattern + @"\b";
Expand Down
Loading