Skip to content

Commit 14cd841

Browse files
authored
Merge pull request #591 from CnCNet/develop
Release 2.11.2.0
2 parents e62a850 + b47495f commit 14cd841

File tree

770 files changed

+76398
-13344
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

770 files changed

+76398
-13344
lines changed

ClientCore/ClientConfiguration.cs

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ public class ClientConfiguration
1616
private const string SETTINGS = "Settings";
1717
private const string LINKS = "Links";
1818
private const string TRANSLATIONS = "Translations";
19+
private const string USER_DEFAULTS = "UserDefaults";
1920

2021
private const string CLIENT_SETTINGS = "DTACnCNetClient.ini";
2122
private const string GAME_OPTIONS = "GameOptions.ini";
@@ -193,7 +194,8 @@ public void RefreshSettings()
193194

194195
public int MaximumRenderHeight => clientDefinitionsIni.GetIntValue(SETTINGS, "MaximumRenderHeight", 800);
195196

196-
public string[] RecommendedResolutions => clientDefinitionsIni.GetStringValue(SETTINGS, "RecommendedResolutions", "1280x720,2560x1440,3840x2160").Split(',');
197+
public string[] RecommendedResolutions => clientDefinitionsIni.GetStringValue(SETTINGS, "RecommendedResolutions",
198+
$"{MinimumRenderWidth}x{MinimumRenderHeight},{MaximumRenderWidth}x{MaximumRenderHeight}").Split(',');
197199

198200
public string WindowTitle => clientDefinitionsIni.GetStringValue(SETTINGS, "WindowTitle", string.Empty)
199201
.L10N("INI:ClientDefinitions:WindowTitle");
@@ -387,6 +389,11 @@ public IEnumerable<string> SupplementalMapFileExtensions
387389
/// </summary>
388390
public bool DisallowJoiningIncompatibleGames => clientDefinitionsIni.GetBooleanValue(SETTINGS, nameof(DisallowJoiningIncompatibleGames), false);
389391

392+
/// <summary>
393+
/// Activates warnings for development builds of XNA Client
394+
/// </summary>
395+
public bool ShowDevelopmentBuildWarnings => clientDefinitionsIni.GetBooleanValue(SETTINGS, nameof(ShowDevelopmentBuildWarnings), true);
396+
390397
#endregion
391398

392399
#region Network definitions
@@ -405,6 +412,16 @@ public IEnumerable<string> SupplementalMapFileExtensions
405412

406413
#endregion
407414

415+
#region User default settings
416+
417+
public bool UserDefault_BorderlessWindowedClient => clientDefinitionsIni.GetBooleanValue(USER_DEFAULTS, "BorderlessWindowedClient", true);
418+
419+
public bool UserDefault_IntegerScaledClient => clientDefinitionsIni.GetBooleanValue(USER_DEFAULTS, "IntegerScaledClient", false);
420+
421+
public bool UserDefault_WriteInstallationPathToRegistry => clientDefinitionsIni.GetBooleanValue(USER_DEFAULTS, "WriteInstallationPathToRegistry", true);
422+
423+
#endregion
424+
408425
public List<string> GetIRCServers()
409426
{
410427
List<string> servers = [];
@@ -419,7 +436,7 @@ public List<string> GetIRCServers()
419436
}
420437

