Skip to content

Commit

Permalink
Make network servers configurable
Browse files Browse the repository at this point in the history
  • Loading branch information
SadPencil committed Mar 14, 2024
1 parent 0f4e4dd commit 4115094
Show file tree
Hide file tree
Showing 11 changed files with 216 additions and 62 deletions.
42 changes: 40 additions & 2 deletions ClientCore/ClientConfiguration.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,14 @@ public class ClientConfiguration
private const string CLIENT_SETTINGS = "DTACnCNetClient.ini";
private const string GAME_OPTIONS = "GameOptions.ini";
private const string CLIENT_DEFS = "ClientDefinitions.ini";
private const string NETWORK_DEFS = "NetworkDefinitions.ini";

private static ClientConfiguration _instance;

private IniFile gameOptions_ini;
private IniFile DTACnCNetClient_ini;
private IniFile clientDefinitionsIni;
private IniFile networkDefinitionIni;

protected ClientConfiguration()
{
Expand All @@ -36,14 +38,16 @@ protected ClientConfiguration()

FileInfo clientDefinitionsFile = SafePath.GetFile(baseResourceDirectory.FullName, CLIENT_DEFS);

if (clientDefinitionsFile is null)
if (!(clientDefinitionsFile?.Exists ?? false))
throw new FileNotFoundException($"Couldn't find {CLIENT_DEFS} at {baseResourceDirectory}. Please verify that you're running the client from the correct directory.");

clientDefinitionsIni = new IniFile(clientDefinitionsFile.FullName);

DTACnCNetClient_ini = new IniFile(SafePath.CombineFilePath(ProgramConstants.GetResourcePath(), CLIENT_SETTINGS));

gameOptions_ini = new IniFile(SafePath.CombineFilePath(baseResourceDirectory.FullName, GAME_OPTIONS));

networkDefinitionIni = new IniFile(SafePath.CombineFilePath(ProgramConstants.GetResourcePath(), NETWORK_DEFS));
}

/// <summary>
Expand Down Expand Up @@ -99,7 +103,7 @@ public void RefreshSettings()

public string AltUIBackgroundColor => DTACnCNetClient_ini.GetStringValue(GENERAL, "AltUIBackgroundColor", "196,196,196");

public string WindowBorderColor => DTACnCNetClient_ini.GetStringValue(GENERAL, "WindowBorderColor", "128,128,128");
public string WindowBorderColor => DTACnCNetClient_ini.GetStringValue(GENERAL, "WindowBorderColor", "128,128,128");

public string PanelBorderColor => DTACnCNetClient_ini.GetStringValue(GENERAL, "PanelBorderColor", "255,255,255");

Expand Down Expand Up @@ -385,6 +389,40 @@ public IEnumerable<string> SupplementalMapFileExtensions

#endregion

#region Network definitions

public string CnCNetTunnelListURL => networkDefinitionIni.GetStringValue(SETTINGS, "CnCNetTunnelListURL", "http://cncnet.org/master-list");

public string CnCNetPlayerCountURL => networkDefinitionIni.GetStringValue(SETTINGS, "CnCNetPlayerCountURL", "http://api.cncnet.org/status");

public string CnCNetMapDBDownloadURL => networkDefinitionIni.GetStringValue(SETTINGS, "CnCNetMapDBDownloadURL", "http://mapdb.cncnet.org");

public string CnCNetMapDBUploadURL => networkDefinitionIni.GetStringValue(SETTINGS, "CnCNetMapDBUploadURL", "http://mapdb.cncnet.org/upload");

public bool DisableDiscordIntegration => networkDefinitionIni.GetBooleanValue(SETTINGS, "DisableDiscordIntegration", false);

public List<string> IRCServers => GetIRCServers();

#endregion

public List<string> GetIRCServers()
{
List<string> servers = [];

IniSection serversSection = networkDefinitionIni.GetSection("IRCServers");
if (serversSection != null)
foreach ((_, string value) in serversSection.Keys)
if (!string.IsNullOrWhiteSpace(value))
servers.Add(value);

return servers;
}

public bool IsDiscordIntegrationGloballyDisabled()
{
return string.IsNullOrWhiteSpace(DiscordAppId) || DisableDiscordIntegration;
}

public OSVersion GetOperatingSystemVersion()
{
#if NETFRAMEWORK
Expand Down
6 changes: 3 additions & 3 deletions DTAConfig/OptionPanels/CnCNetOptionsPanel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ private void InitOptions()
chkConnectOnStartup.Bottom + 12, 0, 0);
chkDiscordIntegration.Text = "Show detailed game info in Discord status".L10N("Client:DTAConfig:DiscordStatus");

