@@ -68,6 +68,7 @@ private List<string> _modManifest
68
68
}
69
69
70
70
private string _latestVersionGuid = null ! ;
71
+ private string _latestVersionDirectory = null ! ;
71
72
private PackageManifest _versionPackageManifest = null ! ;
72
73
73
74
private bool _isInstalling = false ;
@@ -76,7 +77,7 @@ private List<string> _modManifest
76
77
private double _taskbarProgressMaximum ;
77
78
private long _totalDownloadedBytes = 0 ;
78
79
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 ) ;
80
81
private bool _noConnection = false ;
81
82
82
83
private AsyncMutex ? _mutex ;
@@ -331,6 +332,7 @@ private async Task GetLatestVersionInfo()
331
332
key . SetValueSafe ( "www.roblox.com" , Deployment . IsDefaultChannel ? "" : Deployment . Channel ) ;
332
333
333
334
_latestVersionGuid = clientVersion . VersionGuid ;
335
+ _latestVersionDirectory = Path . Combine ( Paths . Versions , _latestVersionGuid ) ;
334
336
335
337
string pkgManifestUrl = Deployment . GetLocation ( $ "/{ _latestVersionGuid } -rbxPkgManifest.txt") ;
336
338
var pkgManifestData = await App . HttpClient . GetStringAsync ( pkgManifestUrl ) ;
@@ -531,18 +533,13 @@ public void Cancel()
531
533
try
532
534
{
533
535
// 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 ) ;
536
538
}
537
539
catch ( Exception ex )
538
540
{
539
541
App . Logger . WriteLine ( LOG_IDENT , "Could not fully clean up installation!" ) ;
540
542
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 ( ) ;
546
543
}
547
544
}
548
545
else if ( _appPid != 0 )
@@ -667,69 +664,67 @@ private async Task<bool> CheckForUpdates()
667
664
668
665
return false ;
669
666
}
670
- #endregion
667
+ #endregion
671
668
672
669
#region Roblox Install
673
- private async Task UpgradeRoblox ( )
670
+ private void CleanupVersionsFolder ( )
674
671
{
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" ;
681
673
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 ) )
687
675
{
688
- if ( Directory . Exists ( AppData . OldDirectory ) )
689
- Directory . Delete ( AppData . OldDirectory , true ) ;
676
+ string dirName = Path . GetFileName ( dir ) ;
690
677
691
- try
678
+ if ( dirName != App . State . Prop . Player . VersionGuid && dirName != App . State . Prop . Studio . VersionGuid )
692
679
{
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
705
681
{
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
+ }
709
692
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" ;
714
696
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 ) ;
718
699
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 ;
721
703
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 ) ;
723
709
}
710
+ }
724
711
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 ) ;
726
720
727
- Directory . CreateDirectory ( AppData . Directory ) ;
721
+ Directory . CreateDirectory ( Paths . Base ) ;
722
+ Directory . CreateDirectory ( Paths . Downloads ) ;
723
+ Directory . CreateDirectory ( Paths . Versions ) ;
724
+
725
+ _isInstalling = true ;
728
726
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 ) ;
733
728
734
729
var cachedPackageHashes = Directory . GetFiles ( Paths . Downloads ) . Select ( x => Path . GetFileName ( x ) ) ;
735
730
@@ -797,7 +792,7 @@ private async Task UpgradeRoblox()
797
792
await Task . WhenAll ( extractionTasks ) ;
798
793
799
794
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 ) ;
801
796
802
797
if ( _cancelTokenSource . IsCancellationRequested )
803
798
return ;
@@ -832,7 +827,7 @@ private async Task UpgradeRoblox()
832
827
return ;
833
828
}
834
829
835
- string baseDirectory = Path . Combine ( AppData . Directory , AppData . PackageDirectoryMap [ package . Name ] ) ;
830
+ string baseDirectory = Path . Combine ( _latestVersionDirectory , AppData . PackageDirectoryMap [ package . Name ] ) ;
836
831
837
832
ExtractPackage ( package ) ;
838
833
@@ -856,13 +851,17 @@ private async Task UpgradeRoblox()
856
851
857
852
// finishing and cleanup
858
853
854
+ MigrateCompatibilityFlags ( ) ;
855
+
859
856
AppData . State . VersionGuid = _latestVersionGuid ;
860
857
861
858
AppData . State . PackageHashes . Clear ( ) ;
862
859
863
860
foreach ( var package in _versionPackageManifest )
864
861
AppData . State . PackageHashes . Add ( package . Name , package . Signature ) ;
865
862
863
+ CleanupVersionsFolder ( ) ;
864
+
866
865
var allPackageHashes = new List < string > ( ) ;
867
866
868
867
allPackageHashes . AddRange ( App . State . Prop . Player . PackageHashes . Values ) ;
@@ -903,8 +902,6 @@ private async Task UpgradeRoblox()
903
902
904
903
App . State . Save ( ) ;
905
904
906
- lockFile . Delete ( ) ;
907
-
908
905
_isInstalling = false ;
909
906
}
910
907
@@ -938,7 +935,17 @@ private async Task ApplyModifications()
938
935
939
936
const string path = "rbxasset://fonts/CustomFont.ttf" ;
940
937
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 ) )
942
949
{
943
950
string jsonFilename = Path . GetFileName ( jsonFilePath ) ;
944
951
string modFilepath = Path . Combine ( modFontFamiliesFolder , jsonFilename ) ;
@@ -999,7 +1006,7 @@ private async Task ApplyModifications()
999
1006
modFolderFiles . Add ( relativeFile ) ;
1000
1007
1001
1008
string fileModFolder = Path . Combine ( _playerModFolder , relativeFile ) ;
1002
- string fileVersionFolder = Path . Combine ( AppData . Directory , relativeFile ) ;
1009
+ string fileVersionFolder = Path . Combine ( _latestVersionDirectory , relativeFile ) ;
1003
1010
1004
1011
if ( File . Exists ( fileVersionFolder ) && MD5Hash . FromFile ( fileModFolder ) == MD5Hash . FromFile ( fileVersionFolder ) )
1005
1012
{
@@ -1035,7 +1042,7 @@ private async Task ApplyModifications()
1035
1042
{
1036
1043
App . Logger . WriteLine ( LOG_IDENT , $ "{ fileLocation } was removed as a mod but does not belong to a package") ;
1037
1044
1038
- string versionFileLocation = Path . Combine ( AppData . Directory , fileLocation ) ;
1045
+ string versionFileLocation = Path . Combine ( _latestVersionDirectory , fileLocation ) ;
1039
1046
1040
1047
if ( File . Exists ( versionFileLocation ) )
1041
1048
File . Delete ( versionFileLocation ) ;
@@ -1223,7 +1230,7 @@ private void ExtractPackage(Package package, List<string>? files = null)
1223
1230
return ;
1224
1231
}
1225
1232
1226
- string packageFolder = Path . Combine ( AppData . Directory , packageDir ) ;
1233
+ string packageFolder = Path . Combine ( _latestVersionDirectory , packageDir ) ;
1227
1234
string ? fileFilter = null ;
1228
1235
1229
1236
// for sharpziplib, each file in the filter needs to be a regex
0 commit comments