Revert "refactor!: removal of fastflag configuration/#1321"

This reverts commit c3013a09c5.
This commit is contained in:
bluepilledgreat 2024-04-21 13:26:21 +01:00
parent c7bb481432
commit c0d61654e5
17 changed files with 1229 additions and 1 deletions

View File

@ -43,6 +43,7 @@ namespace Bloxstrap
public static readonly JsonManager<Settings> Settings = new(); public static readonly JsonManager<Settings> Settings = new();
public static readonly JsonManager<State> State = new(); public static readonly JsonManager<State> State = new();
public static readonly FastFlagManager FastFlags = new();
public static readonly HttpClient HttpClient = new( public static readonly HttpClient HttpClient = new(
new HttpClientLoggingHandler( new HttpClientLoggingHandler(
@ -178,6 +179,7 @@ namespace Bloxstrap
Settings.Load(); Settings.Load();
State.Load(); State.Load();
FastFlags.Load();
} }
if (!IsUninstall && !IsMenuLaunch) if (!IsUninstall && !IsMenuLaunch)

View File

@ -193,6 +193,7 @@ namespace Bloxstrap
await InstallWebView2(); await InstallWebView2();
App.FastFlags.Save();
await ApplyModifications(); await ApplyModifications();
if (App.IsFirstRun || FreshInstall) if (App.IsFirstRun || FreshInstall)

View File

@ -0,0 +1,229 @@
using System.Windows.Forms;
using Windows.Win32;
using Windows.Win32.Graphics.Gdi;
namespace Bloxstrap
{
public class FastFlagManager : JsonManager<Dictionary<string, object>>
{
public override string FileLocation => Path.Combine(Paths.Modifications, "ClientSettings\\ClientAppSettings.json");
// this is the value of the 'FStringPartTexturePackTablePre2022' flag
public const string OldTexturesFlagValue = "{\"foil\":{\"ids\":[\"rbxassetid://7546645012\",\"rbxassetid://7546645118\"],\"color\":[255,255,255,255]},\"brick\":{\"ids\":[\"rbxassetid://7546650097\",\"rbxassetid://7546645118\"],\"color\":[204,201,200,232]},\"cobblestone\":{\"ids\":[\"rbxassetid://7546652947\",\"rbxassetid://7546645118\"],\"color\":[212,200,187,250]},\"concrete\":{\"ids\":[\"rbxassetid://7546653951\",\"rbxassetid://7546654144\"],\"color\":[208,208,208,255]},\"diamondplate\":{\"ids\":[\"rbxassetid://7547162198\",\"rbxassetid://7546645118\"],\"color\":[170,170,170,255]},\"fabric\":{\"ids\":[\"rbxassetid://7547101130\",\"rbxassetid://7546645118\"],\"color\":[105,104,102,244]},\"glass\":{\"ids\":[\"rbxassetid://7547304948\",\"rbxassetid://7546645118\"],\"color\":[254,254,254,7]},\"granite\":{\"ids\":[\"rbxassetid://7547164710\",\"rbxassetid://7546645118\"],\"color\":[113,113,113,255]},\"grass\":{\"ids\":[\"rbxassetid://7547169285\",\"rbxassetid://7546645118\"],\"color\":[165,165,159,255]},\"ice\":{\"ids\":[\"rbxassetid://7547171356\",\"rbxassetid://7546645118\"],\"color\":[255,255,255,255]},\"marble\":{\"ids\":[\"rbxassetid://7547177270\",\"rbxassetid://7546645118\"],\"color\":[199,199,199,255]},\"metal\":{\"ids\":[\"rbxassetid://7547288171\",\"rbxassetid://7546645118\"],\"color\":[199,199,199,255]},\"pebble\":{\"ids\":[\"rbxassetid://7547291361\",\"rbxassetid://7546645118\"],\"color\":[208,208,208,255]},\"corrodedmetal\":{\"ids\":[\"rbxassetid://7547184629\",\"rbxassetid://7546645118\"],\"color\":[159,119,95,200]},\"sand\":{\"ids\":[\"rbxassetid://7547295153\",\"rbxassetid://7546645118\"],\"color\":[220,220,220,255]},\"slate\":{\"ids\":[\"rbxassetid://7547298114\",\"rbxassetid://7547298323\"],\"color\":[193,193,193,255]},\"wood\":{\"ids\":[\"rbxassetid://7547303225\",\"rbxassetid://7547298786\"],\"color\":[227,227,227,255]},\"woodplanks\":{\"ids\":[\"rbxassetid://7547332968\",\"rbxassetid://7546645118\"],\"color\":[212,209,203,255]},\"asphalt\":{\"ids\":[\"rbxassetid://9873267379\",\"rbxassetid://9438410548\"],\"color\":[123,123,123,234]},\"basalt\":{\"ids\":[\"rbxassetid://9873270487\",\"rbxassetid://9438413638\"],\"color\":[154,154,153,238]},\"crackedlava\":{\"ids\":[\"rbxassetid://9438582231\",\"rbxassetid://9438453972\"],\"color\":[74,78,80,156]},\"glacier\":{\"ids\":[\"rbxassetid://9438851661\",\"rbxassetid://9438453972\"],\"color\":[226,229,229,243]},\"ground\":{\"ids\":[\"rbxassetid://9439044431\",\"rbxassetid://9438453972\"],\"color\":[114,114,112,240]},\"leafygrass\":{\"ids\":[\"rbxassetid://9873288083\",\"rbxassetid://9438453972\"],\"color\":[121,117,113,234]},\"limestone\":{\"ids\":[\"rbxassetid://9873289812\",\"rbxassetid://9438453972\"],\"color\":[235,234,230,250]},\"mud\":{\"ids\":[\"rbxassetid://9873319819\",\"rbxassetid://9438453972\"],\"color\":[130,130,130,252]},\"pavement\":{\"ids\":[\"rbxassetid://9873322398\",\"rbxassetid://9438453972\"],\"color\":[142,142,144,236]},\"rock\":{\"ids\":[\"rbxassetid://9873515198\",\"rbxassetid://9438453972\"],\"color\":[154,154,154,248]},\"salt\":{\"ids\":[\"rbxassetid://9439566986\",\"rbxassetid://9438453972\"],\"color\":[220,220,221,255]},\"sandstone\":{\"ids\":[\"rbxassetid://9873521380\",\"rbxassetid://9438453972\"],\"color\":[174,171,169,246]},\"snow\":{\"ids\":[\"rbxassetid://9439632387\",\"rbxassetid://9438453972\"],\"color\":[218,218,218,255]}}";
public static IReadOnlyDictionary<string, string> PresetFlags = new Dictionary<string, string>
{
{ "Network.Log", "FLogNetwork" },
{ "HTTP.Log", "DFLogHttpTraceLight" },
{ "HTTP.Proxy.Enable", "DFFlagDebugEnableHttpProxy" },
{ "HTTP.Proxy.Address.1", "DFStringDebugPlayerHttpProxyUrl" },
{ "HTTP.Proxy.Address.2", "DFStringHttpCurlProxyHostAndPort" },
{ "HTTP.Proxy.Address.3", "DFStringHttpCurlProxyHostAndPortForExternalUrl" },
{ "Rendering.Framerate", "DFIntTaskSchedulerTargetFps" },
{ "Rendering.ManualFullscreen", "FFlagHandleAltEnterFullscreenManually" },
{ "Rendering.TexturePack", "FStringPartTexturePackTable2022" },
{ "Rendering.DisableScaling", "DFFlagDisableDPIScale" },
{ "Rendering.Lighting.Voxel", "DFFlagDebugRenderForceTechnologyVoxel" },
{ "Rendering.Lighting.ShadowMap", "FFlagDebugForceFutureIsBrightPhase2" },
{ "Rendering.Lighting.Future", "FFlagDebugForceFutureIsBrightPhase3" },
{ "UI.Hide", "DFIntCanHideGuiGroupId" },
{ "UI.FlagState", "FStringDebugShowFlagState" },
{ "UI.Menu.GraphicsSlider", "FFlagFixGraphicsQuality" },
{ "UI.Menu.Style.DisableV2", "FFlagDisableNewIGMinDUA" },
{ "UI.Menu.Style.EnableV4.1", "FFlagEnableInGameMenuControls" },
{ "UI.Menu.Style.EnableV4.2", "FFlagEnableInGameMenuModernization" },
{ "UI.Menu.Style.ABTest.1", "FFlagEnableMenuControlsABTest" },
{ "UI.Menu.Style.ABTest.2", "FFlagEnableMenuModernizationABTest" },
{ "UI.Menu.Style.ABTest.3", "FFlagEnableMenuModernizationABTest2" },
{ "UI.Menu.Style.ABTest.4", "FFlagEnableV3MenuABTest3" }
};
public static IReadOnlyDictionary<string, string> LightingModes => new Dictionary<string, string>
{
{ "Chosen by game", "None" },
{ "Voxel (Phase 1)", "Voxel" },
{ "ShadowMap (Phase 2)", "ShadowMap" },
{ "Future (Phase 3)", "Future" }
};
public static IReadOnlyDictionary<string, string?> MSAAModes => new Dictionary<string, string?>
{
{ "Automatic", null },
{ "1x MSAA", "1" },
{ "2x MSAA", "2" },
{ "4x MSAA", "4" },
{ "8x MSAA", "8" }
};
// this is one hell of a dictionary definition lmao
// since these all set the same flags, wouldn't making this use bitwise operators be better?
public static IReadOnlyDictionary<string, Dictionary<string, string?>> IGMenuVersions => new Dictionary<string, Dictionary<string, string?>>
{
{
"Default",
new Dictionary<string, string?>
{
{ "DisableV2", null },
{ "EnableV4", null },
{ "ABTest", null }
}
},
{
"Version 1 (2015)",
new Dictionary<string, string?>
{
{ "DisableV2", "True" },
{ "EnableV4", "False" },
{ "ABTest", "False" }
}
},
{
"Version 2 (2020)",
new Dictionary<string, string?>
{
{ "DisableV2", "False" },
{ "EnableV4", "False" },
{ "ABTest", "False" }
}
},
{
"Version 4 (2023)",
new Dictionary<string, string?>
{
{ "DisableV2", "True" },
{ "EnableV4", "True" },
{ "ABTest", "False" }
}
}
};
// all fflags are stored as strings
// to delete a flag, set the value as null
public void SetValue(string key, object? value)
{
const string LOG_IDENT = "FastFlagManager::SetValue";
if (value is null)
{
if (Prop.ContainsKey(key))
App.Logger.WriteLine(LOG_IDENT, $"Deletion of '{key}' is pending");
Prop.Remove(key);
}
else
{
if (Prop.ContainsKey(key))
{
if (key == Prop[key].ToString())
return;
App.Logger.WriteLine(LOG_IDENT, $"Changing of '{key}' from '{Prop[key]}' to '{value}' is pending");
}
else
{
App.Logger.WriteLine(LOG_IDENT, $"Setting of '{key}' to '{value}' is pending");
}
Prop[key] = value.ToString()!;
}
}
// this returns null if the fflag doesn't exist
public string? GetValue(string key)
{
// check if we have an updated change for it pushed first
if (Prop.TryGetValue(key, out object? value) && value is not null)
return value.ToString();
return null;
}
public void SetPreset(string prefix, object? value)
{
foreach (var pair in PresetFlags.Where(x => x.Key.StartsWith(prefix)))
SetValue(pair.Value, value);
}
public void SetPresetEnum(string prefix, string target, object? value)
{
foreach (var pair in PresetFlags.Where(x => x.Key.StartsWith(prefix)))
{
if (pair.Key.StartsWith($"{prefix}.{target}"))
SetValue(pair.Value, value);
else
SetValue(pair.Value, null);
}
}
public string? GetPreset(string name) => GetValue(PresetFlags[name]);
public string GetPresetEnum(IReadOnlyDictionary<string, string> mapping, string prefix, string value)
{
foreach (var pair in mapping)
{
if (pair.Value == "None")
continue;
if (GetPreset($"{prefix}.{pair.Value}") == value)
return pair.Key;
}
return mapping.First().Key;
}
public override void Save()
{
// convert all flag values to strings before saving
foreach (var pair in Prop)
Prop[pair.Key] = pair.Value.ToString()!;
base.Save();
}
public override void Load()
{
base.Load();
if (GetPreset("Rendering.ManualFullscreen") != "False")
SetPreset("Rendering.ManualFullscreen", "False");
// TODO - remove when activity tracking has been revamped
if (GetPreset("Network.Log") != "7")
SetPreset("Network.Log", "7");
string? val = GetPreset("UI.Menu.Style.EnableV4.1");
if (GetPreset("UI.Menu.Style.EnableV4.2") != val)
SetPreset("UI.Menu.Style.EnableV4.2", val);
if (GetPreset("Rendering.Framerate") is not null)
return;
// set it to be the framerate of the primary display by default
var screen = Screen.AllScreens.Where(x => x.Primary).Single();
var devmode = new DEVMODEW();
PInvoke.EnumDisplaySettings(screen.DeviceName, ENUM_DISPLAY_SETTINGS_MODE.ENUM_CURRENT_SETTINGS, ref devmode);
uint framerate = devmode.dmDisplayFrequency;
if (framerate <= 100)
framerate *= 2;
SetPreset("Rendering.Framerate", framerate);
}
}
}

View File

@ -131,6 +131,7 @@ namespace Bloxstrap
App.IsSetupComplete = false; App.IsSetupComplete = false;
App.FastFlags.Load();
Controls.ShowMenu(); Controls.ShowMenu();
// exit if we don't click the install button on installation // exit if we don't click the install button on installation
@ -209,6 +210,37 @@ namespace Bloxstrap
Bootstrapper.Register(); Bootstrapper.Register();
// update migrations
if (App.BuildMetadata.CommitRef.StartsWith("tag"))
{
if (existingVersionInfo.ProductVersion == "2.4.0")
{
App.FastFlags.SetValue("DFFlagDisableDPIScale", null);
App.FastFlags.SetValue("DFFlagVariableDPIScale2", null);
App.FastFlags.Save();
}
else if (existingVersionInfo.ProductVersion == "2.5.0")
{
App.FastFlags.SetValue("FIntDebugForceMSAASamples", null);
if (App.FastFlags.GetPreset("UI.Menu.Style.DisableV2") is not null)
App.FastFlags.SetPreset("UI.Menu.Style.ABTest", false);
App.FastFlags.Save();
}
else if (existingVersionInfo.ProductVersion == "2.5.3")
{
App.FastFlags.SetValue("FFlagDebugGraphicsPreferD3D11", null);
App.FastFlags.SetValue("FFlagDebugGraphicsPreferD3D11FL10", null);
App.FastFlags.SetValue("FFlagDebugGraphicsPreferVulkan", null);
App.FastFlags.SetValue("FFlagRenderVulkanFixMinimizeWindow", null);
App.FastFlags.SetValue("FFlagDebugGraphicsPreferOpenGL", null);
App.FastFlags.Save();
}
}
if (isAutoUpgrade) if (isAutoUpgrade)
{ {
App.NotifyIcon?.ShowAlert( App.NotifyIcon?.ShowAlert(

View File

@ -0,0 +1,9 @@
namespace Bloxstrap.Models
{
public class FastFlag
{
// public bool Enabled { get; set; }
public string Name { get; set; } = null!;
public string Value { get; set; } = null!;
}
}

View File

@ -0,0 +1,60 @@
<ui:UiWindow x:Class="Bloxstrap.UI.Elements.Dialogs.AddFastFlagDialog"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:ui="http://schemas.lepo.co/wpfui/2022/xaml"
xmlns:local="clr-namespace:Bloxstrap.UI.Elements.Dialogs"
mc:Ignorable="d"
Title="Add FastFlag"
MinHeight="0"
Width="480"
SizeToContent="Height"
ResizeMode="NoResize"
Background="{ui:ThemeResource ApplicationBackgroundBrush}"
ExtendsContentIntoTitleBar="True"
WindowStartupLocation="CenterScreen">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<ui:TitleBar Grid.Row="0" Grid.ColumnSpan="2" Padding="8" Title="Add FastFlag" ShowMinimize="False" ShowMaximize="False" CanMaximize="False" KeyboardNavigation.TabNavigation="None" />
<Grid Grid.Row="1" Margin="15">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<TextBlock Grid.Row="0" Grid.Column="0" VerticalAlignment="Center" MinWidth="100" Text="Name" Margin="0,0,0,12" />
<TextBox Grid.Row="0" Grid.Column="1" Name="FlagNameTextBox" Margin="0,0,0,12" />
<TextBlock Grid.Row="1" Grid.Column="0" VerticalAlignment="Center" MinWidth="100" Text="Value" />
<TextBox Grid.Row="1" Grid.Column="1" Name="FlagValueTextBox" />
</Grid>
<Border Grid.Row="2" Margin="0,10,0,0" Padding="15" Background="{ui:ThemeResource SolidBackgroundFillColorSecondaryBrush}">
<StackPanel Orientation="Horizontal" FlowDirection="LeftToRight" HorizontalAlignment="Right">
<Button MinWidth="100" Content="OK" Click="OKButton_Click">
<Button.Style>
<Style TargetType="Button" BasedOn="{StaticResource {x:Type Button}}">
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=FlagNameTextBox, Path=Text.Length}" Value="0">
<Setter Property="IsEnabled" Value="False" />
</DataTrigger>
</Style.Triggers>
</Style>
</Button.Style>
</Button>
<Button MinWidth="100" Margin="12,0,0,0" Content="Cancel" IsCancel="True" />
</StackPanel>
</Border>
</Grid>
</ui:UiWindow>

View File

@ -0,0 +1,35 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
namespace Bloxstrap.UI.Elements.Dialogs
{
/// <summary>
/// Interaction logic for AddFlagDialog.xaml
/// </summary>
public partial class AddFastFlagDialog
{
public MessageBoxResult Result = MessageBoxResult.Cancel;
public AddFastFlagDialog()
{
InitializeComponent();
}
private void OKButton_Click(object sender, RoutedEventArgs e)
{
Result = MessageBoxResult.OK;
Close();
}
}
}

View File

@ -0,0 +1,60 @@
<ui:UiWindow x:Class="Bloxstrap.UI.Elements.Dialogs.BulkAddFastFlagDialog"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:ui="http://schemas.lepo.co/wpfui/2022/xaml"
xmlns:local="clr-namespace:Bloxstrap.UI.Elements.Dialogs"
mc:Ignorable="d"
Title="Import JSON"
MinHeight="0"
Width="480"
SizeToContent="Height"
ResizeMode="NoResize"
Background="{ui:ThemeResource ApplicationBackgroundBrush}"
ExtendsContentIntoTitleBar="True"
WindowStartupLocation="CenterScreen">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<ui:TitleBar Grid.Row="0" Grid.ColumnSpan="2" Padding="8" Title="Import JSON" ShowMinimize="False" ShowMaximize="False" CanMaximize="False" KeyboardNavigation.TabNavigation="None" />
<Grid Grid.Row="1" Margin="8,4,8,4">
<TextBox x:Name="JsonTextBox" Margin="5" AcceptsTab="True" AcceptsReturn="True" MinHeight="80" MaxHeight="480" />
<TextBlock IsHitTestVisible="False" Margin="18,14,0,0" Foreground="DarkGray">
<TextBlock.Style>
<Style TargetType="{x:Type TextBlock}">
<Setter Property="Visibility" Value="Collapsed"/>
<Style.Triggers>
<DataTrigger Binding="{Binding Text, ElementName=JsonTextBox}" Value="">
<Setter Property="Visibility" Value="Visible"/>
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
Paste in your JSON here...
</TextBlock>
</Grid>
<Border Grid.Row="3" Margin="0,10,0,0" Padding="15" Background="{ui:ThemeResource SolidBackgroundFillColorSecondaryBrush}">
<StackPanel Orientation="Horizontal" FlowDirection="LeftToRight" HorizontalAlignment="Right">
<Button MinWidth="100" Content="OK" Click="OKButton_Click">
<Button.Style>
<Style TargetType="Button" BasedOn="{StaticResource {x:Type Button}}">
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=JsonTextBox, Path=Text.Length}" Value="0">
<Setter Property="IsEnabled" Value="False" />
</DataTrigger>
</Style.Triggers>
</Style>
</Button.Style>
</Button>
<Button MinWidth="100" Margin="12,0,0,0" Content="Cancel" IsCancel="True" />
</StackPanel>
</Border>
</Grid>
</ui:UiWindow>

View File

@ -0,0 +1,35 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
namespace Bloxstrap.UI.Elements.Dialogs
{
/// <summary>
/// Interaction logic for BulkAddFastFlagDialog.xaml
/// </summary>
public partial class BulkAddFastFlagDialog
{
public MessageBoxResult Result = MessageBoxResult.Cancel;
public BulkAddFastFlagDialog()
{
InitializeComponent();
}
private void OKButton_Click(object sender, RoutedEventArgs e)
{
Result = MessageBoxResult.OK;
Close();
}
}
}

View File

@ -39,11 +39,13 @@
<ui:NavigationFluent.Items> <ui:NavigationFluent.Items>
<ui:NavigationItem Content="Integrations" PageType="{x:Type pages:IntegrationsPage}" Icon="Add28" Tag="integrations" /> <ui:NavigationItem Content="Integrations" PageType="{x:Type pages:IntegrationsPage}" Icon="Add28" Tag="integrations" />
<ui:NavigationItem Content="Mods" PageType="{x:Type pages:ModsPage}" Icon="WrenchScrewdriver20" Tag="mods" /> <ui:NavigationItem Content="Mods" PageType="{x:Type pages:ModsPage}" Icon="WrenchScrewdriver20" Tag="mods" />
<ui:NavigationItem Content="FastFlags" PageType="{x:Type pages:FastFlagsPage}" Icon="Flag24" Tag="fastflags" />
<ui:NavigationItem Content="Appearance" PageType="{x:Type pages:AppearancePage}" Icon="PaintBrush24" Tag="appearance" /> <ui:NavigationItem Content="Appearance" PageType="{x:Type pages:AppearancePage}" Icon="PaintBrush24" Tag="appearance" />
<ui:NavigationItem Content="Behaviour" PageType="{x:Type pages:BehaviourPage}" Icon="Settings24" Tag="behaviour" /> <ui:NavigationItem Content="Behaviour" PageType="{x:Type pages:BehaviourPage}" Icon="Settings24" Tag="behaviour" />
<ui:NavigationItem Content="Installation" PageType="{x:Type pages:InstallationPage}" Icon="HardDrive20" Tag="installation" /> <ui:NavigationItem Content="Installation" PageType="{x:Type pages:InstallationPage}" Icon="HardDrive20" Tag="installation" />
<ui:NavigationItem Content="About" PageType="{x:Type pages:AboutPage}" Icon="QuestionCircle48" Tag="about" /> <ui:NavigationItem Content="About" PageType="{x:Type pages:AboutPage}" Icon="QuestionCircle48" Tag="about" />
<ui:NavigationItem Content="FastFlag Editor" PageType="{x:Type pages:FastFlagEditorPage}" Tag="fastflageditor" Visibility="Collapsed" />
<ui:NavigationItem Content="Before you install..." PageType="{x:Type pages:PreInstallPage}" Tag="preinstall" Visibility="Collapsed" /> <ui:NavigationItem Content="Before you install..." PageType="{x:Type pages:PreInstallPage}" Tag="preinstall" Visibility="Collapsed" />
</ui:NavigationFluent.Items> </ui:NavigationFluent.Items>
</ui:NavigationFluent> </ui:NavigationFluent>

View File

@ -0,0 +1,95 @@
<ui:UiPage x:Class="Bloxstrap.UI.Elements.Menu.Pages.FastFlagEditorPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:ui="http://schemas.lepo.co/wpfui/2022/xaml"
xmlns:local="clr-namespace:Bloxstrap.UI.Elements.Menu.Pages"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800"
Title="FastFlagEditorPage"
Loaded="Page_Loaded">
<Grid Margin="0,0,14,14">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<TextBlock Grid.Row="0" Margin="0,0,0,16" Text="Manage your own FastFlags. Double click a column to edit." FontSize="14" Foreground="{DynamicResource TextFillColorSecondaryBrush}" />
<StackPanel Grid.Row="1" Margin="0,0,0,16" Orientation="Horizontal">
<ui:Button Icon="ArrowLeft48" Content="Back" Click="BackButton_Click" />
<ui:Button Icon="Add28" Content="Add new" Click="AddButton_Click" Margin="12,0,0,0" />
<ui:Button Icon="Delete48" Content="Delete selected" Click="DeleteButton_Click" Appearance="Danger" Margin="12,0,0,0">
<ui:Button.Style>
<Style TargetType="ui:Button" BasedOn="{StaticResource {x:Type ui:Button}}">
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=DataGrid, Path=SelectedItems.Count}" Value="0">
<Setter Property="IsEnabled" Value="False" />
</DataTrigger>
</Style.Triggers>
</Style>
</ui:Button.Style>
</ui:Button>
<ToggleButton x:Name="TogglePresetsButton" Content="Show preset flags" Click="ToggleButton_Click" Margin="12,0,0,0" />
<ui:Button Icon="ArrowImport24" Content="Import JSON" Margin="12,0,0,0" Click="ImportJSONButton_Click" />
</StackPanel>
<ui:TextBox x:Name="SearchTextBox" Grid.Row="2" Margin="0,0,0,16" Icon="Search32" PlaceholderText="Search" TextChanged="SearchTextBox_TextChanged" />
<DataGrid Name="DataGrid" Grid.Row="3" HeadersVisibility="Column" GridLinesVisibility="Horizontal" AutoGenerateColumns="False" CanUserAddRows="False" CanUserDeleteRows="False" CellEditEnding="DataGrid_CellEditEnding">
<DataGrid.Style>
<Style TargetType="DataGrid" BasedOn="{StaticResource {x:Type DataGrid}}">
<Setter Property="Background" Value="Transparent" />
<Setter Property="BorderThickness" Value="0" />
</Style>
</DataGrid.Style>
<DataGrid.ColumnHeaderStyle>
<Style TargetType="DataGridColumnHeader">
<Setter Property="Background" Value="{DynamicResource ControlFillColorTertiaryBrush}" />
<Setter Property="Height" Value="32" />
<Setter Property="Padding" Value="8,0,8,0" />
<Setter Property="BorderBrush" Value="{DynamicResource ControlElevationBorderBrush}" />
<Setter Property="BorderThickness" Value="1" />
</Style>
</DataGrid.ColumnHeaderStyle>
<DataGrid.CellStyle>
<Style TargetType="DataGridCell">
<Style.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter Property="Foreground">
<Setter.Value>
<SolidColorBrush Color="{DynamicResource TextOnAccentFillColorPrimary}" />
</Setter.Value>
</Setter>
<Setter Property="Background">
<Setter.Value>
<SolidColorBrush Color="{DynamicResource SystemAccentColorSecondary}" />
</Setter.Value>
</Setter>
</Trigger>
</Style.Triggers>
<Setter Property="Height" Value="32" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="DataGridCell">
<Border Background="{TemplateBinding Background}" Padding="6,0,6,0">
<ContentPresenter VerticalAlignment="Center" />
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</DataGrid.CellStyle>
<DataGrid.Columns>
<DataGridTextColumn Header="Name" Binding="{Binding Name}" />
<DataGridTextColumn Header="Value" Binding="{Binding Value}" Width="*" />
</DataGrid.Columns>
</DataGrid>
</Grid>
</ui:UiPage>

View File

@ -0,0 +1,309 @@
using System.Collections.ObjectModel;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using Microsoft.Win32;
using Wpf.Ui.Mvvm.Contracts;
using Bloxstrap.UI.Elements.Dialogs;
using System.Xml.Linq;
namespace Bloxstrap.UI.Elements.Menu.Pages
{
/// <summary>
/// Interaction logic for FastFlagEditorPage.xaml
/// </summary>
public partial class FastFlagEditorPage
{
// believe me when i say there is absolutely zero point to using mvvm for this
// using a datagrid is a codebehind thing only and thats it theres literally no way around it
private readonly ObservableCollection<FastFlag> _fastFlagList = new();
private bool _showPresets = false;
private string _searchFilter = "";
public FastFlagEditorPage()
{
InitializeComponent();
}
private void ReloadList()
{
var selectedEntry = DataGrid.SelectedItem as FastFlag;
_fastFlagList.Clear();
var presetFlags = FastFlagManager.PresetFlags.Values;
foreach (var pair in App.FastFlags.Prop.OrderBy(x => x.Key))
{
if (!_showPresets && presetFlags.Contains(pair.Key))
continue;
if (!pair.Key.ToLower().Contains(_searchFilter.ToLower()))
continue;
var entry = new FastFlag
{
// Enabled = true,
Name = pair.Key,
Value = pair.Value.ToString()!
};
/* if (entry.Name.StartsWith("Disable"))
{
entry.Enabled = false;
entry.Name = entry.Name[7..];
} */
_fastFlagList.Add(entry);
}
if (DataGrid.ItemsSource is null)
DataGrid.ItemsSource = _fastFlagList;
if (selectedEntry is null)
return;
var newSelectedEntry = _fastFlagList.Where(x => x.Name == selectedEntry.Name).FirstOrDefault();
if (newSelectedEntry is null)
return;
DataGrid.SelectedItem = newSelectedEntry;
DataGrid.ScrollIntoView(newSelectedEntry);
}
private void ClearSearch(bool refresh = true)
{
SearchTextBox.Text = "";
_searchFilter = "";
if (refresh)
ReloadList();
}
// refresh list on page load to synchronize with preset page
private void Page_Loaded(object sender, RoutedEventArgs e) => ReloadList();
private void DataGrid_CellEditEnding(object sender, DataGridCellEditEndingEventArgs e)
{
int index = e.Row.GetIndex();
FastFlag entry = _fastFlagList[index];
switch (e.Column.Header)
{
/* case "Enabled":
bool enabled = (bool)((CheckBox)e.EditingElement).IsChecked!;
if (enabled)
{
App.FastFlags.SetValue(entry.Name, entry.Value);
App.FastFlags.SetValue($"Disable{entry.Name}", null);
}
else
{
App.FastFlags.SetValue(entry.Name, null);
App.FastFlags.SetValue($"Disable{entry.Name}", entry.Value);
}
break; */
case "Name":
var textbox = e.EditingElement as TextBox;
string oldName = entry.Name;
string newName = textbox!.Text;
if (newName == oldName)
return;
if (App.FastFlags.GetValue(newName) is not null)
{
Controls.ShowMessageBox("A FastFlag with this name already exists.", MessageBoxImage.Information);
e.Cancel = true;
textbox.Text = oldName;
return;
}
App.FastFlags.SetValue(oldName, null);
App.FastFlags.SetValue(newName, entry.Value);
if (!newName.Contains(_searchFilter))
ClearSearch();
break;
case "Value":
string newValue = ((TextBox)e.EditingElement).Text;
App.FastFlags.SetValue(entry.Name, newValue);
break;
}
}
private void BackButton_Click(object sender, RoutedEventArgs e)
{
if (Window.GetWindow(this) is INavigationWindow window)
window.Navigate(typeof(FastFlagsPage));
}
private void AddButton_Click(object sender, RoutedEventArgs e)
{
var dialog = new AddFastFlagDialog();
dialog.ShowDialog();
if (dialog.Result != MessageBoxResult.OK)
return;
string name = dialog.FlagNameTextBox.Text;
FastFlag? entry;
if (App.FastFlags.GetValue(name) is null)
{
entry = new FastFlag
{
// Enabled = true,
Name = dialog.FlagNameTextBox.Text,
Value = dialog.FlagValueTextBox.Text
};
if (!name.Contains(_searchFilter))
ClearSearch();
_fastFlagList.Add(entry);
App.FastFlags.SetValue(entry.Name, entry.Value);
}
else
{
Controls.ShowMessageBox("An entry for this FastFlag already exists.", MessageBoxImage.Information);
bool refresh = false;
if (!_showPresets && FastFlagManager.PresetFlags.Values.Contains(name))
{
TogglePresetsButton.IsChecked = true;
_showPresets = true;
refresh = true;
}
if (!name.Contains(_searchFilter))
{
ClearSearch(false);
refresh = true;
}
if (refresh)
ReloadList();
entry = _fastFlagList.Where(x => x.Name == name).FirstOrDefault();
}
DataGrid.SelectedItem = entry;
DataGrid.ScrollIntoView(entry);
}
private void DeleteButton_Click(object sender, RoutedEventArgs e)
{
var tempList = new List<FastFlag>();
foreach (FastFlag entry in DataGrid.SelectedItems)
tempList.Add(entry);
foreach (FastFlag entry in tempList)
{
_fastFlagList.Remove(entry);
App.FastFlags.SetValue(entry.Name, null);
}
}
private void ToggleButton_Click(object sender, RoutedEventArgs e)
{
if (sender is not ToggleButton button)
return;
_showPresets = button.IsChecked ?? false;
ReloadList();
}
private void ImportJSONButton_Click(object sender, RoutedEventArgs e)
{
string json = "";
Dictionary<string, object>? list = null;
while (list is null)
{
var dialog = new BulkAddFastFlagDialog();
dialog.JsonTextBox.Text = json;
dialog.ShowDialog();
if (dialog.Result != MessageBoxResult.OK)
return;
json = dialog.JsonTextBox.Text;
try
{
list = JsonSerializer.Deserialize<Dictionary<string, object>>(json);
if (list is null)
throw new Exception("JSON deserialization returned null");
}
catch (Exception ex)
{
Controls.ShowMessageBox(
"The JSON you've entered does not appear to be valid. Please double check it and try again.\n" +
"\n" +
"More information:\n" +
$"{ex.Message}",
MessageBoxImage.Error
);
}
}
var conflictingFlags = App.FastFlags.Prop.Where(x => list.ContainsKey(x.Key)).Select(x => x.Key);
bool overwriteConflicting = false;
if (conflictingFlags.Any())
{
int count = conflictingFlags.Count();
string message = "Some of the flags you are attempting to import already have set values. Would you like to overwrite their current values with the ones defined in the import?\n" +
"\n" +
$"There are {count} conflicting flag definitions:\n" +
String.Join(", ", conflictingFlags.Take(25));
if (count > 25)
message += "...";
var result = Controls.ShowMessageBox(message, MessageBoxImage.Question, MessageBoxButton.YesNo);
overwriteConflicting = result == MessageBoxResult.Yes;
}
foreach (var pair in list)
{
if (App.FastFlags.Prop.ContainsKey(pair.Key) && !overwriteConflicting)
continue;
App.FastFlags.SetValue(pair.Key, pair.Value);
}
ClearSearch();
}
private void SearchTextBox_TextChanged(object sender, TextChangedEventArgs e)
{
if (sender is not TextBox textbox)
return;
_searchFilter = textbox.Text;
ReloadList();
}
}
}

View File

@ -0,0 +1,195 @@
<ui:UiPage x:Class="Bloxstrap.UI.Elements.Menu.Pages.FastFlagsPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:models="clr-namespace:Bloxstrap.UI.ViewModels"
xmlns:ui="http://schemas.lepo.co/wpfui/2022/xaml"
mc:Ignorable="d"
d:DesignHeight="1000" d:DesignWidth="800"
Title="FastFlagsPage"
Scrollable="True"
Loaded="Page_Loaded">
<StackPanel Margin="0,0,14,14">
<TextBlock Margin="0,0,0,16" Text="Control how specific Roblox engine parameters and features are configured." FontSize="14" Foreground="{DynamicResource TextFillColorSecondaryBrush}" />
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<ui:CardAction Grid.Column="0" Margin="0,0,4,0" Icon="EditSettings24" Command="{Binding OpenFastFlagEditorCommand}">
<StackPanel>
<TextBlock FontSize="14" Text="FastFlag Editor" />
<TextBlock Margin="0,2,0,0" FontSize="12" Text="Manage your own FastFlags." Padding="0,0,16,0" Foreground="{DynamicResource TextFillColorTertiaryBrush}" />
</StackPanel>
</ui:CardAction>
<ui:CardAction Grid.Column="1" Margin="4,0,0,0" Icon="BookQuestionMark24" Command="models:GlobalViewModel.OpenWebpageCommand" CommandParameter="https://github.com/pizzaboxer/bloxstrap/wiki/A-guide-to-FastFlags">
<StackPanel>
<TextBlock FontSize="14" Text="Help" />
<TextBlock Margin="0,2,0,0" FontSize="12" Text="Learn more about FastFlags." Padding="0,0,16,0" Foreground="{DynamicResource TextFillColorTertiaryBrush}" />
</StackPanel>
</ui:CardAction>
</Grid>
<StackPanel Visibility="{Binding Source={x:Static models:GlobalViewModel.ShowDebugStuff}, Mode=OneTime}">
<TextBlock Text="Debug" FontSize="16" FontWeight="Medium" Margin="0,16,0,0" />
<ui:CardControl Margin="0,8,0,0">
<ui:CardControl.Header>
<StackPanel>
<TextBlock FontSize="14" Text="HTTP request logging" />
<TextBlock Margin="0,2,0,0" FontSize="12" Text="Enables logging of HTTP requests (DFLogHttpTraceLight=12)." Foreground="{DynamicResource TextFillColorTertiaryBrush}" />
</StackPanel>
</ui:CardControl.Header>
<ui:ToggleSwitch IsChecked="{Binding HttpRequestLogging, Mode=TwoWay}" />
</ui:CardControl>
<ui:CardControl Margin="0,8,0,0">
<ui:CardControl.Header>
<StackPanel>
<TextBlock FontSize="14" Text="HTTP proxy address" />
<TextBlock Margin="0,2,0,0" FontSize="12" Text="Set blank if not using a proxy. Don't forget to add cacert.pem as a mod." Foreground="{DynamicResource TextFillColorTertiaryBrush}" />
</StackPanel>
</ui:CardControl.Header>
<ui:TextBox Margin="5,0,0,0" Padding="10,5,10,5" Width="200" Text="{Binding HttpRequestProxy, Mode=TwoWay}" />
</ui:CardControl>
<ui:CardControl Margin="0,8,0,0">
<ui:CardControl.Header>
<StackPanel>
<TextBlock FontSize="14" Text="Flag state overlay" />
<TextBlock Margin="0,2,0,0" FontSize="12" Text="Show values of specified flags during runtime. Each flag is comma separated." Foreground="{DynamicResource TextFillColorTertiaryBrush}" />
</StackPanel>
</ui:CardControl.Header>
<ui:TextBox Margin="5,0,0,0" Padding="10,5,10,5" Width="200" Text="{Binding StateOverlayFlags, Mode=TwoWay}" />
</ui:CardControl>
</StackPanel>
<TextBlock Text="Presets" FontSize="16" FontWeight="Medium" Margin="0,16,0,0" />
<TextBlock Foreground="{DynamicResource TextFillColorSecondaryBrush}">
FastFlag preset for Direct3D
<Hyperlink Foreground="{DynamicResource TextFillColorPrimaryBrush}" Command="models:GlobalViewModel.OpenWebpageCommand" CommandParameter="https://github.com/pizzaboxer/bloxstrap/wiki/A-guide-to-FastFlags#exclusive-fullscreen">exclusive fullscreen</Hyperlink>
using Alt+Enter is already enabled by default.
</TextBlock>
<ui:CardControl Margin="0,8,0,0">
<ui:CardControl.Header>
<StackPanel>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0" FontSize="14" Text="Framerate limit" />
<TextBlock Grid.Column="1" Margin="4,0,0,0">
<Hyperlink TextDecorations="None" ToolTip="More information on this preset" Command="models:GlobalViewModel.OpenWebpageCommand" CommandParameter="https://github.com/pizzaboxer/bloxstrap/wiki/A-guide-to-FastFlags#framerate-limit">
<ui:SymbolIcon Symbol="QuestionCircle48" Margin="0,1,0,0" />
</Hyperlink>
</TextBlock>
</Grid>
<TextBlock Margin="0,2,0,0" FontSize="12" Text="Use a large number like 9999 for no limit. Set as 0 for defaults. " Foreground="{DynamicResource TextFillColorTertiaryBrush}" />
</StackPanel>
</ui:CardControl.Header>
<ui:TextBox Margin="5,0,0,0" Padding="10,5,10,5" Width="200" Text="{Binding FramerateLimit, Mode=TwoWay}" PreviewTextInput="ValidateInt32" />
</ui:CardControl>
<ui:CardControl Margin="0,8,0,0">
<ui:CardControl.Header>
<StackPanel>
<TextBlock FontSize="14" Text="Preferred lighting technology" />
<TextBlock Margin="0,2,0,0" FontSize="12" Text="Choose which lighting technology should be forced enabled in all games." Foreground="{DynamicResource TextFillColorTertiaryBrush}" />
</StackPanel>
</ui:CardControl.Header>
<ComboBox Margin="5,0,0,0" Padding="10,5,10,5" Width="200" ItemsSource="{Binding LightingModes.Keys, Mode=OneTime}" Text="{Binding SelectedLightingMode, Mode=TwoWay}" />
</ui:CardControl>
<ui:CardControl Margin="0,8,0,0">
<ui:CardControl.Header>
<StackPanel>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0" FontSize="14" Text="Preferred escape menu version" />
<TextBlock Grid.Column="1" Margin="4,0,0,0">
<Hyperlink TextDecorations="None" ToolTip="More information on this preset" Command="models:GlobalViewModel.OpenWebpageCommand" CommandParameter="https://github.com/pizzaboxer/bloxstrap/wiki/A-guide-to-FastFlags#escape-menu-version">
<ui:SymbolIcon Symbol="QuestionCircle48" Margin="0,1,0,0" />
</Hyperlink>
</TextBlock>
</Grid>
<TextBlock Margin="0,2,0,0" FontSize="12" Text="Choose which version of the escape menu to use." Foreground="{DynamicResource TextFillColorTertiaryBrush}" />
</StackPanel>
</ui:CardControl.Header>
<ComboBox Margin="5,0,0,0" Padding="10,5,10,5" Width="200" ItemsSource="{Binding IGMenuVersions.Keys, Mode=OneTime}" Text="{Binding SelectedIGMenuVersion, Mode=TwoWay}" />
</ui:CardControl>
<ui:CardControl Margin="0,8,0,0">
<ui:CardControl.Header>
<StackPanel>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0" FontSize="14" Text="Enable ability to hide GUIs" />
<TextBlock Grid.Column="1" Margin="4,0,0,0">
<Hyperlink TextDecorations="None" ToolTip="More information on this preset" Command="models:GlobalViewModel.OpenWebpageCommand" CommandParameter="https://github.com/pizzaboxer/bloxstrap/wiki/A-guide-to-FastFlags#gui-hiding">
<ui:SymbolIcon Symbol="QuestionCircle48" Margin="0,1,0,0" />
</Hyperlink>
</TextBlock>
</Grid>
<TextBlock Margin="0,2,0,0" FontSize="12" Foreground="{DynamicResource TextFillColorTertiaryBrush}">
Toggled with <Hyperlink Foreground="{DynamicResource TextFillColorPrimaryBrush}" Command="models:GlobalViewModel.OpenWebpageCommand" CommandParameter="https://github.com/pizzaboxer/bloxstrap/wiki/A-guide-to-FastFlags#gui-hiding">keyboard shortcuts</Hyperlink>. Only works if you're in the <Hyperlink Foreground="{DynamicResource TextFillColorPrimaryBrush}" Command="models:GlobalViewModel.OpenWebpageCommand" CommandParameter="https://www.roblox.com/groups/32380007/Bloxstrap">Bloxstrap group</Hyperlink>.
</TextBlock>
</StackPanel>
</ui:CardControl.Header>
<ui:ToggleSwitch IsChecked="{Binding GuiHidingEnabled, Mode=TwoWay}" />
</ui:CardControl>
<ui:CardControl Margin="0,8,0,0">
<ui:CardControl.Header>
<StackPanel>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0" FontSize="14" Text="Use old material textures" />
<TextBlock Grid.Column="1" Margin="4,0,0,0">
<Hyperlink TextDecorations="None" ToolTip="More information on this preset" Command="models:GlobalViewModel.OpenWebpageCommand" CommandParameter="https://github.com/pizzaboxer/bloxstrap/wiki/A-guide-to-FastFlags#old-material-textures">
<ui:SymbolIcon Symbol="QuestionCircle48" Margin="0,1,0,0" />
</Hyperlink>
</TextBlock>
</Grid>
<TextBlock Margin="0,2,0,0" FontSize="12" Text="Toggle whether to use the old material textures used prior to 2022." Foreground="{DynamicResource TextFillColorTertiaryBrush}" />
</StackPanel>
</ui:CardControl.Header>
<ui:ToggleSwitch IsChecked="{Binding Pre2022TexturesEnabled, Mode=TwoWay}" />
</ui:CardControl>
<ui:CardControl Margin="0,8,0,0">
<ui:CardControl.Header>
<StackPanel>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0" FontSize="14" Text="Preserve rendering quality with display scaling" />
<TextBlock Grid.Column="1" Margin="4,0,0,0">
<Hyperlink TextDecorations="None" ToolTip="More information on this preset" Command="models:GlobalViewModel.OpenWebpageCommand" CommandParameter="https://github.com/pizzaboxer/bloxstrap/wiki/A-guide-to-FastFlags#dpi-scaling-fixes">
<ui:SymbolIcon Symbol="QuestionCircle48" Margin="0,1,0,0" />
</Hyperlink>
</TextBlock>
</Grid>
<TextBlock Margin="0,2,0,0" FontSize="12" Text="Roblox reduces your rendering quality, depending on display scaling. This toggle disables that." Foreground="{DynamicResource TextFillColorTertiaryBrush}" />
</StackPanel>
</ui:CardControl.Header>
<ui:ToggleSwitch IsChecked="{Binding FixDisplayScaling, Mode=TwoWay}" />
</ui:CardControl>
<ui:CardControl Margin="0,8,0,0">
<ui:CardControl.Header>
<StackPanel>
<TextBlock FontSize="14" Text="Use alternate graphics quality selector" />
<TextBlock Margin="0,2,0,0" FontSize="12" Text="Toggle between using the consolidated 1-10 / fine-grained 1-21 graphics quality slider." Foreground="{DynamicResource TextFillColorTertiaryBrush}" />
</StackPanel>
</ui:CardControl.Header>
<ui:ToggleSwitch IsChecked="{Binding AlternateGraphicsSelectorEnabled, Mode=TwoWay}" />
</ui:CardControl>
</StackPanel>
</ui:UiPage>

View File

@ -0,0 +1,36 @@
using System.Windows;
using System.Windows.Input;
using Bloxstrap.UI.ViewModels.Menu;
namespace Bloxstrap.UI.Elements.Menu.Pages
{
/// <summary>
/// Interaction logic for FastFlagsPage.xaml
/// </summary>
public partial class FastFlagsPage
{
bool _initialLoad = false;
public FastFlagsPage()
{
DataContext = new FastFlagsViewModel(this);
InitializeComponent();
}
private void Page_Loaded(object sender, RoutedEventArgs e)
{
// refresh datacontext on page load to synchronize with editor page
if (!_initialLoad)
{
_initialLoad = true;
return;
}
DataContext = new FastFlagsViewModel(this);
}
private void ValidateInt32(object sender, TextCompositionEventArgs e) => e.Handled = !Int32.TryParse(e.Text, out int _);
}
}

View File

@ -29,7 +29,7 @@
</Border> </Border>
<StackPanel Grid.Row="1" Grid.Column="1"> <StackPanel Grid.Row="1" Grid.Column="1">
<TextBlock FontSize="14" TextWrapping="Wrap" Text="After installation has finished, the Bloxstrap Menu will be registered as an application in the Start menu. If you ever need to access it again to re-adjust your settings, or access resources such as mod management, you can find it there." /> <TextBlock FontSize="14" TextWrapping="Wrap" Text="After installation has finished, the Bloxstrap Menu will be registered as an application in the Start menu. If you ever need to access it again to re-adjust your settings, or access resources such as FastFlag management, you can find it there." />
<TextBlock Margin="0,16,0,0" FontSize="14" TextWrapping="Wrap"> <TextBlock Margin="0,16,0,0" FontSize="14" TextWrapping="Wrap">
If you ever need help or guidance with anything, be sure to check the If you ever need help or guidance with anything, be sure to check the
<Hyperlink Foreground="{DynamicResource TextFillColorPrimaryBrush}" Command="models:GlobalViewModel.OpenWebpageCommand" CommandParameter="https://www.github.com/pizzaboxer/bloxstrap/wiki">Wiki</Hyperlink>. <Hyperlink Foreground="{DynamicResource TextFillColorPrimaryBrush}" Command="models:GlobalViewModel.OpenWebpageCommand" CommandParameter="https://www.github.com/pizzaboxer/bloxstrap/wiki">Wiki</Hyperlink>.

View File

@ -0,0 +1,127 @@
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using Wpf.Ui.Mvvm.Contracts;
using CommunityToolkit.Mvvm.Input;
using Bloxstrap.UI.Elements.Menu.Pages;
namespace Bloxstrap.UI.ViewModels.Menu
{
public class FastFlagsViewModel : NotifyPropertyChangedViewModel
{
private readonly Page _page;
public FastFlagsViewModel(Page page)
{
_page = page;
}
private void OpenFastFlagEditor()
{
if (Window.GetWindow(_page) is INavigationWindow window)
window.Navigate(typeof(FastFlagEditorPage));
}
public ICommand OpenFastFlagEditorCommand => new RelayCommand(OpenFastFlagEditor);
public Visibility ShowDebugFlags => App.Settings.Prop.OhHeyYouFoundMe ? Visibility.Visible : Visibility.Collapsed;
public bool HttpRequestLogging
{
get => App.FastFlags.GetPreset("HTTP.Log") is not null;
set => App.FastFlags.SetPreset("HTTP.Log", value ? 12 : null);
}
public string HttpRequestProxy
{
get => App.FastFlags.GetPreset("HTTP.Proxy.Address.1") ?? "";
set
{
App.FastFlags.SetPreset("HTTP.Proxy.Enable", String.IsNullOrEmpty(value) ? null : true);
App.FastFlags.SetPreset("HTTP.Proxy.Address", String.IsNullOrEmpty(value) ? null : value);
}
}
public string StateOverlayFlags
{
get => App.FastFlags.GetPreset("UI.FlagState") ?? "";
set => App.FastFlags.SetPreset("UI.FlagState", String.IsNullOrEmpty(value) ? null : value);
}
public int FramerateLimit
{
get => int.TryParse(App.FastFlags.GetPreset("Rendering.Framerate"), out int x) ? x : 60;
set => App.FastFlags.SetPreset("Rendering.Framerate", value);
}
public bool FixDisplayScaling
{
get => App.FastFlags.GetPreset("Rendering.DisableScaling") == "True";
set => App.FastFlags.SetPreset("Rendering.DisableScaling", value ? "True" : null);
}
public bool AlternateGraphicsSelectorEnabled
{
get => App.FastFlags.GetPreset("UI.Menu.GraphicsSlider") == "True";
set => App.FastFlags.SetPreset("UI.Menu.GraphicsSlider", value ? "True" : null);
}
public bool Pre2022TexturesEnabled
{
get => App.FastFlags.GetPreset("Rendering.TexturePack") == FastFlagManager.OldTexturesFlagValue;
set => App.FastFlags.SetPreset("Rendering.TexturePack", value ? FastFlagManager.OldTexturesFlagValue : null);
}
public IReadOnlyDictionary<string, Dictionary<string, string?>> IGMenuVersions => FastFlagManager.IGMenuVersions;
public string SelectedIGMenuVersion
{
get
{
// yeah this kinda sucks
foreach (var version in IGMenuVersions)
{
bool flagsMatch = true;
foreach (var flag in version.Value)
{
foreach (var presetFlag in FastFlagManager.PresetFlags.Where(x => x.Key.StartsWith($"UI.Menu.Style.{flag.Key}")))
{
if (App.FastFlags.GetValue(presetFlag.Value) != flag.Value)
flagsMatch = false;
}
}
if (flagsMatch)
return version.Key;
}
return IGMenuVersions.First().Key;
}
set
{
foreach (var flag in IGMenuVersions[value])
App.FastFlags.SetPreset($"UI.Menu.Style.{flag.Key}", flag.Value);
}
}
public IReadOnlyDictionary<string, string> LightingModes => FastFlagManager.LightingModes;
public string SelectedLightingMode
{
get => App.FastFlags.GetPresetEnum(LightingModes, "Rendering.Lighting", "True");
set => App.FastFlags.SetPresetEnum("Rendering.Lighting", LightingModes[value], "True");
}
public bool GuiHidingEnabled
{
get => App.FastFlags.GetPreset("UI.Hide") == "32380007";
set => App.FastFlags.SetPreset("UI.Hide", value ? "32380007" : null);
}
}
}

View File

@ -34,6 +34,7 @@ namespace Bloxstrap.UI.ViewModels.Menu
if (!App.IsFirstRun) if (!App.IsFirstRun)
{ {
App.ShouldSaveConfigs = true; App.ShouldSaveConfigs = true;
App.FastFlags.Save();
CloseWindow(); CloseWindow();
return; return;