if (String.IsNullOrEmpty(ClientConfiguration.Instance.DiscordAppId))
if (ClientConfiguration.Instance.IsDiscordIntegrationGloballyDisabled())
{
chkDiscordIntegration.AllowChecking = false;
chkDiscordIntegration.Checked = false;
Expand Down Expand Up @@ -317,7 +317,7 @@ public override void Load()
chkSkipLoginWindow.Checked = IniSettings.SkipConnectDialog;
chkPersistentMode.Checked = IniSettings.PersistentMode;

chkDiscordIntegration.Checked = !String.IsNullOrEmpty(ClientConfiguration.Instance.DiscordAppId)
chkDiscordIntegration.Checked = !ClientConfiguration.Instance.IsDiscordIntegrationGloballyDisabled()
&& IniSettings.DiscordIntegration;

chkAllowGameInvitesFromFriendsOnly.Checked = IniSettings.AllowGameInvitesFromFriendsOnly;
Expand Down Expand Up @@ -352,7 +352,7 @@ public override bool Save()
IniSettings.SkipConnectDialog.Value = chkSkipLoginWindow.Checked;
IniSettings.PersistentMode.Value = chkPersistentMode.Checked;

if (!String.IsNullOrEmpty(ClientConfiguration.Instance.DiscordAppId))
if (!ClientConfiguration.Instance.IsDiscordIntegrationGloballyDisabled())
{
IniSettings.DiscordIntegration.Value = chkDiscordIntegration.Checked;
}
Expand Down
2 changes: 1 addition & 1 deletion DXMainClient/DXGUI/Generic/MainMenu.cs
Original file line number Diff line number Diff line change
Expand Up @@ -410,7 +410,7 @@ private void SettingsSaved(object sender, EventArgs e)
if (!connectionManager.IsConnected)
ProgramConstants.PLAYERNAME = UserINISettings.Instance.PlayerName;

if (UserINISettings.Instance.DiscordIntegration)
if (UserINISettings.Instance.DiscordIntegration && !ClientConfiguration.Instance.IsDiscordIntegrationGloballyDisabled())
discordHandler.Connect();
else
discordHandler.Disconnect();
Expand Down
2 changes: 1 addition & 1 deletion DXMainClient/Domain/DiscordHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ public RichPresence CurrentPresence
/// </summary>
public DiscordHandler()
{
if (!UserINISettings.Instance.DiscordIntegration || string.IsNullOrEmpty(ClientConfiguration.Instance.DiscordAppId))
if (!UserINISettings.Instance.DiscordIntegration || ClientConfiguration.Instance.IsDiscordIntegrationGloballyDisabled())
return;

InitializeClient();
Expand Down
4 changes: 3 additions & 1 deletion DXMainClient/Domain/MainClientConstants.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ namespace DTAClient.Domain
{
public static class MainClientConstants
{
public const string CNCNET_TUNNEL_LIST_URL = "http://cncnet.org/master-list";
public static string CNCNET_TUNNEL_LIST_URL = "http://cncnet.org/master-list";

public static string GAME_NAME_LONG = "CnCNet Client";
public static string GAME_NAME_SHORT = "CnCNet";
Expand Down Expand Up @@ -92,6 +92,8 @@ public static void Initialize()

CREDITS_URL = clientConfiguration.CreditsURL;

CNCNET_TUNNEL_LIST_URL = clientConfiguration.CnCNetTunnelListURL;

USE_ISOMETRIC_CELLS = clientConfiguration.UseIsometricCells;
TDRA_WAYPOINT_COEFFICIENT = clientConfiguration.WaypointCoefficient;
MAP_CELL_SIZE_X = clientConfiguration.MapCellSizeX;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,10 +50,15 @@ private static int GetCnCNetPlayerCount()
{
try
{
// Don't fetch the player count if it is explicitly disabled
// For example, the official CnCNet server might be unavailable/unstable in a country with Internet censorship,
// which causes lags in the splash screen. In the worst case, say if packets are dropped, it waits until timeouts --- 30 seconds
if (string.IsNullOrWhiteSpace(ClientConfiguration.Instance.CnCNetPlayerCountURL))
return -1;

WebClient client = new WebClient();

Check warning on line 59 in DXMainClient/Domain/Multiplayer/CnCNet/CnCNetPlayerCountTask.cs

View workflow job for this annotation

GitHub Actions / build-clients (Ares)

'WebClient.WebClient()' is obsolete: 'WebRequest, HttpWebRequest, ServicePoint, and WebClient are obsolete. Use HttpClient instead.' (https://aka.ms/dotnet-warnings/SYSLIB0014)

Check warning on line 59 in DXMainClient/Domain/Multiplayer/CnCNet/CnCNetPlayerCountTask.cs

View workflow job for this annotation

GitHub Actions / build-clients (TS)

'WebClient.WebClient()' is obsolete: 'WebRequest, HttpWebRequest, ServicePoint, and WebClient are obsolete. Use HttpClient instead.' (https://aka.ms/dotnet-warnings/SYSLIB0014)
Stream data = client.OpenRead(ClientConfiguration.Instance.CnCNetPlayerCountURL);

Stream data = client.OpenRead("http://api.cncnet.org/status");

string info = string.Empty;

using (StreamReader reader = new StreamReader(data))
Expand Down
26 changes: 20 additions & 6 deletions DXMainClient/Domain/Multiplayer/CnCNet/MapSharer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,6 @@ public static class MapSharer

private static readonly object locker = new object();

private const string MAPDB_URL = "http://mapdb.cncnet.org/upload";

/// <summary>
/// Adds a map into the CnCNet map upload queue.
/// </summary>
Expand Down Expand Up @@ -78,8 +76,14 @@ private static void Upload(object mapAndGame)

Logger.Log("MapSharer: Starting upload of " + map.BaseFilePath);

bool success = false;
string message = MapUpload(MAPDB_URL, map, myGameId, out success);
if (string.IsNullOrWhiteSpace(ClientConfiguration.Instance.CnCNetMapDBUploadURL))
{
Logger.Log("MapSharer: Upload URL is not set.");
MapUploadFailed?.Invoke(null, new MapEventArgs(map));
return;
}

string message = MapUpload(ClientConfiguration.Instance.CnCNetMapDBUploadURL, map, myGameId, out bool success);

if (success)
{
Expand Down Expand Up @@ -380,12 +384,21 @@ private static string DownloadMain(string sha1, string myGame, string mapName, o

using (TWebClient webClient = new TWebClient())
{
// TODO enable proxy support for some users
webClient.Proxy = null;

if (string.IsNullOrWhiteSpace(ClientConfiguration.Instance.CnCNetMapDBDownloadURL))
{
success = false;
return "MapSharer: Download URL is not set.";
}

string url = string.Format(CultureInfo.InvariantCulture, "{0}/{1}/{2}.zip", ClientConfiguration.Instance.CnCNetMapDBDownloadURL, myGame, sha1);

try
{
Logger.Log("MapSharer: Downloading URL: " + "http://mapdb.cncnet.org/" + myGame + "/" + sha1 + ".zip");
webClient.DownloadFile("http://mapdb.cncnet.org/" + myGame + "/" + sha1 + ".zip", destinationFile.FullName);
Logger.Log($"MapSharer: Downloading URL: {url}");
webClient.DownloadFile(url, destinationFile.FullName);
}
catch (Exception ex)
{
Expand Down Expand Up @@ -449,6 +462,7 @@ class TWebClient : WebClient

public TWebClient()

Check warning on line 463 in DXMainClient/Domain/Multiplayer/CnCNet/MapSharer.cs

View workflow job for this annotation

GitHub Actions / build-clients (TS)

'WebClient.WebClient()' is obsolete: 'WebRequest, HttpWebRequest, ServicePoint, and WebClient are obsolete. Use HttpClient instead.' (https://aka.ms/dotnet-warnings/SYSLIB0014)

Check warning on line 463 in DXMainClient/Domain/Multiplayer/CnCNet/MapSharer.cs

View workflow job for this annotation

GitHub Actions / build-clients (YR)

'WebClient.WebClient()' is obsolete: 'WebRequest, HttpWebRequest, ServicePoint, and WebClient are obsolete. Use HttpClient instead.' (https://aka.ms/dotnet-warnings/SYSLIB0014)
{
// TODO enable proxy support for some users
this.Proxy = null;
}

Expand Down
87 changes: 59 additions & 28 deletions DXMainClient/Domain/Multiplayer/CnCNet/TunnelHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -143,48 +143,78 @@ private Task PingCurrentTunnelAsync(bool checkTunnelList = false)
});
}

/// <summary>
/// Downloads and parses the list of CnCNet tunnels.
/// </summary>
/// <returns>A list of tunnel servers.</returns>
private List<CnCNetTunnel> RefreshTunnels()
{
FileInfo tunnelCacheFile = SafePath.GetFile(ProgramConstants.ClientUserFilesPath, "tunnel_cache");

List<CnCNetTunnel> returnValue = new List<CnCNetTunnel>();
private bool IsOnlineTunnelDataAvailable() => !string.IsNullOrWhiteSpace(MainClientConstants.CNCNET_TUNNEL_LIST_URL);
private bool IsOfflineTunnelDataAvailable() => SafePath.GetFile(ProgramConstants.ClientUserFilesPath, "tunnel_cache").Exists;

private byte[] GetRawTunnelDataOnline()
{
WebClient client = new WebClient();

Check warning on line 151 in DXMainClient/Domain/Multiplayer/CnCNet/TunnelHandler.cs

View workflow job for this annotation

GitHub Actions / build-clients (Ares)

'WebClient.WebClient()' is obsolete: 'WebRequest, HttpWebRequest, ServicePoint, and WebClient are obsolete. Use HttpClient instead.' (https://aka.ms/dotnet-warnings/SYSLIB0014)

Check warning on line 151 in DXMainClient/Domain/Multiplayer/CnCNet/TunnelHandler.cs

View workflow job for this annotation

GitHub Actions / build-clients (TS)

'WebClient.WebClient()' is obsolete: 'WebRequest, HttpWebRequest, ServicePoint, and WebClient are obsolete. Use HttpClient instead.' (https://aka.ms/dotnet-warnings/SYSLIB0014)

Check warning on line 151 in DXMainClient/Domain/Multiplayer/CnCNet/TunnelHandler.cs

View workflow job for this annotation

GitHub Actions / build-clients (YR)

'WebClient.WebClient()' is obsolete: 'WebRequest, HttpWebRequest, ServicePoint, and WebClient are obsolete. Use HttpClient instead.' (https://aka.ms/dotnet-warnings/SYSLIB0014)
return client.DownloadData(MainClientConstants.CNCNET_TUNNEL_LIST_URL);
}

byte[] data;
private byte[] GetRawTunnelDataOffline()
{
FileInfo tunnelCacheFile = SafePath.GetFile(ProgramConstants.ClientUserFilesPath, "tunnel_cache");
return File.ReadAllBytes(tunnelCacheFile.FullName);
}

private byte[] GetRawTunnelData(int retryCount = 2)
{
Logger.Log("Fetching tunnel server info.");

try
{
data = client.DownloadData(MainClientConstants.CNCNET_TUNNEL_LIST_URL);
}
catch (Exception ex)
if (IsOnlineTunnelDataAvailable())
{
Logger.Log("Error when downloading tunnel server info: " + ex.ToString());
Logger.Log("Retrying.");
try
for (int i = 0; i < retryCount; i++)
{
data = client.DownloadData(MainClientConstants.CNCNET_TUNNEL_LIST_URL);
}
catch
{
if (!tunnelCacheFile.Exists)
try
{
Logger.Log("Tunnel cache file doesn't exist!");
return returnValue;
byte[] data = GetRawTunnelDataOnline();
return data;
}
else
catch (Exception ex)
{
Logger.Log("Fetching tunnel server list failed. Using cached tunnel data.");
data = File.ReadAllBytes(tunnelCacheFile.FullName);
Logger.Log("Error when downloading tunnel server info: " + ex.Message);
if (i < retryCount - 1)
Logger.Log("Retrying.");
else
Logger.Log("Fetching tunnel server list failed.");
}
}
}
else
{
// Don't fetch the latest tunnel list if it is explicitly disabled
// For example, the official CnCNet server might be unavailable/unstable in a country with Internet censorship,
// where players might either establish a substitute server or manually distribute the tunnel cache file
Logger.Log("Fetching tunnel server list online is disabled.");
}

if (IsOfflineTunnelDataAvailable())
{
Logger.Log("Using cached tunnel data.");
byte[] data = GetRawTunnelDataOffline();
return data;
}
else
Logger.Log("Tunnel cache file doesn't exist!");

return null;
}


/// <summary>
/// Downloads and parses the list of CnCNet tunnels.
/// </summary>
/// <returns>A list of tunnel servers.</returns>
private List<CnCNetTunnel> RefreshTunnels()
{
List<CnCNetTunnel> returnValue = new List<CnCNetTunnel>();

FileInfo tunnelCacheFile = SafePath.GetFile(ProgramConstants.ClientUserFilesPath, "tunnel_cache");

byte[] data = GetRawTunnelData();
if (data is null)
return returnValue;

string convertedData = Encoding.Default.GetString(data);

Expand Down Expand Up @@ -234,6 +264,7 @@ private List<CnCNetTunnel> RefreshTunnels()
}
}

Logger.Log($"Successfully refreshed tunnel cache with {returnValue.Count} servers.");
return returnValue;
}

Expand Down
Loading

0 comments on commit 4115094

Please sign in to comment.