Add logging

saves to bloxstrap folder if installed, temp local appdata folder if not installed or uninstalling
This commit is contained in:
pizzaboxer 2023-02-13 22:05:10 +00:00
parent 72783ec391
commit a634351c9d
12 changed files with 175 additions and 66 deletions

View File

@ -30,7 +30,7 @@ namespace Bloxstrap
public static string BaseDirectory = null!; public static string BaseDirectory = null!;
public static bool ShouldSaveConfigs { get; set; } = false; public static bool ShouldSaveConfigs { get; set; } = false;
public static bool IsSetupComplete { get; set; } = true; public static bool IsSetupComplete { get; set; } = true;
public static bool IsFirstRun { get; private set; } = false; public static bool IsFirstRun { get; private set; } = true;
public static bool IsQuiet { get; private set; } = false; public static bool IsQuiet { get; private set; } = false;
public static bool IsUninstall { get; private set; } = false; public static bool IsUninstall { get; private set; } = false;
public static bool IsNoLaunch { get; private set; } = false; public static bool IsNoLaunch { get; private set; } = false;
@ -40,6 +40,8 @@ namespace Bloxstrap
public static string Version = Assembly.GetExecutingAssembly().GetName().Version!.ToString()[..^2]; public static string Version = Assembly.GetExecutingAssembly().GetName().Version!.ToString()[..^2];
// singletons
public static Logger Logger { get; private set; } = null!;
public static readonly JsonManager<Settings> Settings = new(); public static readonly JsonManager<Settings> Settings = new();
public static readonly JsonManager<State> State = new(); public static readonly JsonManager<State> State = new();
public static readonly HttpClient HttpClient = new(new HttpClientHandler { AutomaticDecompression = DecompressionMethods.All }); public static readonly HttpClient HttpClient = new(new HttpClientHandler { AutomaticDecompression = DecompressionMethods.All });
@ -55,7 +57,7 @@ namespace Bloxstrap
public static void Terminate(int code = Bootstrapper.ERROR_SUCCESS) public static void Terminate(int code = Bootstrapper.ERROR_SUCCESS)
{ {
Debug.WriteLine($"[App] Terminating with exit code {code}"); Logger.WriteLine($"[App::Terminate] Terminating with exit code {code}");
Settings.Save(); Settings.Save();
State.Save(); State.Save();
Environment.Exit(code); Environment.Exit(code);
@ -94,7 +96,6 @@ namespace Bloxstrap
if (registryKey is null) if (registryKey is null)
{ {
IsFirstRun = true;
BaseDirectory = Path.Combine(Directories.LocalAppData, ProjectName); BaseDirectory = Path.Combine(Directories.LocalAppData, ProjectName);
if (!IsQuiet) if (!IsQuiet)
@ -105,6 +106,7 @@ namespace Bloxstrap
} }
else else
{ {
IsFirstRun = false;
BaseDirectory = (string)registryKey.GetValue("InstallLocation")!; BaseDirectory = (string)registryKey.GetValue("InstallLocation")!;
registryKey.Close(); registryKey.Close();
} }
@ -115,6 +117,10 @@ namespace Bloxstrap
Directories.Initialize(BaseDirectory); Directories.Initialize(BaseDirectory);
string logdir = IsFirstRun || IsUninstall ? Path.Combine(Directories.LocalAppData, "Temp") : Path.Combine(Directories.Base, "Logs");
string timestamp = DateTime.UtcNow.ToString("yyyyMMdd'T'HHmmss'Z'");
Logger = new(Path.Combine(logdir, $"{ProjectName}_{timestamp}.log"));
// we shouldn't save settings on the first run until the first installation is finished, // we shouldn't save settings on the first run until the first installation is finished,
// just in case the user decides to cancel the install // just in case the user decides to cancel the install
if (!IsFirstRun) if (!IsFirstRun)
@ -182,16 +188,19 @@ namespace Bloxstrap
Task bootstrapperTask = Task.Run(() => bootstrapper.Run()).ContinueWith(t => Task bootstrapperTask = Task.Run(() => bootstrapper.Run()).ContinueWith(t =>
{ {
// TODO: add error logging Logger.WriteLine("[App::OnStartup] Bootstrapper task has finished");
Debug.WriteLine("[App] Bootstrapper task has finished");
if (t.Exception is null) if (t.Exception is null)
return; return;
Logger.WriteLine("[App::OnStartup] An exception occurred when running the bootstrapper");
Logger.WriteLine($"[App::OnStartup] {t.Exception}");
#if DEBUG #if DEBUG
throw t.Exception; throw t.Exception;
#else #else
dialog?.ShowError(t.Exception.ToString()); var exception = t.Exception.InnerExceptions.Count >= 1 ? t.Exception.InnerExceptions[0] : t.Exception;
dialog?.ShowError($"{exception.GetType()}: {exception.Message}");
#endif #endif
}); });

View File

@ -91,7 +91,7 @@ namespace Bloxstrap
private void SetStatus(string message) private void SetStatus(string message)
{ {
Debug.WriteLine($"[Bootstrapper] {message}"); App.Logger.WriteLine($"[Bootstrapper::SetStatus] {message}");
if (Dialog is not null) if (Dialog is not null)
Dialog.Message = message; Dialog.Message = message;
@ -99,6 +99,8 @@ namespace Bloxstrap
public async Task Run() public async Task Run()
{ {
App.Logger.WriteLine("[Bootstrapper::Run] Running bootstrapper");
if (App.IsUninstall) if (App.IsUninstall)
{ {
Uninstall(); Uninstall();
@ -142,10 +144,15 @@ namespace Bloxstrap
{ {
string currentVersion = $"{App.ProjectName} v{App.Version}"; string currentVersion = $"{App.ProjectName} v{App.Version}";
App.Logger.WriteLine($"[Bootstrapper::CheckForUpdates] Checking for {App.ProjectName} updates...");
var releaseInfo = await Utilities.GetJson<GithubRelease>($"https://api.github.com/repos/{App.ProjectRepository}/releases/latest"); var releaseInfo = await Utilities.GetJson<GithubRelease>($"https://api.github.com/repos/{App.ProjectRepository}/releases/latest");
if (releaseInfo?.Assets is null || currentVersion == releaseInfo.Name) if (releaseInfo?.Assets is null || currentVersion == releaseInfo.Name)
{
App.Logger.WriteLine($"[Bootstrapper::CheckForUpdates] No updates found");
return; return;
}
SetStatus($"Getting the latest {App.ProjectName}..."); SetStatus($"Getting the latest {App.ProjectName}...");
@ -155,7 +162,7 @@ namespace Bloxstrap
Directory.CreateDirectory(Directories.Updates); Directory.CreateDirectory(Directories.Updates);
Debug.WriteLine($"Downloading {releaseInfo.Name}..."); App.Logger.WriteLine($"[Bootstrapper::CheckForUpdates] Downloading {releaseInfo.Name}...");
if (!File.Exists(downloadLocation)) if (!File.Exists(downloadLocation))
{ {
@ -165,7 +172,7 @@ namespace Bloxstrap
await response.Content.CopyToAsync(fileStream); await response.Content.CopyToAsync(fileStream);
} }
Debug.WriteLine($"Starting {releaseInfo.Name}..."); App.Logger.WriteLine($"[Bootstrapper::CheckForUpdates] Starting {releaseInfo.Name}...");
ProcessStartInfo startInfo = new() ProcessStartInfo startInfo = new()
{ {
@ -255,8 +262,10 @@ namespace Bloxstrap
return; return;
} }
if (App.Settings.Prop.RFUEnabled && Process.GetProcessesByName("rbxfpsunlocker").Length == 0) if (App.Settings.Prop.RFUEnabled && Process.GetProcessesByName("rbxfpsunlocker").Length == 0)
{ {
App.Logger.WriteLine("[Bootstrapper::StartRoblox] Using rbxfpsunlocker");
ProcessStartInfo startInfo = new() ProcessStartInfo startInfo = new()
{ {
WorkingDirectory = Path.Combine(Directories.Integrations, "rbxfpsunlocker"), WorkingDirectory = Path.Combine(Directories.Integrations, "rbxfpsunlocker"),
@ -269,8 +278,16 @@ namespace Bloxstrap
shouldWait = true; shouldWait = true;
} }
if (App.Settings.Prop.UseDiscordRichPresence)
{
App.Logger.WriteLine("[Bootstrapper::StartRoblox] Using Discord Rich Presence");
richPresence = new DiscordRichPresence();
shouldWait = true;
}
if (App.Settings.Prop.MultiInstanceLaunching) if (App.Settings.Prop.MultiInstanceLaunching)
{ {
App.Logger.WriteLine("[Bootstrapper::StartRoblox] Creating singleton mutex");
// this might be a bit problematic since this mutex will be released when the first launched instance is closed... // this might be a bit problematic since this mutex will be released when the first launched instance is closed...
singletonMutex = new Mutex(true, "ROBLOX_singletonMutex"); singletonMutex = new Mutex(true, "ROBLOX_singletonMutex");
shouldWait = true; shouldWait = true;
@ -278,25 +295,21 @@ namespace Bloxstrap
// event fired, wait for 3 seconds then close // event fired, wait for 3 seconds then close
await Task.Delay(3000); await Task.Delay(3000);
Dialog?.CloseBootstrapper();
if (App.Settings.Prop.UseDiscordRichPresence) // keep bloxstrap open in the background if needed
{
richPresence = new DiscordRichPresence();
richPresence.MonitorGameActivity();
shouldWait = true;
}
if (!shouldWait) if (!shouldWait)
return; return;
// keep bloxstrap open in the background richPresence?.MonitorGameActivity();
Dialog?.CloseBootstrapper();
App.Logger.WriteLine("[Bootstrapper::StartRoblox] Waiting for Roblox to close");
await gameClient.WaitForExitAsync(); await gameClient.WaitForExitAsync();
richPresence?.Dispose(); richPresence?.Dispose();
if (App.Settings.Prop.RFUAutoclose && rbxFpsUnlocker is not null) if (App.Settings.Prop.RFUAutoclose)
rbxFpsUnlocker.Kill(); rbxFpsUnlocker?.Kill();
} }
public void CancelInstall() public void CancelInstall()
@ -307,6 +320,8 @@ namespace Bloxstrap
return; return;
} }
App.Logger.WriteLine("[Bootstrapper::CancelInstall] Cancelling install...");
_cancelTokenSource.Cancel(); _cancelTokenSource.Cancel();
_cancelFired = true; _cancelFired = true;
@ -320,8 +335,8 @@ namespace Bloxstrap
} }
catch (Exception e) catch (Exception e)
{ {
Debug.WriteLine("[Bootstrapper} Could not fully clean up installation!"); App.Logger.WriteLine("[Bootstrapper::CancelInstall] Could not fully clean up installation!");
Debug.WriteLine(e); App.Logger.WriteLine($"[Bootstrapper::CancelInstall] {e}");
} }
App.Terminate(ERROR_INSTALL_USEREXIT); App.Terminate(ERROR_INSTALL_USEREXIT);
@ -371,10 +386,14 @@ namespace Bloxstrap
uninstallKey.SetValue("URLInfoAbout", $"https://github.com/{App.ProjectRepository}"); uninstallKey.SetValue("URLInfoAbout", $"https://github.com/{App.ProjectRepository}");
uninstallKey.SetValue("URLUpdateInfo", $"https://github.com/{App.ProjectRepository}/releases/latest"); uninstallKey.SetValue("URLUpdateInfo", $"https://github.com/{App.ProjectRepository}/releases/latest");
uninstallKey.Close(); uninstallKey.Close();
App.Logger.WriteLine("[Bootstrapper::StartRoblox] Registered application version");
} }
public static void CheckInstall() public static void CheckInstall()
{ {
App.Logger.WriteLine("[Bootstrapper::StartRoblox] Checking install");
// check if launch uri is set to our bootstrapper // check if launch uri is set to our bootstrapper
// this doesn't go under register, so we check every launch // this doesn't go under register, so we check every launch
// just in case the stock bootstrapper changes it back // just in case the stock bootstrapper changes it back
@ -470,7 +489,7 @@ namespace Bloxstrap
} }
catch (Exception e) catch (Exception e)
{ {
Debug.WriteLine($"Could not fully uninstall! ({e})"); App.Logger.WriteLine($"Could not fully uninstall! ({e})");
} }
Dialog?.ShowSuccess($"{App.ProjectName} has succesfully uninstalled"); Dialog?.ShowSuccess($"{App.ProjectName} has succesfully uninstalled");
@ -563,7 +582,10 @@ namespace Bloxstrap
foreach (string filename in Directory.GetFiles(Directories.Downloads)) foreach (string filename in Directory.GetFiles(Directories.Downloads))
{ {
if (!_versionPackageManifest.Exists(package => filename.Contains(package.Signature))) if (!_versionPackageManifest.Exists(package => filename.Contains(package.Signature)))
{
App.Logger.WriteLine($"Deleting unused package {filename}");
File.Delete(filename); File.Delete(filename);
}
} }
string oldVersionFolder = Path.Combine(Directories.Versions, App.State.Prop.VersionGuid); string oldVersionFolder = Path.Combine(Directories.Versions, App.State.Prop.VersionGuid);
@ -716,12 +738,12 @@ namespace Bloxstrap
string calculatedMD5 = Utilities.MD5File(packageLocation); string calculatedMD5 = Utilities.MD5File(packageLocation);
if (calculatedMD5 != package.Signature) if (calculatedMD5 != package.Signature)
{ {
Debug.WriteLine($"{package.Name} is corrupted ({calculatedMD5} != {package.Signature})! Deleting and re-downloading..."); App.Logger.WriteLine($"[Bootstrapper::DownloadPackage] {package.Name} is corrupted ({calculatedMD5} != {package.Signature})! Deleting and re-downloading...");
file.Delete(); file.Delete();
} }
else else
{ {
Debug.WriteLine($"{package.Name} is already downloaded, skipping..."); App.Logger.WriteLine($"[Bootstrapper::DownloadPackage] {package.Name} is already downloaded, skipping...");
_totalDownloadedBytes += package.PackedSize; _totalDownloadedBytes += package.PackedSize;
UpdateProgressbar(); UpdateProgressbar();
return; return;
@ -732,7 +754,7 @@ namespace Bloxstrap
// let's cheat! if the stock bootstrapper already previously downloaded the file, // let's cheat! if the stock bootstrapper already previously downloaded the file,
// then we can just copy the one from there // then we can just copy the one from there
Debug.WriteLine($"Found existing version of {package.Name} ({robloxPackageLocation})! Copying to Downloads folder..."); App.Logger.WriteLine($"[Bootstrapper::DownloadPackage] Found existing version of {package.Name} ({robloxPackageLocation})! Copying to Downloads folder...");
File.Copy(robloxPackageLocation, packageLocation); File.Copy(robloxPackageLocation, packageLocation);
_totalDownloadedBytes += package.PackedSize; _totalDownloadedBytes += package.PackedSize;
UpdateProgressbar(); UpdateProgressbar();
@ -741,7 +763,7 @@ namespace Bloxstrap
if (!File.Exists(packageLocation)) if (!File.Exists(packageLocation))
{ {
Debug.WriteLine($"Downloading {package.Name} ({package.Signature})..."); App.Logger.WriteLine($"[Bootstrapper::DownloadPackage] Downloading {package.Name} ({package.Signature})...");
{ {
var response = await App.HttpClient.GetAsync(packageUrl, HttpCompletionOption.ResponseHeadersRead, _cancelTokenSource.Token); var response = await App.HttpClient.GetAsync(packageUrl, HttpCompletionOption.ResponseHeadersRead, _cancelTokenSource.Token);
@ -771,7 +793,7 @@ namespace Bloxstrap
} }
} }
Debug.WriteLine($"Finished downloading {package.Name}!"); App.Logger.WriteLine($"[Bootstrapper::DownloadPackage] Finished downloading {package.Name}!");
} }
} }
@ -784,7 +806,7 @@ namespace Bloxstrap
string packageFolder = Path.Combine(_versionFolder, PackageDirectories[package.Name]); string packageFolder = Path.Combine(_versionFolder, PackageDirectories[package.Name]);
string extractPath; string extractPath;
Debug.WriteLine($"Extracting {package.Name} to {packageFolder}..."); App.Logger.WriteLine($"[Bootstrapper::ExtractPackage] Extracting {package.Name} to {packageFolder}...");
using (ZipArchive archive = await Task.Run(() => ZipFile.OpenRead(packageLocation))) using (ZipArchive archive = await Task.Run(() => ZipFile.OpenRead(packageLocation)))
{ {
@ -798,7 +820,7 @@ namespace Bloxstrap
extractPath = Path.Combine(packageFolder, entry.FullName); extractPath = Path.Combine(packageFolder, entry.FullName);
//Debug.WriteLine($"[{package.Name}] Writing {extractPath}..."); //App.Logger.WriteLine($"[{package.Name}] Writing {extractPath}...");
string? directory = Path.GetDirectoryName(extractPath); string? directory = Path.GetDirectoryName(extractPath);
@ -811,7 +833,7 @@ namespace Bloxstrap
} }
} }
Debug.WriteLine($"Finished extracting {package.Name}"); App.Logger.WriteLine($"[Bootstrapper::ExtractPackage] Finished extracting {package.Name}");
_packagesExtracted += 1; _packagesExtracted += 1;
} }

