Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
94 commits
Select commit Hold shift + click to select a range
4235a2f
PD2Launcherv2: Remove bogus Services directory from the project
Slacker86 May 29, 2026
0c2128e
PD2Launcherv2: Decouple IsDisableUpdates from Messages.ConfigurationC…
Slacker86 May 29, 2026
04159a7
PD2Launcherv2: Colors: Introduce Red* set of colors and derived brush…
Slacker86 May 29, 2026
d661994
PD2Launcherv2: Views.OptionsView: Put the D2GL/3dfx note under the ri…
Slacker86 May 29, 2026
55ed7f5
PD2Launcherv2, PD2Shared: Add ForceSoftwareRenderer to LauncherOptions
Slacker86 May 29, 2026
2f6b456
PD2Shared: ILocalStorage: Introduce LoadSectionIfExists<T>()
Slacker86 May 29, 2026
95e031c
PD2Launcherv2: Get rid of PD2Launcherv2.Constants class
Slacker86 Jul 21, 2026
2f1ef81
PD2Launcherv2: Introduce Utils.MsgBox
Slacker86 May 29, 2026
0fb35b0
PD2Shared: Introduce Utils.Env
Slacker86 May 29, 2026
cb8e67e
PD2Shared: Add Serilog and its selected sinks as dependencies
Slacker86 May 29, 2026
8c48f54
PD2Shared: Introduce Constants.VersionString
Slacker86 May 29, 2026
21a282b
eqpublish.ps1: Update accordingly after introducing Constants.Version…
Slacker86 Jul 24, 2026
634b3a8
PD2Shared: Introduce Logging namespace and incorporate logging into t…
Slacker86 May 29, 2026
4529485
PD2Launcherv2: Improve unhandled exception handlers
Slacker86 May 29, 2026
870c978
PD2Launcherv2: Perform sanity checks on boot
Slacker86 May 29, 2026
fb459dc
PD2Shared: Introduce Utils.Wine
Slacker86 May 29, 2026
e68809c
PD2Shared: Make LocalStorage.Update() more robust
Slacker86 May 29, 2026
b17fc55
PD2Launcherv2: MainWindow: Hide MainFrame in the designer
Slacker86 May 29, 2026
a8dcf97
PD2Launcherv2: MainWindow: Show an indicator if running under Wine
Slacker86 May 29, 2026
244e2b2
PD2Launcherv2: MainWindow: Offer applying launcher options for Wine c…
Slacker86 May 29, 2026
d523331
PD2Shared: Utils.Wine: Add means of configuring Wine for PD2
Slacker86 May 29, 2026
8325c01
PD2Launcherv2: OptionsView: Remove dead code
Slacker86 May 29, 2026
edc0315
PD2Launcherv2: View(Model)s/OptionsView(Model): Allow applying/removi…
Slacker86 May 29, 2026
4a1f1e8
PD2Launcherv2: MainWindow: Offer applying PD2-specific Wine configura…
Slacker86 May 29, 2026
3411bd6
PD2Launcherv2, PD2Shared: Add UseHttp2 to LauncherOptions
Slacker86 May 29, 2026
4e12731
PD2Launcherv2: MainWindow: Remove an odd callback trigger in CloseBut…
Slacker86 May 29, 2026
add387c
PD2Launcherv2: Update Resources/Images/empty_button.png
Slacker86 May 29, 2026
ccbbd37
PD2Launcherv2: Resources/Images: Update image exif tags with explicit…
Slacker86 May 29, 2026
7d0abb8
PD2Launcherv2: Resources/Images: Remove bogus PhysicalPixel (PixelsPe…
Slacker86 May 29, 2026
e9741ee
PD2Launcherv2: ControlStyles: Update ImageFillProgressBarStyle visuals
Slacker86 May 29, 2026
f59f9df
PD2Launcherv2: CustomImageButton: Add DisabledImageSource
Slacker86 May 29, 2026
c059090
PD2Launcherv2: CustomControl: Introduce BlankButtonWithText
Slacker86 May 29, 2026
9d06b0b
PD2Launcherv2: ControlStyles: Introduce the PixelPerfectWindow style
Slacker86 May 29, 2026
2dd0337
PD2Launcherv2: ControlStyles: CustomImageButton: Remove any Stretch p…
Slacker86 May 29, 2026
d5026ce
PD2Launcherv2: ControlStyles: CustomVerticalScrollBar: Resize subcont…
Slacker86 May 29, 2026
fdf8da8
PD2Launcherv2: ControlStyles: ScrollBar: Resize subcontrols to their …
Slacker86 May 29, 2026
bf4411e
PD2Launcherv2: ControlStyles: CustomCheckBoxStyle, CustomRadioButtonS…
Slacker86 May 29, 2026
c3b6411
PD2Launcherv2: ControlStyles: Pick a darker color for CustomVerticalS…
Slacker86 May 29, 2026
bc81e71
PD2Shared: Add BouncyCastle.Cryptography as a dependency
Slacker86 May 29, 2026
c3bd103
PD2Shared: Introduce Extensions.GeneralDigestEx
Slacker86 May 29, 2026
15575e4
PD2Shared: Remove excessive exception handling from LaunchGameHelpers…
Slacker86 May 29, 2026
160a5b9
PD2Shared: Introduce Extensions.HttpResponseMessageEx
Slacker86 Jun 27, 2026
4e47f91
PD2Shared: Replace Helpers.GameFileUpdateHelpers with GameFileUpdate …
Slacker86 May 29, 2026
da1981b
PD2Launcherv2: Introduce Utils.ProgressWithCookie
Slacker86 Jun 17, 2026
67bc91f
PD2Launcherv2: MainWindow: Utilize ProgressWithCookie
Slacker86 Jun 17, 2026
f1ef5a5
PD2Launcherv2: MainWindow: Redo the 'Donate here' button as a BlankBu…
Slacker86 May 29, 2026
d1c2c7a
PD2Launcherv2: MainWindow: Add offline indicator
Slacker86 May 29, 2026
b728904
PD2Launcherv2: MainWindow: Toggle offline indicator in place of 'Upda…
Slacker86 May 29, 2026
77b2dfd
PD2Launcherv2: Introduce Utils.Shell
Slacker86 May 29, 2026
847f9a6
PD2Launcherv2: MainWindow: Add GoToLogButton
Slacker86 May 29, 2026
8e3bf8c
PD2Launcherv2: Add the Resources/Icons/icon.ico as a Resource and exp…
Slacker86 May 29, 2026
f38c4c8
PD2Shared: Add System.IO.Hashing as a dependency
Slacker86 May 31, 2026
e064512
PD2Shared: GameFileUpdate: Abstract out all hashing into a Hash and D…
Slacker86 May 31, 2026
a5eb341
PD2Shared: Remove now obsolete Extensions.GeneralDigestEx
Slacker86 May 31, 2026
0ef1fca
PD2Shared: GameFileUpdater: Add LogManifestStats()
Slacker86 Jun 4, 2026
3307fda
PD2Launcherv2: Rename Resources/Fonts/exocet-blizzard-heavy.otf -> .ttf
Slacker86 Jun 6, 2026
e7d62f9
PD2Launcherv2: BlankButtonWithText: Add ButtonKind
Slacker86 Jun 6, 2026
2e575c1
PD2Launcherv2: MainWindow: Revamp OptionsButton and LootButton into B…
Slacker86 Jun 6, 2026
1734ed3
PD2Launcherv2: MainWindow: Disable OptionsButton and LootButton when …
Slacker86 Jun 6, 2026
8050e42
PD2Launcherv2: Revamp sanity checks
Slacker86 Jun 19, 2026
eaea857
PD2Shared: Logging: Improve exceptions in Logging.SetUp()
Slacker86 Jun 20, 2026
94eef5f
PD2Launcherv2: MainWindow: Add a slight delay after launching the gam…
Slacker86 Jun 22, 2026
d81526b
PD2Shared: GameFileUpdater: Avoid locks in DownloadFilesAsync()
Slacker86 Jul 3, 2026
ba8159d
PD2Shared: GameFileUpdater: Avoid locks in QueryDownloadsAsync()
Slacker86 Jul 3, 2026
83363c8
PD2Shared: GameFileUpdater: Avoid locks in ValidateFilesAsync()
Slacker86 Jul 3, 2026
95cd32b
PD2Launcherv2, PD2Shared: SanityChecks: Add CheckGameDirPathEncoding()
Slacker86 Jul 5, 2026
925c34b
PD2Shared: GameFileUpdater: Improve throughput estimator in DownloadF…
Slacker86 Jul 5, 2026
27b64e8
PD2Shared, PD2Launcherv2: Update Utils.Wine slightly and log detected…
Slacker86 Jul 11, 2026
4ec13ef
PD2Launcherv2: Make Messages.LauncherOptionsChangeMessage init-only
Slacker86 Jul 9, 2026
e30c2c7
PD2Shared: Introduce Utils.Win32
Slacker86 Jun 12, 2026
35a6fd7
PD2Shared: Logging: Put the new Utils.Win32.GetLastException() routin…
Slacker86 Jul 10, 2026
f73cf75
PD2Launcherv2: OptionsView: Rename '3dfx'/'ddraw' to 'D2GL (-3dfx)'/'…
Slacker86 Aug 18, 2026
f2a4309
PD2Launcherv2: Introduce the Utils.Gl namespace
Slacker86 Jul 10, 2026
d787717
PD2Launcherv2: Sanity checks: Add a TestGlContext "non-check"
Slacker86 Jul 10, 2026
978fb4a
PD2Launcherv2: MainWindow: Prompt the user depending on GlTest.BestCt…
Slacker86 Jul 10, 2026
9ee03d8
PD2Launcherv2: Log how long it took to reach MainWindow.ContentRendered
Slacker86 Jul 12, 2026
c02c0b0
PD2Shared, PD2Launcherv2: Collect and display more Wine-related versi…
Slacker86 Jul 12, 2026
56a7855
PD2Launcherv2: MainWindow, ControlStyles: Remove Hyperlink line artif…
Slacker86 Jul 14, 2026
28709c4
PD2Launcherv2: MainWindow: Focus frames after navigation
Slacker86 Jul 14, 2026
519ee39
PD2Launcherv2: MainWindow: Remove any attempts to nullify FocusVisual…
Slacker86 Jul 14, 2026
cf96a3a
PD2Launcherv2: ControlStyles: Match CloseButtonStyle's regular Border…
Slacker86 Jul 14, 2026
daa34de
PD2Launcherv2: ControlStyles: CustomColorChangeButton: Remove border …
Slacker86 Jul 14, 2026
96a8391
PD2Launcherv2: FiltersView: Better align headings with their buttons
Slacker86 Jul 14, 2026
b3d9d8d
PD2Launcherv2: FiltersView: Shift the right-hand side buttons slightly
Slacker86 Jul 14, 2026
dac74c0
PD2Launcherv2: Views: Merge the common ControlStyles into each Resour…
Slacker86 Jul 14, 2026
36baec1
PD2Launcherv2: ControlStyles: Change all StaticResource -> DynamicRes…
Slacker86 Jul 14, 2026
84b9d9b
PD2Shared: Wine.ApplyWineConfiguration(): Also enable 'EmulateModeset'
Slacker86 Jul 14, 2026
4a2047e
PD2Launcherv2: Add 'Close after launch' checkbox to the launcher
Slacker86 Jul 15, 2026
e089ecd
PD2Shared: Add LaunchGameHelpers.IsGameRunning
Slacker86 Jul 16, 2026
4fe6ce0
PD2Launcherv2: MainWindow: Make CenterWindowOnScreen() actually work
Slacker86 Jul 16, 2026
b58b728
PD2Launcherv2: ControlStyles: Retarget PixelPerfectWindow -> PixelPer…
Slacker86 Jul 25, 2026
1b269d3
PD2Shared: LaunchGameHelpers: Start the game executable via shell
Slacker86 Aug 5, 2026
9184410
PD2Shared, PD2Launcherv2: Embed debug symbols in Release binaries
Slacker86 Aug 5, 2026
73c6a13
PD2Shared: GameFileUpdater: Only report network stalls when network s…
Slacker86 Aug 8, 2026
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
6 changes: 1 addition & 5 deletions PD2Launcherv2/App.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -10,17 +10,13 @@
<ResourceDictionary Source="Resources/Styles/ControlStyles.xaml"/>
</ResourceDictionary.MergedDictionaries>

<!-- Global Style to remove the focus visual style from all controls -->
<Style TargetType="{x:Type Control}">
<Setter Property="FocusVisualStyle" Value="{x:Null}"/>
</Style>
<conv:InverseBooleanConverter x:Key="InverseBool"/>
<conv:BooleanToVisibilityConverter x:Key="BoolToVisConverter"/>
<conv:StringToIntConverter x:Key="StringToIntConverter"/>
<local:ViewModelLocator x:Key="ViewModelLocator"/>

<!-- Font Family Resources -->
<FontFamily x:Key="BlizzHeavy">pack://application:,,,/Resources/Fonts/exocet-blizzard-heavy.otf#Exocet Blizzard OT Light Bold</FontFamily>
<FontFamily x:Key="BlizzHeavy">pack://application:,,,/Resources/Fonts/exocet-blizzard-heavy.ttf#Exocet Blizzard OT Light Bold</FontFamily>
<FontFamily x:Key="BlizzLight">pack://application:,,,/Resources/Fonts/exocet-blizzard-light.ttf#Exocet Blizzard OT Light Regular</FontFamily>
<FontFamily x:Key="BlizzMedium">pack://application:,,,/Resources/Fonts/exocet-blizzard-medium.ttf#Exocet Blizzard OT Medium Regular</FontFamily>

Expand Down
147 changes: 99 additions & 48 deletions PD2Launcherv2/App.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,13 @@
using System.Net.Http;
using System.Text;
using System.Windows;
using PD2Launcherv2.Utils;
using PD2Shared.GameFileUpdate;
using PD2Shared.Logging;
using static PD2Shared.Logging.LoggingStatic;
using PD2Shared.Utils;

[assembly: System.Runtime.CompilerServices.RuntimeCompatibilityAttribute(WrapNonExceptionThrows = true)]

namespace PD2Launcherv2
{
Expand All @@ -19,6 +26,8 @@ namespace PD2Launcherv2
/// </summary>
public partial class App : Application
{
private readonly Stopwatch _bootStopwatch = Stopwatch.StartNew();

/// <summary>
/// Holds the service provider for dependency injection.
/// </summary>
Expand Down Expand Up @@ -58,7 +67,7 @@ private static void ConfigureServices(ServiceCollection services)
services.AddSingleton<LaunchGameHelpers>();
services.AddSingleton<NewsHelpers>();
services.AddSingleton<DDrawHelpers>();
services.AddSingleton<GameFileUpdateHelpers>();
services.AddSingleton<GameFileUpdater>();
services.AddSingleton<FileUpdateHelpers>(provider =>
new FileUpdateHelpers( provider.GetRequiredService<HttpClient>()));
services.AddTransient<OptionsViewModel>();
Expand Down Expand Up @@ -98,7 +107,7 @@ protected override async void OnStartup(StartupEventArgs e)

try
{
if (Process.GetProcessesByName("Game").Any())
if (LaunchGameHelpers.IsGameRunning)
{
Debug.WriteLine("Game already running.");
return;
Expand All @@ -110,8 +119,8 @@ protected override async void OnStartup(StartupEventArgs e)
await filterHelpers.CheckAndUpdateFilterAsync(selected);
}

var launcherArgs = localStorage.LoadSection<LauncherArgs>(StorageKey.LauncherArgs);
if (!launcherArgs.disableAutoUpdate)
var launcherOptions = localStorage.LoadSection<LauncherOptions>(StorageKey.LauncherOptions);
if (!launcherOptions.DisableAutoUpdate)
{
try
{
Expand All @@ -136,23 +145,107 @@ protected override async void OnStartup(StartupEventArgs e)
return;
}

// This is a bit meh, but let's keep the convention and make this case-insensitive
var createConsole = e.Args.Any(arg => arg.Equals("--console", StringComparison.OrdinalIgnoreCase));

// This is not expected to throw
Logging.SetUp(createConsole);

if (Wine.IsRunningUnderWine)
{
if (Wine.Version != null)
{
string wineVersionStr = Wine.Version.ToString();

if (Wine.BuildId != null)
{
wineVersionStr += $" ({Wine.BuildId})";
}

if (Wine.OsName != null)
{
wineVersionStr += $" on {Wine.OsName}";

if (Wine.OsRelease != null)
{
wineVersionStr += $" {Wine.OsRelease}";
}
}

L.CallerInformation($"Running under Wine {wineVersionStr}");
}
else
{
L.CallerInformation($"Running under an undetermined Wine version");
}
}

L.CallerInformation($"Using up to {Environment.ProcessorCount} concurrent task(s)");

if (!SanityChecks.Run())
{
L.CallerInformation($"Sanity checks failed and user declined to continue.");

this.Shutdown(1);
return;
}

// Normal UI mode
base.OnStartup(e);
var mainWindow = _serviceProvider.GetService<MainWindow>();

if (mainWindow != null)
{
mainWindow.ContentRendered += MainWindow_ContentRendered;
}

mainWindow?.Show();
}

private void MainWindow_ContentRendered(object? sender, EventArgs e)
{
((MainWindow)sender!).ContentRendered -= MainWindow_ContentRendered;

L.CallerDebug($"Time till {nameof(MainWindow)} rendered: {_bootStopwatch.Elapsed}.");
}

protected override void OnExit(ExitEventArgs e)
{
Logging.ShutDown(e.ApplicationExitCode);

base.OnExit(e);
}

// Handle non-UI thread exceptions
private void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
{
LogException(e.ExceptionObject as Exception);
// Blindly cast the object to Exception thanks to RuntimeCompatibilityAttribute (https://learn.microsoft.com/en-us/dotnet/api/system.unhandledexceptioneventargs.exceptionobject#remarks)
var ex = (Exception)e.ExceptionObject;

L.Fatal(ex, "Unhandled exception");

this.Dispatcher.Invoke(() =>
{
MsgBox.Exception(ex, "Unhandled exception:");

// Unlike DispatcherUnhandledException, WER will still kick in.
// However, due to reliance on task asynchronous programming model, it is very unlikely that this handler will ever be used.
this.Shutdown(1);
});
}

// Handle UI thread exceptions
private void App_DispatcherUnhandledException(object sender, System.Windows.Threading.DispatcherUnhandledExceptionEventArgs e)
{
LogException(e.Exception);
var ex = e.Exception;

L.Fatal(ex, "Unhandled exception");
MsgBox.Exception(ex, "Unhandled exception:");

e.Handled = true; // Prevent application from crashing

// ...yet shut it down on our own terms now, knowing that we have prevented Windows Error Reporting from kicking in.
this.Shutdown(1);
}

private void CleanUpTempStorageFiles()
Expand All @@ -174,47 +267,5 @@ private void CleanUpTempStorageFiles()
}
}
}

private void LogException(Exception ex)
{
if (ex == null) return;

string logPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory);

string logFile = Path.Combine(logPath, $"pd2launcher_error__{DateTime.Now:yyyy-MM-dd_HH-mm-ss}.txt");

// Use StackTrace to get more detailed info about where the exception occurred
var stackTrace = new StackTrace(ex, true);
var frame = stackTrace.GetFrames()?.FirstOrDefault();
var method = frame?.GetMethod();
var declaringType = method?.DeclaringType;
var methodName = method?.Name;

// Prepare the log entry
var sb = new StringBuilder();
sb.AppendLine("==============================================================================");
sb.AppendLine($"Timestamp: {DateTime.Now}");
sb.AppendLine("Exception Class:");
sb.AppendLine(declaringType?.FullName ?? "N/A");
sb.AppendLine("Exception Method:");
sb.AppendLine($"{methodName ?? "N/A"}");
sb.AppendLine("Exception Message:");
sb.AppendLine(ex.Message);
sb.AppendLine("Stack Trace:");
sb.AppendLine(ex.StackTrace);

// Include inner exception details if available
if (ex.InnerException != null)
{
sb.AppendLine("Inner Exception Message:");
sb.AppendLine(ex.InnerException.Message);
sb.AppendLine("Inner Exception Stack Trace:");
sb.AppendLine(ex.InnerException.StackTrace);
}
sb.AppendLine("==============================================================================");

// Append the log entry to the file
File.AppendAllText(logFile, sb.ToString());
}
}
}
145 changes: 0 additions & 145 deletions PD2Launcherv2/Constants.cs

This file was deleted.

Loading