Skip to content

Commit 9e02141

Browse files
committed
Merge branch 'main' of https://github.com/pizzaboxer/bloxstrap into wip
2 parents f99bbe4 + 1dc3186 commit 9e02141

23 files changed

+137
-124
lines changed

Bloxstrap/AppData/CommonAppData.cs

+5-5
Original file line numberDiff line numberDiff line change
@@ -42,13 +42,13 @@ public abstract class CommonAppData
4242
};
4343

4444
public virtual string ExecutableName { get; } = null!;
45-
46-
public virtual string Directory { get; } = null!;
4745

48-
public string LockFilePath => Path.Combine(Directory, "Bloxstrap.lock");
49-
46+
public string Directory => Path.Combine(Paths.Versions, State.VersionGuid);
47+
5048
public string ExecutablePath => Path.Combine(Directory, ExecutableName);
51-
49+
50+
public virtual AppState State { get; } = null!;
51+
5252
public virtual IReadOnlyDictionary<string, string> PackageDirectoryMap { get; set; }
5353

5454

Bloxstrap/AppData/IAppData.cs

-4
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,6 @@ internal interface IAppData
1212

1313
string Directory { get; }
1414

15-
string OldDirectory { get; }
16-
17-
string LockFilePath { get; }
18-
1915
string ExecutablePath { get; }
2016

2117
AppState State { get; }

Bloxstrap/AppData/RobloxPlayerData.cs

+1-5
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,7 @@ public class RobloxPlayerData : CommonAppData, IAppData
1616

1717
public override string ExecutableName => "RobloxPlayerBeta.exe";
1818

19-
public override string Directory => Path.Combine(Paths.Roblox, "Player");
20-
21-
public string OldDirectory => Path.Combine(Paths.Roblox, "Player.old");
22-
23-
public AppState State => App.State.Prop.Player;
19+
public override AppState State => App.State.Prop.Player;
2420

2521
public override IReadOnlyDictionary<string, string> PackageDirectoryMap { get; set; } = new Dictionary<string, string>()
2622
{

Bloxstrap/AppData/RobloxStudioData.cs

+1-5
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,7 @@ public class RobloxStudioData : CommonAppData, IAppData
1010

1111
public override string ExecutableName => "RobloxStudioBeta.exe";
1212

13-
public override string Directory => Path.Combine(Paths.Roblox, "Studio");
14-
15-
public string OldDirectory => Path.Combine(Paths.Roblox, "Studio.old");
16-
17-
public AppState State => App.State.Prop.Studio;
13+
public override AppState State => App.State.Prop.Studio;
1814

1915
public override IReadOnlyDictionary<string, string> PackageDirectoryMap { get; set; } = new Dictionary<string, string>()
2016
{

Bloxstrap/Bloxstrap.csproj

+2-2
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@
77
<UseWPF>true</UseWPF>
88
<UseWindowsForms>True</UseWindowsForms>
99
<ApplicationIcon>Bloxstrap.ico</ApplicationIcon>
10-
<Version>2.8.1</Version>
11-
<FileVersion>2.8.1</FileVersion>
10+
<Version>2.8.2</Version>
11+
<FileVersion>2.8.2</FileVersion>
1212
<ApplicationManifest>app.manifest</ApplicationManifest>
1313
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
1414
<IncludeSourceRevisionInInformationalVersion>false</IncludeSourceRevisionInInformationalVersion>

Bloxstrap/Bootstrapper.cs

+70-63
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ private List<string> _modManifest
6868
}
6969

7070
private string _latestVersionGuid = null!;
71+
private string _latestVersionDirectory = null!;
7172
private PackageManifest _versionPackageManifest = null!;
7273

7374
private bool _isInstalling = false;
@@ -76,7 +77,7 @@ private List<string> _modManifest
7677
private double _taskbarProgressMaximum;
7778
private long _totalDownloadedBytes = 0;
7879

79-
private bool _mustUpgrade => String.IsNullOrEmpty(AppData.State.VersionGuid) || File.Exists(AppData.LockFilePath) || !File.Exists(AppData.ExecutablePath);
80+
private bool _mustUpgrade => String.IsNullOrEmpty(AppData.State.VersionGuid) || !File.Exists(AppData.ExecutablePath);
8081
private bool _noConnection = false;
8182

8283
private AsyncMutex? _mutex;
@@ -331,6 +332,7 @@ private async Task GetLatestVersionInfo()
331332
key.SetValueSafe("www.roblox.com", Deployment.IsDefaultChannel ? "" : Deployment.Channel);
332333

333334
_latestVersionGuid = clientVersion.VersionGuid;
335+
_latestVersionDirectory = Path.Combine(Paths.Versions, _latestVersionGuid);
334336

335337
string pkgManifestUrl = Deployment.GetLocation($"/{_latestVersionGuid}-rbxPkgManifest.txt");
336338
var pkgManifestData = await App.HttpClient.GetStringAsync(pkgManifestUrl);
@@ -531,18 +533,13 @@ public void Cancel()
531533
try
532534
{
533535
// clean up install
534-
if (Directory.Exists(AppData.Directory))
535-
Directory.Delete(AppData.Directory, true);
536+
if (Directory.Exists(_latestVersionDirectory))
537+
Directory.Delete(_latestVersionDirectory, true);
536538
}
537539
catch (Exception ex)
538540
{
539541
App.Logger.WriteLine(LOG_IDENT, "Could not fully clean up installation!");
540542
App.Logger.WriteException(LOG_IDENT, ex);
541-
542-
// assurance to make sure the next launch does a fresh install
543-
// we probably shouldn't be using the lockfile to do this, but meh
544-
var lockFile = new FileInfo(AppData.LockFilePath);
545-
lockFile.Create().Dispose();
546543
}
547544
}
548545
else if (_appPid != 0)
@@ -667,69 +664,67 @@ private async Task<bool> CheckForUpdates()
667664