View File

@ -7,6 +7,7 @@ namespace Bloxstrap.Helpers
{ {
// note that these are directories that aren't tethered to the basedirectory // note that these are directories that aren't tethered to the basedirectory
// so these can safely be called before initialization // so these can safely be called before initialization
public static string UserProfile => Environment.GetFolderPath(Environment.SpecialFolder.UserProfile);
public static string LocalAppData => Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData); public static string LocalAppData => Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);
public static string Desktop => Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory); public static string Desktop => Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory);
public static string StartMenu => Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.StartMenu), "Programs", App.ProjectName); public static string StartMenu => Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.StartMenu), "Programs", App.ProjectName);

View File

@ -32,12 +32,28 @@ namespace Bloxstrap.Helpers.Integrations
public DiscordRichPresence() public DiscordRichPresence()
{ {
RichPresence.OnReady += (_, e) =>
App.Logger.WriteLine($"[DiscordRichPresence::DiscordRichPresence] Received ready from user {e.User.Username} ({e.User.ID})");
RichPresence.OnPresenceUpdate += (_, e) =>
App.Logger.WriteLine("[DiscordRichPresence::DiscordRichPresence] Updated presence");
RichPresence.OnConnectionEstablished += (_, e) =>
App.Logger.WriteLine("[DiscordRichPresence::DiscordRichPresence] Established connection with Discord RPC!");
//spams log as it tries to connect every ~15 sec when discord is closed so not now
//RichPresence.OnConnectionFailed += (_, e) =>
// App.Logger.WriteLine("[DiscordRichPresence::DiscordRichPresence] Failed to establish connection with Discord RPC!");
RichPresence.OnClose += (_, e) =>
App.Logger.WriteLine($"[DiscordRichPresence::DiscordRichPresence] Lost connection to Discord RPC - {e.Reason} ({e.Code})");
RichPresence.Initialize(); RichPresence.Initialize();
} }
private async Task ExamineLogEntry(string entry) private async Task ExamineLogEntry(string entry)
{ {
Debug.WriteLine(entry); // App.Logger.WriteLine(entry);
if (entry.Contains(GameJoiningEntry) && !ActivityInGame && ActivityPlaceId == 0) if (entry.Contains(GameJoiningEntry) && !ActivityInGame && ActivityPlaceId == 0)
{ {
@ -51,7 +67,7 @@ namespace Bloxstrap.Helpers.Integrations
ActivityJobId = match.Groups[1].Value; ActivityJobId = match.Groups[1].Value;
ActivityMachineAddress = match.Groups[3].Value; ActivityMachineAddress = match.Groups[3].Value;
Debug.WriteLine($"[DiscordRichPresence] Joining Game ({ActivityPlaceId}/{ActivityJobId}/{ActivityMachineAddress})"); App.Logger.WriteLine($"[DiscordRichPresence::ExamineLogEntry] Joining Game ({ActivityPlaceId}/{ActivityJobId}/{ActivityMachineAddress})");
} }
else if (entry.Contains(GameJoinedEntry) && !ActivityInGame && ActivityPlaceId != 0) else if (entry.Contains(GameJoinedEntry) && !ActivityInGame && ActivityPlaceId != 0)
{ {
@ -60,14 +76,14 @@ namespace Bloxstrap.Helpers.Integrations
if (match.Groups.Count != 3 || match.Groups[1].Value != ActivityMachineAddress) if (match.Groups.Count != 3 || match.Groups[1].Value != ActivityMachineAddress)
return; return;
Debug.WriteLine($"[DiscordRichPresence] Joined Game ({ActivityPlaceId}/{ActivityJobId}/{ActivityMachineAddress})"); App.Logger.WriteLine($"[DiscordRichPresence::ExamineLogEntry] Joined Game ({ActivityPlaceId}/{ActivityJobId}/{ActivityMachineAddress})");
ActivityInGame = true; ActivityInGame = true;
await SetPresence(); await SetPresence();
} }
else if (entry.Contains(GameDisconnectedEntry) && ActivityInGame && ActivityPlaceId != 0) else if (entry.Contains(GameDisconnectedEntry) && ActivityInGame && ActivityPlaceId != 0)
{ {
Debug.WriteLine($"[DiscordRichPresence] Disconnected from Game ({ActivityPlaceId}/{ActivityJobId}/{ActivityMachineAddress})"); App.Logger.WriteLine($"[DiscordRichPresence::ExamineLogEntry] Disconnected from Game ({ActivityPlaceId}/{ActivityJobId}/{ActivityMachineAddress})");
ActivityInGame = false; ActivityInGame = false;
ActivityPlaceId = 0; ActivityPlaceId = 0;
@ -136,7 +152,7 @@ namespace Bloxstrap.Helpers.Integrations
} }
else else
{ {
//Debug.WriteLine(log); //App.Logger.WriteLine(log);
await ExamineLogEntry(log); await ExamineLogEntry(log);
} }
} }