421438
public bool DiscordIntegrationGloballyDisabled => string.IsNullOrWhiteSpace(DiscordAppId) || DisableDiscordIntegration;
422-
439+
423440
public OSVersion GetOperatingSystemVersion()
424441
{
425442
#if NETFRAMEWORK

ClientCore/CnCNet5/GameCollection.cs

Lines changed: 14 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
using System.Reflection;
77
using Rampastring.Tools;
88
using SixLabors.ImageSharp;
9+
using ClientCore.Extensions;
910

1011
namespace ClientCore.CnCNet5
1112
{
@@ -65,7 +66,7 @@ public void Initialize()
6566
GameBroadcastChannel = "#cncnet-dta-games",
6667
InternalName = "dta",
6768
RegistryInstallPath = "HKCU\\Software\\TheDawnOfTheTiberiumAge",
68-
UIName = "Dawn of the Tiberium Age",
69+
UIName = "Dawn of the Tiberium Age".L10N("Client:Core:DawnoftheTiberiumAge"),
6970
Texture = AssetLoader.TextureFromImage(dtaIcon)
7071
},
7172

@@ -76,7 +77,7 @@ public void Initialize()
7677
GameBroadcastChannel = "#cncnet-ti-games",
7778
InternalName = "ti",
7879
RegistryInstallPath = "HKCU\\Software\\TwistedInsurrection",
79-
UIName = "Twisted Insurrection",
80+
UIName = "Twisted Insurrection".L10N("Client:Core:TwistedInsurrection"),
8081
Texture = AssetLoader.TextureFromImage(tiIcon)
8182
},
8283

@@ -87,7 +88,7 @@ public void Initialize()
8788
GameBroadcastChannel = "#cncnet-mo-games",
8889
InternalName = "mo",
8990
RegistryInstallPath = "HKCU\\Software\\MentalOmega",
90-
UIName = "Mental Omega",
91+
UIName = "Mental Omega".L10N("Client:Core:MentalOmega"),
9192
Texture = AssetLoader.TextureFromImage(moIcon)
9293
},
9394

@@ -98,7 +99,7 @@ public void Initialize()
9899
GameBroadcastChannel = "#redres-games",
99100
InternalName = "rr",
100101
RegistryInstallPath = "HKLM\\Software\\RedResurrection",
101-
UIName = "YR Red-Resurrection",
102+
UIName = "YR Red-Resurrection".L10N("Client:Core:YRRedResurrection"),
102103
Texture = AssetLoader.TextureFromImage(rrIcon)
103104
},
104105

@@ -109,7 +110,7 @@ public void Initialize()
109110
GameBroadcastChannel = "#rote-games",
110111
InternalName = "re",
111112
RegistryInstallPath = "HKLM\\Software\\RiseoftheEast",
112-
UIName = "Rise of the East",
113+
UIName = "Rise of the East".L10N("Client:Core:RiseoftheEast"),
113114
Texture = AssetLoader.TextureFromImage(reIcon)
114115
},
115116

@@ -120,7 +121,7 @@ public void Initialize()
120121
GameBroadcastChannel = "#cncreloaded-games",
121122
InternalName = "cncr",
122123
RegistryInstallPath = "HKCU\\Software\\CnCReloaded",
123-
UIName = "C&C: Reloaded",
124+
UIName = "C&C: Reloaded".L10N("Client:Core:CnCReloaded"),
124125
Texture = AssetLoader.TextureFromImage(cncrIcon)
125126
},
126127

@@ -131,7 +132,7 @@ public void Initialize()
131132
GameBroadcastChannel = "#cncnet-td-games",
132133
InternalName = "td",
133134
RegistryInstallPath = "HKLM\\Software\\Westwood\\Tiberian Dawn",
134-
UIName = "Tiberian Dawn",
135+
UIName = "Tiberian Dawn".L10N("Client:Core:TiberianDawn"),
135136
Texture = AssetLoader.TextureFromImage(tdIcon),
136137
Supported = false
137138
},
@@ -143,7 +144,7 @@ public void Initialize()
143144
GameBroadcastChannel = "#cncnet-ra-games",
144145
InternalName = "ra",
145146
RegistryInstallPath = "HKLM\\Software\\Westwood\\Red Alert",
146-
UIName = "Red Alert",
147+
UIName = "Red Alert".L10N("Client:Core:RedAlert"),
147148
Texture = AssetLoader.TextureFromImage(raIcon),
148149
Supported = false
149150
},
@@ -155,7 +156,7 @@ public void Initialize()
155156
GameBroadcastChannel = "#cncnet-d2k-games",
156157
InternalName = "d2k",
157158
RegistryInstallPath = "HKLM\\Software\\Westwood\\Dune 2000",
158-
UIName = "Dune 2000",
159+
UIName = "Dune 2000".L10N("Client:Core:Dune2000"),
159160
Texture = AssetLoader.TextureFromImage(d2kIcon),
160161
Supported = false
161162
},
@@ -167,7 +168,7 @@ public void Initialize()
167168
GameBroadcastChannel = "#cncnet-ts-games",
168169
InternalName = "ts",
169170
RegistryInstallPath = "HKLM\\Software\\Westwood\\Tiberian Sun",
170-
UIName = "Tiberian Sun",
171+
UIName = "Tiberian Sun".L10N("Client:Core:TiberianSun"),
171172
Texture = AssetLoader.TextureFromImage(tsIcon)
172173
},
173174