668665
return false;
669666
}
670-
#endregion
667+
#endregion
671668

672669
#region Roblox Install
673-
private async Task UpgradeRoblox()
670+
private void CleanupVersionsFolder()
674671
{
675-
const string LOG_IDENT = "Bootstrapper::UpgradeRoblox";
676-
677-
if (String.IsNullOrEmpty(AppData.State.VersionGuid))
678-
SetStatus(Strings.Bootstrapper_Status_Installing);
679-
else
680-
SetStatus(Strings.Bootstrapper_Status_Upgrading);
672+
const string LOG_IDENT = "Bootstrapper::CleanupVersionsFolder";
681673

682-
Directory.CreateDirectory(Paths.Base);
683-
Directory.CreateDirectory(Paths.Downloads);
684-
Directory.CreateDirectory(Paths.Roblox);
685-
686-
if (Directory.Exists(AppData.Directory))
674+
foreach (string dir in Directory.GetDirectories(Paths.Versions))
687675
{
688-
if (Directory.Exists(AppData.OldDirectory))
689-
Directory.Delete(AppData.OldDirectory, true);
676+
string dirName = Path.GetFileName(dir);
690677

691-
try
678+
if (dirName != App.State.Prop.Player.VersionGuid && dirName != App.State.Prop.Studio.VersionGuid)
692679
{
693-
// test to see if any files are in use
694-
// if you have a better way to check for this, please let me know!
695-
Directory.Move(AppData.Directory, AppData.OldDirectory);
696-
}
697-
catch (Exception ex)
698-
{
699-
App.Logger.WriteLine(LOG_IDENT, "Could not clear old files, aborting update.");
700-
App.Logger.WriteException(LOG_IDENT, ex);
701-
702-
// 0x80070020 is the HRESULT that indicates that a process is still running
703-
// (either RobloxPlayerBeta or RobloxCrashHandler), so we'll silently ignore it
704-
if ((uint)ex.HResult != 0x80070020)
680+
try
705681
{
706-
// ensure no files are marked as read-only for good measure
707-
foreach (var file in Directory.GetFiles(AppData.Directory, "*", SearchOption.AllDirectories))
708-
Filesystem.AssertReadOnly(file);
682+
Directory.Delete(dir, true);
683+
}
684+
catch (IOException ex)
685+
{
686+
App.Logger.WriteLine(LOG_IDENT, $"Failed to delete {dir}");
687+
App.Logger.WriteException(LOG_IDENT, ex);
688+
}
689+
}
690+
}
691+
}
709692

710-
Frontend.ShowMessageBox(
711-
Strings.Bootstrapper_FilesInUse,
712-
_mustUpgrade ? MessageBoxImage.Error : MessageBoxImage.Warning
713-
);
693+
private void MigrateCompatibilityFlags()
694+
{
695+
const string LOG_IDENT = "Bootstrapper::MigrateCompatibilityFlags";
714696

715-
if (_mustUpgrade)
716-
App.Terminate(ErrorCode.ERROR_CANCELLED);
717-
}
697+
string oldClientLocation = Path.Combine(Paths.Versions, AppData.State.VersionGuid, AppData.ExecutableName);
698+
string newClientLocation = Path.Combine(_latestVersionDirectory, AppData.ExecutableName);
718699

719-
return;
720-
}
700+
// move old compatibility flags for the old location
701+
using RegistryKey appFlagsKey = Registry.CurrentUser.CreateSubKey($"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\AppCompatFlags\\Layers");
702+
string? appFlags = appFlagsKey.GetValue(oldClientLocation) as string;
721703

