mirror of
https://github.com/bloxstraplabs/bloxstrap.git
synced 2025-04-22 18:41:26 -07:00
- Features - Add Discord Rich Presence support (the nuget package is like a year and a half out of date so submodule it is lol) - Add update checker - Add start menu folder creation - Bugfixes - Fix "Directory is not empty" error when updating Roblox - Fix uninstalling sometimes not working properly - Quality of Life - Split Bootstrapper class into partial files - Renamed TaskDialogStyle to VistaDialog for name simplification
209 lines
7.6 KiB
C#
209 lines
7.6 KiB
C#
using System.Diagnostics;
|
|
using System.IO.Compression;
|
|
|
|
using Bloxstrap.Helpers;
|
|
using Bloxstrap.Helpers.RSMM;
|
|
|
|
namespace Bloxstrap
|
|
{
|
|
partial class Bootstrapper
|
|
{
|
|
private async Task CheckLatestVersion()
|
|
{
|
|
if (Program.BaseDirectory is null)
|
|
return;
|
|
|
|
Message = "Connecting to Roblox...";
|
|
|
|
VersionGuid = await Client.GetStringAsync($"{Program.BaseUrlSetup}/version");
|
|
VersionFolder = Path.Combine(Program.BaseDirectory, "Versions", VersionGuid);
|
|
VersionPackageManifest = await PackageManifest.Get(VersionGuid);
|
|
VersionFileManifest = await FileManifest.Get(VersionGuid);
|
|
}
|
|
|
|
private async Task InstallLatestVersion()
|
|
{
|
|
if (Program.BaseDirectory is null)
|
|
return;
|
|
|
|
CheckIfRunning();
|
|
|
|
if (FreshInstall)
|
|
Message = "Installing Roblox...";
|
|
else
|
|
Message = "Upgrading Roblox...";
|
|
|
|
Directory.CreateDirectory(Program.BaseDirectory);
|
|
|
|
CancelEnabled = true;
|
|
|
|
// i believe the original bootstrapper bases the progress bar off zip
|
|
// extraction progress, but here i'm doing package download progress
|
|
|
|
ProgressStyle = ProgressBarStyle.Continuous;
|
|
|
|
ProgressIncrement = (int)Math.Floor((decimal)1 / VersionPackageManifest.Count * 100);
|
|
|
|
Directory.CreateDirectory(Path.Combine(Program.BaseDirectory, "Downloads"));
|
|
|
|
foreach (Package package in VersionPackageManifest)
|
|
{
|
|
// no await, download all the packages at once
|
|
DownloadPackage(package);
|
|
}
|
|
|
|
do
|
|
{
|
|
// wait for download to finish (and also round off the progress bar if needed)
|
|
|
|
if (Progress == ProgressIncrement * VersionPackageManifest.Count)
|
|
Progress = 100;
|
|
|
|
await Task.Delay(1000);
|
|
}
|
|
while (Progress != 100);
|
|
|
|
ProgressStyle = ProgressBarStyle.Marquee;
|
|
|
|
Debug.WriteLine("Finished downloading");
|
|
|
|
Directory.CreateDirectory(Path.Combine(Program.BaseDirectory, "Versions"));
|
|
|
|
foreach (Package package in VersionPackageManifest)
|
|
{
|
|
// extract all the packages at once (shouldn't be too heavy on cpu?)
|
|
ExtractPackage(package);
|
|
}
|
|
|
|
Debug.WriteLine("Finished extracting packages");
|
|
|
|
Message = "Configuring Roblox...";
|
|
|
|
string appSettingsLocation = Path.Combine(VersionFolder, "AppSettings.xml");
|
|
await File.WriteAllTextAsync(appSettingsLocation, AppSettings);
|
|
|
|
if (!FreshInstall)
|
|
{
|
|
// let's take this opportunity to delete any packages we don't need anymore
|
|
foreach (string filename in Directory.GetFiles(DownloadsFolder))
|
|
{
|
|
if (!VersionPackageManifest.Exists(package => filename.Contains(package.Signature)))
|
|
File.Delete(filename);
|
|
}
|
|
|
|
// and also to delete our old version folder
|
|
Directory.Delete(Path.Combine(Program.BaseDirectory, "Versions", Program.Settings.VersionGuid), true);
|
|
}
|
|
|
|
CancelEnabled = false;
|
|
|
|
Program.Settings.VersionGuid = VersionGuid;
|
|
}
|
|
|
|
private async void ApplyModifications()
|
|
{
|
|
// i guess we can just assume that if the hash does not match the manifest, then it's a mod
|
|
// probably not the best way to do this? don't think file corruption is that much of a worry here
|
|
|
|
// TODO - i'm thinking i could have a manifest on my website like rbxManifest.txt
|
|
// for integrity checking and to quickly fix/alter stuff (like ouch.ogg being renamed)
|
|
// but that probably wouldn't be great to check on every run in case my webserver ever goes down
|
|
// interesting idea nonetheless, might add it sometime
|
|
|
|
// TODO - i'm hoping i can take this idea of content mods much further
|
|
// for stuff like easily installing (community-created?) texture/shader/audio mods
|
|
// but for now, let's just keep it at this
|
|
|
|
await ModifyDeathSound();
|
|
}
|
|
|
|
private async void DownloadPackage(Package package)
|
|
{
|
|
string packageUrl = $"{Program.BaseUrlSetup}/{VersionGuid}-{package.Name}";
|
|
string packageLocation = Path.Combine(DownloadsFolder, package.Signature);
|
|
string robloxPackageLocation = Path.Combine(Program.LocalAppData, "Roblox", "Downloads", package.Signature);
|
|
|
|
if (File.Exists(packageLocation))
|
|
{
|
|
FileInfo file = new(packageLocation);
|
|
|
|
string calculatedMD5 = Utilities.CalculateMD5(packageLocation);
|
|
if (calculatedMD5 != package.Signature)
|
|
{
|
|
Debug.WriteLine($"{package.Name} is corrupted ({calculatedMD5} != {package.Signature})! Deleting and re-downloading...");
|
|
file.Delete();
|
|
}
|
|
else
|
|
{
|
|
Debug.WriteLine($"{package.Name} is already downloaded, skipping...");
|
|
Progress += ProgressIncrement;
|
|
return;
|
|
}
|
|
}
|
|
else if (File.Exists(robloxPackageLocation))
|
|
{
|
|
// let's cheat! if the stock bootstrapper already previously downloaded the file,
|
|
// then we can just copy the one from there
|
|
|
|
Debug.WriteLine($"Found existing version of {package.Name} ({robloxPackageLocation})! Copying to Downloads folder...");
|
|
File.Copy(robloxPackageLocation, packageLocation);
|
|
Progress += ProgressIncrement;
|
|
return;
|
|
}
|
|
|
|
if (!File.Exists(packageLocation))
|
|
{
|
|
Debug.WriteLine($"Downloading {package.Name}...");
|
|
|
|
var response = await Client.GetAsync(packageUrl);
|
|
|
|
if (CancelFired)
|
|
return;
|
|
|
|
using (var fileStream = new FileStream(packageLocation, FileMode.CreateNew))
|
|
{
|
|
await response.Content.CopyToAsync(fileStream);
|
|
}
|
|
|
|
Debug.WriteLine($"Finished downloading {package.Name}!");
|
|
Progress += ProgressIncrement;
|
|
}
|
|
}
|
|
|
|
private void ExtractPackage(Package package)
|
|
{
|
|
if (CancelFired)
|
|
return;
|
|
|
|
string packageLocation = Path.Combine(DownloadsFolder, package.Signature);
|
|
string packageFolder = Path.Combine(VersionFolder, PackageDirectories[package.Name]);
|
|
string extractPath;
|
|
|
|
Debug.WriteLine($"Extracting {package.Name} to {packageFolder}...");
|
|
|
|
using (ZipArchive archive = ZipFile.OpenRead(packageLocation))
|
|
{
|
|
foreach (ZipArchiveEntry entry in archive.Entries)
|
|
{
|
|
if (CancelFired)
|
|
return;
|
|
|
|
if (entry.FullName.EndsWith(@"\"))
|
|
continue;
|
|
|
|
extractPath = Path.Combine(packageFolder, entry.FullName);
|
|
|
|
Debug.WriteLine($"[{package.Name}] Writing {extractPath}...");
|
|
|
|
Directory.CreateDirectory(Path.GetDirectoryName(extractPath));
|
|
|
|
if (File.Exists(extractPath))
|
|
File.Delete(extractPath);
|
|
|
|
entry.ExtractToFile(extractPath);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|