View File

@ -90,7 +90,7 @@ namespace Bloxstrap.Helpers.Integrations
File.Delete(fileLocation); File.Delete(fileLocation);
} }
Debug.WriteLine("Installing/Updating rbxfpsunlocker..."); App.Logger.WriteLine("[RbxFpsUnlocker::CheckInstall] Installing/Updating rbxfpsunlocker...");
{ {
byte[] bytes = await App.HttpClient.GetByteArrayAsync(downloadUrl); byte[] bytes = await App.HttpClient.GetByteArrayAsync(downloadUrl);

View File

@ -69,7 +69,7 @@ namespace Bloxstrap.Helpers.Integrations
public static async Task DownloadConfig() public static async Task DownloadConfig()
{ {
Debug.WriteLine("[ReShade] Downloading/Upgrading config file..."); App.Logger.WriteLine("[ReShade::DownloadConfig] Downloading/Upgrading config file...");
{ {
byte[] bytes = await App.HttpClient.GetByteArrayAsync($"{BaseUrl}/config.zip"); byte[] bytes = await App.HttpClient.GetByteArrayAsync($"{BaseUrl}/config.zip");
@ -117,7 +117,7 @@ namespace Bloxstrap.Helpers.Integrations
public static void SynchronizeConfigFile() public static void SynchronizeConfigFile()
{ {
Debug.WriteLine($"[ReShade] Synchronizing configuration file..."); App.Logger.WriteLine($"[ReShade::SynchronizeConfigFile] Synchronizing configuration file...");
// yeah, this is going to be a bit of a pain // yeah, this is going to be a bit of a pain
// keep in mind the config file is going to be in two places: the mod folder and the version folder // keep in mind the config file is going to be in two places: the mod folder and the version folder
@ -134,21 +134,21 @@ namespace Bloxstrap.Helpers.Integrations
// we shouldn't be here if the mod config doesn't already exist // we shouldn't be here if the mod config doesn't already exist
if (!File.Exists(modFolderConfigPath)) if (!File.Exists(modFolderConfigPath))
{ {
Debug.WriteLine($"[ReShade] ReShade.ini in modifications folder does not exist, aborting sync"); App.Logger.WriteLine($"[ReShade::SynchronizeConfigFile] ReShade.ini in modifications folder does not exist, aborting sync");
return; return;
} }
// copy to the version folder if it doesn't already exist there // copy to the version folder if it doesn't already exist there
if (!File.Exists(versionFolderConfigPath)) if (!File.Exists(versionFolderConfigPath))
{ {
Debug.WriteLine($"[ReShade] ReShade.ini in version folder does not exist, synchronized with modifications folder"); App.Logger.WriteLine($"[ReShade::SynchronizeConfigFile] ReShade.ini in version folder does not exist, synchronized with modifications folder");
File.Copy(modFolderConfigPath, versionFolderConfigPath); File.Copy(modFolderConfigPath, versionFolderConfigPath);
} }
// if both the mod and version configs match, then we don't need to do anything // if both the mod and version configs match, then we don't need to do anything
if (Utilities.MD5File(modFolderConfigPath) == Utilities.MD5File(versionFolderConfigPath)) if (Utilities.MD5File(modFolderConfigPath) == Utilities.MD5File(versionFolderConfigPath))
{ {
Debug.WriteLine($"[ReShade] ReShade.ini in version and modifications folder match"); App.Logger.WriteLine($"[ReShade::SynchronizeConfigFile] ReShade.ini in version and modifications folder match");
return; return;
} }
@ -158,13 +158,13 @@ namespace Bloxstrap.Helpers.Integrations
if (modFolderConfigFile.LastWriteTime > versionFolderConfigFile.LastWriteTime) if (modFolderConfigFile.LastWriteTime > versionFolderConfigFile.LastWriteTime)
{ {
// overwrite version config if mod config was modified most recently // overwrite version config if mod config was modified most recently
Debug.WriteLine($"[ReShade] ReShade.ini in version folder is older, synchronized with modifications folder"); App.Logger.WriteLine($"[ReShade::SynchronizeConfigFile] ReShade.ini in version folder is older, synchronized with modifications folder");
File.Copy(modFolderConfigPath, versionFolderConfigPath, true); File.Copy(modFolderConfigPath, versionFolderConfigPath, true);
} }
else if (versionFolderConfigFile.LastWriteTime > modFolderConfigFile.LastWriteTime) else if (versionFolderConfigFile.LastWriteTime > modFolderConfigFile.LastWriteTime)
{ {
// overwrite mod config if version config was modified most recently // overwrite mod config if version config was modified most recently
Debug.WriteLine($"[ReShade] ReShade.ini in modifications folder is older, synchronized with version folder"); App.Logger.WriteLine($"[ReShade::SynchronizeConfigFile] ReShade.ini in modifications folder is older, synchronized with version folder");
File.Copy(versionFolderConfigPath, modFolderConfigPath, true); File.Copy(versionFolderConfigPath, modFolderConfigPath, true);
} }
} }
@ -177,7 +177,7 @@ namespace Bloxstrap.Helpers.Integrations
if (Directory.Exists(Path.Combine(ShadersFolder, name))) if (Directory.Exists(Path.Combine(ShadersFolder, name)))
return; return;
Debug.WriteLine($"[ReShade] Downloading shaders for {name}"); App.Logger.WriteLine($"[ReShade::DownloadShaders] Downloading shaders for {name}");
{ {
byte[] bytes = await App.HttpClient.GetByteArrayAsync(downloadUrl); byte[] bytes = await App.HttpClient.GetByteArrayAsync(downloadUrl);
@ -238,7 +238,7 @@ namespace Bloxstrap.Helpers.Integrations
public static void DeleteShaders(string name) public static void DeleteShaders(string name)
{ {
Debug.WriteLine($"[ReShade] Deleting shaders for {name}"); App.Logger.WriteLine($"[ReShade::DeleteShaders] Deleting shaders for {name}");
string shadersPath = Path.Combine(ShadersFolder, name); string shadersPath = Path.Combine(ShadersFolder, name);
string texturesPath = Path.Combine(TexturesFolder, name); string texturesPath = Path.Combine(TexturesFolder, name);
@ -276,7 +276,7 @@ namespace Bloxstrap.Helpers.Integrations
public static async Task InstallExtraviPresets() public static async Task InstallExtraviPresets()
{ {
Debug.WriteLine("[ReShade] Installing Extravi's presets..."); App.Logger.WriteLine("[ReShade::InstallExtraviPresets] Installing Extravi's presets...");
foreach (string name in ExtraviPresetsShaders) foreach (string name in ExtraviPresetsShaders)
await DownloadShaders(name); await DownloadShaders(name);
@ -303,7 +303,7 @@ namespace Bloxstrap.Helpers.Integrations
if (!Directory.Exists(PresetsFolder)) if (!Directory.Exists(PresetsFolder))
return; return;
Debug.WriteLine("[ReShade] Uninstalling Extravi's presets..."); App.Logger.WriteLine("[ReShade::UninstallExtraviPresets] Uninstalling Extravi's presets...");
FileInfo[] presets = new DirectoryInfo(PresetsFolder).GetFiles(); FileInfo[] presets = new DirectoryInfo(PresetsFolder).GetFiles();
@ -319,7 +319,7 @@ namespace Bloxstrap.Helpers.Integrations
public static async Task CheckModifications() public static async Task CheckModifications()
{ {
Debug.WriteLine("[ReShade] Checking ReShade modifications... "); App.Logger.WriteLine("[ReShade::CheckModifications] Checking ReShade modifications... ");
string injectorLocation = Path.Combine(Directories.Modifications, "dxgi.dll"); string injectorLocation = Path.Combine(Directories.Modifications, "dxgi.dll");
@ -332,7 +332,7 @@ namespace Bloxstrap.Helpers.Integrations
if (!App.Settings.Prop.UseReShade) if (!App.Settings.Prop.UseReShade)
{ {
Debug.WriteLine("[ReShade] Uninstalling ReShade..."); App.Logger.WriteLine("[ReShade::CheckModifications] Uninstalling ReShade...");
// delete any stock config files // delete any stock config files
File.Delete(injectorLocation); File.Delete(injectorLocation);
@ -380,7 +380,7 @@ namespace Bloxstrap.Helpers.Integrations
if (shouldFetchReShade) if (shouldFetchReShade)
{ {
Debug.WriteLine("[ReShade] Installing/Upgrading ReShade..."); App.Logger.WriteLine("[ReShade::CheckModifications] Installing/Upgrading ReShade...");
{ {
byte[] bytes = await App.HttpClient.GetByteArrayAsync($"{BaseUrl}/dxgi.zip"); byte[] bytes = await App.HttpClient.GetByteArrayAsync($"{BaseUrl}/dxgi.zip");

View File

@ -25,42 +25,42 @@ namespace Bloxstrap.Helpers
//if (String.IsNullOrEmpty(FileLocation)) //if (String.IsNullOrEmpty(FileLocation))
// throw new ArgumentNullException("No FileLocation has been set"); // throw new ArgumentNullException("No FileLocation has been set");
Debug.WriteLine($"[JsonManager<{typeof(T).Name}>] Loading JSON from {FileLocation}..."); App.Logger.WriteLine($"[JsonManager<{typeof(T).Name}>::Load] Loading JSON from {FileLocation}...");
try try
{ {
T? settings = JsonSerializer.Deserialize<T>(File.ReadAllText(FileLocation)); T? settings = JsonSerializer.Deserialize<T>(File.ReadAllText(FileLocation));
Prop = settings ?? throw new ArgumentNullException("Deserialization returned null"); Prop = settings ?? throw new ArgumentNullException("Deserialization returned null");
Debug.WriteLine($"[JsonManager<{typeof(T).Name}>] JSON loaded successfully!"); App.Logger.WriteLine($"[JsonManager<{typeof(T).Name}>::Load] JSON loaded successfully!");
} }
catch (Exception ex) catch (Exception ex)
{ {
Debug.WriteLine($"[JsonManager<{typeof(T).Name}>] Failed to load JSON! ({ex.Message})"); App.Logger.WriteLine($"[JsonManager<{typeof(T).Name}>::Load] Failed to load JSON! ({ex.Message})");
} }
} }
public void Save() public void Save()
{ {
Debug.WriteLine($"[JsonManager<{typeof(T).Name}>] Attempting to save JSON to {FileLocation}..."); App.Logger.WriteLine($"[JsonManager<{typeof(T).Name}>::Save] Attempting to save JSON to {FileLocation}...");
//if (!ShouldSave || String.IsNullOrEmpty(FileLocation)) //if (!ShouldSave || String.IsNullOrEmpty(FileLocation))
//{ //{
// Debug.WriteLine($"[JsonManager<{typeof(T).Name}>] Aborted save (ShouldSave set to false or FileLocation not set)"); // App.Logger.WriteLine($"[JsonManager<{typeof(T).Name}>] Aborted save (ShouldSave set to false or FileLocation not set)");
// return; // return;
//} //}
//if (!ShouldSave) //if (!ShouldSave)
if (!App.ShouldSaveConfigs) if (!App.ShouldSaveConfigs)
{ {
Debug.WriteLine($"[JsonManager<{typeof(T).Name}>] Aborted save (ShouldSave set to false)"); App.Logger.WriteLine($"[JsonManager<{typeof(T).Name}>::Save] Aborted save (ShouldSave set to false)");
return; return;
} }
string json = JsonSerializer.Serialize(Prop, new JsonSerializerOptions { WriteIndented = true }); string json = JsonSerializer.Serialize(Prop, new JsonSerializerOptions { WriteIndented = true });
File.WriteAllText(FileLocation, json); File.WriteAllText(FileLocation, json);
Debug.WriteLine($"[JsonManager<{typeof(T).Name}>] JSON saved!"); App.Logger.WriteLine($"[JsonManager<{typeof(T).Name}>::Save] JSON saved!");
} }
} }
} }

View File

@ -0,0 +1,50 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Printing;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace Bloxstrap.Helpers
{
// https://stackoverflow.com/a/53873141/11852173
public class Logger
{
private readonly SemaphoreSlim _semaphore = new(1, 1);
private readonly FileStream _filestream;
public Logger(string filename)
{
string? directory = Path.GetDirectoryName(filename);
if (directory is not null)
Directory.CreateDirectory(directory);
_filestream = File.Open(filename, FileMode.Create, FileAccess.Write, FileShare.Read);
WriteLine($"[Logger::Logger] {App.ProjectName} v{App.Version} - Initialized at {filename}");
}
public async void WriteLine(string message)
{
string timestamp = DateTime.UtcNow.ToString("yyyy-MM-dd'T'HH:mm:ss'Z'");
string conout = $"{timestamp} {message}";
byte[] fileout = Encoding.Unicode.GetBytes($"{conout.Replace(Directories.UserProfile, "<UserProfileFolder>")}\r\n");
Debug.WriteLine(conout);
try
{
await _semaphore.WaitAsync();
await _filestream.WriteAsync(fileout);
await _filestream.FlushAsync();
}
finally
{
_semaphore.Release();
}
}
}
}

View File

@ -61,7 +61,10 @@ namespace Bloxstrap.Helpers
); );
if (result == MessageBoxResult.Yes) if (result == MessageBoxResult.Yes)
{
App.Logger.WriteLine($"[Protocol::ParseUri] Changed Roblox build channel from {App.Settings.Prop.Channel} to {val}");
App.Settings.Prop.Channel = val; App.Settings.Prop.Channel = val;
}
} }
// we'll set the arg when launching // we'll set the arg when launching
@ -106,7 +109,7 @@ namespace Bloxstrap.Helpers
} }
catch (Exception e) catch (Exception e)
{ {
Debug.WriteLine($"Failed to unregister {key}: {e}"); App.Logger.WriteLine($"[Protocol::Unregister] Failed to unregister {key}: {e}");
} }
} }
} }

View File

@ -5,7 +5,7 @@
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:ui="http://schemas.lepo.co/wpfui/2022/xaml" xmlns:ui="http://schemas.lepo.co/wpfui/2022/xaml"
mc:Ignorable="d" mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800" d:DesignHeight="700" d:DesignWidth="800"
Title="AboutPage" Title="AboutPage"
Scrollable="True"> Scrollable="True">
@ -18,7 +18,7 @@
<Border Grid.Column="0" Width="60" Height="60" VerticalAlignment="Center"> <Border Grid.Column="0" Width="60" Height="60" VerticalAlignment="Center">
<Border.Background> <Border.Background>
<ImageBrush ImageSource="pack://application:,,,/Resources/IconBloxstrap-png.png" /> <ImageBrush ImageSource="pack://application:,,,/Bloxstrap.ico" />
</Border.Background> </Border.Background>
</Border> </Border>
<StackPanel Grid.Column="1" Margin="12,0,0,0" VerticalAlignment="Center"> <StackPanel Grid.Column="1" Margin="12,0,0,0" VerticalAlignment="Center">

View File

@ -11,7 +11,7 @@
Scrollable="True"> Scrollable="True">
<StackPanel Margin="0,0,14,14"> <StackPanel Margin="0,0,14,14">
<TextBlock Text="Configure how Bloxstrap should function and look." FontSize="14" Foreground="{DynamicResource TextFillColorSecondaryBrush}" /> <TextBlock Text="Configure how Bloxstrap should behave and look." FontSize="14" Foreground="{DynamicResource TextFillColorSecondaryBrush}" />
<TextBlock Text="Behaviour" FontSize="16" FontWeight="Medium" Margin="0,16,0,0" /> <TextBlock Text="Behaviour" FontSize="16" FontWeight="Medium" Margin="0,16,0,0" />
<ui:CardControl Margin="0,8,0,0"> <ui:CardControl Margin="0,8,0,0">

View File

@ -33,10 +33,18 @@
<TextBlock Grid.Row="2" Grid.Column="0" Margin="0,0,16,8" FontSize="14" FontWeight="Medium" Text="Take Screenshot" /> <TextBlock Grid.Row="2" Grid.Column="0" Margin="0,0,16,8" FontSize="14" FontWeight="Medium" Text="Take Screenshot" />
<TextBlock Grid.Row="2" Grid.Column="1" Margin="0,0,0,8" VerticalAlignment="Bottom" Text="Print Screen" Foreground="{DynamicResource TextFillColorTertiaryBrush}" /> <TextBlock Grid.Row="2" Grid.Column="1" Margin="0,0,0,8" VerticalAlignment="Bottom" Text="Print Screen" Foreground="{DynamicResource TextFillColorTertiaryBrush}" />
<TextBlock Grid.Row="0" Grid.Column="2" Grid.RowSpan="3" Margin="32,0,0,0" TextWrapping="Wrap" Text="If you're using a laptop keyboard, you may have to hold down the Fn key when pressing F6. Any screenshots you take are saved to your pictures folder." Foreground="{DynamicResource TextFillColorSecondaryBrush}" /> <TextBlock Grid.Row="0" Grid.Column="2" Grid.RowSpan="3" Margin="32,0,0,0" TextWrapping="Wrap" Foreground="{DynamicResource TextFillColorSecondaryBrush}">
If you're using a laptop keyboard, you may have to hold down the Fn key when pressing F6.
<LineBreak />
<LineBreak />
Any screenshots you take are saved to your pictures folder.
</TextBlock>
</Grid> </Grid>
<TextBlock Text="Adding your own shaders and presets" FontSize="16" FontWeight="Medium" Margin="0,16,0,0" /> <TextBlock Text="Selecting a preset" FontSize="16" FontWeight="Medium" Margin="0,16,0,0" />
<TextBlock Margin="0,8,0,0" TextWrapping="Wrap" Text="Presets are how ReShade is configured to use shaders and textures. To select a preset, open the menu with Shift + Tab, and select the dropdown beneath the tabs to show all available presets to pick from. If you don't have any available, you can either use Extravi's ReShade presets in the Integrations menu, or add your own as detailed below." Foreground="{DynamicResource TextFillColorSecondaryBrush}" />
<TextBlock Text="Adding your own presets and shaders" FontSize="16" FontWeight="Medium" Margin="0,16,0,0" />
<TextBlock Margin="0,8,0,0" TextWrapping="Wrap" Text="While Bloxstrap provides Extravi's ReShade presets as a great way to enhance Roblox's graphics, it also provides the ability to install custom shaders and presets." Foreground="{DynamicResource TextFillColorSecondaryBrush}" /> <TextBlock Margin="0,8,0,0" TextWrapping="Wrap" Text="While Bloxstrap provides Extravi's ReShade presets as a great way to enhance Roblox's graphics, it also provides the ability to install custom shaders and presets." Foreground="{DynamicResource TextFillColorSecondaryBrush}" />
<TextBlock Margin="0,8,0,0" TextWrapping="Wrap" Text="To install custom presets, just extract the necessary .ini files to the ReShade Presets folder. Though, you may also need to add additional shaders and textures." Foreground="{DynamicResource TextFillColorSecondaryBrush}" /> <TextBlock Margin="0,8,0,0" TextWrapping="Wrap" Text="To install custom presets, just extract the necessary .ini files to the ReShade Presets folder. Though, you may also need to add additional shaders and textures." Foreground="{DynamicResource TextFillColorSecondaryBrush}" />
<TextBlock Margin="0,8,0,0" TextWrapping="Wrap" Text="To install shaders (known as effects), extract the necessary files to the ReShade Shaders folder. The same goes for textures, where you extract them to the ReShade Textures folder. You could alternatively extract them to organized subfolders like how Bloxstrap does them, though you'll have to configure ReShade to look in those folders." Foreground="{DynamicResource TextFillColorSecondaryBrush}" /> <TextBlock Margin="0,8,0,0" TextWrapping="Wrap" Text="To install shaders (known as effects), extract the necessary files to the ReShade Shaders folder. The same goes for textures, where you extract them to the ReShade Textures folder. You could alternatively extract them to organized subfolders like how Bloxstrap does them, though you'll have to configure ReShade to look in those folders." Foreground="{DynamicResource TextFillColorSecondaryBrush}" />