@@ -178,7 +179,7 @@ public void Initialize()
178179
GameBroadcastChannel = "#cncnet-yr-games",
179180
InternalName = "yr",
180181
RegistryInstallPath = "HKLM\\Software\\Westwood\\Yuri's Revenge",
181-
UIName = "Yuri's Revenge",
182+
UIName = "Yuri's Revenge".L10N("Client:Core:YurisRevenge"),
182183
Texture = AssetLoader.TextureFromImage(yrIcon)
183184
},
184185

@@ -189,7 +190,7 @@ public void Initialize()
189190
GameBroadcastChannel = "#cncnet-ss-games",
190191
InternalName = "ss",
191192
RegistryInstallPath = "HKLM\\Software\\Westwood\\Sole Survivor",
192-
UIName = "Sole Survivor",
193+
UIName = "Sole Survivor".L10N("Client:Core:SoleSurvivor"),
193194
Texture = AssetLoader.TextureFromImage(ssIcon),
194195
Supported = false
195196
}
@@ -202,7 +203,7 @@ public void Initialize()
202203
{
203204
ChatChannel = "#cncnet",
204205
InternalName = "cncnet",
205-
UIName = "General CnCNet Chat",
206+
UIName = "General CnCNet Chat".L10N("Client:Core:GeneralCnCNetChat"),
206207
AlwaysEnabled = true,
207208
Texture = AssetLoader.TextureFromImage(cncnetIcon)
208209
}

ClientCore/FileHelper.cs

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.IO;
4+
using System.Linq;
5+
using System.Runtime.InteropServices;
6+
using System.Runtime.Versioning;
7+
using System.Text;
8+
using System.Threading.Tasks;
9+
10+
using ClientCore.Extensions;
11+
12+
using Rampastring.Tools;
13+
14+
namespace ClientCore
15+
{
16+
public class FileHelper
17+
{
18+
19+
/// <summary>
20+
/// Establishes a hard link between an existing file and a new file. This function is only supported on the NTFS file system, and only for files, not directories.
21+
/// <br/>
22+
/// https://learn.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-createhardlinkw
23+
/// </summary>
24+
/// <param name="lpFileName">The name of the new file.</param>
25+
/// <param name="lpExistingFileName">The name of the existing file.</param>
26+
/// <param name="lpSecurityAttributes">Reserved; must be NULL.</param>
27+
/// <returns>If the function succeeds, the return value is nonzero. If the function fails, the return value is zero (0).</returns>
28+
[DllImport("Kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode, EntryPoint = "CreateHardLinkW")]
29+
[DefaultDllImportSearchPaths(DllImportSearchPath.System32)]
30+
[SupportedOSPlatform("windows")]
31+
private static extern bool CreateHardLink(string lpFileName, string lpExistingFileName, IntPtr lpSecurityAttributes);
32+
33+
/// <summary>
34+
/// The link function makes a new link to the existing file named by oldname, under the new name newname.
35+
/// <br/>
36+
/// https://www.gnu.org/software/libc/manual/html_node/Hard-Links.html
37+
/// <param name="oldname"></param>
38+
/// <param name="newname"></param>
39+
/// <returns>This function returns a value of 0 if it is successful and -1 on failure.</returns>
40+
[DllImport("libc", EntryPoint = "link", SetLastError = true)]
41+
[SupportedOSPlatform("linux")]
42+
[SupportedOSPlatform("osx")]
43+
private static extern int link([MarshalAs(UnmanagedType.LPUTF8Str)] string oldname, [MarshalAs(UnmanagedType.LPUTF8Str)] string newname);
44+
45+
/// <summary>
46+
/// Creates hard link to the source file or copy that file, if got an error.
47+
/// </summary>
48+
/// <param name="source"></param>
49+
/// <param name="destination"></param>
50+
/// <param name="fallback"></param>
51+
/// <exception cref="IOException"></exception>
52+
/// <exception cref="PlatformNotSupportedException"></exception>
53+
public static void CreateHardLinkFromSource(string source, string destination, bool fallback = true)
54+
{
55+
if (fallback)
56+
{
57+
try
58+
{
59+
CreateHardLinkFromSource(source, destination, fallback: false);
60+
}
61+
catch (Exception ex)
62+
{
63+
Logger.Log($"Failed to create hard link at {destination}. Fallback to copy. {ex.Message}");
64+
File.Copy(source, destination, true);
65+
}
66+
67+
return;
68+
}
69+
70+
if (File.Exists(destination))
71+
{
72+
FileInfo destinationFile = new(destination);
73+
destinationFile.IsReadOnly = false;
74+
destinationFile.Delete();
75+
}
76+
77+
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
78+
{
79+
if (!CreateHardLink(destination, source, IntPtr.Zero))
80+
Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error());
81+
}
82+
else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux) || RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
83+
{
84+
if (link(source, destination) != 0)
85+
throw new IOException(string.Format("Unable to create hard link at {0} with the following error code: {1}"
86+
.L10N("Client:DTAConfig:CreateHardLinkFailed"), destination, Marshal.GetLastWin32Error()));
87+
}
88+
else
89+
{
90+
throw new PlatformNotSupportedException();
91+
}
92+
}
93+
}
94+
}

ClientCore/Settings/UserINISettings.cs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,8 @@ protected UserINISettings(IniFile iniFile)
6363
Renderer = new StringSetting(iniFile, COMPATIBILITY, "Renderer", string.Empty);
6464
WindowedMode = new BoolSetting(iniFile, VIDEO, WINDOWED_MODE_KEY, false);
6565
BorderlessWindowedMode = new BoolSetting(iniFile, VIDEO, "NoWindowFrame", false);
66-
BorderlessWindowedClient = new BoolSetting(iniFile, VIDEO, "BorderlessWindowedClient", true);
66+
BorderlessWindowedClient = new BoolSetting(iniFile, VIDEO, "BorderlessWindowedClient", ClientConfiguration.Instance.UserDefault_BorderlessWindowedClient);
67+
IntegerScaledClient = new BoolSetting(iniFile, VIDEO, "IntegerScaledClient", ClientConfiguration.Instance.UserDefault_IntegerScaledClient);
6768
ClientFPS = new IntSetting(iniFile, VIDEO, "ClientFPS", 60);
6869
DisplayToggleableExtraTextures = new BoolSetting(iniFile, VIDEO, "DisplayToggleableExtraTextures", true);
6970

@@ -86,7 +87,7 @@ protected UserINISettings(IniFile iniFile)
8687
ChatColor = new IntSetting(iniFile, MULTIPLAYER, "ChatColor", -1);
8788
LANChatColor = new IntSetting(iniFile, MULTIPLAYER, "LANChatColor", -1);
8889
PingUnofficialCnCNetTunnels = new BoolSetting(iniFile, MULTIPLAYER, "PingCustomTunnels", true);
89-
WritePathToRegistry = new BoolSetting(iniFile, OPTIONS, "WriteInstallationPathToRegistry", true);
90+
WritePathToRegistry = new BoolSetting(iniFile, OPTIONS, "WriteInstallationPathToRegistry", ClientConfiguration.Instance.UserDefault_WriteInstallationPathToRegistry);
9091
PlaySoundOnGameHosted = new BoolSetting(iniFile, MULTIPLAYER, "PlaySoundOnGameHosted", true);
9192
SkipConnectDialog = new BoolSetting(iniFile, MULTIPLAYER, "SkipConnectDialog", false);
9293
PersistentMode = new BoolSetting(iniFile, MULTIPLAYER, "PersistentMode", false);
@@ -151,6 +152,7 @@ protected UserINISettings(IniFile iniFile)
151152
public IntSetting ClientResolutionX { get; set; }
152153
public IntSetting ClientResolutionY { get; set; }
153154
public BoolSetting BorderlessWindowedClient { get; private set; }
155+
public BoolSetting IntegerScaledClient { get; private set; }
154156
public IntSetting ClientFPS { get; private set; }
155157
public BoolSetting DisplayToggleableExtraTextures { get; private set; }
156158