722-
Directory.Delete(AppData.OldDirectory, true);
704+
if (appFlags is not null)
705+
{
706+
App.Logger.WriteLine(LOG_IDENT, $"Migrating app compatibility flags from {oldClientLocation} to {newClientLocation}...");
707+
appFlagsKey.SetValueSafe(newClientLocation, appFlags);
708+
appFlagsKey.DeleteValueSafe(oldClientLocation);
723709
}
710+
}
724711

725-
_isInstalling = true;
712+
private async Task UpgradeRoblox()
713+
{
714+
const string LOG_IDENT = "Bootstrapper::UpgradeRoblox";
715+
716+
if (String.IsNullOrEmpty(AppData.State.VersionGuid))
717+
SetStatus(Strings.Bootstrapper_Status_Installing);
718+
else
719+
SetStatus(Strings.Bootstrapper_Status_Upgrading);
726720

727-
Directory.CreateDirectory(AppData.Directory);
721+
Directory.CreateDirectory(Paths.Base);
722+
Directory.CreateDirectory(Paths.Downloads);
723+
Directory.CreateDirectory(Paths.Versions);
724+
725+
_isInstalling = true;
728726

729-
// installer lock, it should only be present while roblox is in the process of upgrading
730-
// if it's present while we're launching, then it's an unfinished install and must be reinstalled
731-
var lockFile = new FileInfo(AppData.LockFilePath);
732-
lockFile.Create().Dispose();
727+
Directory.CreateDirectory(_latestVersionDirectory);
733728

734729
var cachedPackageHashes = Directory.GetFiles(Paths.Downloads).Select(x => Path.GetFileName(x));
735730

@@ -797,7 +792,7 @@ private async Task UpgradeRoblox()
797792
await Task.WhenAll(extractionTasks);
798793

799794
App.Logger.WriteLine(LOG_IDENT, "Writing AppSettings.xml...");
800-
await File.WriteAllTextAsync(Path.Combine(AppData.Directory, "AppSettings.xml"), AppSettings);
795+
await File.WriteAllTextAsync(Path.Combine(_latestVersionDirectory, "AppSettings.xml"), AppSettings);
801796

802797
if (_cancelTokenSource.IsCancellationRequested)
803798
return;
@@ -832,7 +827,7 @@ private async Task UpgradeRoblox()
832827
return;
833828
}
834829

835-
string baseDirectory = Path.Combine(AppData.Directory, AppData.PackageDirectoryMap[package.Name]);
830+
string baseDirectory = Path.Combine(_latestVersionDirectory, AppData.PackageDirectoryMap[package.Name]);
836831

837832
ExtractPackage(package);
838833

@@ -856,13 +851,17 @@ private async Task UpgradeRoblox()
856851

857852
// finishing and cleanup
858853

854+
MigrateCompatibilityFlags();
855+
859856
AppData.State.VersionGuid = _latestVersionGuid;
860857

861858
AppData.State.PackageHashes.Clear();
862859

863860
foreach (var package in _versionPackageManifest)
864861
AppData.State.PackageHashes.Add(package.Name, package.Signature);
865862

863+
CleanupVersionsFolder();
864+
866865
var allPackageHashes = new List<string>();
867866

868867
allPackageHashes.AddRange(App.State.Prop.Player.PackageHashes.Values);
@@ -903,8 +902,6 @@ private async Task UpgradeRoblox()
903902

904903
App.State.Save();
905904

906-
lockFile.Delete();
907-
908905
_isInstalling = false;
909906
}
910907

@@ -938,7 +935,17 @@ private async Task ApplyModifications()
938935

939936
const string path = "rbxasset://fonts/CustomFont.ttf";
940937

