commit e220c2e20df932b3c6529a7ed4f83ef4acf362bf Author: murdle Date: Thu May 1 14:24:44 2025 -0700 versionmanager + some more diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..46e9cdd --- /dev/null +++ b/.gitignore @@ -0,0 +1,134 @@ +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. + +# User-specific files +*.suo +*.user +*.sln.docstates + .idea/ + +# Build results + +[Dd]ebug/ +[Rr]elease/ +x64/ +[Bb]in/ +[Oo]bj/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +*_i.c +*_p.c +*_i.h +*.ilk +*.meta +*.obj +*.pch +*.pdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.log +*.svclog +*.scc + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opensdf +*.sdf +*.cachefile + +# Visual Studio profiler +*.psess +*.vsp +*.vspx + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# Click-Once directory +publish/ + +# Publish Web Output +*.Publish.xml +*.pubxml +*.azurePubxml + +# NuGet Packages Directory +## TODO: If you have NuGet Package Restore enabled, uncomment the next line +packages/ +## TODO: If the tool you use requires repositories.config, also uncomment the next line +!packages/repositories.config + +# Windows Azure Build Output +csx/ +*.build.csdef + +# Windows Store app package directory +AppPackages/ + +# Others +sql/ +*.Cache +ClientBin/ +[Ss]tyle[Cc]op.* +![Ss]tyle[Cc]op.targets +~$* +*~ +*.dbmdl +*.[Pp]ublish.xml + +*.publishsettings + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file to a newer +# Visual Studio version. Backup files are not needed, because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm + +# SQL Server files +App_Data/*.mdf +App_Data/*.ldf + +# ========================= +# Windows detritus +# ========================= + +# Windows image file caches +Thumbs.db +ehthumbs.db + +# Folder config file +Desktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Mac desktop service store files +.DS_Store + +_NCrunch* \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..788f0fa --- /dev/null +++ b/README.md @@ -0,0 +1,6 @@ +# Roblox Legacy Patcher +## What is this? +This is a C# application which automatically downloads the latest version of Roblox Studio and makes it work on Windows 8.1 and below. It can run natively on Windows 8 and 8.1 with a patch, but a wrapper is also used if you're on Windows 7 due to missing DX apis. + +## Notice +Currently, the application only allows you to run Roblox Studio. Because of Roblox's anticheat (aka Hyperion), we have not been able to get the client to work as of right now. diff --git a/RobloxLegacy.sln b/RobloxLegacy.sln new file mode 100644 index 0000000..8d0da02 --- /dev/null +++ b/RobloxLegacy.sln @@ -0,0 +1,16 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RobloxLegacy", "RobloxLegacy\RobloxLegacy.csproj", "{B3AE869E-4EC7-424E-AF85-AAC61974D3A2}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {B3AE869E-4EC7-424E-AF85-AAC61974D3A2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B3AE869E-4EC7-424E-AF85-AAC61974D3A2}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B3AE869E-4EC7-424E-AF85-AAC61974D3A2}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B3AE869E-4EC7-424E-AF85-AAC61974D3A2}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection +EndGlobal diff --git a/RobloxLegacy/AppData/IAppData.cs b/RobloxLegacy/AppData/IAppData.cs new file mode 100644 index 0000000..f97b578 --- /dev/null +++ b/RobloxLegacy/AppData/IAppData.cs @@ -0,0 +1,7 @@ +namespace RobloxLegacy.AppData; + +public interface IAppData +{ + string Name { get; } + Dictionary PackageFiles { get; } +} \ No newline at end of file diff --git a/RobloxLegacy/AppData/StudioData.cs b/RobloxLegacy/AppData/StudioData.cs new file mode 100644 index 0000000..d41668c --- /dev/null +++ b/RobloxLegacy/AppData/StudioData.cs @@ -0,0 +1,47 @@ +namespace RobloxLegacy.AppData; + +public class StudioData : IAppData +{ + public string Name => "WindowsStudio64"; + public Dictionary PackageFiles { get; } = new() + { + ["RobloxStudio.zip"] = "", + ["RibbonConfig.zip"] = "RibbonConfig/", + ["redist.zip"] = "", + ["Libraries.zip"] = "", + ["LibrariesQt5.zip"] = "", + ["WebView2.zip"] = "", + ["WebView2RuntimeInstaller.zip"] = "", + + ["shaders.zip"] = "shaders/", + ["ssl.zip"] = "ssl/", + ["Qml.zip"] = "Qml/", + ["Plugins.zip"] = "Plugins/", + ["StudioFonts.zip"] = "StudioFonts/", + ["BuiltInPlugins.zip"] = "BuiltInPlugins/", + ["ApplicationConfig.zip"] = "ApplicationConfig/", + ["BuiltInStandalonePlugins.zip"] = "BuiltInStandalonePlugins/", + + ["content-qt_translations.zip"] = "content/qt_translations/", + ["content-sky.zip"] = "content/sky/", + ["content-fonts.zip"] = "content/fonts/", + ["content-avatar.zip"] = "content/avatar/", + ["content-models.zip"] = "content/models/", + ["content-sounds.zip"] = "content/sounds/", + ["content-configs.zip"] = "content/configs/", + ["content-api-docs.zip"] = "content/api_docs/", + ["content-textures2.zip"] = "content/textures/", + ["content-studio_svg_textures.zip"] = "content/studio_svg_textures/", + + ["content-platform-fonts.zip"] = "PlatformContent/pc/fonts/", + ["content-platform-dictionaries.zip"] = "PlatformContent/pc/shared_compression_dictionaries/", + ["content-terrain.zip"] = "PlatformContent/pc/terrain/", + ["content-textures3.zip"] = "PlatformContent/pc/textures/", + + ["extracontent-translations.zip"] = "ExtraContent/translations/", + ["extracontent-luapackages.zip"] = "ExtraContent/LuaPackages/", + ["extracontent-textures.zip"] = "ExtraContent/textures/", + ["extracontent-scripts.zip"] = "ExtraContent/scripts/", + ["extracontent-models.zip"] = "ExtraContent/models/" + }; +} \ No newline at end of file diff --git a/RobloxLegacy/Program.cs b/RobloxLegacy/Program.cs new file mode 100644 index 0000000..f4a2413 --- /dev/null +++ b/RobloxLegacy/Program.cs @@ -0,0 +1,3 @@ +// See https://aka.ms/new-console-template for more information + +Console.WriteLine("hi"); \ No newline at end of file diff --git a/RobloxLegacy/RobloxLegacy.csproj b/RobloxLegacy/RobloxLegacy.csproj new file mode 100644 index 0000000..0a2f3d3 --- /dev/null +++ b/RobloxLegacy/RobloxLegacy.csproj @@ -0,0 +1,14 @@ + + + + Exe + net8.0 + enable + enable + + + + + + + diff --git a/RobloxLegacy/Utilities/Logger.cs b/RobloxLegacy/Utilities/Logger.cs new file mode 100644 index 0000000..3b297f0 --- /dev/null +++ b/RobloxLegacy/Utilities/Logger.cs @@ -0,0 +1,9 @@ +namespace RobloxLegacy.Utilities; + +public static class Logger +{ + public static void Log(string msg) + { + Console.Write($"[+] {msg}"); + } +} \ No newline at end of file diff --git a/RobloxLegacy/VersionManager.cs b/RobloxLegacy/VersionManager.cs new file mode 100644 index 0000000..46773ef --- /dev/null +++ b/RobloxLegacy/VersionManager.cs @@ -0,0 +1,58 @@ +using System.Text.Json.Serialization; +using System.IO.Compression; +using RobloxLegacy.AppData; +using RobloxLegacy.Utilities; + +namespace RobloxLegacy; + +public abstract class VersionData +{ + [JsonPropertyName("version")] + public required string Version { get; set; } + + [JsonPropertyName("clientVersionUpload")] + public required string UploadHash { get; set; } +} + +public class VersionManager(IAppData appData) +{ + private static readonly HttpClient Client = new(); + private const string CdnUrl = "https://setup.rbxcdn.com"; + + private static string GetVersionPath(string version) + { + var localAppDataPath = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData); + return Path.Combine(localAppDataPath, "Roblox", "Versions", version); + } + + private async Task GetLatestVersion() + { + var url = $"https://clientsettings.roblox.com/v2/client-version/{appData.Name}/channel/LIVE"; + var response = await Client.GetAsync(url); + if(!response.IsSuccessStatusCode) // just to be safe + return null; + var version = await response.Content.ReadAsAsync(); + return version; + } + + private static void ExtractBundle(string version, string folder, Stream file) + { + var extractPath = Path.Combine(GetVersionPath(version), folder); + ZipFile.ExtractToDirectory(file, extractPath); + } + + public async Task InstallPackage() + { + var version = await GetLatestVersion(); + if(version == null) + throw new Exception("No version data found"); + + Logger.Log($"Installing {appData.Name} version {version.Version}"); + foreach (var file in appData.PackageFiles) + { + var fileName = $"{version.UploadHash}-{file.Key}"; + var fileStream = await Client.GetStreamAsync($"{CdnUrl}/{fileName}"); + ExtractBundle(version.UploadHash, file.Value, fileStream); + } + } +} \ No newline at end of file