ClientGUI/XNAClientToggleButton.cs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using System;
22
using Microsoft.Xna.Framework.Graphics;
3+
using Rampastring.Tools;
34
using Rampastring.XNAUI;
45
using Rampastring.XNAUI.XNAControls;
56

@@ -66,5 +67,26 @@ public void SetToolTipText(string text)
6667
public XNAClientToggleButton(WindowManager windowManager) : base(windowManager)
6768
{
6869
}
70+
71+
protected override void ParseControlINIAttribute(IniFile iniFile, string key, string value)
72+
{
73+
switch (key)
74+
{
75+
case nameof(CheckedTexture):
76+
CheckedTexture = AssetLoader.LoadTexture(value);
77+
UpdateIdleTexture();
78+
break;
79+
case nameof(UncheckedTexture):
80+
UncheckedTexture = AssetLoader.LoadTexture(value);
81+
UpdateIdleTexture();
82+
break;
83+
case nameof(ToolTip):
84+
SetToolTipText(value);
85+
break;
86+
default:
87+
base.ParseControlINIAttribute(iniFile, key, value);
88+
break;
89+
}
90+
}
6991
}
7092
}

ClientUpdater/Updater.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -410,7 +410,7 @@ internal static void UpdateUserAgent(HttpClient httpClient)
410410
if (UpdaterVersion != "N/A")
411411
httpClient.DefaultRequestHeaders.UserAgent.Add(new(nameof(Updater), UpdaterVersion));
412412

413-
httpClient.DefaultRequestHeaders.UserAgent.Add(new("Client", Assembly.GetEntryAssembly().GetName().Version.ToString()));
413+
httpClient.DefaultRequestHeaders.UserAgent.Add(new("Client", GitVersionInformation.AssemblySemVer));
414414
}
415415

416416
/// <summary>

DTAConfig/DirectDrawWrapper.cs

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -163,12 +163,20 @@ public bool IsCompatibleWithOS(OSVersion os)
163163
/// </summary>
164164
public void Apply()
165165
{
166+
string ddrawDllSourcePath = SafePath.CombineFilePath(ProgramConstants.GetBaseResourcePath(), ddrawDLLPath);
167+
string ddrawDllTargetPath = SafePath.CombineFilePath(ProgramConstants.GamePath, "ddraw.dll");
168+
166169
if (!string.IsNullOrEmpty(ddrawDLLPath))
167170
{
168-
File.Copy(SafePath.CombineFilePath(ProgramConstants.GetBaseResourcePath(), ddrawDLLPath), SafePath.CombineFilePath(ProgramConstants.GamePath, "ddraw.dll"), true);
171+
FileHelper.CreateHardLinkFromSource(ddrawDllSourcePath, ddrawDllTargetPath);
172+
new FileInfo(ddrawDllSourcePath).IsReadOnly = true;
173+
new FileInfo(ddrawDllTargetPath).IsReadOnly = true;
169174
}
170175
else
171-
File.Delete(SafePath.CombineFilePath(ProgramConstants.GamePath, "ddraw.dll"));
176+
{
177+
new FileInfo(ddrawDllTargetPath).IsReadOnly = false;
178+
File.Delete(ddrawDllTargetPath);
179+
}
172180

173181

174182
if (!string.IsNullOrEmpty(ConfigFileName) && !string.IsNullOrEmpty(resConfigFileName)

0 commit comments

Comments
 (0)