941-
foreach (string jsonFilePath in Directory.GetFiles(Path.Combine(AppData.Directory, "content\\fonts\\families")))
938+
// lets make sure the content/fonts/families path exists in the version directory
939+
string contentFolder = Path.Combine(_latestVersionDirectory, "content");
940+
Directory.CreateDirectory(contentFolder);
941+
942+
string fontsFolder = Path.Combine(contentFolder, "fonts");
943+
Directory.CreateDirectory(fontsFolder);
944+
945+
string familiesFolder = Path.Combine(fontsFolder, "families");
946+
Directory.CreateDirectory(familiesFolder);
947+
948+
foreach (string jsonFilePath in Directory.GetFiles(familiesFolder))
942949
{
943950
string jsonFilename = Path.GetFileName(jsonFilePath);
944951
string modFilepath = Path.Combine(modFontFamiliesFolder, jsonFilename);
@@ -999,7 +1006,7 @@ private async Task ApplyModifications()
9991006
modFolderFiles.Add(relativeFile);
10001007

10011008
string fileModFolder = Path.Combine(_playerModFolder, relativeFile);
1002-
string fileVersionFolder = Path.Combine(AppData.Directory, relativeFile);
1009+
string fileVersionFolder = Path.Combine(_latestVersionDirectory, relativeFile);
10031010

10041011
if (File.Exists(fileVersionFolder) && MD5Hash.FromFile(fileModFolder) == MD5Hash.FromFile(fileVersionFolder))
10051012
{
@@ -1035,7 +1042,7 @@ private async Task ApplyModifications()
10351042
{
10361043
App.Logger.WriteLine(LOG_IDENT, $"{fileLocation} was removed as a mod but does not belong to a package");
10371044

1038-
string versionFileLocation = Path.Combine(AppData.Directory, fileLocation);
1045+
string versionFileLocation = Path.Combine(_latestVersionDirectory, fileLocation);
10391046

10401047
if (File.Exists(versionFileLocation))
10411048
File.Delete(versionFileLocation);
@@ -1223,7 +1230,7 @@ private void ExtractPackage(Package package, List<string>? files = null)
12231230
return;
12241231
}
12251232

1226-
string packageFolder = Path.Combine(AppData.Directory, packageDir);
1233+
string packageFolder = Path.Combine(_latestVersionDirectory, packageDir);
12271234
string? fileFilter = null;
12281235

12291236
// for sharpziplib, each file in the filter needs to be a regex

Bloxstrap/Extensions/RegistryKeyEx.cs

+14
Original file line numberDiff line numberDiff line change
@@ -17,5 +17,19 @@ public static void SetValueSafe(this RegistryKey registryKey, string? name, obje
1717
App.Terminate(ErrorCode.ERROR_INSTALL_FAILURE);
1818
}
1919
}
20+
21+
public static void DeleteValueSafe(this RegistryKey registryKey, string name)
22+
{
23+
try
24+
{
25+
App.Logger.WriteLine("RegistryKeyEx::DeleteValueSafe", $"Deleting {registryKey}\\{name}");
26+
registryKey.DeleteValue(name);
27+
}
28+
catch (UnauthorizedAccessException)
29+
{
30+
Frontend.ShowMessageBox(Strings.Dialog_RegistryWriteError, System.Windows.MessageBoxImage.Error);
31+
App.Terminate(ErrorCode.ERROR_INSTALL_FAILURE);
32+
}
33+
}
2034
}
2135
}

Bloxstrap/Installer.cs

+12-10
Original file line numberDiff line numberDiff line change
@@ -287,8 +287,8 @@ public static void DoUninstall(bool keepData)
287287

288288
() => File.Delete(StartMenuShortcut),
289289

290+
() => Directory.Delete(Paths.Versions, true),
290291
() => Directory.Delete(Paths.Downloads, true),
291-
() => Directory.Delete(Paths.Roblox, true),
292292

293293
() => File.Delete(App.State.FileLocation)
294294
};
@@ -549,15 +549,6 @@ public static void HandleUpgrade()
549549

550550
App.FastFlags.SetValue("FFlagDisableNewIGMinDUA", null);
551551
App.FastFlags.SetValue("FFlagFixGraphicsQuality", null);
552-
553-
try
554-
{
555-
Directory.Delete(Path.Combine(Paths.Base, "Versions"), true);
556-
}
557-
catch (Exception ex)
558-
{
559-
App.Logger.WriteException(LOG_IDENT, ex);
560-
}
561552
}
562553

563554
if (Utilities.CompareVersions(existingVer, "2.8.1") == VersionComparison.LessThan)
@@ -574,6 +565,17 @@ public static void HandleUpgrade()
574565
App.FastFlags.SetValue("FFlagEnableInGameMenuChromeABTest4", null);
575566
}
576567

568+
if (Utilities.CompareVersions(existingVer, "2.8.2") == VersionComparison.LessThan)
569+
{
570+
try
571+
{
572+
Directory.Delete(Path.Combine(Paths.Base, "Roblox"), true);
573+
}
574+
catch (Exception ex)
575+
{
576+
App.Logger.WriteException(LOG_IDENT, ex);
577+
}
578+
}
577579

578580
App.Settings.Save();
579581
App.FastFlags.Save();

Bloxstrap/JsonManager.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ public virtual void Save()
6565
{
6666
File.WriteAllText(FileLocation, JsonSerializer.Serialize(Prop, new JsonSerializerOptions { WriteIndented = true }));
6767
}
68-
catch (IOException ex)
68+
catch (Exception ex) when (ex is IOException or UnauthorizedAccessException)
6969
{
7070
App.Logger.WriteLine(LOG_IDENT, "Failed to save");
7171
App.Logger.WriteException(LOG_IDENT, ex);

0 commit comments

Comments
 (0)