diff --git a/ProjectSrc/App.config b/ProjectSrc/App.config deleted file mode 100644 index 57a2b76..0000000 --- a/ProjectSrc/App.config +++ /dev/null @@ -1,11 +0,0 @@ - - - - -
- - - - - - diff --git a/ProjectSrc/Bootstrapper/FileManifest.cs b/ProjectSrc/Bootstrapper/FileManifest.cs index aecd540..6e97ef0 100644 --- a/ProjectSrc/Bootstrapper/FileManifest.cs +++ b/ProjectSrc/Bootstrapper/FileManifest.cs @@ -36,7 +36,7 @@ private FileManifest(string data, bool remapExtraContent = false) if (eof) break; - else if (remapExtraContent && path.StartsWith("ExtraContent", Program.StringFormat)) + else if (remapExtraContent && path.StartsWith("ExtraContent", App.StringFormat)) path = path.Replace("ExtraContent", "content"); // ~~ AWFUL TEMPORARY HACK. ~~ @@ -66,7 +66,7 @@ public static async Task Get(ClientVersionInfo info, bool remapExt { string versionGuid = info.VersionGuid; - string fileManifestUrl = $"{Program.BaseUrl}/channel/common/{versionGuid}-rbxManifest.txt"; + string fileManifestUrl = $"{App.BaseUrl}/channel/common/{versionGuid}-rbxManifest.txt"; string fileManifestData; using (WebClient http = new WebClient()) diff --git a/ProjectSrc/Bootstrapper/PackageManifest.cs b/ProjectSrc/Bootstrapper/PackageManifest.cs index 6bc5aaa..3c221aa 100644 --- a/ProjectSrc/Bootstrapper/PackageManifest.cs +++ b/ProjectSrc/Bootstrapper/PackageManifest.cs @@ -76,7 +76,7 @@ private PackageManifest(string data) public static async Task Get(ClientVersionInfo info) { string versionGuid = info.VersionGuid; - string pkgManifestUrl = $"{Program.BaseUrl}/channel/common/{versionGuid}-rbxPkgManifest.txt"; + string pkgManifestUrl = $"{App.BaseUrl}/channel/common/{versionGuid}-rbxPkgManifest.txt"; string pkgManifestData; using (WebClient http = new WebClient()) diff --git a/ProjectSrc/Bootstrapper/StudioBootstrapper.cs b/ProjectSrc/Bootstrapper/StudioBootstrapper.cs index ee74f95..8e824b2 100644 --- a/ProjectSrc/Bootstrapper/StudioBootstrapper.cs +++ b/ProjectSrc/Bootstrapper/StudioBootstrapper.cs @@ -8,7 +8,6 @@ using System.Net; using System.Runtime.InteropServices; using System.Threading.Tasks; -using System.Windows.Forms; using Newtonsoft.Json; using RobloxDeployHistory; @@ -17,6 +16,7 @@ namespace RobloxStudioModManager { public delegate void MessageFeed(string message); + public delegate Task ConfirmPrompt(string message, string title); public class StudioBootstrapper { @@ -32,6 +32,7 @@ public class StudioBootstrapper public event MessageFeed EchoFeed; public event MessageFeed StatusFeed; + public event ConfirmPrompt ConfirmFeed; private readonly IBootstrapperState mainState; private readonly VersionManifest versionData; @@ -51,7 +52,7 @@ public class StudioBootstrapper public int Progress = 0; public int MaxProgress = 0; - public ProgressBarStyle ProgressBarStyle = ProgressBarStyle.Continuous; + public BootstrapProgressStyle ProgressBarStyle = BootstrapProgressStyle.Determinate; public object ProgressLock = new object(); @@ -68,7 +69,7 @@ public class StudioBootstrapper public StudioBootstrapper(IBootstrapperState state = null) { - mainState = state ?? Program.State; + mainState = state ?? App.State; versionData = mainState.VersionData; channelData = mainState.ChannelData; fileRegistry = mainState.FileManifest; @@ -108,7 +109,7 @@ private static string computeSignature(Stream source) string result = BitConverter .ToString(hash) .Replace("-", "") - .ToLower(Program.Format); + .ToLower(App.Format); return result; } @@ -234,7 +235,7 @@ private void deleteUnusedFiles() if (!fileManifest.ContainsKey(fileName)) foreach (string pkgName in BadManifests) - if (fileName.StartsWith(pkgName, Program.StringFormat)) + if (fileName.StartsWith(pkgName, App.StringFormat)) lookupKey = fileName.Substring(pkgName.Length + 1); if (!fileManifest.ContainsKey(lookupKey)) @@ -275,10 +276,10 @@ private void deleteUnusedFiles() public static async Task GetTargetVersionInfo(string targetVersion = "", VersionManifest versionData = null, ChannelManifest channelData = null) { if (versionData == null) - versionData = Program.State.VersionData; + versionData = App.State.VersionData; if (channelData == null) - channelData = Program.State.ChannelData; + channelData = App.State.ChannelData; var logData = await StudioDeployLogs.Get(); HashSet targets = logData.CurrentLogs; @@ -299,10 +300,10 @@ public static async Task GetTargetVersionInfo(string targetVe public static async Task GetCurrentVersionInfo(string targetVersion = "", VersionManifest versionData = null, ChannelManifest channelData = null) { if (versionData == null) - versionData = Program.State.VersionData; + versionData = App.State.VersionData; if (channelData == null) - channelData = Program.State.ChannelData; + channelData = App.State.ChannelData; if (!string.IsNullOrEmpty(targetVersion)) { @@ -310,7 +311,7 @@ public static async Task GetCurrentVersionInfo(string targetV return await result.ConfigureAwait(false); } - var logData = await StudioDeployLogs.Get(Program.AllowUnsupportedVersions, channelData.ChannelName, channelData.ChannelToken); + var logData = await StudioDeployLogs.Get(App.AllowUnsupportedVersions, channelData.ChannelName, channelData.ChannelToken); var build = logData.CurrentLogs.LastOrDefault(); var info = new ClientVersionInfo(build); @@ -325,7 +326,7 @@ private string fixFilePath(string pkgName, string filePath) string pkgDir = pkgName.Replace(".zip", ""); if (BadManifests.Contains(pkgDir)) - if (!filePath.StartsWith(pkgDir, Program.StringFormat)) + if (!filePath.StartsWith(pkgDir, App.StringFormat)) filePath = pkgDir + '\\' + filePath; if (RemapExtraContent) @@ -361,7 +362,7 @@ private async Task packageExists(Package package) echo($"Verifying availability of: {package.Name}"); string pkgName = package.Name; - var zipFileUrl = new Uri($"{Program.BaseUrl}/channel/common/{buildVersion}-{pkgName}"); + var zipFileUrl = new Uri($"{App.BaseUrl}/channel/common/{buildVersion}-{pkgName}"); var request = WebRequest.Create(zipFileUrl) as HttpWebRequest; request.Headers.Set("UserAgent", UserAgent); @@ -382,7 +383,7 @@ private async Task installPackage(Package package) { byte[] result = null; string pkgName = package.Name; - string zipFileUrl = $"{Program.BaseUrl}/channel/common/{buildVersion}-{pkgName}"; + string zipFileUrl = $"{App.BaseUrl}/channel/common/{buildVersion}-{pkgName}"; using (var localHttp = new WebClient()) { @@ -452,7 +453,7 @@ private void extractPackage(Package package) int numFiles = archive.Entries .Select(entry => entry.FullName) - .Where(name => !name.EndsWith("/", Program.StringFormat)) + .Where(name => !name.EndsWith("/", App.StringFormat)) .Count(); string localRootDir = null; @@ -468,10 +469,10 @@ private void extractPackage(Package package) if (entry.Length == 0) skip = true; - if (entry.Name.EndsWith(".robloxrc", Program.StringFormat)) + if (entry.Name.EndsWith(".robloxrc", App.StringFormat)) skip = true; - if (entry.Name.EndsWith(".luarc", Program.StringFormat)) + if (entry.Name.EndsWith(".luarc", App.StringFormat)) skip = true; if (skip) @@ -512,7 +513,7 @@ private void extractPackage(Package package) } else { - var query = fileManifest.SkipWhile(pair => !pair.Key.EndsWith(entryPath, Program.StringFormat)).Take(1); + var query = fileManifest.SkipWhile(pair => !pair.Key.EndsWith(entryPath, App.StringFormat)).Take(1); newFileSig = query.Any() ? query.First().Value : null; } } @@ -539,7 +540,7 @@ private void extractPackage(Package package) if (filePath != file) appendNewManifestEntry(filePath, newFileSig); - if (filePath.EndsWith(entryPath, Program.StringFormat)) + if (filePath.EndsWith(entryPath, App.StringFormat)) { // We can infer what the root extraction // directory is for the files in this package! @@ -646,25 +647,21 @@ private async Task shutdownStudioProcesses() if (initialRunning.Count > 0) { - DialogResult result = DialogResult.OK; + bool proceed = true; - if (mainState == Program.State) + if (mainState == App.State) { - result = MessageBox.Show + proceed = ConfirmFeed == null || await ConfirmFeed.Invoke ( "All Roblox Studio processes need to be closed in order to update Roblox Studio!\n" + "Press Ok once you've saved your work, or\n" + "Press Cancel to skip this update temporarily.", - "Notice", - MessageBoxButtons.OKCancel, - MessageBoxIcon.Warning, - MessageBoxDefaultButton.Button1, - MessageBoxOptions.DefaultDesktopOnly - ); + "Notice" + ).ConfigureAwait(true); } - if (result == DialogResult.Cancel) + if (!proceed) { safeToContinue = true; cancelled = true; @@ -707,7 +704,7 @@ private async Task shutdownStudioProcesses() Progress = 0; MaxProgress = retries * granularity; - ProgressBarStyle = ProgressBarStyle.Continuous; + ProgressBarStyle = BootstrapProgressStyle.Determinate; for (int i = 0; i < retries; i++) { @@ -775,7 +772,7 @@ public async Task Bootstrap(string targetVersion = "") using (var http = new WebClient()) { var json = await http - .DownloadStringTaskAsync(Program.BaseConfigUrl + "KnownRoots.json") + .DownloadStringTaskAsync(App.BaseConfigUrl + "KnownRoots.json") .ConfigureAwait(false); var knownRoots = JsonConvert.DeserializeObject>(json); @@ -826,7 +823,7 @@ public async Task Bootstrap(string targetVersion = "") Progress = 0; MaxProgress = 0; - ProgressBarStyle = ProgressBarStyle.Continuous; + ProgressBarStyle = BootstrapProgressStyle.Determinate; // Verify all of these packages are available to install. foreach (Package package in pkgManifest) @@ -864,7 +861,7 @@ await Task Progress = 1; MaxProgress = 1; - ProgressBarStyle = ProgressBarStyle.Marquee; + ProgressBarStyle = BootstrapProgressStyle.Indeterminate; var timeout = Task.Delay(2000); await timeout.ConfigureAwait(false); @@ -974,11 +971,11 @@ await Task versionData.VersionGuid = buildVersion; versionData.VersionOverload = targetVersion; - ProgressBarStyle = ProgressBarStyle.Marquee; + ProgressBarStyle = BootstrapProgressStyle.Indeterminate; } else { - ProgressBarStyle = ProgressBarStyle.Marquee; + ProgressBarStyle = BootstrapProgressStyle.Indeterminate; echo("Update cancelled. Launching on current version."); } } @@ -989,8 +986,8 @@ await Task using (var http = new WebClient()) { - OAuth2Config_JSON = await http.DownloadStringTaskAsync(Program.BaseConfigUrl + "OAuth2Config.json"); - AppSettings_XML = await http.DownloadStringTaskAsync(Program.BaseConfigUrl + "AppSettings.xml"); + OAuth2Config_JSON = await http.DownloadStringTaskAsync(App.BaseConfigUrl + "OAuth2Config.json"); + AppSettings_XML = await http.DownloadStringTaskAsync(App.BaseConfigUrl + "AppSettings.xml"); } string appSettings = Path.Combine(studioDir, "AppSettings.xml"); @@ -1006,19 +1003,19 @@ await Task // Only update the registry protocols if the main registry // is the global one assigned to the program itself. - if (mainState == Program.State) + if (mainState == App.State) { setStatus("Configuring Roblox Studio..."); echo("Updating registry protocols..."); var studioPath = GetLocalStudioPath(); - Program.UpdateStudioRegistryProtocols(studioPath); + App.UpdateStudioRegistryProtocols(studioPath); } if (ApplyModManagerPatches && string.IsNullOrEmpty(OverrideStudioDirectory)) { echo("Applying flag configuration..."); - FlagEditor.ApplyFlags(); + FlagManager.ApplyFlags(); // Secret feature only for me :( // Feel free to patch in your own thing if you want. @@ -1029,7 +1026,7 @@ await Task #endif } - ProgressBarStyle = ProgressBarStyle.Marquee; + ProgressBarStyle = BootstrapProgressStyle.Indeterminate; MaxProgress = 1; Progress = 1; diff --git a/ProjectSrc/FodyWeavers.xml b/ProjectSrc/FodyWeavers.xml deleted file mode 100644 index 4da11b3..0000000 --- a/ProjectSrc/FodyWeavers.xml +++ /dev/null @@ -1,5 +0,0 @@ - - - - - \ No newline at end of file diff --git a/ProjectSrc/Forms/BootstrapperForm.Designer.cs b/ProjectSrc/Forms/BootstrapperForm.Designer.cs deleted file mode 100644 index e62e8bb..0000000 --- a/ProjectSrc/Forms/BootstrapperForm.Designer.cs +++ /dev/null @@ -1,139 +0,0 @@ -namespace RobloxStudioModManager -{ - partial class BootstrapperForm - { - /// - /// Required designer variable. - /// - private System.ComponentModel.IContainer components = null; - - /// - /// Clean up any resources being used. - /// - /// true if managed resources should be disposed; otherwise, false. - protected override void Dispose(bool disposing) - { - if (disposing && (components != null)) - { - components.Dispose(); - } - base.Dispose(disposing); - } - - #region Windows Form Designer generated code - - /// - /// Required method for Designer support - do not modify - /// the contents of this method with the code editor. - /// - private void InitializeComponent() - { - this.components = new System.ComponentModel.Container(); - this.progressBar = new System.Windows.Forms.ProgressBar(); - this.logo = new System.Windows.Forms.PictureBox(); - this.statusLbl = new System.Windows.Forms.Label(); - this.log = new System.Windows.Forms.RichTextBox(); - this.progressTimer = new System.Windows.Forms.Timer(this.components); - ((System.ComponentModel.ISupportInitialize)(this.logo)).BeginInit(); - this.SuspendLayout(); - // - // progressBar - // - this.progressBar.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left) - | System.Windows.Forms.AnchorStyles.Right))); - this.progressBar.Location = new System.Drawing.Point(6, 194); - this.progressBar.Margin = new System.Windows.Forms.Padding(1); - this.progressBar.MarqueeAnimationSpeed = 1; - this.progressBar.Name = "progressBar"; - this.progressBar.Size = new System.Drawing.Size(582, 29); - this.progressBar.Step = 0; - this.progressBar.Style = System.Windows.Forms.ProgressBarStyle.Marquee; - this.progressBar.TabIndex = 1; - this.progressBar.Value = 100; - // - // logo - // - this.logo.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) - | System.Windows.Forms.AnchorStyles.Left))); - this.logo.BackColor = System.Drawing.Color.Transparent; - this.logo.BackgroundImage = global::RobloxStudioModManager.Properties.Resources.Logo; - this.logo.BackgroundImageLayout = System.Windows.Forms.ImageLayout.Zoom; - this.logo.InitialImage = global::RobloxStudioModManager.Properties.Resources.Logo; - this.logo.Location = new System.Drawing.Point(6, 8); - this.logo.Margin = new System.Windows.Forms.Padding(2); - this.logo.Name = "logo"; - this.logo.Size = new System.Drawing.Size(121, 153); - this.logo.TabIndex = 9; - this.logo.TabStop = false; - this.logo.WaitOnLoad = true; - // - // statusLbl - // - this.statusLbl.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); - this.statusLbl.AutoSize = true; - this.statusLbl.Font = new System.Drawing.Font("Segoe UI Light", 16F); - this.statusLbl.Location = new System.Drawing.Point(0, 163); - this.statusLbl.Margin = new System.Windows.Forms.Padding(0); - this.statusLbl.Name = "statusLbl"; - this.statusLbl.Size = new System.Drawing.Size(225, 30); - this.statusLbl.TabIndex = 11; - this.statusLbl.Text = "Checking for updates..."; - this.statusLbl.TextAlign = System.Drawing.ContentAlignment.MiddleLeft; - // - // log - // - this.log.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) - | System.Windows.Forms.AnchorStyles.Left) - | System.Windows.Forms.AnchorStyles.Right))); - this.log.BackColor = System.Drawing.Color.White; - this.log.Font = new System.Drawing.Font("Consolas", 8.25F); - this.log.ForeColor = System.Drawing.Color.Black; - this.log.Location = new System.Drawing.Point(131, 8); - this.log.Margin = new System.Windows.Forms.Padding(2); - this.log.Name = "log"; - this.log.ReadOnly = true; - this.log.Size = new System.Drawing.Size(458, 154); - this.log.TabIndex = 12; - this.log.Text = ""; - // - // progressTimer - // - this.progressTimer.Enabled = true; - // - // BootstrapperForm - // - this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F); - this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi; - this.ClientSize = new System.Drawing.Size(596, 249); - this.Controls.Add(this.log); - this.Controls.Add(this.statusLbl); - this.Controls.Add(this.logo); - this.Controls.Add(this.progressBar); - this.DoubleBuffered = true; - this.Font = new System.Drawing.Font("Consolas", 8.25F); - this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle; - this.Icon = global::RobloxStudioModManager.Properties.Resources.Icon; - this.Margin = new System.Windows.Forms.Padding(1); - this.MinimumSize = new System.Drawing.Size(451, 205); - this.Name = "BootstrapperForm"; - this.SizeGripStyle = System.Windows.Forms.SizeGripStyle.Show; - this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen; - this.Text = "Roblox Studio Bootstrapper"; - this.TopMost = true; - this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.BootstrapperForm_FormClosing); - this.FormClosed += new System.Windows.Forms.FormClosedEventHandler(this.BootstrapperForm_FormClosed); - ((System.ComponentModel.ISupportInitialize)(this.logo)).EndInit(); - this.ResumeLayout(false); - this.PerformLayout(); - - } - - #endregion - - private System.Windows.Forms.ProgressBar progressBar; - private System.Windows.Forms.PictureBox logo; - private System.Windows.Forms.Label statusLbl; - private System.Windows.Forms.RichTextBox log; - private System.Windows.Forms.Timer progressTimer; - } -} \ No newline at end of file diff --git a/ProjectSrc/Forms/BootstrapperForm.cs b/ProjectSrc/Forms/BootstrapperForm.cs deleted file mode 100644 index 65bd932..0000000 --- a/ProjectSrc/Forms/BootstrapperForm.cs +++ /dev/null @@ -1,163 +0,0 @@ -using System; -using System.Collections.Concurrent; -using System.Diagnostics.Contracts; -using System.Threading; -using System.Threading.Tasks; -using System.Windows.Forms; - -using RobloxDeployHistory; - -namespace RobloxStudioModManager -{ - public partial class BootstrapperForm : Form - { - public StudioBootstrapper Bootstrapper { get; private set; } - private ConcurrentBag logQueue = new ConcurrentBag(); - private readonly bool exitOnClose = false; - - public BootstrapperForm(StudioBootstrapper bootstrapper, bool exitWhenClosed = false) - { - Contract.Requires(bootstrapper != null); - InitializeComponent(); - - Bootstrapper = bootstrapper; - exitOnClose = exitWhenClosed; - - bootstrapper.EchoFeed += new MessageFeed(echo); - bootstrapper.StatusFeed += new MessageFeed(setStatus); - - Show(); - BringToFront(); - } - - public async Task Bootstrap() - { - var state = Program.State; - var targetVersion = state.TargetVersion; - - progressTimer.Tick += new EventHandler((sender, args) => - { - var progress = Bootstrapper.Progress; - progressBar.Style = Bootstrapper.ProgressBarStyle; - - var maxProgress = Bootstrapper.MaxProgress; - progressBar.Maximum = maxProgress; - - if (progress > maxProgress) - { - progressBar.Value = Math.Max(0, maxProgress - 1); - return; - } - - if (!logQueue.IsEmpty) - { - string blob = string.Join("\n", logQueue) + '\n'; - var newQueue = new ConcurrentBag(); - - Interlocked.Exchange(ref logQueue, newQueue); - log.AppendText(blob); - } - - progressBar.Value = Math.Min(progress, maxProgress); - Refresh(); - }); - - var bootstrap = Bootstrapper.Bootstrap(targetVersion); - await bootstrap.ConfigureAwait(true); - } - - public static async Task BringUpToDate(string expectedVersion, string updateReason) - { - var versionData = Program.State.VersionData; - string currentVersion = versionData.VersionGuid; - - if (currentVersion != expectedVersion) - { - DialogResult check = DialogResult.Yes; - - if (!string.IsNullOrEmpty(currentVersion)) - { - check = MessageBox.Show - ( - "Roblox Studio is out of date!\n" - + updateReason + - "\nWould you like to update now?", - - "Out of date!", - MessageBoxButtons.YesNo, - MessageBoxIcon.Warning - ); - } - - if (check == DialogResult.Yes) - { - var bootstrapper = new StudioBootstrapper(); - - using (var installer = new BootstrapperForm(bootstrapper)) - { - var bootstrap = installer.Bootstrap(); - await bootstrap.ConfigureAwait(true); - } - } - } - } - - private void setStatus(string status) - { - if (statusLbl.InvokeRequired) - { - var action = new Action(setStatus); - statusLbl.Invoke(action, status); - } - else - { - statusLbl.Text = status; - statusLbl.Refresh(); - BringToFront(); - } - } - - private void echo(string msg) - { - logQueue.Add(msg); - } - - private void BootstrapperForm_FormClosed(object sender, FormClosedEventArgs e) - { - Program.SaveState(); - - if (exitOnClose && e.CloseReason == CloseReason.UserClosing) - { - Application.Exit(); - } - } - - private void BootstrapperForm_FormClosing(object sender, FormClosingEventArgs e) - { - if (e.CloseReason != CloseReason.UserClosing) - return; - - DialogResult result = MessageBox.Show - ( - this, - - "The installation has not finished yet!\n" + - "Closing this window will exit the mod manager.\n" + - "Are you sure you want to continue?", - - "Warning", - - MessageBoxButtons.YesNo, - MessageBoxIcon.Warning - ); - - if (result != DialogResult.No) - { - Environment.Exit(0); - return; - } - - e.Cancel = true; - } - } -} diff --git a/ProjectSrc/Forms/FlagCreator.Designer.cs b/ProjectSrc/Forms/FlagCreator.Designer.cs deleted file mode 100644 index 5ca8166..0000000 --- a/ProjectSrc/Forms/FlagCreator.Designer.cs +++ /dev/null @@ -1,170 +0,0 @@ - -namespace RobloxStudioModManager -{ - partial class FlagCreator - { - /// - /// Required designer variable. - /// - private System.ComponentModel.IContainer components = null; - - /// - /// Clean up any resources being used. - /// - /// true if managed resources should be disposed; otherwise, false. - protected override void Dispose(bool disposing) - { - if (disposing && (components != null)) - { - components.Dispose(); - } - base.Dispose(disposing); - } - - #region Windows Form Designer generated code - - /// - /// Required method for Designer support - do not modify - /// the contents of this method with the code editor. - /// - private void InitializeComponent() - { - this.nameLabel = new System.Windows.Forms.Label(); - this.flagName = new System.Windows.Forms.TextBox(); - this.typeLabel = new System.Windows.Forms.Label(); - this.flagType = new System.Windows.Forms.ComboBox(); - this.cancelButton = new System.Windows.Forms.Button(); - this.createButton = new System.Windows.Forms.Button(); - this.flagClass = new System.Windows.Forms.ComboBox(); - this.classLabel = new System.Windows.Forms.Label(); - this.SuspendLayout(); - // - // nameLabel - // - this.nameLabel.AutoSize = true; - this.nameLabel.Font = new System.Drawing.Font("Segoe UI", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.nameLabel.Location = new System.Drawing.Point(12, 8); - this.nameLabel.Name = "nameLabel"; - this.nameLabel.Size = new System.Drawing.Size(63, 25); - this.nameLabel.TabIndex = 0; - this.nameLabel.Text = "Name:"; - // - // flagName - // - this.flagName.Location = new System.Drawing.Point(81, 11); - this.flagName.Name = "flagName"; - this.flagName.Size = new System.Drawing.Size(235, 26); - this.flagName.TabIndex = 1; - // - // typeLabel - // - this.typeLabel.AutoSize = true; - this.typeLabel.Font = new System.Drawing.Font("Segoe UI", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.typeLabel.Location = new System.Drawing.Point(12, 81); - this.typeLabel.Name = "typeLabel"; - this.typeLabel.Size = new System.Drawing.Size(53, 25); - this.typeLabel.TabIndex = 2; - this.typeLabel.Text = "Type:"; - // - // flagType - // - this.flagType.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; - this.flagType.FormattingEnabled = true; - this.flagType.Items.AddRange(new object[] { - "Flag", - "Int", - "Log", - "String"}); - this.flagType.Location = new System.Drawing.Point(81, 84); - this.flagType.Name = "flagType"; - this.flagType.Size = new System.Drawing.Size(235, 28); - this.flagType.TabIndex = 3; - // - // cancelButton - // - this.cancelButton.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left) - | System.Windows.Forms.AnchorStyles.Right))); - this.cancelButton.Location = new System.Drawing.Point(17, 130); - this.cancelButton.Name = "cancelButton"; - this.cancelButton.Size = new System.Drawing.Size(142, 33); - this.cancelButton.TabIndex = 4; - this.cancelButton.Text = "Cancel"; - this.cancelButton.UseVisualStyleBackColor = true; - this.cancelButton.Click += new System.EventHandler(this.cancelButton_Click); - // - // createButton - // - this.createButton.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left) - | System.Windows.Forms.AnchorStyles.Right))); - this.createButton.Location = new System.Drawing.Point(174, 130); - this.createButton.Name = "createButton"; - this.createButton.Size = new System.Drawing.Size(142, 33); - this.createButton.TabIndex = 5; - this.createButton.Text = "Create"; - this.createButton.UseVisualStyleBackColor = true; - this.createButton.Click += new System.EventHandler(this.createButton_Click); - // - // flagClass - // - this.flagClass.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; - this.flagClass.FormattingEnabled = true; - this.flagClass.Items.AddRange(new object[] { - "Fast (F)", - "Dynamic Fast (DF)", - "Synchronized Fast (SF)"}); - this.flagClass.Location = new System.Drawing.Point(81, 47); - this.flagClass.Name = "flagClass"; - this.flagClass.Size = new System.Drawing.Size(235, 28); - this.flagClass.TabIndex = 7; - // - // classLabel - // - this.classLabel.AutoSize = true; - this.classLabel.Font = new System.Drawing.Font("Segoe UI", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.classLabel.Location = new System.Drawing.Point(12, 45); - this.classLabel.Name = "classLabel"; - this.classLabel.Size = new System.Drawing.Size(56, 25); - this.classLabel.TabIndex = 6; - this.classLabel.Text = "Class:"; - // - // FlagCreator - // - this.AcceptButton = this.createButton; - this.AutoScaleDimensions = new System.Drawing.SizeF(144F, 144F); - this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi; - this.ClientSize = new System.Drawing.Size(331, 176); - this.Controls.Add(this.flagClass); - this.Controls.Add(this.classLabel); - this.Controls.Add(this.createButton); - this.Controls.Add(this.cancelButton); - this.Controls.Add(this.flagType); - this.Controls.Add(this.typeLabel); - this.Controls.Add(this.flagName); - this.Controls.Add(this.nameLabel); - this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog; - this.Margin = new System.Windows.Forms.Padding(4); - this.MaximizeBox = false; - this.MinimizeBox = false; - this.Name = "FlagCreator"; - this.ShowIcon = false; - this.ShowInTaskbar = false; - this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen; - this.Text = "Add Custom Flag"; - this.TopMost = true; - this.ResumeLayout(false); - this.PerformLayout(); - - } - - #endregion - - private System.Windows.Forms.Label nameLabel; - private System.Windows.Forms.TextBox flagName; - private System.Windows.Forms.Label typeLabel; - private System.Windows.Forms.ComboBox flagType; - private System.Windows.Forms.Button cancelButton; - private System.Windows.Forms.Button createButton; - private System.Windows.Forms.ComboBox flagClass; - private System.Windows.Forms.Label classLabel; - } -} \ No newline at end of file diff --git a/ProjectSrc/Forms/FlagCreator.cs b/ProjectSrc/Forms/FlagCreator.cs deleted file mode 100644 index d57e41d..0000000 --- a/ProjectSrc/Forms/FlagCreator.cs +++ /dev/null @@ -1,54 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text.RegularExpressions; -using System.Windows.Forms; - -namespace RobloxStudioModManager -{ - public partial class FlagCreator : Form - { - public CustomFlag Result { get; private set; } - private static readonly string[] classes = new string[3] { "F", "DF", "SF" }; - - public FlagCreator() - { - InitializeComponent(); - flagType.SelectedIndex = 0; - flagClass.SelectedIndex = 0; - } - - private void createButton_Click(object sender, EventArgs e) - { - string classType = classes[flagClass.SelectedIndex]; - string type = classType + flagType.SelectedItem.ToString(); - string name = Regex.Replace(flagName.Text, "[^A-z0-9_]", ""); - - if (flagName.Text != name) - flagName.Text = name; - - if (string.IsNullOrEmpty(name)) - { - MessageBox.Show - ( - $"Please enter a name for the {type}!", - "Invalid submission!", - - MessageBoxButtons.OK, - MessageBoxIcon.Error - ); - - return; - } - - Result = new CustomFlag(type, name); - DialogResult = DialogResult.OK; - - Close(); - } - - private void cancelButton_Click(object sender, EventArgs e) - { - Close(); - } - } -} diff --git a/ProjectSrc/Forms/FlagEditor.Designer.cs b/ProjectSrc/Forms/FlagEditor.Designer.cs deleted file mode 100644 index 630aaad..0000000 --- a/ProjectSrc/Forms/FlagEditor.Designer.cs +++ /dev/null @@ -1,347 +0,0 @@ -namespace RobloxStudioModManager -{ - partial class FlagEditor - { - /// - /// Required designer variable. - /// - private System.ComponentModel.IContainer components = null; - - - #region Windows Form Designer generated code - - /// - /// Required method for Designer support - do not modify - /// the contents of this method with the code editor. - /// - private void InitializeComponent() - { - this.components = new System.ComponentModel.Container(); - System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle1 = new System.Windows.Forms.DataGridViewCellStyle(); - System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(FlagEditor)); - this.tabs = new System.Windows.Forms.TabControl(); - this.viewFlagsTab = new System.Windows.Forms.TabPage(); - this.addCustom = new System.Windows.Forms.Button(); - this.overrideStatus = new System.Windows.Forms.Label(); - this.overrideSelected = new System.Windows.Forms.Button(); - this.flagSearchFilter = new System.Windows.Forms.TextBox(); - this.searchTitle = new System.Windows.Forms.Label(); - this.flagDataGridView = new System.Windows.Forms.DataGridView(); - this.nameColumn = new System.Windows.Forms.DataGridViewTextBoxColumn(); - this.typeColumn = new System.Windows.Forms.DataGridViewTextBoxColumn(); - this.valueColumn = new System.Windows.Forms.DataGridViewTextBoxColumn(); - this.overridesTab = new System.Windows.Forms.TabPage(); - this.removeAll = new System.Windows.Forms.Button(); - this.removeSelected = new System.Windows.Forms.Button(); - this.overrideDataGridView = new System.Windows.Forms.DataGridView(); - this.overrideNameColumn = new System.Windows.Forms.DataGridViewTextBoxColumn(); - this.overrideTypeColumn = new System.Windows.Forms.DataGridViewTextBoxColumn(); - this.initialOverrideValueColumn = new System.Windows.Forms.DataGridViewTextBoxColumn(); - this.notification = new System.Windows.Forms.NotifyIcon(this.components); - this.tabs.SuspendLayout(); - this.viewFlagsTab.SuspendLayout(); - ((System.ComponentModel.ISupportInitialize)(this.flagDataGridView)).BeginInit(); - this.overridesTab.SuspendLayout(); - ((System.ComponentModel.ISupportInitialize)(this.overrideDataGridView)).BeginInit(); - this.SuspendLayout(); - // - // tabs - // - this.tabs.Controls.Add(this.viewFlagsTab); - this.tabs.Controls.Add(this.overridesTab); - this.tabs.Dock = System.Windows.Forms.DockStyle.Fill; - this.tabs.Location = new System.Drawing.Point(0, 0); - this.tabs.Margin = new System.Windows.Forms.Padding(3, 4, 3, 4); - this.tabs.Name = "tabs"; - this.tabs.SelectedIndex = 0; - this.tabs.Size = new System.Drawing.Size(513, 563); - this.tabs.TabIndex = 0; - // - // viewFlagsTab - // - this.viewFlagsTab.Controls.Add(this.addCustom); - this.viewFlagsTab.Controls.Add(this.overrideStatus); - this.viewFlagsTab.Controls.Add(this.overrideSelected); - this.viewFlagsTab.Controls.Add(this.flagSearchFilter); - this.viewFlagsTab.Controls.Add(this.searchTitle); - this.viewFlagsTab.Controls.Add(this.flagDataGridView); - this.viewFlagsTab.Location = new System.Drawing.Point(4, 22); - this.viewFlagsTab.Margin = new System.Windows.Forms.Padding(3, 4, 3, 4); - this.viewFlagsTab.Name = "viewFlagsTab"; - this.viewFlagsTab.Padding = new System.Windows.Forms.Padding(3, 4, 3, 4); - this.viewFlagsTab.Size = new System.Drawing.Size(505, 537); - this.viewFlagsTab.TabIndex = 0; - this.viewFlagsTab.Text = "View Flags"; - this.viewFlagsTab.UseVisualStyleBackColor = true; - // - // addCustom - // - this.addCustom.Location = new System.Drawing.Point(201, 37); - this.addCustom.Margin = new System.Windows.Forms.Padding(3, 4, 3, 4); - this.addCustom.Name = "addCustom"; - this.addCustom.Size = new System.Drawing.Size(130, 20); - this.addCustom.TabIndex = 5; - this.addCustom.Text = "Add Custom"; - this.addCustom.UseVisualStyleBackColor = true; - this.addCustom.Click += new System.EventHandler(this.addCustom_Click); - // - // overrideStatus - // - this.overrideStatus.AutoSize = true; - this.overrideStatus.Location = new System.Drawing.Point(62, 66); - this.overrideStatus.Name = "overrideStatus"; - this.overrideStatus.Size = new System.Drawing.Size(0, 13); - this.overrideStatus.TabIndex = 4; - // - // overrideSelected - // - this.overrideSelected.Location = new System.Drawing.Point(65, 37); - this.overrideSelected.Margin = new System.Windows.Forms.Padding(3, 4, 3, 4); - this.overrideSelected.Name = "overrideSelected"; - this.overrideSelected.Size = new System.Drawing.Size(130, 20); - this.overrideSelected.TabIndex = 3; - this.overrideSelected.Text = "Override Selected"; - this.overrideSelected.UseVisualStyleBackColor = true; - this.overrideSelected.Click += new System.EventHandler(this.overrideSelected_Click); - // - // flagSearchFilter - // - this.flagSearchFilter.AutoCompleteMode = System.Windows.Forms.AutoCompleteMode.Suggest; - this.flagSearchFilter.AutoCompleteSource = System.Windows.Forms.AutoCompleteSource.CustomSource; - this.flagSearchFilter.Location = new System.Drawing.Point(65, 13); - this.flagSearchFilter.Margin = new System.Windows.Forms.Padding(1, 4, 3, 4); - this.flagSearchFilter.Name = "flagSearchFilter"; - this.flagSearchFilter.Size = new System.Drawing.Size(429, 20); - this.flagSearchFilter.TabIndex = 2; - this.flagSearchFilter.TextChanged += new System.EventHandler(this.flagSearchFilter_TextChanged); - // - // searchTitle - // - this.searchTitle.AutoSize = true; - this.searchTitle.Font = new System.Drawing.Font("Segoe UI Semilight", 11F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.searchTitle.Location = new System.Drawing.Point(7, 10); - this.searchTitle.Margin = new System.Windows.Forms.Padding(1, 0, 1, 0); - this.searchTitle.Name = "searchTitle"; - this.searchTitle.Size = new System.Drawing.Size(56, 20); - this.searchTitle.TabIndex = 1; - this.searchTitle.Text = "Search:"; - // - // flagDataGridView - // - this.flagDataGridView.AllowUserToAddRows = false; - this.flagDataGridView.AllowUserToDeleteRows = false; - this.flagDataGridView.AllowUserToResizeColumns = false; - this.flagDataGridView.AllowUserToResizeRows = false; - this.flagDataGridView.AutoSizeRowsMode = System.Windows.Forms.DataGridViewAutoSizeRowsMode.DisplayedCells; - this.flagDataGridView.BackgroundColor = System.Drawing.SystemColors.Control; - this.flagDataGridView.BorderStyle = System.Windows.Forms.BorderStyle.None; - this.flagDataGridView.ColumnHeadersHeightSizeMode = System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.AutoSize; - this.flagDataGridView.Columns.AddRange(new System.Windows.Forms.DataGridViewColumn[] { - this.nameColumn, - this.typeColumn, - this.valueColumn}); - this.flagDataGridView.Dock = System.Windows.Forms.DockStyle.Bottom; - this.flagDataGridView.EditMode = System.Windows.Forms.DataGridViewEditMode.EditProgrammatically; - this.flagDataGridView.Location = new System.Drawing.Point(3, 83); - this.flagDataGridView.Margin = new System.Windows.Forms.Padding(3, 4, 3, 4); - this.flagDataGridView.MultiSelect = false; - this.flagDataGridView.Name = "flagDataGridView"; - this.flagDataGridView.RowHeadersVisible = false; - this.flagDataGridView.RowHeadersWidthSizeMode = System.Windows.Forms.DataGridViewRowHeadersWidthSizeMode.DisableResizing; - this.flagDataGridView.RowTemplate.Resizable = System.Windows.Forms.DataGridViewTriState.False; - this.flagDataGridView.ScrollBars = System.Windows.Forms.ScrollBars.Vertical; - this.flagDataGridView.SelectionMode = System.Windows.Forms.DataGridViewSelectionMode.FullRowSelect; - this.flagDataGridView.Size = new System.Drawing.Size(499, 450); - this.flagDataGridView.TabIndex = 0; - this.flagDataGridView.VirtualMode = true; - this.flagDataGridView.CellFormatting += new System.Windows.Forms.DataGridViewCellFormattingEventHandler(this.flagDataGridView_CellFormatting); - this.flagDataGridView.CellMouseClick += new System.Windows.Forms.DataGridViewCellMouseEventHandler(this.flagDataGridView_CellMouseClick); - this.flagDataGridView.CellValueNeeded += new System.Windows.Forms.DataGridViewCellValueEventHandler(this.flagDataGridView_CellValueNeeded); - // - // nameColumn - // - this.nameColumn.AutoSizeMode = System.Windows.Forms.DataGridViewAutoSizeColumnMode.None; - this.nameColumn.FillWeight = 250F; - this.nameColumn.HeaderText = "Name"; - this.nameColumn.MinimumWidth = 8; - this.nameColumn.Name = "nameColumn"; - this.nameColumn.ReadOnly = true; - this.nameColumn.Resizable = System.Windows.Forms.DataGridViewTriState.False; - this.nameColumn.SortMode = System.Windows.Forms.DataGridViewColumnSortMode.NotSortable; - this.nameColumn.Width = 278; - // - // typeColumn - // - this.typeColumn.AutoSizeMode = System.Windows.Forms.DataGridViewAutoSizeColumnMode.None; - this.typeColumn.FillWeight = 50F; - this.typeColumn.HeaderText = "Type"; - this.typeColumn.MinimumWidth = 8; - this.typeColumn.Name = "typeColumn"; - this.typeColumn.ReadOnly = true; - this.typeColumn.Resizable = System.Windows.Forms.DataGridViewTriState.False; - this.typeColumn.SortMode = System.Windows.Forms.DataGridViewColumnSortMode.NotSortable; - this.typeColumn.Width = 55; - // - // valueColumn - // - this.valueColumn.AutoSizeMode = System.Windows.Forms.DataGridViewAutoSizeColumnMode.None; - this.valueColumn.FillWeight = 150F; - this.valueColumn.HeaderText = "Value"; - this.valueColumn.MinimumWidth = 8; - this.valueColumn.Name = "valueColumn"; - this.valueColumn.ReadOnly = true; - this.valueColumn.SortMode = System.Windows.Forms.DataGridViewColumnSortMode.NotSortable; - this.valueColumn.Width = 165; - // - // overridesTab - // - this.overridesTab.Controls.Add(this.removeAll); - this.overridesTab.Controls.Add(this.removeSelected); - this.overridesTab.Controls.Add(this.overrideDataGridView); - this.overridesTab.Location = new System.Drawing.Point(4, 22); - this.overridesTab.Margin = new System.Windows.Forms.Padding(3, 4, 3, 4); - this.overridesTab.Name = "overridesTab"; - this.overridesTab.Padding = new System.Windows.Forms.Padding(3, 4, 3, 4); - this.overridesTab.Size = new System.Drawing.Size(505, 537); - this.overridesTab.TabIndex = 1; - this.overridesTab.Text = "Overrides"; - this.overridesTab.UseVisualStyleBackColor = true; - // - // removeAll - // - this.removeAll.Location = new System.Drawing.Point(255, 8); - this.removeAll.Margin = new System.Windows.Forms.Padding(3, 4, 3, 4); - this.removeAll.Name = "removeAll"; - this.removeAll.Size = new System.Drawing.Size(241, 29); - this.removeAll.TabIndex = 3; - this.removeAll.Text = "Remove All"; - this.removeAll.UseVisualStyleBackColor = true; - this.removeAll.Click += new System.EventHandler(this.removeAll_Click); - // - // removeSelected - // - this.removeSelected.Location = new System.Drawing.Point(7, 8); - this.removeSelected.Margin = new System.Windows.Forms.Padding(3, 4, 3, 4); - this.removeSelected.Name = "removeSelected"; - this.removeSelected.Size = new System.Drawing.Size(241, 29); - this.removeSelected.TabIndex = 2; - this.removeSelected.Text = "Remove Selected"; - this.removeSelected.UseVisualStyleBackColor = true; - this.removeSelected.Click += new System.EventHandler(this.removeSelected_Click); - // - // overrideDataGridView - // - this.overrideDataGridView.AllowUserToAddRows = false; - this.overrideDataGridView.AllowUserToDeleteRows = false; - this.overrideDataGridView.AllowUserToResizeColumns = false; - this.overrideDataGridView.AllowUserToResizeRows = false; - this.overrideDataGridView.BackgroundColor = System.Drawing.SystemColors.Control; - this.overrideDataGridView.BorderStyle = System.Windows.Forms.BorderStyle.None; - this.overrideDataGridView.ColumnHeadersHeightSizeMode = System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.AutoSize; - this.overrideDataGridView.Columns.AddRange(new System.Windows.Forms.DataGridViewColumn[] { - this.overrideNameColumn, - this.overrideTypeColumn, - this.initialOverrideValueColumn}); - this.overrideDataGridView.Dock = System.Windows.Forms.DockStyle.Bottom; - this.overrideDataGridView.EditMode = System.Windows.Forms.DataGridViewEditMode.EditOnEnter; - this.overrideDataGridView.Location = new System.Drawing.Point(3, 42); - this.overrideDataGridView.Margin = new System.Windows.Forms.Padding(3, 4, 3, 4); - this.overrideDataGridView.MultiSelect = false; - this.overrideDataGridView.Name = "overrideDataGridView"; - this.overrideDataGridView.RowHeadersVisible = false; - this.overrideDataGridView.RowHeadersWidthSizeMode = System.Windows.Forms.DataGridViewRowHeadersWidthSizeMode.AutoSizeToAllHeaders; - dataGridViewCellStyle1.BackColor = System.Drawing.Color.Silver; - this.overrideDataGridView.RowsDefaultCellStyle = dataGridViewCellStyle1; - this.overrideDataGridView.RowTemplate.DefaultCellStyle.BackColor = System.Drawing.Color.White; - this.overrideDataGridView.ScrollBars = System.Windows.Forms.ScrollBars.Vertical; - this.overrideDataGridView.SelectionMode = System.Windows.Forms.DataGridViewSelectionMode.FullRowSelect; - this.overrideDataGridView.Size = new System.Drawing.Size(499, 491); - this.overrideDataGridView.TabIndex = 1; - this.overrideDataGridView.CellEndEdit += new System.Windows.Forms.DataGridViewCellEventHandler(this.overrideDataGridView_CellEndEdit); - this.overrideDataGridView.CellMouseEnter += new System.Windows.Forms.DataGridViewCellEventHandler(this.overrideDataGridView_CellMouseEnter); - this.overrideDataGridView.CellMouseLeave += new System.Windows.Forms.DataGridViewCellEventHandler(this.overrideDataGridView_CellMouseLeave); - // - // overrideNameColumn - // - this.overrideNameColumn.AutoSizeMode = System.Windows.Forms.DataGridViewAutoSizeColumnMode.Fill; - this.overrideNameColumn.DataPropertyName = "Name"; - this.overrideNameColumn.FillWeight = 150F; - this.overrideNameColumn.HeaderText = "Name"; - this.overrideNameColumn.MinimumWidth = 8; - this.overrideNameColumn.Name = "overrideNameColumn"; - this.overrideNameColumn.ReadOnly = true; - this.overrideNameColumn.SortMode = System.Windows.Forms.DataGridViewColumnSortMode.NotSortable; - // - // overrideTypeColumn - // - this.overrideTypeColumn.AutoSizeMode = System.Windows.Forms.DataGridViewAutoSizeColumnMode.Fill; - this.overrideTypeColumn.DataPropertyName = "Type"; - this.overrideTypeColumn.FillWeight = 40F; - this.overrideTypeColumn.HeaderText = "Type"; - this.overrideTypeColumn.MinimumWidth = 8; - this.overrideTypeColumn.Name = "overrideTypeColumn"; - this.overrideTypeColumn.ReadOnly = true; - this.overrideTypeColumn.SortMode = System.Windows.Forms.DataGridViewColumnSortMode.NotSortable; - // - // initialOverrideValueColumn - // - this.initialOverrideValueColumn.AutoSizeMode = System.Windows.Forms.DataGridViewAutoSizeColumnMode.Fill; - this.initialOverrideValueColumn.DataPropertyName = "Value"; - this.initialOverrideValueColumn.HeaderText = "Value"; - this.initialOverrideValueColumn.MinimumWidth = 8; - this.initialOverrideValueColumn.Name = "initialOverrideValueColumn"; - this.initialOverrideValueColumn.SortMode = System.Windows.Forms.DataGridViewColumnSortMode.NotSortable; - // - // notification - // - this.notification.Icon = global::RobloxStudioModManager.Properties.Resources.Icon; - this.notification.Text = "notification"; - this.notification.Visible = true; - // - // FlagEditor - // - this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F); - this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi; - this.ClientSize = new System.Drawing.Size(513, 563); - this.Controls.Add(this.tabs); - this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog; - this.Icon = global::RobloxStudioModManager.Properties.Resources.Icon; - this.Margin = new System.Windows.Forms.Padding(3, 4, 3, 4); - this.MaximizeBox = false; - this.Name = "FlagEditor"; - this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen; - this.Text = "Flag Editor"; - this.Load += new System.EventHandler(this.FlagEditor_Load); - this.tabs.ResumeLayout(false); - this.viewFlagsTab.ResumeLayout(false); - this.viewFlagsTab.PerformLayout(); - ((System.ComponentModel.ISupportInitialize)(this.flagDataGridView)).EndInit(); - this.overridesTab.ResumeLayout(false); - ((System.ComponentModel.ISupportInitialize)(this.overrideDataGridView)).EndInit(); - this.ResumeLayout(false); - - } - - #endregion - - private System.Windows.Forms.TabControl tabs; - private System.Windows.Forms.TabPage viewFlagsTab; - private System.Windows.Forms.TabPage overridesTab; - private System.Windows.Forms.DataGridView flagDataGridView; - private System.Windows.Forms.TextBox flagSearchFilter; - private System.Windows.Forms.Label searchTitle; - private System.Windows.Forms.Button overrideSelected; - private System.Windows.Forms.DataGridView overrideDataGridView; - private System.Windows.Forms.Label overrideStatus; - private System.Windows.Forms.Button removeAll; - private System.Windows.Forms.Button removeSelected; - private System.Windows.Forms.DataGridViewTextBoxColumn overrideNameColumn; - private System.Windows.Forms.DataGridViewTextBoxColumn overrideTypeColumn; - private System.Windows.Forms.DataGridViewTextBoxColumn initialOverrideValueColumn; - private System.Windows.Forms.Button addCustom; - private System.Windows.Forms.DataGridViewTextBoxColumn nameColumn; - private System.Windows.Forms.DataGridViewTextBoxColumn typeColumn; - private System.Windows.Forms.DataGridViewTextBoxColumn valueColumn; - private System.Windows.Forms.NotifyIcon notification; - } -} \ No newline at end of file diff --git a/ProjectSrc/Forms/FlagEditor.cs b/ProjectSrc/Forms/FlagEditor.cs deleted file mode 100644 index 6990eb6..0000000 --- a/ProjectSrc/Forms/FlagEditor.cs +++ /dev/null @@ -1,677 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Data; -using System.Diagnostics; -using System.Drawing; -using System.IO; -using System.Linq; -using System.Net; -using System.Reflection; -using System.Threading.Tasks; -using System.Windows.Forms; - -using Newtonsoft.Json; -using Newtonsoft.Json.Linq; - -namespace RobloxStudioModManager -{ - public partial class FlagEditor : Form - { - internal class ClientSettings - { - public Dictionary ApplicationSettings = null; - } - - private static VersionManifest versionRegistry => Program.State.VersionData; - private static SortedDictionary flagRegistry => Program.State.FlagEditor; - - private DataTable overrideTable; - private readonly Dictionary overrideRowLookup = new Dictionary(); - - private static readonly IReadOnlyDictionary flagTypes = new Dictionary() - { - {"Flag", "false"}, - {"Int", "0"}, - {"String", " "}, - {"Log", "0"}, - }; - - private const string OVERRIDE_STATUS_OFF = "No local overrides were found on load."; - private const string OVERRIDE_STATUS_ON = "Values highlighted in red were overridden locally."; - - private List flags = new List(); - private List allFlags = new List(); - - private static FVariable lastCustomFlag = null; - private readonly Dictionary flagLookup = new Dictionary(); - private string currentSearch = ""; - - public FlagEditor() - { - InitializeComponent(); - - overrideStatus.Text = OVERRIDE_STATUS_OFF; - overrideStatus.Visible = false; - - overrideStatus.Refresh(); - } - - protected override void Dispose(bool disposing) - { - if (disposing) - { - components?.Dispose(); - overrideTable?.Dispose(); - Program.SaveState(); - } - - base.Dispose(disposing); - } - - private bool confirm(string header, string message) - { - DialogResult result = MessageBox.Show(message, header, MessageBoxButtons.YesNo, MessageBoxIcon.Warning); - return result == DialogResult.Yes; - } - - private static void applyRowColor(DataGridViewRow row, Color color) - { - foreach (DataGridViewCell cell in row.Cells) - { - cell.Style.BackColor = color; - } - } - - private static string getFlagKeyByRow(DataGridViewRow row) - { - var cells = row.Cells; - - string name = cells[0].Value as string; - string type = cells[1].Value as string; - - return type + name; - } - - private bool rowMatchesSelectedRow(DataGridViewRow row) - { - FVariable selectedFlag = lastCustomFlag; - - if (selectedFlag == null && flagDataGridView.SelectedRows.Count == 1) - { - DataGridViewRow selectedRow = flagDataGridView.SelectedRows[0]; - selectedFlag = flags[selectedRow.Index]; - } - - return selectedFlag?.Key == getFlagKeyByRow(row); - } - - private void addFlagOverride(FVariable flag, bool init = false) - { - string key = flag.Key; - - if (!overrideRowLookup.ContainsKey(key)) - { - if (!init && flag.Type.EndsWith("Flag", Program.StringFormat)) - { - if (bool.TryParse(flag.Value, out bool value)) - { - string str = (!value) - .ToString(Program.Format) - .ToLower(Program.Format); - - flag.SetValue(str); - } - } - - DataRow row = overrideTable.Rows.Add - ( - flag.Name, - flag.Type, - flag.Value.ToLower(Program.Format) - ); - - overrideRowLookup.Add(key, row); - } - - overrideStatus.Text = OVERRIDE_STATUS_ON; - overrideStatus.ForeColor = Color.Red; - - if (!init) - { - // Find the row that corresponds to the flag we added. - var query = overrideDataGridView.Rows - .Cast() - .Where(rowMatchesSelectedRow); - - if (query.Any()) - { - // Select it. - var overrideRow = query.First(); - overrideDataGridView.CurrentCell = overrideRow.Cells[0]; - } - - // Clear last custom flag. - lastCustomFlag = null; - - // Switch to the overrides tab. - tabs.SelectedTab = overridesTab; - - // Record this flag in the registry. - flagRegistry[key] = flag; - } - } - - private void refreshFlags() - { - if (allFlags == null) - return; - - string search = flagSearchFilter.Text.ToLowerInvariant(); - - flags = allFlags - .Where(flag => flag.Name.ToLowerInvariant().Contains(search)) - .OrderBy(flag => flag.Name) - .ToList(); - - flagLookup.Clear(); - - for (int i = 0; i < flags.Count; i++) - { - FVariable flag = flags[i]; - flagLookup[flag.Key] = i; - flag.Dirty = true; - } - - // Start populating flag browser rows. - var currentCount = flagDataGridView.RowCount; - - if (currentCount == 0) - { - flagDataGridView.Rows.Add(); - currentCount = 1; - } - - var diff = flags.Count - currentCount; - flagDataGridView.SuspendLayout(); - - if (diff > 0) - flagDataGridView.Rows.AddCopies(0, diff); - else if (diff < 0) - flagDataGridView.RowCount += diff; - - flagDataGridView.ResumeLayout(); - } - - private async void InitializeEditor() - { - var flagNames = new HashSet(); - var studioPath = StudioBootstrapper.GetStudioPath(); - - var studioDir = StudioBootstrapper.GetStudioDirectory(); - var extraContentDir = Path.Combine(studioDir, "ExtraContent"); - - string lastFlagScanVersion = versionRegistry.LastFlagScanVersion; - string versionGuid = versionRegistry.VersionGuid; - - var cppFlags = StudioFFlagDumper.DumpCppFlags(studioPath); - var flagDump = Path.Combine(studioDir, "FFlags.json"); - var flagInfo = new FileInfo(flagDump); - - if (lastFlagScanVersion != versionGuid || !flagInfo.Exists) - { - cppFlags.ForEach(flag => flagNames.Add(flag)); - - var newJson = JsonConvert.SerializeObject(flagNames); - File.WriteAllText(flagDump, newJson); - - versionRegistry.LastFlagScanVersion = versionGuid; - Program.SaveState(); - } - - var rawFlagNames = File.ReadAllText(flagDump); - var cachedFlagNames = JsonConvert.DeserializeObject(rawFlagNames); - - foreach (var name in cachedFlagNames) - flagNames.Add(name); - - // Initialize flag browser - var json = new Dictionary(); - - using (var http = new WebClient()) - { - var settings = await http.DownloadStringTaskAsync("https://clientsettingscdn.roblox.com/v2/settings/application/PCDesktopClient"); - var data = JsonConvert.DeserializeObject(settings); - - foreach (var pair in data.ApplicationSettings) - { - string key = pair.Key; - - if (key.EndsWith("_PlaceFilter")) - continue; - - json.Add(key, pair.Value); - } - } - - foreach (var key in flagNames) - { - if (!json.ContainsKey(key)) - { - string flagClass = ""; - - if (key.StartsWith("SF")) - flagClass = "SF"; - else if (key.StartsWith("DF")) - flagClass = "DF"; - else if (key.StartsWith("F")) - flagClass = "F"; - - if (flagClass != "") - { - var prefix = key.Substring(flagClass.Length); - - foreach (var pair in flagTypes) - { - if (prefix.StartsWith(pair.Key)) - { - json.Add(key, pair.Value); - break; - } - } - } - else - { - json.Add(key, "??"); - } - } - } - - int numFlags = json.Count; - var flagSetup = new List(numFlags); - - foreach (string customFlag in flagNames) - { - if (!json.ContainsKey(customFlag)) - { - if (!flagRegistry.TryGetValue(customFlag, out var flag)) - continue; - - if (!flag.Custom) - continue; - - flagSetup.Add(flag); - } - } - - foreach (var pair in json) - { - string key = pair.Key, - value = pair.Value; - - if (!flagRegistry.TryGetValue(key, out var flag)) - flag = new FVariable(key, value); - - if (flag.Type == "") - continue; - - flagSetup.Add(flag); - } - - allFlags = flagSetup - .OrderBy(flag => flag.Key) - .ToList(); - - var propInfo = typeof(DataGridView).GetProperty("DoubleBuffered", BindingFlags.Instance | BindingFlags.NonPublic); - propInfo.SetValue(flagDataGridView, true, null); - refreshFlags(); - - // Initialize override table. - overrideTable = new DataTable(); - - foreach (DataGridViewColumn column in overrideDataGridView.Columns) - overrideTable.Columns.Add(column.DataPropertyName); - - var overrideView = new DataView(overrideTable) { Sort = "Name" }; - - foreach (var flagName in flagRegistry.Keys) - { - var flag = flagRegistry[flagName]; - addFlagOverride(flag, true); - } - - overrideStatus.Visible = true; - overrideDataGridView.DataSource = overrideView; - } - - private async void FlagEditor_Load(object sender, EventArgs e) - { - Enabled = false; - UseWaitCursor = true; - - TopMost = true; - BringToFront(); - - Refresh(); - - var init = Task.Run(() => - { - var initializer = new Action(InitializeEditor); - Invoke(initializer); - }); - - await init.ConfigureAwait(true); - - Enabled = true; - UseWaitCursor = false; - } - - private void flagDataGridView_CellValueNeeded(object sender, DataGridViewCellValueEventArgs e) - { - int row = e.RowIndex; - int col = e.ColumnIndex; - - if (flags.Count == 0) - { - e.Value = ""; - return; - } - - FVariable flag = flags[row]; - string value = "?"; - - if (col == 0) - value = flag.Name; - else if (col == 1) - value = flag.Type; - else if (col == 2) - value = flag.Value; - - e.Value = value; - } - - private void overrideSelected_Click(object sender, EventArgs e) - { - if (flagDataGridView.SelectedRows.Count == 1) - { - var selectedRow = flagDataGridView.SelectedRows[0]; - FVariable selectedFlag = flags[selectedRow.Index]; - addFlagOverride(selectedFlag); - } - } - - private void removeSelected_Click(object sender, EventArgs e) - { - var selectedRows = overrideDataGridView.SelectedRows; - - if (selectedRows.Count > 0) - { - var selectedRow = selectedRows[0]; - string flagKey = getFlagKeyByRow(selectedRow); - - FVariable flag = flagRegistry[flagKey]; - flag.Clear(); - - if (overrideRowLookup.ContainsKey(flagKey)) - { - DataRow rowToDelete = overrideRowLookup[flagKey]; - overrideRowLookup.Remove(flagKey); - rowToDelete.Delete(); - } - - selectedRow.Visible = false; - selectedRow.Dispose(); - - flagRegistry.Remove(flagKey); - } - - if (overrideDataGridView.Rows.Count == 0) - { - overrideStatus.Text = OVERRIDE_STATUS_OFF; - overrideStatus.ForeColor = Color.Black; - } - } - - private void removeAll_Click(object sender, EventArgs e) - { - bool doRemove = confirm("Confirmation", "Are you sure you would like to remove all flag overrides?\nThis will also delete any custom flags!"); - - if (doRemove) - { - var flagNames = flagRegistry.Keys.ToList(); - - foreach (string flagName in flagNames) - { - var flag = flagRegistry[flagName]; - flag.Clear(); - - flagRegistry.Remove(flagName); - } - - overrideStatus.Text = OVERRIDE_STATUS_OFF; - overrideStatus.ForeColor = Color.Black; - - overrideTable.Rows.Clear(); - overrideRowLookup.Clear(); - } - } - - private void overrideDataGridView_CellEndEdit(object sender, DataGridViewCellEventArgs e) - { - DataGridViewRow row = overrideDataGridView.Rows[e.RowIndex]; - string flagKey = getFlagKeyByRow(row); - - DataGridViewCell cell = row.Cells[e.ColumnIndex]; - string value = cell.Value as string; - - var cells = row.Cells; - var flagType = cells[1].Value as string; - - // Check if this input should be cancelled. - var format = Program.StringFormat; - bool badInput = false; - - if (flagType.EndsWith("Flag", format)) - { - string test = value - .ToUpperInvariant() - .Trim(); - - badInput = (test != "FALSE" && test != "TRUE"); - } - else if (flagType.EndsWith("Int", format)) - { - badInput = !int.TryParse(value, out int _); - } - - if (flagLookup.ContainsKey(flagKey)) - { - int index = flagLookup[flagKey]; - FVariable flag = flags[index]; - - if (!badInput) - { - flag.SetValue(value); - return; - } - - // If we have bad input, reset the value to the original value. - cell.Value = flag.Reset; - } - } - - private void flagSearchFilter_TextChanged(object sender, EventArgs e) - { - if (flagSearchFilter.Text != currentSearch) - { - currentSearch = flagSearchFilter.Text; - flagDataGridView.RowCount = 0; - refreshFlags(); - } - } - - private void overrideDataGridView_CellMouseEnter(object sender, DataGridViewCellEventArgs e) - { - if (e.ColumnIndex == 2 && e.RowIndex >= 0) - { - DataGridViewRow row = overrideDataGridView.Rows[e.RowIndex]; - var cells = row.Cells; - - var valueCell = cells[2]; - Type cellType = valueCell.GetType(); - - string flagType = cells[1].Value as string; - - if (flagType.EndsWith("Flag", Program.StringFormat) && cellType != typeof(DataGridViewComboBoxCell)) - { - // Switch the cell to a combo box. - // The user needs to select either true or false. - var newValueCell = new DataGridViewComboBoxCell(); - newValueCell.Items.Add("true"); - newValueCell.Items.Add("false"); - - newValueCell.Value = valueCell.Value - .ToString() - .ToLower(Program.Format); - - row.Cells[2] = newValueCell; - newValueCell.ReadOnly = false; - } - } - } - - private void overrideDataGridView_CellMouseLeave(object sender, DataGridViewCellEventArgs e) - { - if (e.ColumnIndex == 2 && e.RowIndex >= 0) - { - DataGridViewRow row = overrideDataGridView.Rows[e.RowIndex]; - var cells = row.Cells; - - var valueCell = cells[2]; - Type cellType = valueCell.GetType(); - - string flagType = cells[1].Value as string; - - if (flagType.EndsWith("Flag", Program.StringFormat) && cellType != typeof(DataGridViewTextBoxCell)) - { - string value = valueCell.Value.ToString(); - var newValueCell = new DataGridViewTextBoxCell() { Value = value }; - - row.Cells[2] = newValueCell; - newValueCell.ReadOnly = true; - } - } - } - - private void flagDataGridView_CellFormatting(object sender, DataGridViewCellFormattingEventArgs e) - { - int index = e.RowIndex; - var row = flagDataGridView.Rows[index]; - - if (flags.Count == 0) - { - applyRowColor(row, Color.White); - return; - } - - FVariable flag = flags[index]; - - if (flag.Dirty) - { - if (flagRegistry.ContainsKey(flag.Key)) - { - var valueCell = row.Cells[2]; - valueCell.Value = flag.Value; - applyRowColor(row, Color.Pink); - } - else - { - applyRowColor(row, Color.White); - } - - flag.Dirty = false; - } - } - - public static void ApplyFlags() - { - var json = new JObject(); - - foreach (string flagName in flagRegistry.Keys) - { - var flag = flagRegistry[flagName]; - string value = flag.Value; - - var token = JToken.FromObject(value); - json.Add(flagName, token); - }; - - string file = json.ToString(); - string studioDir = StudioBootstrapper.GetStudioDirectory(); - string localAppData = Environment.GetEnvironmentVariable("LocalAppData"); - - string clientSettings_DEPRECATED = Path.Combine(studioDir, "ClientSettings"); - Directory.CreateDirectory(clientSettings_DEPRECATED); - - string filePath_DEPRECATED = Path.Combine(clientSettings_DEPRECATED, "ClientAppSettings.json"); - File.WriteAllText(filePath_DEPRECATED, file); - - string clientSettings_NEW = Path.Combine(localAppData, "Roblox", "ClientSettings"); - Directory.CreateDirectory(clientSettings_NEW); - - string filePath_NEW = Path.Combine(clientSettings_NEW, "ClientAppSettings.json"); - File.WriteAllText(filePath_NEW, file); - } - - private void addCustom_Click(object sender, EventArgs e) - { - using (FlagCreator flagCreator = new FlagCreator()) - { - Enabled = false; - UseWaitCursor = true; - - flagCreator.BringToFront(); - flagCreator.ShowDialog(); - - Enabled = true; - UseWaitCursor = false; - - if (flagCreator.DialogResult == DialogResult.OK) - { - var customFlag = flagCreator.Result; - string flagType = customFlag.Type; - - string flagValue = flagTypes - .Select(pair => pair.Key) - .Where(key => flagType.EndsWith(key, Program.StringFormat)) - .Select(key => flagTypes[key]) - .FirstOrDefault(); - - string flagName = flagType + customFlag.Name; - var newFlag = new FVariable(flagName, flagValue, true); - - flagRegistry[flagName] = newFlag; - lastCustomFlag = newFlag; - - addFlagOverride(newFlag); - } - } - } - - private void flagDataGridView_CellMouseClick(object sender, DataGridViewCellMouseEventArgs e) - { - if (e.ColumnIndex != 2) - return; - - if (e.Button != MouseButtons.Right) - return; - - var rowIndex = e.RowIndex; - FVariable flag = flags[rowIndex]; - Clipboard.SetText(flag.Value); - - notification.BalloonTipTitle = flag.Name; - notification.BalloonTipText = "Value copied to clipboard!"; - notification.ShowBalloonTip(2000); - } - } -} \ No newline at end of file diff --git a/ProjectSrc/Forms/Launcher.Designer.cs b/ProjectSrc/Forms/Launcher.Designer.cs deleted file mode 100644 index 8260c7e..0000000 --- a/ProjectSrc/Forms/Launcher.Designer.cs +++ /dev/null @@ -1,276 +0,0 @@ -namespace RobloxStudioModManager -{ - partial class Launcher - { - /// - /// Required designer variable. - /// - private System.ComponentModel.IContainer components = null; - - /// - /// Clean up any resources being used. - /// - /// true if managed resources should be disposed; otherwise, false. - protected override void Dispose(bool disposing) - { - if (disposing && (components != null)) - { - components.Dispose(); - } - base.Dispose(disposing); - } - - #region Windows Form Designer generated code - - /// - /// Required method for Designer support - do not modify - /// the contents of this method with the code editor. - /// - private void InitializeComponent() - { - this.launchStudio = new System.Windows.Forms.Button(); - this.manageMods = new System.Windows.Forms.Button(); - this.forceRebuild = new System.Windows.Forms.CheckBox(); - this.openFlagEditor = new System.Windows.Forms.Button(); - this.openStudioDirectory = new System.Windows.Forms.CheckBox(); - this.targetVersionLabel = new System.Windows.Forms.Label(); - this.title = new System.Windows.Forms.Label(); - this.targetVersion = new System.Windows.Forms.ComboBox(); - this.releaseTag = new System.Windows.Forms.Label(); - this.logo = new System.Windows.Forms.PictureBox(); - this.channelNameBox = new System.Windows.Forms.TextBox(); - this.channelNameTitle = new System.Windows.Forms.Label(); - this.channelTokenTitle = new System.Windows.Forms.Label(); - this.channelTokenBox = new System.Windows.Forms.TextBox(); - ((System.ComponentModel.ISupportInitialize)(this.logo)).BeginInit(); - this.SuspendLayout(); - // - // launchStudio - // - this.launchStudio.AccessibleName = "Launch Roblox Studio"; - this.launchStudio.AccessibleRole = System.Windows.Forms.AccessibleRole.None; - this.launchStudio.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); - this.launchStudio.Cursor = System.Windows.Forms.Cursors.Default; - this.launchStudio.Font = new System.Drawing.Font("Segoe UI", 9F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.launchStudio.Location = new System.Drawing.Point(11, 123); - this.launchStudio.Margin = new System.Windows.Forms.Padding(6, 3, 3, 3); - this.launchStudio.Name = "launchStudio"; - this.launchStudio.Size = new System.Drawing.Size(142, 23); - this.launchStudio.TabIndex = 6; - this.launchStudio.Text = "Launch Studio"; - this.launchStudio.UseVisualStyleBackColor = true; - this.launchStudio.Click += new System.EventHandler(this.launchStudio_Click); - // - // manageMods - // - this.manageMods.AccessibleName = "Open Mod Folder"; - this.manageMods.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); - this.manageMods.Cursor = System.Windows.Forms.Cursors.Default; - this.manageMods.Font = new System.Drawing.Font("Segoe UI", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.manageMods.Location = new System.Drawing.Point(11, 152); - this.manageMods.Margin = new System.Windows.Forms.Padding(6, 3, 3, 3); - this.manageMods.Name = "manageMods"; - this.manageMods.Size = new System.Drawing.Size(142, 23); - this.manageMods.TabIndex = 9; - this.manageMods.Text = "Open Mod Folder"; - this.manageMods.UseVisualStyleBackColor = true; - this.manageMods.Click += new System.EventHandler(this.manageMods_Click); - // - // forceRebuild - // - this.forceRebuild.AccessibleName = "Force Client Rebuild"; - this.forceRebuild.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); - this.forceRebuild.AutoSize = true; - this.forceRebuild.Location = new System.Drawing.Point(11, 234); - this.forceRebuild.Margin = new System.Windows.Forms.Padding(2); - this.forceRebuild.Name = "forceRebuild"; - this.forceRebuild.Size = new System.Drawing.Size(119, 17); - this.forceRebuild.TabIndex = 12; - this.forceRebuild.Text = "Force Reinstallation"; - this.forceRebuild.UseVisualStyleBackColor = true; - // - // openFlagEditor - // - this.openFlagEditor.AccessibleName = "Open Flag Editor"; - this.openFlagEditor.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); - this.openFlagEditor.Font = new System.Drawing.Font("Segoe UI", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.openFlagEditor.Location = new System.Drawing.Point(11, 181); - this.openFlagEditor.Margin = new System.Windows.Forms.Padding(6, 3, 3, 3); - this.openFlagEditor.Name = "openFlagEditor"; - this.openFlagEditor.Size = new System.Drawing.Size(142, 23); - this.openFlagEditor.TabIndex = 15; - this.openFlagEditor.Text = "Edit Fast Flags"; - this.openFlagEditor.UseVisualStyleBackColor = true; - this.openFlagEditor.Click += new System.EventHandler(this.editFVariables_Click); - // - // openStudioDirectory - // - this.openStudioDirectory.AccessibleName = "Just Open Studio Path"; - this.openStudioDirectory.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); - this.openStudioDirectory.AutoSize = true; - this.openStudioDirectory.Location = new System.Drawing.Point(11, 212); - this.openStudioDirectory.Margin = new System.Windows.Forms.Padding(2); - this.openStudioDirectory.Name = "openStudioDirectory"; - this.openStudioDirectory.Size = new System.Drawing.Size(140, 17); - this.openStudioDirectory.TabIndex = 14; - this.openStudioDirectory.Text = "Open Working Directory"; - this.openStudioDirectory.UseVisualStyleBackColor = true; - // - // targetVersionLabel - // - this.targetVersionLabel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); - this.targetVersionLabel.AutoSize = true; - this.targetVersionLabel.BackColor = System.Drawing.Color.Transparent; - this.targetVersionLabel.CausesValidation = false; - this.targetVersionLabel.Font = new System.Drawing.Font("Segoe UI", 9F); - this.targetVersionLabel.ForeColor = System.Drawing.SystemColors.ControlText; - this.targetVersionLabel.Location = new System.Drawing.Point(168, 114); - this.targetVersionLabel.Name = "targetVersionLabel"; - this.targetVersionLabel.Size = new System.Drawing.Size(83, 15); - this.targetVersionLabel.TabIndex = 17; - this.targetVersionLabel.Text = "Target Version:"; - // - // title - // - this.title.Font = new System.Drawing.Font("Segoe UI Light", 20F); - this.title.Location = new System.Drawing.Point(135, 18); - this.title.Name = "title"; - this.title.Size = new System.Drawing.Size(176, 88); - this.title.TabIndex = 20; - this.title.Text = "Roblox Studio\r\nMod Manager"; - this.title.TextAlign = System.Drawing.ContentAlignment.MiddleLeft; - // - // targetVersion - // - this.targetVersion.AccessibleName = "Target Version"; - this.targetVersion.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); - this.targetVersion.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; - this.targetVersion.FormattingEnabled = true; - this.targetVersion.Items.AddRange(new object[] { - "(Use Latest)"}); - this.targetVersion.Location = new System.Drawing.Point(171, 131); - this.targetVersion.Name = "targetVersion"; - this.targetVersion.Size = new System.Drawing.Size(152, 21); - this.targetVersion.TabIndex = 18; - this.targetVersion.SelectedIndexChanged += new System.EventHandler(this.targetVersion_SelectedIndexChanged); - // - // releaseTag - // - this.releaseTag.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); - this.releaseTag.AutoSize = true; - this.releaseTag.ForeColor = System.Drawing.Color.DarkGray; - this.releaseTag.Location = new System.Drawing.Point(266, 5); - this.releaseTag.Name = "releaseTag"; - this.releaseTag.Size = new System.Drawing.Size(0, 13); - this.releaseTag.TabIndex = 23; - this.releaseTag.TextAlign = System.Drawing.ContentAlignment.TopRight; - // - // logo - // - this.logo.BackgroundImage = global::RobloxStudioModManager.Properties.Resources.Logo; - this.logo.BackgroundImageLayout = System.Windows.Forms.ImageLayout.Zoom; - this.logo.Location = new System.Drawing.Point(37, 18); - this.logo.Margin = new System.Windows.Forms.Padding(2); - this.logo.Name = "logo"; - this.logo.Size = new System.Drawing.Size(90, 88); - this.logo.TabIndex = 22; - this.logo.TabStop = false; - // - // channelNameBox - // - this.channelNameBox.Location = new System.Drawing.Point(171, 176); - this.channelNameBox.Name = "channelNameBox"; - this.channelNameBox.Size = new System.Drawing.Size(152, 20); - this.channelNameBox.TabIndex = 24; - this.channelNameBox.Text = "LIVE"; - // - // channelNameTitle - // - this.channelNameTitle.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); - this.channelNameTitle.AutoSize = true; - this.channelNameTitle.BackColor = System.Drawing.Color.Transparent; - this.channelNameTitle.CausesValidation = false; - this.channelNameTitle.Font = new System.Drawing.Font("Segoe UI", 9F); - this.channelNameTitle.ForeColor = System.Drawing.SystemColors.ControlText; - this.channelNameTitle.Location = new System.Drawing.Point(168, 158); - this.channelNameTitle.Name = "channelNameTitle"; - this.channelNameTitle.Size = new System.Drawing.Size(89, 15); - this.channelNameTitle.TabIndex = 25; - this.channelNameTitle.Text = "Channel Name:"; - // - // channelTokenTitle - // - this.channelTokenTitle.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); - this.channelTokenTitle.AutoSize = true; - this.channelTokenTitle.BackColor = System.Drawing.Color.Transparent; - this.channelTokenTitle.CausesValidation = false; - this.channelTokenTitle.Font = new System.Drawing.Font("Segoe UI", 9F); - this.channelTokenTitle.ForeColor = System.Drawing.SystemColors.ControlText; - this.channelTokenTitle.Location = new System.Drawing.Point(168, 206); - this.channelTokenTitle.Name = "channelTokenTitle"; - this.channelTokenTitle.Size = new System.Drawing.Size(127, 15); - this.channelTokenTitle.TabIndex = 26; - this.channelTokenTitle.Text = "Channel Access Token:"; - // - // channelTokenBox - // - this.channelTokenBox.Location = new System.Drawing.Point(171, 221); - this.channelTokenBox.Name = "channelTokenBox"; - this.channelTokenBox.Size = new System.Drawing.Size(152, 20); - this.channelTokenBox.TabIndex = 27; - this.channelTokenBox.UseSystemPasswordChar = true; - this.channelTokenBox.Leave += new System.EventHandler(this.channelTokenBox_Leave); - // - // Launcher - // - this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); - this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; - this.BackColor = System.Drawing.SystemColors.Control; - this.ClientSize = new System.Drawing.Size(335, 274); - this.Controls.Add(this.channelTokenBox); - this.Controls.Add(this.channelTokenTitle); - this.Controls.Add(this.channelNameTitle); - this.Controls.Add(this.channelNameBox); - this.Controls.Add(this.releaseTag); - this.Controls.Add(this.logo); - this.Controls.Add(this.title); - this.Controls.Add(this.targetVersion); - this.Controls.Add(this.targetVersionLabel); - this.Controls.Add(this.openFlagEditor); - this.Controls.Add(this.openStudioDirectory); - this.Controls.Add(this.forceRebuild); - this.Controls.Add(this.manageMods); - this.Controls.Add(this.launchStudio); - this.DoubleBuffered = true; - this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle; - this.Icon = global::RobloxStudioModManager.Properties.Resources.Icon; - this.MaximizeBox = false; - this.Name = "Launcher"; - this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen; - this.Text = "Roblox Studio Mod Manager"; - this.Load += new System.EventHandler(this.Launcher_Load); - ((System.ComponentModel.ISupportInitialize)(this.logo)).EndInit(); - this.ResumeLayout(false); - this.PerformLayout(); - - } - - #endregion - - private System.Windows.Forms.Button launchStudio; - private System.Windows.Forms.Button manageMods; - private System.Windows.Forms.CheckBox forceRebuild; - private System.Windows.Forms.Button openFlagEditor; - private System.Windows.Forms.CheckBox openStudioDirectory; - private System.Windows.Forms.Label targetVersionLabel; - private System.Windows.Forms.Label title; - private System.Windows.Forms.ComboBox targetVersion; - private System.Windows.Forms.Label releaseTag; - private System.Windows.Forms.PictureBox logo; - private System.Windows.Forms.TextBox channelNameBox; - private System.Windows.Forms.Label channelNameTitle; - private System.Windows.Forms.Label channelTokenTitle; - private System.Windows.Forms.TextBox channelTokenBox; - } -} - diff --git a/ProjectSrc/Forms/Launcher.cs b/ProjectSrc/Forms/Launcher.cs deleted file mode 100644 index bf2bb74..0000000 --- a/ProjectSrc/Forms/Launcher.cs +++ /dev/null @@ -1,499 +0,0 @@ -using RobloxDeployHistory; -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Drawing; -using System.IO; -using System.Linq; -using System.Media; -using System.Net; -using System.Windows.Forms; - -namespace RobloxStudioModManager -{ - public partial class Launcher : Form - { - private static VersionManifest versionRegistry => Program.State.VersionData; - private readonly string[] args = null; - - public Launcher(params string[] mainArgs) - { - if (mainArgs.Length > 0) - args = mainArgs; - - InitializeComponent(); - releaseTag.Text = Program.ReleaseTag; - } - - private void promptNewRelease(string releaseTag) - { - #if !DEBUG - Enabled = false; - - DialogResult result = MessageBox.Show - ( - "There's a new version of the mod manager available!\n" + - "This version is likely broken or no longer supported.\n" + - "Would you like to check it out?", - - "Update available!", - MessageBoxButtons.YesNo, - MessageBoxIcon.Information - ); - - if (result == DialogResult.Yes) - { - Process.Start($"https://www.github.com/{Program.RepoOwner}/{Program.RepoName}/releases/tag/{releaseTag}"); - Application.Exit(); - } - - Enabled = true; - #endif - } - - private async void setVersionHistory(string channelName = "LIVE", string channelToken = "") - { - // Grab the version currently being targeted. - string targetId = Program.State.TargetVersion; - const string latest = "(Use Latest)"; - - // Clear the current list of target items. - targetVersion.Items.Clear(); - targetVersion.Items.Add(latest); - - // Populate the items list using the deploy history. - var deployLogs = await StudioDeployLogs.Get(Program.AllowUnsupportedVersions, channelName, channelToken); - HashSet targets = deployLogs.CurrentLogs; - - targetVersion.Enabled = deployLogs.HasHistory; - targetVersionLabel.Enabled = deployLogs.HasHistory; - - if (deployLogs.ChannelName == channelName || deployLogs.ChannelName == "zbeta") - { - if (!string.IsNullOrEmpty(channelName)) Program.State.ChannelData.ChannelName = channelName; - if (!string.IsNullOrEmpty(channelToken)) Program.State.ChannelData.ChannelToken = channelToken; - } - else - { - MessageBox.Show("Could not fetch client version info with the channel name and token!\nEnsure you have entered them correctly.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); - Program.State.ChannelData.ChannelName = "LIVE"; - Program.State.ChannelData.ChannelToken = ""; - channelNameBox.Text = "LIVE"; - channelTokenBox.Text = ""; - } - - if (deployLogs.HasHistory) - { - var items = targets - .OrderByDescending(t => t.CommitId) - .Cast() - .ToArray(); - - targetVersion.Items.AddRange(items); - } - - // Select the deploy log being targeted. - DeployLog target = targets - .Where(log => log.VersionId == targetId) - .FirstOrDefault(); - - if (target != null) - { - targetVersion.SelectedItem = target; - UseWaitCursor = false; - Enabled = true; - return; - } - - // If the target isn't valid, fallback to live. - targetVersion.SelectedItem = latest; - } - - private async void Launcher_Load(object sender, EventArgs e) - { - Enabled = false; - UseWaitCursor = true; - - if (args != null) - { - launchStudio_Click(); - Hide(); - return; - } - - using (var http = new WebClient()) - { - var get = http.DownloadStringTaskAsync(Program.BaseConfigUrl + "LatestReleaseTag.txt"); - - await get.ContinueWith(task => - { - if (task.IsFaulted) - { - MessageBox.Show("Could not fetch latest release tag!\nYou may not have an internet connection.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); - return; - } - - if (!task.IsCompleted) - return; - - string releaseTag = task.Result.Trim(); - - if (releaseTag == Program.ReleaseTag) - return; - - Invoke(new Action(promptNewRelease), releaseTag); - }); - } - - setVersionHistory(); - UseWaitCursor = false; - Enabled = true; - } - - public static string getModPath() - { - string root = Path.Combine(Program.RootDir, "ModFiles"); - - if (!Directory.Exists(root)) - { - // Build a folder structure so the usage is more clear. - Directory.CreateDirectory(root); - - string[] folderPaths = new string[] - { - "BuiltInPlugins", - "ClientSettings", - - "content/avatar", - "content/fonts", - "content/models", - "content/scripts", - "content/sky", - "content/sounds", - "content/textures", - "content/translations" - }; - - foreach (string f in folderPaths) - { - string path = Path.Combine(root, f); - Directory.CreateDirectory(path); - } - } - - return root; - } - - private void manageMods_Click(object sender, EventArgs e) - { - string modPath = getModPath(); - - var open = new ProcessStartInfo() - { - FileName = modPath, - UseShellExecute = true, - Verb = "open" - }; - - Process.Start(open); - } - - private static Form createFlagWarningPrompt() - { - var warningForm = new Form() - { - Text = "WARNING: HERE BE DRAGONS", - - Width = 425, - Height = 250, - MaximizeBox = false, - MinimizeBox = false, - - FormBorderStyle = FormBorderStyle.FixedDialog, - StartPosition = FormStartPosition.CenterScreen, - - ShowInTaskbar = false - }; - - var errorIcon = new PictureBox() - { - Image = SystemIcons.Error.ToBitmap(), - Location = new Point(12, 12), - Size = new Size(32, 32), - }; - - var dontShowAgain = new CheckBox() - { - AutoSize = true, - Location = new Point(54, 145), - Text = "Do not show this warning again.", - Font = new Font("Microsoft Sans Serif", 9.75f), - }; - - var buttonPanel = new FlowLayoutPanel() - { - FlowDirection = FlowDirection.RightToLeft, - BackColor = SystemColors.ControlLight, - Padding = new Padding(4), - Dock = DockStyle.Bottom, - Size = new Size(0, 40) - }; - - var infoLabel = new Label() - { - AutoSize = true, - - Font = new Font("Microsoft Sans Serif", 9.75f), - Text = "Editing flags can make Roblox Studio unstable, and could potentially corrupt your places and game data.\n\n" + - "You should not edit them unless you are just experimenting with new features locally, and you know what you're doing.\n\n" + - "Are you sure you would like to continue?", - - Location = new Point(50, 14), - MaximumSize = new Size(350, 0), - }; - - var yes = new Button() - { - Size = new Size(100, 23), - Text = "Yes", - }; - - var no = new Button() - { - Size = new Size(100, 23), - Text = "No", - }; - - yes.Click += (sender, e) => - { - warningForm.DialogResult = DialogResult.Yes; - warningForm.Enabled = dontShowAgain.Checked; - warningForm.Close(); - }; - - no.Click += (sender, e) => - { - warningForm.DialogResult = DialogResult.No; - warningForm.Enabled = dontShowAgain.Checked; - warningForm.Close(); - }; - - buttonPanel.Controls.Add(no); - buttonPanel.Controls.Add(yes); - - warningForm.Controls.Add(errorIcon); - warningForm.Controls.Add(infoLabel); - warningForm.Controls.Add(buttonPanel); - warningForm.Controls.Add(dontShowAgain); - - return warningForm; - } - - private async void editFVariables_Click(object sender, EventArgs e) - { - bool allow = true; - - // Create a warning prompt if the user hasn't disabled this warning. - var warningDisabled = Program.State.DisableFlagWarning; - - if (!warningDisabled) - { - SystemSounds.Hand.Play(); - allow = false; - - using (Form warningPrompt = createFlagWarningPrompt()) - { - warningPrompt.ShowDialog(); - - if (warningPrompt.DialogResult == DialogResult.Yes) - { - Program.State.DisableFlagWarning = warningPrompt.Enabled; - allow = true; - } - } - } - - if (allow) - { - Enabled = false; - UseWaitCursor = true; - - var info = await StudioBootstrapper.GetCurrentVersionInfo(); - Hide(); - - await BootstrapperForm.BringUpToDate(info.VersionGuid, "Some newer flags might be missing."); - - using (FlagEditor editor = new FlagEditor()) - editor.ShowDialog(); - - Show(); - BringToFront(); - - Enabled = true; - UseWaitCursor = false; - } - } - - private async void launchStudio_Click(object sender = null, EventArgs e = null) - { - var overrideGuid = ""; - - if (args != null && args.Length > 0 && args[0].StartsWith("version-")) - overrideGuid = args[0]; - - var bootstrapper = new StudioBootstrapper - { - ForceInstall = forceRebuild.Checked, - ApplyModManagerPatches = true, - OverrideGuid = overrideGuid - }; - - Hide(); - - using (var installer = new BootstrapperForm(bootstrapper)) - await installer.Bootstrap(); - - string studioRoot = StudioBootstrapper.GetStudioDirectory(); - string modPath = getModPath(); - - var modFiles = Directory.GetFiles(modPath, "*.*", SearchOption.AllDirectories); - - foreach (string file in modFiles) - { - try - { - var info = new FileInfo(file); - var filePath = file; - var delete = false; - - if (info.Length == 0 && info.Name.StartsWith("DELETE")) - { - var dir = info.DirectoryName; - - var realName = info.Name - .Substring(6) - .TrimStart(); - - filePath = Path.Combine(dir, realName); - delete = true; - } - - string relativeFile = filePath.Replace(modPath, studioRoot); - - string relativeDir = Directory - .GetParent(relativeFile) - .ToString(); - - if (!Directory.Exists(relativeDir)) - Directory.CreateDirectory(relativeDir); - - byte[] contents = info.Length > 0 - ? File.ReadAllBytes(file) - : Array.Empty(); - - if (File.Exists(relativeFile)) - { - byte[] relative = File.ReadAllBytes(relativeFile); - - if (relative.Length == contents.Length) - if (relative.SequenceEqual(contents)) - continue; - - if (delete) - { - File.Delete(relativeFile); - continue; - } - - info.CopyTo(relativeFile, true); - } - else - { - if (delete) - continue; - - File.WriteAllBytes(relativeFile, contents); - } - } - catch - { - Console.WriteLine("Failed to overwrite {0}!", file); - } - } - - var robloxStudioInfo = new ProcessStartInfo() - { - FileName = StudioBootstrapper.GetStudioPath(), - Arguments = $"" - }; - - if (args != null) - { - string firstArg = args[0]; - - if (firstArg != null && firstArg.StartsWith("roblox-studio", Program.StringFormat)) - { - // Arguments were passed by URI. - robloxStudioInfo.Arguments = firstArg; - } - else - { - // Arguments were passed directly. - for (int i = 0; i < args.Length; i++) - { - string arg = args[i]; - - if (arg.Contains(' ')) - arg = $"\"{arg}\""; - - robloxStudioInfo.Arguments += ' ' + arg; - } - } - } - - - if (openStudioDirectory.Checked) - { - Process.Start(studioRoot); - } - else - { - string currentVersion = versionRegistry.VersionGuid; - versionRegistry.LastExecutedVersion = currentVersion; - - Process.Start(robloxStudioInfo); - } - - Program.SaveState(); - Environment.Exit(Environment.ExitCode); - } - - private void targetVersion_SelectedIndexChanged(object sender, EventArgs e) - { - if (targetVersion.SelectedIndex == 0) - { - Program.State.TargetVersion = ""; - return; - } - - if (!(targetVersion.SelectedItem is DeployLog target)) return; - Program.State.TargetVersion = target.VersionId; - - if (target.Unsupported) - { - MessageBox.Show( - "This version of Roblox Studio is no longer supported!\nYou are strongly advised against using it in the future.\nNo technical support will be provided, use it at your own risk!", - "Tread Lightly!", - - MessageBoxButtons.OK, - MessageBoxIcon.Warning - ); - } - } - - private void channelTokenBox_Leave(object sender, EventArgs e) - { - setVersionHistory(channelNameBox.Text, channelTokenBox.Text); - } - } -} diff --git a/ProjectSrc/Properties/AssemblyInfo.cs b/ProjectSrc/Properties/AssemblyInfo.cs deleted file mode 100644 index 7a46b03..0000000 --- a/ProjectSrc/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,38 +0,0 @@ -using System.Resources; -using System.Reflection; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. -[assembly: AssemblyTitle("Roblox Studio Mod Manager")] -[assembly: AssemblyDescription("An unofficial, open-source, custom bootstrapper for Roblox Studio that provides more flexibility to power users looking to make experimental customizations to Roblox Studio, and test new features before they are available to the public.")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("")] -[assembly: AssemblyProduct("Roblox Studio Mod Manager")] -[assembly: AssemblyCopyright("")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] - -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from -// COM, set the ComVisible attribute to true on that type. -[assembly: ComVisible(false)] - -// The following GUID is for the ID of the typelib if this project is exposed to COM -[assembly: Guid("c5691c74-2875-4593-b5f3-fa135fdb7b82")] - -// Version information for an assembly consists of the following four values: -// -// Major Version -// Minor Version -// Build Number -// Revision -// -// You can specify all the values or you can default the Build and Revision Numbers -// by using the '*' as shown below: -// [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("1.0.0.0")] -[assembly: AssemblyFileVersion("1.0.0.0")] -[assembly: NeutralResourcesLanguage("en-US")] diff --git a/ProjectSrc/Properties/Resources.Designer.cs b/ProjectSrc/Properties/Resources.Designer.cs deleted file mode 100644 index 3372d72..0000000 --- a/ProjectSrc/Properties/Resources.Designer.cs +++ /dev/null @@ -1,83 +0,0 @@ -//------------------------------------------------------------------------------ -// -// This code was generated by a tool. -// Runtime Version:4.0.30319.42000 -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - -namespace RobloxStudioModManager.Properties { - using System; - - - /// - /// A strongly-typed resource class, for looking up localized strings, etc. - /// - // This class was auto-generated by the StronglyTypedResourceBuilder - // class via a tool like ResGen or Visual Studio. - // To add or remove a member, edit your .ResX file then rerun ResGen - // with the /str option, or rebuild your VS project. - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0")] - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] - [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] - internal class Resources { - - private static global::System.Resources.ResourceManager resourceMan; - - private static global::System.Globalization.CultureInfo resourceCulture; - - [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - internal Resources() { - } - - /// - /// Returns the cached ResourceManager instance used by this class. - /// - [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] - internal static global::System.Resources.ResourceManager ResourceManager { - get { - if (object.ReferenceEquals(resourceMan, null)) { - global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("RobloxStudioModManager.Properties.Resources", typeof(Resources).Assembly); - resourceMan = temp; - } - return resourceMan; - } - } - - /// - /// Overrides the current thread's CurrentUICulture property for all - /// resource lookups using this strongly typed resource class. - /// - [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] - internal static global::System.Globalization.CultureInfo Culture { - get { - return resourceCulture; - } - set { - resourceCulture = value; - } - } - - /// - /// Looks up a localized resource of type System.Drawing.Icon similar to (Icon). - /// - internal static System.Drawing.Icon Icon { - get { - object obj = ResourceManager.GetObject("Icon", resourceCulture); - return ((System.Drawing.Icon)(obj)); - } - } - - /// - /// Looks up a localized resource of type System.Drawing.Bitmap. - /// - internal static System.Drawing.Bitmap Logo { - get { - object obj = ResourceManager.GetObject("Logo", resourceCulture); - return ((System.Drawing.Bitmap)(obj)); - } - } - } -} diff --git a/ProjectSrc/Properties/Resources.resx b/ProjectSrc/Properties/Resources.resx deleted file mode 100644 index 20e6afc..0000000 --- a/ProjectSrc/Properties/Resources.resx +++ /dev/null @@ -1,68 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - - ..\Resources\Icon.ico;System.Drawing.Icon, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a - - - ..\Resources\Logo.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a - - \ No newline at end of file diff --git a/ProjectSrc/RobloxStudioModManager.csproj b/ProjectSrc/RobloxStudioModManager.csproj deleted file mode 100644 index 487e3d7..0000000 --- a/ProjectSrc/RobloxStudioModManager.csproj +++ /dev/null @@ -1,291 +0,0 @@ - - - - - Debug - AnyCPU - {FAD2621F-B280-4D6D-A260-F410C5B06E0C} - WinExe - Properties - RobloxStudioModManager - RobloxStudioModManager - v4.7.2 - 512 - false - - - - publish\ - true - Disk - false - Foreground - 7 - Days - false - false - true - https://www.twitter.com/MaxGee1019 - Roblox Studio Mod Manager - CloneTrooper1019 - 0 - 1.0.0.%2a - false - true - - - x64 - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - false - Off - true - - - x64 - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - - - - - Resources\Icon.ico - - - false - - - true - - - LocalIntranet - - - false - - - - - - - - - - - - bin\Internal\ - TRACE;ROBLOX_INTERNAL - true - pdbonly - x64 - 7.3 - prompt - true - - - app.manifest - - - true - bin\x64\Debug\ - DEBUG;TRACE - full - x64 - Off - 7.3 - prompt - true - - - bin\x64\Release\ - TRACE - true - pdbonly - x64 - 7.3 - prompt - true - - - bin\x64\Internal\ - TRACE;ROBLOX_INTERNAL - true - pdbonly - x64 - 7.3 - prompt - true - - - bin\DebugInternal\ - TRACE;ROBLOX_INTERNAL - true - pdbonly - x64 - 7.3 - prompt - true - - - bin\x64\DebugInternal\ - TRACE;ROBLOX_INTERNAL - false - pdbonly - x64 - 7.3 - prompt - true - - - - - - - - - - - - - - - - - - - - - Form - - - FlagCreator.cs - - - - - - - - - - - - - - - - Form - - - BootstrapperForm.cs - - - Form - - - FlagEditor.cs - - - True - True - Resources.resx - - - Form - - - Launcher.cs - - - - - ResXFileCodeGenerator - Designer - Resources.Designer.cs - - - - - - - - - - False - Microsoft .NET Framework 4.5 %28x86 and x64%29 - true - - - False - .NET Framework 3.5 SP1 Client Profile - false - - - False - .NET Framework 3.5 SP1 - false - - - - - - - - - - - {1ce1a9df-c2ff-49c4-9b7c-792c962c339f} - RobloxDeployHistory - - - - - - - - 4.1.0 - - - 1.0.9 - - - 4.7.0 - - - 13.0.1 - - - 5.1.0 - - - - - if not $(ConfigurationName) == Release goto :end -echo Copying release build. -copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\$(TargetFileName)" -echo Done! -:end - - - if not $(ConfigurationName) == Release goto :end -echo Clearing instances of $(TargetFileName) -taskkill /f /im $(TargetFileName) /fi "memusage gt 2" -:end - - - \ No newline at end of file diff --git a/ProjectSrc/RobloxStudioModManager.sln b/ProjectSrc/RobloxStudioModManager.sln index bbcc388..82f5e35 100644 --- a/ProjectSrc/RobloxStudioModManager.sln +++ b/ProjectSrc/RobloxStudioModManager.sln @@ -1,9 +1,9 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 17 -VisualStudioVersion = 17.3.32929.385 +# Visual Studio Version 18 +VisualStudioVersion = 18.7.11911.148 stable MinimumVisualStudioVersion = 10.0.40219.1 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RobloxStudioModManager", "RobloxStudioModManager.csproj", "{FAD2621F-B280-4D6D-A260-F410C5B06E0C}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RobloxStudioModManager", "WinUI\RobloxStudioModManager.csproj", "{4E0D71E5-26EF-43A0-9E7E-DDBAC358C5F1}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Include", "Include", "{599F227F-86C3-4CB6-B12D-6CBF086B240E}" EndProject @@ -13,32 +13,22 @@ Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU Debug|x64 = Debug|x64 - Internal|Any CPU = Internal|Any CPU - Internal|x64 = Internal|x64 Release|Any CPU = Release|Any CPU Release|x64 = Release|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {FAD2621F-B280-4D6D-A260-F410C5B06E0C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {FAD2621F-B280-4D6D-A260-F410C5B06E0C}.Debug|Any CPU.Build.0 = Debug|Any CPU - {FAD2621F-B280-4D6D-A260-F410C5B06E0C}.Debug|x64.ActiveCfg = Debug|x64 - {FAD2621F-B280-4D6D-A260-F410C5B06E0C}.Debug|x64.Build.0 = Debug|x64 - {FAD2621F-B280-4D6D-A260-F410C5B06E0C}.Internal|Any CPU.ActiveCfg = Internal|Any CPU - {FAD2621F-B280-4D6D-A260-F410C5B06E0C}.Internal|Any CPU.Build.0 = Internal|Any CPU - {FAD2621F-B280-4D6D-A260-F410C5B06E0C}.Internal|x64.ActiveCfg = Internal|x64 - {FAD2621F-B280-4D6D-A260-F410C5B06E0C}.Internal|x64.Build.0 = Internal|x64 - {FAD2621F-B280-4D6D-A260-F410C5B06E0C}.Release|Any CPU.ActiveCfg = Release|Any CPU - {FAD2621F-B280-4D6D-A260-F410C5B06E0C}.Release|Any CPU.Build.0 = Release|Any CPU - {FAD2621F-B280-4D6D-A260-F410C5B06E0C}.Release|x64.ActiveCfg = Release|x64 - {FAD2621F-B280-4D6D-A260-F410C5B06E0C}.Release|x64.Build.0 = Release|x64 + {4E0D71E5-26EF-43A0-9E7E-DDBAC358C5F1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {4E0D71E5-26EF-43A0-9E7E-DDBAC358C5F1}.Debug|Any CPU.Build.0 = Debug|Any CPU + {4E0D71E5-26EF-43A0-9E7E-DDBAC358C5F1}.Debug|x64.ActiveCfg = Debug|Any CPU + {4E0D71E5-26EF-43A0-9E7E-DDBAC358C5F1}.Debug|x64.Build.0 = Debug|Any CPU + {4E0D71E5-26EF-43A0-9E7E-DDBAC358C5F1}.Release|Any CPU.ActiveCfg = Release|Any CPU + {4E0D71E5-26EF-43A0-9E7E-DDBAC358C5F1}.Release|Any CPU.Build.0 = Release|Any CPU + {4E0D71E5-26EF-43A0-9E7E-DDBAC358C5F1}.Release|x64.ActiveCfg = Release|Any CPU + {4E0D71E5-26EF-43A0-9E7E-DDBAC358C5F1}.Release|x64.Build.0 = Release|Any CPU {1CE1A9DF-C2FF-49C4-9B7C-792C962C339F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {1CE1A9DF-C2FF-49C4-9B7C-792C962C339F}.Debug|Any CPU.Build.0 = Debug|Any CPU {1CE1A9DF-C2FF-49C4-9B7C-792C962C339F}.Debug|x64.ActiveCfg = Debug|x64 {1CE1A9DF-C2FF-49C4-9B7C-792C962C339F}.Debug|x64.Build.0 = Debug|x64 - {1CE1A9DF-C2FF-49C4-9B7C-792C962C339F}.Internal|Any CPU.ActiveCfg = Debug|Any CPU - {1CE1A9DF-C2FF-49C4-9B7C-792C962C339F}.Internal|Any CPU.Build.0 = Debug|Any CPU - {1CE1A9DF-C2FF-49C4-9B7C-792C962C339F}.Internal|x64.ActiveCfg = Release|x64 - {1CE1A9DF-C2FF-49C4-9B7C-792C962C339F}.Internal|x64.Build.0 = Release|x64 {1CE1A9DF-C2FF-49C4-9B7C-792C962C339F}.Release|Any CPU.ActiveCfg = Release|Any CPU {1CE1A9DF-C2FF-49C4-9B7C-792C962C339F}.Release|Any CPU.Build.0 = Release|Any CPU {1CE1A9DF-C2FF-49C4-9B7C-792C962C339F}.Release|x64.ActiveCfg = Release|x64 diff --git a/ProjectSrc/Utility/BackdropHelper.cs b/ProjectSrc/Utility/BackdropHelper.cs new file mode 100644 index 0000000..55ec37a --- /dev/null +++ b/ProjectSrc/Utility/BackdropHelper.cs @@ -0,0 +1,20 @@ +using System; + +using Microsoft.UI.Xaml; +using Microsoft.UI.Xaml.Media; + +namespace RobloxStudioModManager +{ + internal static class BackdropHelper + { + public static bool IsWindows11 => Environment.OSVersion.Version.Build >= 22000; + + // Applies a standard backdrop to a window. + public static void ApplyBackdrop(this Window window) + { + window.SystemBackdrop = IsWindows11 + ? (SystemBackdrop)new MicaBackdrop() + : new DesktopAcrylicBackdrop(); + } + } +} diff --git a/ProjectSrc/Utility/BootstrapProgressStyle.cs b/ProjectSrc/Utility/BootstrapProgressStyle.cs new file mode 100644 index 0000000..13d523c --- /dev/null +++ b/ProjectSrc/Utility/BootstrapProgressStyle.cs @@ -0,0 +1,8 @@ +namespace RobloxStudioModManager +{ + public enum BootstrapProgressStyle + { + Determinate, + Indeterminate + } +} diff --git a/ProjectSrc/Utility/FlagManager.cs b/ProjectSrc/Utility/FlagManager.cs new file mode 100644 index 0000000..b297057 --- /dev/null +++ b/ProjectSrc/Utility/FlagManager.cs @@ -0,0 +1,42 @@ +using System; +using System.IO; + +using Newtonsoft.Json.Linq; + +namespace RobloxStudioModManager +{ + // Agnostic flag application logic. + public static class FlagManager + { + public static void ApplyFlags() + { + var json = new JObject(); + var flagRegistry = App.State.FlagEditor; + + foreach (string flagName in flagRegistry.Keys) + { + var flag = flagRegistry[flagName]; + string value = flag.Value; + + var token = JToken.FromObject(value); + json.Add(flagName, token); + }; + + string file = json.ToString(); + string studioDir = StudioBootstrapper.GetStudioDirectory(); + string localAppData = Environment.GetEnvironmentVariable("LocalAppData"); + + string clientSettings_DEPRECATED = Path.Combine(studioDir, "ClientSettings"); + Directory.CreateDirectory(clientSettings_DEPRECATED); + + string filePath_DEPRECATED = Path.Combine(clientSettings_DEPRECATED, "ClientAppSettings.json"); + File.WriteAllText(filePath_DEPRECATED, file); + + string clientSettings_NEW = Path.Combine(localAppData, "Roblox", "ClientSettings"); + Directory.CreateDirectory(clientSettings_NEW); + + string filePath_NEW = Path.Combine(clientSettings_NEW, "ClientAppSettings.json"); + File.WriteAllText(filePath_NEW, file); + } + } +} diff --git a/ProjectSrc/Utility/RegistryExtensions.cs b/ProjectSrc/Utility/RegistryExtensions.cs new file mode 100644 index 0000000..0b32705 --- /dev/null +++ b/ProjectSrc/Utility/RegistryExtensions.cs @@ -0,0 +1,15 @@ +using System.IO; + +using Microsoft.Win32; + +namespace RobloxStudioModManager +{ + public static class RegistryExtensions + { + public static RegistryKey GetSubKey(this RegistryKey key, params string[] path) + { + string constructedPath = Path.Combine(path); + return key.CreateSubKey(constructedPath, RegistryKeyPermissionCheck.ReadWriteSubTree, RegistryOptions.None); + } + } +} diff --git a/ProjectSrc/Utility/WindowPositioning.cs b/ProjectSrc/Utility/WindowPositioning.cs new file mode 100644 index 0000000..4fcd69e --- /dev/null +++ b/ProjectSrc/Utility/WindowPositioning.cs @@ -0,0 +1,81 @@ +using System; +using System.Runtime.InteropServices; + +using Microsoft.UI; +using Microsoft.UI.Windowing; +using Microsoft.UI.Xaml; + +using Windows.Graphics; + +namespace RobloxStudioModManager +{ + // This class allows windows to define an explicit size, + // replicate the WinForms' old StartPosition default behavior, + // and achieve modal behavior by setting an owner property. + internal static class WindowPositioning + { + private const int GWL_HWNDPARENT = -8; + + [DllImport("user32.dll")] + private static extern IntPtr SetWindowLongPtr(IntPtr hWnd, int nIndex, IntPtr dwNewLong); + + [DllImport("user32.dll")] + private static extern bool EnableWindow(IntPtr hWnd, bool bEnable); + + public static void ResizeAndCenter(AppWindow appWindow, int width, int height, AppWindow owner = null) + { + appWindow.Resize(new SizeInt32(width, height)); + center(appWindow, owner); + } + + // Same as above, but width/height describe the client (content) area + // rather than the outer window. + public static void ResizeClientAndCenter(AppWindow appWindow, int width, int height, AppWindow owner = null) + { + appWindow.ResizeClient(new SizeInt32(width, height)); + center(appWindow, owner); + } + + private static void center(AppWindow appWindow, AppWindow owner) + { + RectInt32 bounds; + + if (owner != null) + { + bounds = new RectInt32(owner.Position.X, owner.Position.Y, owner.Size.Width, owner.Size.Height); + } + else + { + var displayArea = DisplayArea.GetFromWindowId(appWindow.Id, DisplayAreaFallback.Primary); + + if (displayArea == null) + return; + + bounds = displayArea.WorkArea; + } + + var x = bounds.X + (bounds.Width - appWindow.Size.Width) / 2; + var y = bounds.Y + (bounds.Height - appWindow.Size.Height) / 2; + + appWindow.Move(new PointInt32(x, y)); + } + + // Marks the given window as owned by the owner. + // Keeping it tied to the owner, and thus allowing the window to behave as modal. + public static void SetOwner(Window window, Window owner) + { + var hwnd = Win32Interop.GetWindowFromWindowId(window.AppWindow.Id); + var ownerHwnd = Win32Interop.GetWindowFromWindowId(owner.AppWindow.Id); + SetWindowLongPtr(hwnd, GWL_HWNDPARENT, ownerHwnd); + } + + // Disables/re-enables a window's input since WinUI has no ShowDialog(), + // so this is how a dialog window blocks interaction with its owner + // while it's open. + public static void SetEnabled(Window window, bool enabled) + { + var hwnd = Win32Interop.GetWindowFromWindowId(window.AppWindow.Id); + EnableWindow(hwnd, enabled); + } + } +} diff --git a/ProjectSrc/WinUI/App.xaml b/ProjectSrc/WinUI/App.xaml new file mode 100644 index 0000000..7bec65f --- /dev/null +++ b/ProjectSrc/WinUI/App.xaml @@ -0,0 +1,22 @@ + + + + + + + + + + #E4212D + #E9424C + #ED6169 + #F28086 + #C41E29 + #A31A23 + #82151C + + + diff --git a/ProjectSrc/Program.cs b/ProjectSrc/WinUI/App.xaml.cs similarity index 81% rename from ProjectSrc/Program.cs rename to ProjectSrc/WinUI/App.xaml.cs index 2dafe55..19c6bc8 100644 --- a/ProjectSrc/Program.cs +++ b/ProjectSrc/WinUI/App.xaml.cs @@ -1,18 +1,19 @@ using System; -using System.Globalization; using System.Collections.Generic; +using System.Diagnostics; +using System.Globalization; using System.IO; using System.Net; -using System.Windows.Forms; + +using Microsoft.UI.Xaml; +using Microsoft.Win32; using Newtonsoft.Json; using Newtonsoft.Json.Linq; -using Microsoft.Win32; - namespace RobloxStudioModManager { - static class Program + public partial class App : Application { public const string RepoBranch = "main"; public const string RepoOwner = "MaximumADHD"; @@ -33,15 +34,27 @@ static class Program public static bool AllowUnsupportedVersions { get; private set; } - private static JsonSerializerSettings JsonSettings = new JsonSerializerSettings() + private static readonly JsonSerializerSettings JsonSettings = new JsonSerializerSettings() { ContractResolver = new OrdinalSortJson() }; - public static RegistryKey GetSubKey(this RegistryKey key, params string[] path) + private Window mainWindow; + + public App() { - string constructedPath = Path.Combine(path); - return key.CreateSubKey(constructedPath, RegistryKeyPermissionCheck.ReadWriteSubTree, RegistryOptions.None); + InitializeComponent(); + } + + protected override void OnLaunched(LaunchActivatedEventArgs args) + { + var rawArgs = Environment.GetCommandLineArgs(); + var unprocessedArgs = Initialize(rawArgs[1..]); + + AppDomain.CurrentDomain.ProcessExit += (sender, e) => SaveState(); + + mainWindow = new MainWindow(unprocessedArgs); + mainWindow.Activate(); } // This sets up the following: @@ -53,7 +66,7 @@ public static void UpdateStudioRegistryProtocols(string studioPath) { const string _ = ""; // Default empty key/value. - string modManagerPath = Application.ExecutablePath + string modManagerPath = Process.GetCurrentProcess().MainModule.FileName .Replace('"', ' ') .Trim(); @@ -80,19 +93,19 @@ public static void UpdateStudioRegistryProtocols(string studioPath) } // Setup the URI protocol for opening the mod manager through the website. - RegistryKey robloxStudioUri = GetSubKey(classes, "roblox-studio"); + RegistryKey robloxStudioUri = classes.GetSubKey("roblox-studio"); robloxStudioUri.SetValue(_, "URL: Roblox Protocol"); robloxStudioUri.SetValue("URL Protocol", _); - RegistryKey studioUriCmd = GetSubKey(robloxStudioUri, "shell", "open", "command"); + RegistryKey studioUriCmd = robloxStudioUri.GetSubKey("shell", "open", "command"); studioUriCmd.SetValue(_, $"\"{modManagerPath}\" %1"); // Setup authentication route. - RegistryKey robloxStudioAuthUri = GetSubKey(classes, "roblox-studio-auth"); + RegistryKey robloxStudioAuthUri = classes.GetSubKey("roblox-studio-auth"); robloxStudioAuthUri.SetValue(_, "URL: Roblox Protocol"); robloxStudioAuthUri.SetValue("URL Protocol", _); - RegistryKey studioAuthUriCmd = GetSubKey(robloxStudioAuthUri, "shell", "open", "command"); + RegistryKey studioAuthUriCmd = robloxStudioAuthUri.GetSubKey("shell", "open", "command"); studioAuthUriCmd.SetValue(_, $"\"{studioPath}\" %1"); // Set the default icon for all protocols. @@ -105,12 +118,12 @@ public static void UpdateStudioRegistryProtocols(string studioPath) foreach (RegistryKey app in appReg) { - RegistryKey defaultIcon = GetSubKey(app, "DefaultIcon"); + RegistryKey defaultIcon = app.GetSubKey("DefaultIcon"); defaultIcon.SetValue(_, $"{modManagerPath},0"); } } - static void ConvertLegacy(RegistryKey regKey, JObject node) + private static void ConvertLegacy(RegistryKey regKey, JObject node) { foreach (var name in regKey.GetValueNames()) { @@ -138,15 +151,9 @@ public static void SaveState() File.WriteAllText(stateFile, json); } - static void OnExiting(object sender, EventArgs e) - { - SaveState(); - } - - [STAThread] - static void Main(string[] rawArgs) + // Loads/migrates persisted app state and parses launch arguments. + public static string[] Initialize(string[] rawArgs) { - // Initialize application state. var localAppData = Environment.GetEnvironmentVariable("localappdata"); RootDir = Path.Combine(localAppData, "Roblox Studio Mod Manager"); @@ -194,19 +201,14 @@ static void Main(string[] rawArgs) var args = unprocessedArgs.ToArray(); State = JsonConvert.DeserializeObject(json); - + if (State == null) State = new ModManagerState(); // Make sure HTTPS uses TLS 1.2 ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12; - // Standard windows form jank - Application.EnableVisualStyles(); - Application.SetCompatibleTextRenderingDefault(false); - - Application.ApplicationExit += new EventHandler(OnExiting); - Application.Run(new Launcher(args)); + return args; } } } diff --git a/ProjectSrc/Resources/Icon.ico b/ProjectSrc/WinUI/Assets/Icon.ico similarity index 100% rename from ProjectSrc/Resources/Icon.ico rename to ProjectSrc/WinUI/Assets/Icon.ico diff --git a/ProjectSrc/Resources/Logo.png b/ProjectSrc/WinUI/Assets/Logo.png similarity index 100% rename from ProjectSrc/Resources/Logo.png rename to ProjectSrc/WinUI/Assets/Logo.png diff --git a/ProjectSrc/WinUI/BootstrapWindow.xaml b/ProjectSrc/WinUI/BootstrapWindow.xaml new file mode 100644 index 0000000..c64f4b7 --- /dev/null +++ b/ProjectSrc/WinUI/BootstrapWindow.xaml @@ -0,0 +1,81 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ProjectSrc/WinUI/BootstrapWindow.xaml.cs b/ProjectSrc/WinUI/BootstrapWindow.xaml.cs new file mode 100644 index 0000000..db35688 --- /dev/null +++ b/ProjectSrc/WinUI/BootstrapWindow.xaml.cs @@ -0,0 +1,215 @@ +using System; +using System.Collections.Concurrent; +using System.Collections.ObjectModel; +using System.Diagnostics.Contracts; +using System.IO; +using System.Threading; +using System.Threading.Tasks; + +using Microsoft.UI.Windowing; +using Microsoft.UI.Xaml; +using Microsoft.UI.Xaml.Controls; + +namespace RobloxStudioModManager +{ + public sealed partial class BootstrapWindow : Window + { + public StudioBootstrapper Bootstrapper { get; } + + private ConcurrentBag logQueue = new ConcurrentBag(); + private readonly ObservableCollection logLines = new ObservableCollection(); + private readonly bool exitOnClose; + private DispatcherTimer progressTimer; + private bool programmaticClose; + + // Initializes the main bootstrap window. + public BootstrapWindow(StudioBootstrapper bootstrapper, bool exitWhenClosed = false) + { + Contract.Requires(bootstrapper != null); + InitializeComponent(); + + Bootstrapper = bootstrapper; + exitOnClose = exitWhenClosed; + + Title = "Roblox Studio Bootstrapper"; + this.ApplyBackdrop(); + configureWindow(); + + LogListView.ItemsSource = logLines; + + bootstrapper.EchoFeed += new MessageFeed(echo); + bootstrapper.StatusFeed += new MessageFeed(setStatus); + bootstrapper.ConfirmFeed += new ConfirmPrompt(confirm); + + AppWindow.Closing += appWindow_Closing; + Closed += bootstrapWindow_Closed; + + Activate(); + } + + private void configureWindow() + { + AppWindow.SetIcon(Path.Combine(AppContext.BaseDirectory, "Assets", "Icon.ico")); + + if (AppWindow.Presenter is OverlappedPresenter presenter) + { + presenter.IsResizable = false; + presenter.IsMaximizable = false; + presenter.IsMinimizable = true; + presenter.IsAlwaysOnTop = true; + } + + WindowPositioning.ResizeAndCenter(AppWindow, 560, 340); + } + + public async Task Bootstrap() + { + var state = App.State; + var targetVersion = state.TargetVersion; + + progressTimer = new DispatcherTimer + { + Interval = TimeSpan.FromMilliseconds(100) + }; + + progressTimer.Tick += (sender, args) => + { + var progress = Bootstrapper.Progress; + Progress.IsIndeterminate = Bootstrapper.ProgressBarStyle == BootstrapProgressStyle.Indeterminate; + + var maxProgress = Bootstrapper.MaxProgress; + Progress.Maximum = maxProgress; + + if (progress > maxProgress) + { + Progress.Value = Math.Max(0, maxProgress - 1); + return; + } + + if (!logQueue.IsEmpty) + { + var newQueue = new ConcurrentBag(); + var drained = Interlocked.Exchange(ref logQueue, newQueue); + + foreach (var line in drained) + logLines.Add(line); + + LogListView.ScrollIntoView(logLines[logLines.Count - 1]); + } + + Progress.Value = Math.Min(progress, maxProgress); + }; + + progressTimer.Start(); + + var bootstrap = Bootstrapper.Bootstrap(targetVersion); + await bootstrap.ConfigureAwait(true); + } + + // Closes the window without triggering the "installation hasn't + // finished" confirmation prompt. + public void RequestClose() + { + programmaticClose = true; + Close(); + } + + public static async Task BringUpToDate(string expectedVersion, string updateReason, Window owner = null) + { + var versionData = App.State.VersionData; + string currentVersion = versionData.VersionGuid; + + if (currentVersion != expectedVersion) + { + bool proceed = true; + + if (!string.IsNullOrEmpty(currentVersion)) + { + var result = await DialogWindow.ShowAsync( + "Out of date!", + "Roblox Studio is out of date!\n" + updateReason + "\nWould you like to update now?", + "Yes", "No", ContentDialogButton.Primary, DialogIcon.Warning, owner); + + proceed = result == ContentDialogResult.Primary; + } + + if (proceed) + { + var bootstrapper = new StudioBootstrapper(); + var installer = new BootstrapWindow(bootstrapper); + + await installer.Bootstrap(); + installer.RequestClose(); + } + } + } + + private void setStatus(string status) + { + if (DispatcherQueue.HasThreadAccess) + StatusText.Text = status; + else + DispatcherQueue.TryEnqueue(() => StatusText.Text = status); + } + + private void echo(string msg) + { + logQueue.Add(msg); + } + + // Backs StudioBootstrapper.ConfirmFeed. Showing a DialogWindow must + // happen on this window's UI thread, so this always marshals through + // DispatcherQueue rather than assuming the caller is already there. + private Task confirm(string message, string title) + { + var tcs = new TaskCompletionSource(); + + bool enqueued = DispatcherQueue.TryEnqueue(async () => + { + try + { + var result = await DialogWindow.ShowAsync(title, message, "OK", "Cancel", ContentDialogButton.Primary, DialogIcon.Warning, this); + tcs.SetResult(result == ContentDialogResult.Primary); + } + catch (Exception ex) + { + tcs.SetException(ex); + } + }); + + if (!enqueued) + tcs.SetResult(true); + + return tcs.Task; + } + + private async void appWindow_Closing(AppWindow sender, AppWindowClosingEventArgs args) + { + if (programmaticClose) + return; + + // WinUI doesn't have CloseReason like WinForms, + // so we pause the close, ask and then either let it through or just cancel it. + args.Cancel = true; + + var result = await DialogWindow.ShowAsync( + "Warning", + "The installation has not finished yet!\n" + + "Closing this window will exit the mod manager.\n" + + "Are you sure you want to continue?", + "Yes", "No", ContentDialogButton.Close, DialogIcon.Warning, this); + + if (result == ContentDialogResult.Primary) + Environment.Exit(0); + } + + private void bootstrapWindow_Closed(object sender, WindowEventArgs args) + { + progressTimer?.Stop(); + App.SaveState(); + + if (exitOnClose) + Environment.Exit(0); + } + } +} diff --git a/ProjectSrc/WinUI/DialogWindow.xaml b/ProjectSrc/WinUI/DialogWindow.xaml new file mode 100644 index 0000000..1848c81 --- /dev/null +++ b/ProjectSrc/WinUI/DialogWindow.xaml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + +