diff --git a/Bloxstrap/Bootstrapper.cs b/Bloxstrap/Bootstrapper.cs index 92f5a87b..e36c378d 100644 --- a/Bloxstrap/Bootstrapper.cs +++ b/Bloxstrap/Bootstrapper.cs @@ -16,19 +16,6 @@ namespace Bloxstrap public partial class Bootstrapper { #region Properties - private string? LaunchCommandLine; - - private string VersionGuid; - private PackageManifest VersionPackageManifest; - private string VersionFolder; - - private readonly bool FreshInstall; - - private int ProgressIncrement; - private bool CancelFired = false; - - private static readonly HttpClient Client = new(); - // in case a new package is added, you can find the corresponding directory // by opening the stock bootstrapper in a hex editor // TODO - there ideally should be a less static way to do this that's not hardcoded? @@ -79,8 +66,18 @@ public partial class Bootstrapper "By default, two mod presets are provided for restoring the old death\n" + "sound and the old mouse cursor.\n"; - // TODO: reduce reliance on event handlers for signalling property changes to the bootstrapper dialog - // i mean, chances are we can just use IBootstrapperDialog now? + private static readonly HttpClient Client = new(); + + private string? LaunchCommandLine; + + private string VersionGuid; + private PackageManifest VersionPackageManifest; + private string VersionFolder; + + private readonly bool FreshInstall; + + private int ProgressIncrement; + private bool CancelFired = false; public IBootstrapperDialog Dialog; #endregion @@ -498,7 +495,7 @@ private void ApplyModifications() string relativeFile = file.Substring(modFolder.Length + 1); // ignore files placed in the root directory - if (!relativeFile.Contains(@"\")) + if (!relativeFile.Contains('\\')) continue; modFolderFiles.Add(relativeFile); @@ -554,7 +551,7 @@ private void ApplyModifications() File.WriteAllLines(manifestFile, modFolderFiles); } - private void CheckModPreset(bool condition, string location, string base64Contents) + private static void CheckModPreset(bool condition, string location, string base64Contents) { string modFolderLocation = Path.Combine(Directories.Modifications, location); diff --git a/Bloxstrap/Dialogs/BootstrapperStyles/BootstrapperStyleForm.cs b/Bloxstrap/Dialogs/BootstrapperStyles/BootstrapperStyleForm.cs index 71a4c346..a4a88cf8 100644 --- a/Bloxstrap/Dialogs/BootstrapperStyles/BootstrapperStyleForm.cs +++ b/Bloxstrap/Dialogs/BootstrapperStyles/BootstrapperStyleForm.cs @@ -7,7 +7,7 @@ public class BootstrapperStyleForm : Form, IBootstrapperDialog { public Bootstrapper? Bootstrapper { get; set; } - protected virtual string _message { get; set; } + protected virtual string _message { get; set; } = "Please wait..."; protected virtual ProgressBarStyle _progressStyle { get; set; } protected virtual int _progressValue { get; set; } protected virtual bool _cancelEnabled { get; set; } @@ -18,7 +18,7 @@ public string Message set { if (this.InvokeRequired) - this.Invoke(new Action(() => { Message = value; })); + this.Invoke(new Action(() => { _message = value; })); else _message = value; } @@ -30,7 +30,7 @@ public ProgressBarStyle ProgressStyle set { if (this.InvokeRequired) - this.Invoke(new Action(() => { ProgressStyle = value; })); + this.Invoke(new Action(() => { _progressStyle = value; })); else _progressStyle = value; } @@ -42,7 +42,7 @@ public int ProgressValue set { if (this.InvokeRequired) - this.Invoke(new Action(() => { ProgressValue = value; })); + this.Invoke(new Action(() => { _progressValue = value; })); else _progressValue = value; } @@ -54,7 +54,7 @@ public bool CancelEnabled set { if (this.InvokeRequired) - this.Invoke(new Action(() => { CancelEnabled = value; })); + this.Invoke(new Action(() => { _cancelEnabled = value; })); else _cancelEnabled = value; } diff --git a/Bloxstrap/Dialogs/Preferences.cs b/Bloxstrap/Dialogs/Preferences.cs index 139e11bb..e011066f 100644 --- a/Bloxstrap/Dialogs/Preferences.cs +++ b/Bloxstrap/Dialogs/Preferences.cs @@ -37,7 +37,7 @@ public partial class Preferences : Form private BootstrapperStyle SelectedStyle { - get => (BootstrapperStyle)_selectedStyle; + get => _selectedStyle ?? BootstrapperStyle.ProgressDialog; set { @@ -53,7 +53,7 @@ private BootstrapperStyle SelectedStyle private BootstrapperIcon SelectedIcon { - get => (BootstrapperIcon)_selectedIcon; + get => _selectedIcon ?? BootstrapperIcon.IconBloxstrap; set { diff --git a/Bloxstrap/Helpers/Integrations/DiscordRichPresence.cs b/Bloxstrap/Helpers/Integrations/DiscordRichPresence.cs index 32dc3006..172db0b4 100644 --- a/Bloxstrap/Helpers/Integrations/DiscordRichPresence.cs +++ b/Bloxstrap/Helpers/Integrations/DiscordRichPresence.cs @@ -1,4 +1,4 @@ -using Newtonsoft.Json.Linq; +using Bloxstrap.Models; using DiscordRPC; namespace Bloxstrap.Helpers.Integrations @@ -9,22 +9,19 @@ internal class DiscordRichPresence : IDisposable public async Task SetPresence(string placeId) { - string placeName; string placeThumbnail; - string creatorName; - // null checking could probably be a lot more concrete here - JObject placeInfo = await Utilities.GetJson($"https://economy.roblox.com/v2/assets/{placeId}/details"); + var placeInfo = await Utilities.GetJson($"https://economy.roblox.com/v2/assets/{placeId}/details"); - placeName = placeInfo["Name"].Value(); - creatorName = placeInfo["Creator"]["Name"].Value(); - - JObject thumbnailInfo = await Utilities.GetJson($"https://thumbnails.roblox.com/v1/places/gameicons?placeIds={placeId}&returnPolicy=PlaceHolder&size=512x512&format=Png&isCircular=false"); - - if (thumbnailInfo["data"] is null) + if (placeInfo is null || placeInfo.Creator is null) return false; - placeThumbnail = thumbnailInfo["data"][0]["imageUrl"].Value(); + var thumbnailInfo = await Utilities.GetJson($"https://thumbnails.roblox.com/v1/places/gameicons?placeIds={placeId}&returnPolicy=PlaceHolder&size=512x512&format=Png&isCircular=false"); + + if (thumbnailInfo is null) + placeThumbnail = "roblox"; //fallback + else + placeThumbnail = thumbnailInfo.Data[0].ImageUrl; DiscordRPC.Button[]? buttons = null; @@ -50,14 +47,14 @@ public async Task SetPresence(string placeId) RichPresence.SetPresence(new RichPresence() { - Details = placeName, - State = $"by {creatorName}", + Details = placeInfo.Name, + State = $"by {placeInfo.Creator.Name}", Timestamps = new Timestamps() { Start = DateTime.UtcNow }, Buttons = buttons, Assets = new Assets() { LargeImageKey = placeThumbnail, - LargeImageText = placeName, + LargeImageText = placeInfo.Name, SmallImageKey = "roblox", SmallImageText = "Roblox" } diff --git a/Bloxstrap/Helpers/Integrations/RbxFpsUnlocker.cs b/Bloxstrap/Helpers/Integrations/RbxFpsUnlocker.cs index 4d481817..db3baac4 100644 --- a/Bloxstrap/Helpers/Integrations/RbxFpsUnlocker.cs +++ b/Bloxstrap/Helpers/Integrations/RbxFpsUnlocker.cs @@ -5,6 +5,8 @@ using Newtonsoft.Json.Linq; +using Bloxstrap.Models; + namespace Bloxstrap.Helpers.Integrations { internal class RbxFpsUnlocker @@ -35,9 +37,7 @@ public static async Task CheckInstall() if (!Program.Settings.RFUEnabled) { if (Directory.Exists(folderLocation)) - { Directory.Delete(folderLocation, true); - } return; } @@ -45,20 +45,13 @@ public static async Task CheckInstall() DateTime lastReleasePublish; string downloadUrl; - try - { - JObject releaseInfo = await Utilities.GetJson($"https://api.github.com/repos/{ProjectRepository}/releases/latest"); + var releaseInfo = await Utilities.GetJson($"https://api.github.com/repos/{ProjectRepository}/releases/latest"); - // so... rbxfpsunlocker does not actually have any version info for the executable - // meaning the best way we can check for a new version is comparing time last download to time last release published - lastReleasePublish = DateTime.Parse(releaseInfo["created_at"].Value()); - downloadUrl = releaseInfo["assets"][0]["browser_download_url"].Value(); - } - catch (Exception ex) - { - Debug.WriteLine($"Failed to fetch latest version info! ({ex.Message})"); + if (releaseInfo is null || releaseInfo.CreatedAt is null || releaseInfo.Assets is null) return; - } + + lastReleasePublish = DateTime.Parse(releaseInfo.CreatedAt); + downloadUrl = releaseInfo.Assets[0].BrowserDownloadUrl; Directory.CreateDirectory(folderLocation); @@ -79,9 +72,9 @@ public static async Task CheckInstall() { byte[] bytes = await client.GetByteArrayAsync(downloadUrl); - using (MemoryStream zipStream = new MemoryStream(bytes)) + using (MemoryStream zipStream = new(bytes)) { - ZipArchive zip = new ZipArchive(zipStream); + ZipArchive zip = new(zipStream); zip.ExtractToDirectory(folderLocation, true); } } diff --git a/Bloxstrap/Helpers/RSMM/Package.cs b/Bloxstrap/Helpers/RSMM/Package.cs index 9df66c06..bb254b7e 100644 --- a/Bloxstrap/Helpers/RSMM/Package.cs +++ b/Bloxstrap/Helpers/RSMM/Package.cs @@ -4,16 +4,11 @@ namespace Bloxstrap.Helpers.RSMM { internal class Package { - public string Name { get; set; } - public string Signature { get; set; } + public string Name { get; set; } = ""; + public string Signature { get; set; } = ""; public int PackedSize { get; set; } public int Size { get; set; } - public bool Exists { get; set; } - public bool ShouldInstall { get; set; } - - internal byte[] Data { get; set; } - public override string ToString() { return $"[{Signature}] {Name}"; diff --git a/Bloxstrap/Helpers/Updater.cs b/Bloxstrap/Helpers/Updater.cs index 2327fac7..2569bc62 100644 --- a/Bloxstrap/Helpers/Updater.cs +++ b/Bloxstrap/Helpers/Updater.cs @@ -1,8 +1,12 @@ using System.Diagnostics; using System.IO; +using System.Net.Http; +using System.Text.Json; using Newtonsoft.Json.Linq; +using Bloxstrap.Models; + namespace Bloxstrap.Helpers { public class Updater @@ -52,20 +56,13 @@ public static async Task Check() string latestVersion; string releaseNotes; - // get the latest version according to the latest github release info - // it should contain the latest product version, which we can check against - try - { - JObject releaseInfo = await Utilities.GetJson($"https://api.github.com/repos/{Program.ProjectRepository}/releases/latest"); + var releaseInfo = await Utilities.GetJson($"https://api.github.com/repos/{Program.ProjectRepository}/releases/latest"); - latestVersion = releaseInfo["name"].Value(); - releaseNotes = releaseInfo["body"].Value(); - } - catch (Exception ex) - { - Debug.WriteLine($"Failed to fetch latest version info! ({ex.Message})"); + if (releaseInfo is null || releaseInfo.Name is null || releaseInfo.Body is null) return; - } + + latestVersion = releaseInfo.Name; + releaseNotes = releaseInfo.Body; if (currentVersion != latestVersion) { diff --git a/Bloxstrap/Helpers/Utilities.cs b/Bloxstrap/Helpers/Utilities.cs index 12360d08..022136fd 100644 --- a/Bloxstrap/Helpers/Utilities.cs +++ b/Bloxstrap/Helpers/Utilities.cs @@ -2,9 +2,7 @@ using System.IO; using System.Net.Http; using System.Security.Cryptography; - -using Newtonsoft.Json; -using Newtonsoft.Json.Linq; +using System.Text.Json; namespace Bloxstrap.Helpers { @@ -15,16 +13,16 @@ public static void OpenWebsite(string website) Process.Start(new ProcessStartInfo { FileName = website, UseShellExecute = true }); } - public static async Task GetJson(string url) - { - using (HttpClient client = new()) - { - client.DefaultRequestHeaders.Add("User-Agent", Program.ProjectRepository); + public static async Task GetJson(string url) + { + using (HttpClient client = new()) + { + client.DefaultRequestHeaders.Add("User-Agent", Program.ProjectRepository); - string jsonString = await client.GetStringAsync(url); - return (JObject)JsonConvert.DeserializeObject(jsonString); - } - } + string json = await client.GetStringAsync(url); + return JsonSerializer.Deserialize(json); + } + } public static string MD5File(string filename) { @@ -47,7 +45,7 @@ public static string MD5File(string filename) string substr = subject.Substring(subject.LastIndexOf(key) + key.Length); - if (substr.IndexOf(delimiter) == -1) + if (!substr.Contains(delimiter)) return null; return substr.Split(delimiter)[0]; diff --git a/Bloxstrap/Models/GithubRelease.cs b/Bloxstrap/Models/GithubRelease.cs new file mode 100644 index 00000000..475e168f --- /dev/null +++ b/Bloxstrap/Models/GithubRelease.cs @@ -0,0 +1,25 @@ +using System.Text.Json.Serialization; + +namespace Bloxstrap.Models +{ + public class GithubRelease + { + [JsonPropertyName("name")] + public string? Name { get; set; } + + [JsonPropertyName("body")] + public string? Body { get; set; } + + [JsonPropertyName("created_at")] + public string? CreatedAt { get; set; } + + [JsonPropertyName("assets")] + public List? Assets { get; set; } + } + + public class GithubReleaseAsset + { + [JsonPropertyName("browser_download_url")] + public string? BrowserDownloadUrl { get; set; } + } +} diff --git a/Bloxstrap/Models/RobloxAsset.cs b/Bloxstrap/Models/RobloxAsset.cs new file mode 100644 index 00000000..8c4415c5 --- /dev/null +++ b/Bloxstrap/Models/RobloxAsset.cs @@ -0,0 +1,13 @@ +namespace Bloxstrap.Models +{ + public class RobloxAsset + { + public string? Name { get; set; } + public RobloxAssetCreator? Creator { get; set; } + } + + public class RobloxAssetCreator + { + public string? Name { get; set; } + } +} diff --git a/Bloxstrap/Models/RobloxThumbnails.cs b/Bloxstrap/Models/RobloxThumbnails.cs new file mode 100644 index 00000000..45e642ae --- /dev/null +++ b/Bloxstrap/Models/RobloxThumbnails.cs @@ -0,0 +1,16 @@ +using System.Text.Json.Serialization; + +namespace Bloxstrap.Models +{ + public class RobloxThumbnails + { + [JsonPropertyName("data")] + public List? Data { get; set; } + } + + public class RobloxThumbnail + { + [JsonPropertyName("imageUrl")] + public string? ImageUrl { get; set; } + } +} diff --git a/Bloxstrap/Models/SettingsFormat.cs b/Bloxstrap/Models/SettingsFormat.cs new file mode 100644 index 00000000..1960505a --- /dev/null +++ b/Bloxstrap/Models/SettingsFormat.cs @@ -0,0 +1,25 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Bloxstrap.Enums; + +namespace Bloxstrap.Models +{ + public class SettingsFormat + { + public string VersionGuid { get; set; } = ""; + + public bool CheckForUpdates { get; set; } = true; + + public BootstrapperStyle BootstrapperStyle { get; set; } = BootstrapperStyle.ProgressDialog; + public BootstrapperIcon BootstrapperIcon { get; set; } = BootstrapperIcon.IconBloxstrap; + + public bool UseDiscordRichPresence { get; set; } = true; + public bool HideRPCButtons { get; set; } = false; + public bool RFUEnabled { get; set; } = false; + public bool RFUAutoclose { get; set; } = false; + + public bool UseOldDeathSound { get; set; } = true; + public bool UseOldMouseCursor { get; set; } = false; + } +} diff --git a/Bloxstrap/Program.cs b/Bloxstrap/Program.cs index 401f681d..4cdad024 100644 --- a/Bloxstrap/Program.cs +++ b/Bloxstrap/Program.cs @@ -2,7 +2,9 @@ using System.IO; using Microsoft.Win32; + using Bloxstrap.Helpers; +using Bloxstrap.Models; namespace Bloxstrap { @@ -27,8 +29,9 @@ internal static class Program public static string LocalAppData { get; private set; } = ""; public static string StartMenu { get; private set; } = ""; - public static SettingsFormat Settings; public static SettingsManager SettingsManager = new(); + public static SettingsFormat Settings = SettingsManager.Settings; + public static void ShowMessageBox(MessageBoxIcon icon, string message) { diff --git a/Bloxstrap/Settings.cs b/Bloxstrap/SettingsManager.cs similarity index 66% rename from Bloxstrap/Settings.cs rename to Bloxstrap/SettingsManager.cs index fff91bc0..022a5982 100644 --- a/Bloxstrap/Settings.cs +++ b/Bloxstrap/SettingsManager.cs @@ -2,36 +2,18 @@ using System.IO; using System.Text.Json; -using Bloxstrap.Enums; +using Bloxstrap.Models; namespace Bloxstrap { - public class SettingsFormat - { - public string VersionGuid { get; set; } - - public bool CheckForUpdates { get; set; } = true; - - public BootstrapperStyle BootstrapperStyle { get; set; } = BootstrapperStyle.ProgressDialog; - public BootstrapperIcon BootstrapperIcon { get; set; } = BootstrapperIcon.IconBloxstrap; - - public bool UseDiscordRichPresence { get; set; } = true; - public bool HideRPCButtons { get; set; } = false; - public bool RFUEnabled { get; set; } = false; - public bool RFUAutoclose { get; set; } = false; - - public bool UseOldDeathSound { get; set; } = true; - public bool UseOldMouseCursor { get; set; } = false; - } - public class SettingsManager { public SettingsFormat Settings = new(); public bool ShouldSave = false; private bool IsSaving = false; - private string _saveLocation; - public string SaveLocation + private string? _saveLocation; + public string? SaveLocation { get => _saveLocation; @@ -51,7 +33,12 @@ public string SaveLocation try { - Settings = JsonSerializer.Deserialize(settingsJson); + var settings = JsonSerializer.Deserialize(settingsJson); + + if (settings is null) + throw new Exception("Deserialization returned null"); + + Settings = settings; } catch (Exception ex) { @@ -79,7 +66,7 @@ public void Save() string SettingsJson = JsonSerializer.Serialize(Settings, new JsonSerializerOptions { WriteIndented = true }); Debug.WriteLine(SettingsJson); - if (!ShouldSave) + if (!ShouldSave || SaveLocation is null) { Debug.WriteLine("ShouldSave set to false, not saving..."); return;