mirror of
https://github.com/bloxstraplabs/bloxstrap.git
synced 2025-04-10 15:25:42 -07:00
Code as of September 18th 2024
This commit is contained in:
parent
0b20720fdb
commit
82d017570b
@ -34,6 +34,7 @@
|
||||
</Setter>
|
||||
</Style>
|
||||
|
||||
<converters:StringResourceConverter x:Key="StringResourceConverter" />
|
||||
<converters:StringFormatConverter x:Key="StringFormatConverter" />
|
||||
<converters:RangeConverter x:Key="RangeConverter" />
|
||||
<converters:EnumNameConverter x:Key="EnumNameConverter" />
|
||||
|
@ -236,6 +236,36 @@ namespace Bloxstrap
|
||||
State.Load();
|
||||
FastFlags.Load();
|
||||
|
||||
//List<string> tests = new()
|
||||
//{
|
||||
// "UI.FullscreenTitlebarDelay == null || true",
|
||||
// "UI.FullscreenTitlebarDelay == null && true",
|
||||
// "UI.FullscreenTitlebarDelay == null || false",
|
||||
// "UI.FullscreenTitlebarDelay == null && false",
|
||||
// "UI.FullscreenTitlebarDelay == null && false || true",
|
||||
// "UI.FullscreenTitlebarDelay == null && true || false",
|
||||
// "false && false || true",
|
||||
// "(false && false) || true",
|
||||
// "false && (false || true)",
|
||||
// "FFlagDisableNewIGMinDUA != True",
|
||||
// "FStringDebugFlagState == 'hi'",
|
||||
// "FStringDebugFlagState == 'wassup'",
|
||||
// "FStringDebugFlagState == FStringDebugFlagState",
|
||||
// "FStringDebugFlagState != FStringDebugFlagState",
|
||||
// "FLogNetwork == 7",
|
||||
// "FLogNetwork > 9",
|
||||
// "FLogNetwork < 9"
|
||||
//};
|
||||
|
||||
|
||||
//foreach (string test in tests)
|
||||
//{
|
||||
// bool result = new FlexParser(test).Evaluate();
|
||||
// App.Logger.WriteLine(LOG_IDENT, $"'{test}' evaluated to {result}");
|
||||
//}
|
||||
|
||||
//Debugger.Break();
|
||||
|
||||
if (!Locale.SupportedLocales.ContainsKey(Settings.Prop.Locale))
|
||||
{
|
||||
Settings.Prop.Locale = "nil";
|
||||
|
28
Bloxstrap/Enums/FlexTokenType.cs
Normal file
28
Bloxstrap/Enums/FlexTokenType.cs
Normal file
@ -0,0 +1,28 @@
|
||||
namespace Bloxstrap.Enums
|
||||
{
|
||||
public enum FlexTokenType
|
||||
{
|
||||
// data types
|
||||
NULL,
|
||||
NUMBER,
|
||||
BOOL,
|
||||
STRING,
|
||||
FLAG,
|
||||
|
||||
// comparison operators
|
||||
COMPARE_EQ,
|
||||
COMPARE_NEQ,
|
||||
COMPARE_GT,
|
||||
COMPARE_LT,
|
||||
COMPARE_GEQ,
|
||||
COMPARE_LEQ,
|
||||
|
||||
// boolean logic operators
|
||||
LOGIC_AND,
|
||||
LOGIC_OR,
|
||||
|
||||
// yes, "bracket" is technically not the correct term, don't care
|
||||
BRACKET_OPEN,
|
||||
BRACKET_CLOSE
|
||||
}
|
||||
}
|
14
Bloxstrap/Exceptions/FlexParseException.cs
Normal file
14
Bloxstrap/Exceptions/FlexParseException.cs
Normal file
@ -0,0 +1,14 @@
|
||||
namespace Bloxstrap.Exceptions
|
||||
{
|
||||
internal class FlexParseException : Exception
|
||||
{
|
||||
public FlexParseException(string expression, string message, string? position = null)
|
||||
: base($"Invalid syntax encountered when parsing '{expression}' at position {position ?? "EOF"} ({message})") { }
|
||||
|
||||
public FlexParseException(string expression, string message, int position)
|
||||
: this(expression, message, position.ToString()) { }
|
||||
|
||||
public FlexParseException(string expression, string message, FlexToken? token)
|
||||
: this(expression, message, token?.Position.ToString()) { }
|
||||
}
|
||||
}
|
@ -1,6 +1,4 @@
|
||||
using Bloxstrap.Enums.FlagPresets;
|
||||
|
||||
namespace Bloxstrap
|
||||
namespace Bloxstrap
|
||||
{
|
||||
public class FastFlagManager : JsonManager<Dictionary<string, object>>
|
||||
{
|
||||
@ -12,146 +10,13 @@ namespace Bloxstrap
|
||||
|
||||
public bool Changed => !OriginalProp.SequenceEqual(Prop);
|
||||
|
||||
public static IReadOnlyDictionary<string, string> PresetFlags = new Dictionary<string, string>
|
||||
public readonly FFlagPresets PresetConfig;
|
||||
|
||||
public FastFlagManager()
|
||||
{
|
||||
{ "Network.Log", "FLogNetwork" },
|
||||
|
||||
#if DEBUG
|
||||
{ "HTTP.Log", "DFLogHttpTraceLight" },
|
||||
|
||||
{ "HTTP.Proxy.Enable", "DFFlagDebugEnableHttpProxy" },
|
||||
{ "HTTP.Proxy.Address.1", "DFStringDebugPlayerHttpProxyUrl" },
|
||||
{ "HTTP.Proxy.Address.2", "DFStringHttpCurlProxyHostAndPort" },
|
||||
{ "HTTP.Proxy.Address.3", "DFStringHttpCurlProxyHostAndPortForExternalUrl" },
|
||||
#endif
|
||||
|
||||
{ "Rendering.Framerate", "DFIntTaskSchedulerTargetFps" },
|
||||
{ "Rendering.ManualFullscreen", "FFlagHandleAltEnterFullscreenManually" },
|
||||
{ "Rendering.DisableScaling", "DFFlagDisableDPIScale" },
|
||||
{ "Rendering.MSAA", "FIntDebugForceMSAASamples" },
|
||||
{ "Rendering.DisablePostFX", "FFlagDisablePostFx" },
|
||||
{ "Rendering.ShadowIntensity", "FIntRenderShadowIntensity" },
|
||||
|
||||
{ "Rendering.Mode.D3D11", "FFlagDebugGraphicsPreferD3D11" },
|
||||
{ "Rendering.Mode.D3D10", "FFlagDebugGraphicsPreferD3D11FL10" },
|
||||
|
||||
{ "Rendering.Lighting.Voxel", "DFFlagDebugRenderForceTechnologyVoxel" },
|
||||
{ "Rendering.Lighting.ShadowMap", "FFlagDebugForceFutureIsBrightPhase2" },
|
||||
{ "Rendering.Lighting.Future", "FFlagDebugForceFutureIsBrightPhase3" },
|
||||
|
||||
{ "Rendering.TextureQuality.OverrideEnabled", "DFFlagTextureQualityOverrideEnabled" },
|
||||
{ "Rendering.TextureQuality.Level", "DFIntTextureQualityOverride" },
|
||||
{ "Rendering.TerrainTextureQuality", "FIntTerrainArraySliceSize" },
|
||||
|
||||
{ "UI.Hide", "DFIntCanHideGuiGroupId" },
|
||||
{ "UI.FontSize", "FIntFontSizePadding" },
|
||||
#if DEBUG
|
||||
{ "UI.FlagState", "FStringDebugShowFlagState" },
|
||||
#endif
|
||||
|
||||
{ "UI.FullscreenTitlebarDelay", "FIntFullscreenTitleBarTriggerDelayMillis" },
|
||||
|
||||
{ "UI.Menu.Style.V2Rollout", "FIntNewInGameMenuPercentRollout3" },
|
||||
{ "UI.Menu.Style.EnableV4.1", "FFlagEnableInGameMenuControls" },
|
||||
{ "UI.Menu.Style.EnableV4.2", "FFlagEnableInGameMenuModernization" },
|
||||
{ "UI.Menu.Style.EnableV4Chrome", "FFlagEnableInGameMenuChrome" },
|
||||
|
||||
{ "UI.Menu.Style.ABTest.1", "FFlagEnableMenuControlsABTest" },
|
||||
{ "UI.Menu.Style.ABTest.2", "FFlagEnableV3MenuABTest3" },
|
||||
{ "UI.Menu.Style.ABTest.3", "FFlagEnableInGameMenuChromeABTest3" }
|
||||
};
|
||||
|
||||
public static IReadOnlyDictionary<RenderingMode, string> RenderingModes => new Dictionary<RenderingMode, string>
|
||||
{
|
||||
{ RenderingMode.Default, "None" },
|
||||
{ RenderingMode.D3D11, "D3D11" },
|
||||
{ RenderingMode.D3D10, "D3D10" },
|
||||
};
|
||||
|
||||
public static IReadOnlyDictionary<LightingMode, string> LightingModes => new Dictionary<LightingMode, string>
|
||||
{
|
||||
{ LightingMode.Default, "None" },
|
||||
{ LightingMode.Voxel, "Voxel" },
|
||||
{ LightingMode.ShadowMap, "ShadowMap" },
|
||||
{ LightingMode.Future, "Future" }
|
||||
};
|
||||
|
||||
public static IReadOnlyDictionary<MSAAMode, string?> MSAAModes => new Dictionary<MSAAMode, string?>
|
||||
{
|
||||
{ MSAAMode.Default, null },
|
||||
{ MSAAMode.x1, "1" },
|
||||
{ MSAAMode.x2, "2" },
|
||||
{ MSAAMode.x4, "4" }
|
||||
};
|
||||
|
||||
public static IReadOnlyDictionary<TextureQuality, string?> TextureQualityLevels => new Dictionary<TextureQuality, string?>
|
||||
{
|
||||
{ TextureQuality.Default, null },
|
||||
{ TextureQuality.Level0, "0" },
|
||||
{ TextureQuality.Level1, "1" },
|
||||
{ TextureQuality.Level2, "2" },
|
||||
{ TextureQuality.Level3, "3" },
|
||||
};
|
||||
|
||||
// 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<InGameMenuVersion, Dictionary<string, string?>> IGMenuVersions => new Dictionary<InGameMenuVersion, Dictionary<string, string?>>
|
||||
{
|
||||
{
|
||||
InGameMenuVersion.Default,
|
||||
new Dictionary<string, string?>
|
||||
{
|
||||
{ "V2Rollout", null },
|
||||
{ "EnableV4", null },
|
||||
{ "EnableV4Chrome", null },
|
||||
{ "ABTest", null }
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
InGameMenuVersion.V1,
|
||||
new Dictionary<string, string?>
|
||||
{
|
||||
{ "V2Rollout", "0" },
|
||||
{ "EnableV4", "False" },
|
||||
{ "EnableV4Chrome", "False" },
|
||||
{ "ABTest", "False" }
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
InGameMenuVersion.V2,
|
||||
new Dictionary<string, string?>
|
||||
{
|
||||
{ "V2Rollout", "100" },
|
||||
{ "EnableV4", "False" },
|
||||
{ "EnableV4Chrome", "False" },
|
||||
{ "ABTest", "False" }
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
InGameMenuVersion.V4,
|
||||
new Dictionary<string, string?>
|
||||
{
|
||||
{ "V2Rollout", "0" },
|
||||
{ "EnableV4", "True" },
|
||||
{ "EnableV4Chrome", "False" },
|
||||
{ "ABTest", "False" }
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
InGameMenuVersion.V4Chrome,
|
||||
new Dictionary<string, string?>
|
||||
{
|
||||
{ "V2Rollout", "0" },
|
||||
{ "EnableV4", "True" },
|
||||
{ "EnableV4Chrome", "True" },
|
||||
{ "ABTest", "False" }
|
||||
}
|
||||
}
|
||||
};
|
||||
PresetConfig = JsonSerializer.Deserialize<FFlagPresets>(File.ReadAllText("C:\\Users\\pizzaboxer\\Documents\\Projects\\Bloxstrap\\PrototypeSchema.json"));
|
||||
Debug.WriteLine(PresetConfig);
|
||||
}
|
||||
|
||||
// all fflags are stored as strings
|
||||
// to delete a flag, set the value as null
|
||||
@ -170,7 +35,7 @@ namespace Bloxstrap
|
||||
{
|
||||
if (Prop.ContainsKey(key))
|
||||
{
|
||||
if (key == Prop[key].ToString())
|
||||
if (value.ToString() == Prop[key].ToString())
|
||||
return;
|
||||
|
||||
App.Logger.WriteLine(LOG_IDENT, $"Changing of '{key}' from '{Prop[key]}' to '{value}' is pending");
|
||||
@ -184,10 +49,16 @@ namespace Bloxstrap
|
||||
}
|
||||
}
|
||||
|
||||
// this returns null if the fflag doesn't exist
|
||||
/// <summary>
|
||||
/// Returns null if the flag has not been set
|
||||
/// </summary>
|
||||
/// <param name="key"></param>
|
||||
/// <returns></returns>
|
||||
public string? GetValue(string key)
|
||||
{
|
||||
// check if we have an updated change for it pushed first
|
||||
if (PresetConfig.Flags.ContainsKey(key))
|
||||
key = PresetConfig.Flags[key];
|
||||
|
||||
if (Prop.TryGetValue(key, out object? value) && value is not null)
|
||||
return value.ToString();
|
||||
|
||||
@ -196,37 +67,25 @@ namespace Bloxstrap
|
||||
|
||||
public void SetPreset(string prefix, object? value)
|
||||
{
|
||||
foreach (var pair in PresetFlags.Where(x => x.Key.StartsWith(prefix)))
|
||||
foreach (var pair in PresetConfig.Flags.Where(x => x.Key.StartsWith(prefix)))
|
||||
SetValue(pair.Value, value);
|
||||
}
|
||||
|
||||
public void SetPresetEnum(string prefix, string target, object? value)
|
||||
public bool CheckPresetValue(string prefix, string value)
|
||||
{
|
||||
foreach (var pair in PresetFlags.Where(x => x.Key.StartsWith(prefix)))
|
||||
var presets = PresetConfig.Flags.Where(x => x.Key.StartsWith(prefix));
|
||||
|
||||
foreach (var preset in presets)
|
||||
{
|
||||
if (pair.Key.StartsWith($"{prefix}.{target}"))
|
||||
SetValue(pair.Value, value);
|
||||
else
|
||||
SetValue(pair.Value, null);
|
||||
}
|
||||
}
|
||||
|
||||
public string? GetPreset(string name) => GetValue(PresetFlags[name]);
|
||||
|
||||
public T GetPresetEnum<T>(IReadOnlyDictionary<T, string> mapping, string prefix, string value) where T : Enum
|
||||
{
|
||||
foreach (var pair in mapping)
|
||||
{
|
||||
if (pair.Value == "None")
|
||||
continue;
|
||||
|
||||
if (GetPreset($"{prefix}.{pair.Value}") == value)
|
||||
return pair.Key;
|
||||
if (GetValue(preset.Value) != value)
|
||||
return false;
|
||||
}
|
||||
|
||||
return mapping.First().Key;
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool CheckPresetValue(KeyValuePair<string, string> entry) => CheckPresetValue(entry.Key, entry.Value);
|
||||
|
||||
public override void Save()
|
||||
{
|
||||
// convert all flag values to strings before saving
|
||||
@ -248,7 +107,7 @@ namespace Bloxstrap
|
||||
OriginalProp = new(Prop);
|
||||
|
||||
// TODO - remove when activity tracking has been revamped
|
||||
if (GetPreset("Network.Log") != "7")
|
||||
if (GetValue("Network.Log") != "7")
|
||||
SetPreset("Network.Log", "7");
|
||||
}
|
||||
}
|
||||
|
249
Bloxstrap/FlexParser.cs
Normal file
249
Bloxstrap/FlexParser.cs
Normal file
@ -0,0 +1,249 @@
|
||||
namespace Bloxstrap
|
||||
{
|
||||
/// <summary>
|
||||
/// FastFlag Expression Parser
|
||||
/// </summary>
|
||||
public class FlexParser
|
||||
{
|
||||
private readonly string _expression;
|
||||
|
||||
private readonly List<FlexToken> _tokens = new();
|
||||
|
||||
private int _tokenPos = 0;
|
||||
|
||||
private static readonly Dictionary<string, FlexTokenType> _staticTokenMap = new()
|
||||
{
|
||||
{ "null", FlexTokenType.NULL },
|
||||
|
||||
{ "true", FlexTokenType.BOOL },
|
||||
{ "false", FlexTokenType.BOOL },
|
||||
|
||||
{ "==", FlexTokenType.COMPARE_EQ },
|
||||
{ "!=", FlexTokenType.COMPARE_NEQ },
|
||||
|
||||
{ ">", FlexTokenType.COMPARE_GT },
|
||||
{ "<", FlexTokenType.COMPARE_LT },
|
||||
{ ">=", FlexTokenType.COMPARE_GEQ },
|
||||
{ "<=", FlexTokenType.COMPARE_LEQ },
|
||||
|
||||
{ "&&", FlexTokenType.LOGIC_AND },
|
||||
{ "||", FlexTokenType.LOGIC_OR },
|
||||
|
||||
{ "(", FlexTokenType.BRACKET_OPEN },
|
||||
{ ")", FlexTokenType.BRACKET_CLOSE }
|
||||
};
|
||||
|
||||
private static readonly Dictionary<string, FlexTokenType> _regexTokenMap = new()
|
||||
{
|
||||
{ @"^\d+", FlexTokenType.NUMBER },
|
||||
{ @"^('[^']+')", FlexTokenType.STRING },
|
||||
{ @"^([a-zA-Z0-9_\.]+)", FlexTokenType.FLAG }
|
||||
};
|
||||
|
||||
public FlexParser(string expression)
|
||||
{
|
||||
_expression = expression;
|
||||
|
||||
Tokenize();
|
||||
}
|
||||
|
||||
public bool Evaluate() => EvaluateExpression();
|
||||
|
||||
private void Tokenize()
|
||||
{
|
||||
int position = 0;
|
||||
|
||||
while (position < _expression.Length)
|
||||
{
|
||||
string exprSlice = _expression.Substring(position);
|
||||
|
||||
if (exprSlice[0] == ' ')
|
||||
{
|
||||
position++;
|
||||
continue;
|
||||
}
|
||||
|
||||
string exprSliceLower = exprSlice.ToLowerInvariant();
|
||||
|
||||
var mapMatch = _staticTokenMap.FirstOrDefault(x => exprSliceLower.StartsWith(x.Key));
|
||||
|
||||
if (mapMatch.Key is null)
|
||||
{
|
||||
bool matched = false;
|
||||
|
||||
foreach (var entry in _regexTokenMap)
|
||||
{
|
||||
var match = Regex.Match(exprSlice, entry.Key);
|
||||
|
||||
if (match.Success)
|
||||
{
|
||||
matched = true;
|
||||
|
||||
string phrase = match.Groups[match.Groups.Count > 1 ? 1 : 0].Value;
|
||||
_tokens.Add(new(entry.Value, phrase, position));
|
||||
position += phrase.Length;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!matched)
|
||||
throw new FlexParseException(_expression, "unknown identifier", position);
|
||||
}
|
||||
else
|
||||
{
|
||||
_tokens.Add(new(mapMatch.Value, mapMatch.Key, position));
|
||||
position += mapMatch.Key.Length;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The brackets in this example expression are instances of subexpressions: "[FLogNetwork == 7] || [false]"
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
/// <exception cref="FlexParseException"></exception>
|
||||
private bool EvaluateSubExpression()
|
||||
{
|
||||
var token = _tokens.ElementAtOrDefault(_tokenPos++);
|
||||
|
||||
if (token?.Type == FlexTokenType.FLAG)
|
||||
{
|
||||
var compToken = _tokens.ElementAtOrDefault(_tokenPos++);
|
||||
|
||||
if (compToken is null || compToken.Value is null || !compToken.IsComparisonOperator)
|
||||
throw new FlexParseException(_expression, "expected comparison operator", compToken);
|
||||
|
||||
var valueToken = _tokens.ElementAtOrDefault(_tokenPos++);
|
||||
|
||||
if (valueToken is null || !valueToken.IsDataType)
|
||||
throw new FlexParseException(_expression, "expected data", valueToken);
|
||||
|
||||
string? flagValue = token.GetActualValue();
|
||||
|
||||
if (compToken.IsInequalityOperator)
|
||||
{
|
||||
if (flagValue is null || valueToken.Value is null)
|
||||
return false;
|
||||
|
||||
if (valueToken.Type != FlexTokenType.NUMBER)
|
||||
throw new FlexParseException(_expression, "expected integer", valueToken);
|
||||
|
||||
if (!long.TryParse(flagValue, out long intFlagValue))
|
||||
return false;
|
||||
|
||||
long intValue = long.Parse(valueToken.Value);
|
||||
|
||||
switch (compToken.Type)
|
||||
{
|
||||
case FlexTokenType.COMPARE_GT:
|
||||
return intFlagValue > intValue;
|
||||
case FlexTokenType.COMPARE_LT:
|
||||
return intFlagValue < intValue;
|
||||
case FlexTokenType.COMPARE_GEQ:
|
||||
return intFlagValue >= intValue;
|
||||
case FlexTokenType.COMPARE_LEQ:
|
||||
return intFlagValue <= intValue;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (valueToken.Type == FlexTokenType.NULL)
|
||||
return flagValue is null;
|
||||
|
||||
bool result = string.Compare(flagValue, valueToken.GetActualValue(), StringComparison.InvariantCultureIgnoreCase) == 0;
|
||||
|
||||
if (compToken.Type == FlexTokenType.COMPARE_EQ)
|
||||
return result;
|
||||
else
|
||||
return !result;
|
||||
}
|
||||
}
|
||||
else if (token?.Type == FlexTokenType.BOOL)
|
||||
{
|
||||
return token.BoolValue;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private bool EvaluateExpression(int finalPos = 0)
|
||||
{
|
||||
bool result = false;
|
||||
|
||||
if (finalPos == 0)
|
||||
finalPos = _tokens.Count;
|
||||
|
||||
while (_tokenPos < finalPos)
|
||||
{
|
||||
var token = _tokens.ElementAtOrDefault(_tokenPos);
|
||||
|
||||
if (token is null)
|
||||
break;
|
||||
|
||||
if (token.Type == FlexTokenType.FLAG || token.Type == FlexTokenType.BOOL)
|
||||
{
|
||||
result = EvaluateSubExpression();
|
||||
}
|
||||
else if (token.Type == FlexTokenType.BRACKET_OPEN)
|
||||
{
|
||||
var closeBracketToken = _tokens.Find(x => x.Type == FlexTokenType.BRACKET_CLOSE);
|
||||
|
||||
if (closeBracketToken is null)
|
||||
throw new FlexParseException(_expression, "expected closing bracket");
|
||||
|
||||
_tokenPos++;
|
||||
|
||||
result = EvaluateExpression(_tokens.IndexOf(closeBracketToken));
|
||||
|
||||
_tokenPos++;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new FlexParseException(_expression, "identifier was unexpected here", token);
|
||||
}
|
||||
|
||||
var nextToken = _tokens.ElementAtOrDefault(_tokenPos++);
|
||||
|
||||
if (nextToken is null)
|
||||
break;
|
||||
|
||||
if (!nextToken.IsLogicToken)
|
||||
throw new FlexParseException(_expression, "expected boolean operator", nextToken);
|
||||
|
||||
if (nextToken.Type == FlexTokenType.LOGIC_AND)
|
||||
{
|
||||
if (result)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
int bracketNesting = 0;
|
||||
|
||||
while (_tokenPos < finalPos)
|
||||
{
|
||||
token = _tokens[_tokenPos++];
|
||||
|
||||
if (token.Type == FlexTokenType.BRACKET_OPEN)
|
||||
bracketNesting++;
|
||||
else if (token.Type == FlexTokenType.BRACKET_CLOSE)
|
||||
bracketNesting--;
|
||||
else if (bracketNesting == 0 && token.Type == FlexTokenType.LOGIC_OR)
|
||||
break;
|
||||
}
|
||||
|
||||
if (bracketNesting != 0)
|
||||
throw new FlexParseException(_expression, "unclosed bracket");
|
||||
}
|
||||
}
|
||||
else if (nextToken.Type == FlexTokenType.LOGIC_OR && result)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
@ -483,14 +483,14 @@ namespace Bloxstrap
|
||||
{
|
||||
App.FastFlags.SetValue("FIntDebugForceMSAASamples", null);
|
||||
|
||||
if (App.FastFlags.GetPreset("UI.Menu.Style.DisableV2") is not null)
|
||||
if (App.FastFlags.GetValue("UI.Menu.Style.DisableV2") is not null)
|
||||
App.FastFlags.SetPreset("UI.Menu.Style.ABTest", false);
|
||||
}
|
||||
|
||||
if (Utilities.CompareVersions(existingVer, "2.5.3") == VersionComparison.LessThan)
|
||||
{
|
||||
string? val = App.FastFlags.GetPreset("UI.Menu.Style.EnableV4.1");
|
||||
if (App.FastFlags.GetPreset("UI.Menu.Style.EnableV4.2") != val)
|
||||
string? val = App.FastFlags.GetValue("UI.Menu.Style.EnableV4.1");
|
||||
if (App.FastFlags.GetValue("UI.Menu.Style.EnableV4.2") != val)
|
||||
App.FastFlags.SetPreset("UI.Menu.Style.EnableV4.2", val);
|
||||
}
|
||||
|
||||
@ -513,7 +513,7 @@ namespace Bloxstrap
|
||||
if (App.Settings.Prop.BootstrapperStyle == BootstrapperStyle.ClassicFluentDialog)
|
||||
App.Settings.Prop.BootstrapperStyle = BootstrapperStyle.FluentDialog;
|
||||
|
||||
_ = int.TryParse(App.FastFlags.GetPreset("Rendering.Framerate"), out int x);
|
||||
_ = int.TryParse(App.FastFlags.GetValue("Rendering.Framerate"), out int x);
|
||||
if (x == 0)
|
||||
App.FastFlags.SetPreset("Rendering.Framerate", null);
|
||||
}
|
||||
|
139
Bloxstrap/Models/APIs/Config/FFlagPreset.cs
Normal file
139
Bloxstrap/Models/APIs/Config/FFlagPreset.cs
Normal file
@ -0,0 +1,139 @@
|
||||
namespace Bloxstrap.Models.APIs.Config
|
||||
{
|
||||
// technically an entity, whatever
|
||||
public class FFlagPreset
|
||||
{
|
||||
public string Title { get; set; } = null!;
|
||||
|
||||
public string? Description { get; set; }
|
||||
|
||||
public string? HelpLink { get; set; }
|
||||
|
||||
public string Type { get; set; } = null!;
|
||||
|
||||
/// <summary>
|
||||
/// Specific to TextBox and Toggle
|
||||
/// </summary>
|
||||
public Dictionary<string, string>? Apply { get; set; }
|
||||
|
||||
#region ComboBox
|
||||
// Data
|
||||
public Dictionary<string, Dictionary<string, string>>? Options { get; set; }
|
||||
|
||||
// Frontend
|
||||
public List<string>? ComboBoxEntries => Options?.Keys.Prepend("Common.Default").ToList();
|
||||
|
||||
public string ComboBoxSelection
|
||||
{
|
||||
get
|
||||
{
|
||||
if (Options is null || ComboBoxEntries is null)
|
||||
return "";
|
||||
|
||||
foreach (var optionEntry in Options)
|
||||
{
|
||||
bool matches = true;
|
||||
|
||||
foreach (var flagEntry in optionEntry.Value)
|
||||
{
|
||||
if (matches && !App.FastFlags.CheckPresetValue(flagEntry))
|
||||
matches = false;
|
||||
}
|
||||
|
||||
if (matches)
|
||||
return optionEntry.Key;
|
||||
}
|
||||
|
||||
return ComboBoxEntries[0];
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
if (Options is null || ComboBoxEntries is null)
|
||||
throw new InvalidOperationException();
|
||||
|
||||
if (value == ComboBoxEntries[0])
|
||||
{
|
||||
// get all flags that this preset sets
|
||||
var flags = Options.Values.SelectMany(x => x.Keys).Distinct().ToList();
|
||||
|
||||
foreach (string flag in flags)
|
||||
App.FastFlags.SetPreset(flag, null);
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (var entry in Options[value])
|
||||
App.FastFlags.SetPreset(entry.Key, entry.Value);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region TextBox
|
||||
// TODO: filtering (i dont know how tf thats gonna work)
|
||||
|
||||
// Data
|
||||
public string? InputFilter { get; set; }
|
||||
|
||||
public string? Subject { get; set; }
|
||||
|
||||
public string? DefaultValue { get; set; }
|
||||
|
||||
// Frontend
|
||||
public string TextBoxValue
|
||||
{
|
||||
get
|
||||
{
|
||||
if (Subject is null || DefaultValue is null)
|
||||
return "";
|
||||
|
||||
return App.FastFlags.GetValue(Subject) ?? DefaultValue;
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
if (Apply is null || DefaultValue is null)
|
||||
throw new InvalidOperationException();
|
||||
|
||||
if (InputFilter is not null && !Regex.IsMatch(value, InputFilter))
|
||||
{
|
||||
value = TextBoxValue;
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (var entry in Apply)
|
||||
{
|
||||
if (value == DefaultValue)
|
||||
App.FastFlags.SetPreset(entry.Key, null);
|
||||
else
|
||||
App.FastFlags.SetPreset(entry.Key, String.Format(entry.Value, value));
|
||||
}
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Toggle
|
||||
public string? EnabledIf { get; set; }
|
||||
|
||||
public bool ToggleEnabled
|
||||
{
|
||||
get
|
||||
{
|
||||
if (EnabledIf is null)
|
||||
return false;
|
||||
|
||||
return new FlexParser(EnabledIf).Evaluate();
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
if (Apply is null)
|
||||
throw new InvalidOperationException();
|
||||
|
||||
foreach (var entry in Apply)
|
||||
App.FastFlags.SetPreset(entry.Key, value ? entry.Value : null);
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
11
Bloxstrap/Models/APIs/Config/FFlagPresets.cs
Normal file
11
Bloxstrap/Models/APIs/Config/FFlagPresets.cs
Normal file
@ -0,0 +1,11 @@
|
||||
namespace Bloxstrap.Models.APIs.Config
|
||||
{
|
||||
public class FFlagPresets
|
||||
{
|
||||
public string Version { get; set; } = null!;
|
||||
|
||||
public Dictionary<string, string> Flags { get; set; } = null!;
|
||||
|
||||
public Dictionary<string, List<FFlagPreset>> Presets { get; set; } = null!;
|
||||
}
|
||||
}
|
12
Bloxstrap/Models/APIs/Config/TranslationPatch.cs
Normal file
12
Bloxstrap/Models/APIs/Config/TranslationPatch.cs
Normal file
@ -0,0 +1,12 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Bloxstrap.Models.APIs.Config
|
||||
{
|
||||
internal class TranslationPatch
|
||||
{
|
||||
}
|
||||
}
|
56
Bloxstrap/Models/FlexToken.cs
Normal file
56
Bloxstrap/Models/FlexToken.cs
Normal file
@ -0,0 +1,56 @@
|
||||
namespace Bloxstrap.Models
|
||||
{
|
||||
public class FlexToken
|
||||
{
|
||||
public FlexTokenType Type;
|
||||
public string? Value;
|
||||
public int Position;
|
||||
|
||||
public bool IsDataType =>
|
||||
Type == FlexTokenType.FLAG
|
||||
|| Type == FlexTokenType.NUMBER
|
||||
|| Type == FlexTokenType.BOOL
|
||||
|| Type == FlexTokenType.STRING
|
||||
|| Type == FlexTokenType.NULL;
|
||||
|
||||
public bool IsLogicToken =>
|
||||
Type == FlexTokenType.LOGIC_AND
|
||||
|| Type == FlexTokenType.LOGIC_OR;
|
||||
|
||||
public bool IsInequalityOperator =>
|
||||
Type == FlexTokenType.COMPARE_GT
|
||||
|| Type == FlexTokenType.COMPARE_LT
|
||||
|| Type == FlexTokenType.COMPARE_GEQ
|
||||
|| Type == FlexTokenType.COMPARE_LEQ;
|
||||
|
||||
public bool IsComparisonOperator =>
|
||||
IsInequalityOperator
|
||||
|| Type == FlexTokenType.COMPARE_EQ
|
||||
|| Type == FlexTokenType.COMPARE_NEQ;
|
||||
|
||||
public bool BoolValue => Type == FlexTokenType.BOOL && Value == "true";
|
||||
|
||||
public FlexToken(FlexTokenType type, string? value, int position)
|
||||
{
|
||||
Type = type;
|
||||
Value = value;
|
||||
Position = position;
|
||||
}
|
||||
|
||||
public string? GetActualValue()
|
||||
{
|
||||
if (Value is null)
|
||||
return null;
|
||||
|
||||
if (Type == FlexTokenType.STRING)
|
||||
return Value.Substring(1, Value.Length - 2);
|
||||
|
||||
if (Type == FlexTokenType.FLAG)
|
||||
return App.FastFlags.GetValue(Value);
|
||||
|
||||
return Value;
|
||||
}
|
||||
|
||||
public override string ToString() => $"{Type}: {Value}";
|
||||
}
|
||||
}
|
24
Bloxstrap/UI/Converters/StringResourceConverter.cs
Normal file
24
Bloxstrap/UI/Converters/StringResourceConverter.cs
Normal file
@ -0,0 +1,24 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Data;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace Bloxstrap.UI.Converters
|
||||
{
|
||||
class StringResourceConverter : IValueConverter
|
||||
{
|
||||
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
return Strings.ResourceManager.GetStringSafe((string)value);
|
||||
}
|
||||
|
||||
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
}
|
||||
}
|
@ -45,7 +45,7 @@ namespace Bloxstrap.UI.Elements.Settings.Pages
|
||||
|
||||
_fastFlagList.Clear();
|
||||
|
||||
var presetFlags = FastFlagManager.PresetFlags.Values;
|
||||
var presetFlags = App.FastFlags.PresetConfig.Flags.Values;
|
||||
|
||||
foreach (var pair in App.FastFlags.Prop.OrderBy(x => x.Key))
|
||||
{
|
||||
@ -141,7 +141,7 @@ namespace Bloxstrap.UI.Elements.Settings.Pages
|
||||
|
||||
bool refresh = false;
|
||||
|
||||
if (!_showPresets && FastFlagManager.PresetFlags.Values.Contains(name))
|
||||
if (!_showPresets && App.FastFlags.PresetConfig.Flags.Values.Contains(name))
|
||||
{
|
||||
TogglePresetsButton.IsChecked = true;
|
||||
_showPresets = true;
|
||||
|
@ -21,149 +21,87 @@
|
||||
<TextBlock Margin="0,2,0,0" FontSize="12" Text="{x:Static resources:Strings.Menu_FastFlags_Help_Description}" Padding="0,0,16,0" Foreground="{DynamicResource TextFillColorTertiaryBrush}" />
|
||||
</StackPanel>
|
||||
</ui:CardAction>
|
||||
|
||||
<controls:OptionControl
|
||||
Header="{x:Static resources:Strings.Menu_FastFlags_ManagerEnabled_Title}"
|
||||
Description="{x:Static resources:Strings.Menu_FastFlags_ManagerEnabled_Description}">
|
||||
<ui:ToggleSwitch IsChecked="{Binding UseFastFlagManager, Mode=TwoWay}" />
|
||||
</controls:OptionControl>
|
||||
|
||||
<StackPanel Visibility="{Binding ShowDebugFlags, Mode=OneTime}">
|
||||
<TextBlock Text="Debug" FontSize="20" FontWeight="Medium" Margin="0,16,0,0" />
|
||||
|
||||
<controls:OptionControl
|
||||
Header="HTTP request logging"
|
||||
Description="Enables logging of HTTP requests (DFLogHttpTraceLight=12).">
|
||||
<ui:ToggleSwitch IsChecked="{Binding HttpRequestLogging, Mode=TwoWay}" />
|
||||
</controls:OptionControl>
|
||||
|
||||
<controls:OptionControl
|
||||
Header="HTTP proxy address"
|
||||
Description="Set blank if not using a proxy. Don't forget to add cacert.pem as a mod.">
|
||||
<ui:TextBox Margin="5,0,0,0" Padding="10,5,10,5" Width="200" Text="{Binding HttpRequestProxy, Mode=TwoWay}" />
|
||||
</controls:OptionControl>
|
||||
|
||||
<controls:OptionControl
|
||||
Header="Flag state overlay"
|
||||
Description="Show values of specified flags during runtime. Each flag is comma separated.">
|
||||
<ui:TextBox Margin="5,0,0,0" Padding="10,5,10,5" Width="200" Text="{Binding StateOverlayFlags, Mode=TwoWay}" />
|
||||
</controls:OptionControl>
|
||||
</StackPanel>
|
||||
|
||||
<TextBlock Text="{x:Static resources:Strings.Common_Presets}" FontSize="20" FontWeight="Medium" Margin="0,16,0,0" />
|
||||
|
||||
<TextBlock Text="{x:Static resources:Strings.Menu_FastFlags_Presets_Categories_Rendering}" FontSize="16" FontWeight="Medium" Margin="0,16,0,0" />
|
||||
<controls:MarkdownTextBlock MarkdownText="{Binding Source={x:Static resources:Strings.Menu_FastFlags_Presets_D3DExclusiveFullscreenInfo}, Converter={StaticResource StringFormatConverter}, ConverterParameter='https://github.com/pizzaboxer/bloxstrap/wiki/A-guide-to-FastFlags#exclusive-fullscreen'}" Foreground="{DynamicResource TextFillColorSecondaryBrush}" />
|
||||
|
||||
<controls:OptionControl
|
||||
Header="{x:Static resources:Strings.Menu_FastFlags_Presets_MSAA_Title}">
|
||||
<ComboBox Margin="5,0,0,0" Padding="10,5,10,5" Width="200" ItemsSource="{Binding MSAALevels.Keys, Mode=OneTime}" Text="{Binding SelectedMSAALevel, Mode=TwoWay}">
|
||||
<ComboBox.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<TextBlock Text="{Binding Path=., Converter={StaticResource EnumNameConverter}}" />
|
||||
</DataTemplate>
|
||||
</ComboBox.ItemTemplate>
|
||||
</ComboBox>
|
||||
</controls:OptionControl>
|
||||
<!-- first ListView is for each category of presets -->
|
||||
<ListView ItemsSource="{Binding Presets, Mode=OneWay}" Margin="-4">
|
||||
<ListView.ItemContainerStyle>
|
||||
<Style TargetType="{x:Type ListViewItem}" BasedOn="{StaticResource {x:Type ListViewItem}}">
|
||||
<Setter Property="Focusable" Value="False" />
|
||||
</Style>
|
||||
</ListView.ItemContainerStyle>
|
||||
<ListView.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<StackPanel>
|
||||
<TextBlock Text="{Binding Key}" FontSize="16" FontWeight="Medium" Margin="0,16,0,0" />
|
||||
<!-- second ListView is for each preset in the category -->
|
||||
<ListView ItemsSource="{Binding Value}">
|
||||
<ListView.ItemContainerStyle>
|
||||
<Style TargetType="{x:Type ListViewItem}" BasedOn="{StaticResource {x:Type ListViewItem}}">
|
||||
<Setter Property="Focusable" Value="False" />
|
||||
</Style>
|
||||
</ListView.ItemContainerStyle>
|
||||
<ListView.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<controls:OptionControl Header="{Binding Title}" Description="{Binding Description}" HelpLink="{Binding HelpLink}" Margin="-4">
|
||||
<StackPanel>
|
||||
<!-- Toggle type -->
|
||||
<ui:ToggleSwitch IsChecked="{Binding ToggleEnabled, Mode=TwoWay}">
|
||||
<ui:ToggleSwitch.Style>
|
||||
<Style TargetType="ui:ToggleSwitch" BasedOn="{StaticResource {x:Type ui:ToggleSwitch}}">
|
||||
<Style.Triggers>
|
||||
<DataTrigger Binding="{Binding Type}" Value="Toggle">
|
||||
<Setter Property="Visibility" Value="Visible" />
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
<Setter Property="Visibility" Value="Collapsed" />
|
||||
</Style>
|
||||
</ui:ToggleSwitch.Style>
|
||||
</ui:ToggleSwitch>
|
||||
|
||||
<!-- ComboBox type -->
|
||||
<ComboBox Margin="5,0,0,0" Padding="10,5,10,5" Width="200" ItemsSource="{Binding ComboBoxEntries, Mode=OneTime}" Text="{Binding ComboBoxSelection, Mode=TwoWay}">
|
||||
<ComboBox.Style>
|
||||
<Style TargetType="ComboBox" BasedOn="{StaticResource {x:Type ComboBox}}">
|
||||
<Style.Triggers>
|
||||
<DataTrigger Binding="{Binding Type}" Value="ComboBox">
|
||||
<Setter Property="Visibility" Value="Visible" />
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
<Setter Property="Visibility" Value="Collapsed" />
|
||||
</Style>
|
||||
</ComboBox.Style>
|
||||
<ComboBox.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<TextBlock Text="{Binding Path=., Converter={StaticResource StringResourceConverter}}" />
|
||||
</DataTemplate>
|
||||
</ComboBox.ItemTemplate>
|
||||
</ComboBox>
|
||||
|
||||
<controls:OptionControl
|
||||
Header="{x:Static resources:Strings.Menu_FastFlags_Presets_DisablePlayerShadows_Title}">
|
||||
<ui:ToggleSwitch IsChecked="{Binding DisablePlayerShadows, Mode=TwoWay}" />
|
||||
</controls:OptionControl>
|
||||
|
||||
<controls:OptionControl
|
||||
Header="{x:Static resources:Strings.Menu_FastFlags_Presets_DisablePostFX_Title}"
|
||||
HelpLink="https://create.roblox.com/docs/environment/post-processing-effects">
|
||||
<ui:ToggleSwitch IsChecked="{Binding DisablePostFX, Mode=TwoWay}" />
|
||||
</controls:OptionControl>
|
||||
|
||||
<controls:OptionControl
|
||||
Header="{x:Static resources:Strings.Menu_FastFlags_Presets_DisableTerrainTextures_Title}">
|
||||
<ui:ToggleSwitch IsChecked="{Binding DisableTerrainTextures, Mode=TwoWay}" />
|
||||
</controls:OptionControl>
|
||||
|
||||
<controls:OptionControl
|
||||
Header="{x:Static resources:Strings.Menu_FastFlags_Presets_FPSLimit_Title}"
|
||||
Description="{x:Static resources:Strings.Menu_FastFlags_Presets_FPSLimit_Description}"
|
||||
HelpLink="https://github.com/pizzaboxer/bloxstrap/wiki/A-guide-to-FastFlags#framerate-limit">
|
||||
<ui:TextBox Margin="5,0,0,0" Padding="10,5,10,5" Width="200" Text="{Binding FramerateLimit, Mode=TwoWay}" PreviewTextInput="ValidateUInt32" />
|
||||
</controls:OptionControl>
|
||||
|
||||
<controls:OptionControl
|
||||
Header="{x:Static resources:Strings.Menu_FastFlags_Presets_LightingTechnology_Title}"
|
||||
Description="{Binding Source={x:Static resources:Strings.Menu_FastFlags_Presets_LightingTechnology_Description}, Converter={StaticResource StringFormatConverter}, ConverterParameter='https://github.com/pizzaboxer/bloxstrap/wiki/A-guide-to-FastFlags#preferred-lighting-technology'}" Foreground="{DynamicResource TextFillColorSecondaryBrush}"
|
||||
HelpLink="https://github.com/pizzaboxer/bloxstrap/wiki/A-guide-to-FastFlags#preferred-lighting-technology">
|
||||
<ComboBox Margin="5,0,0,0" Padding="10,5,10,5" Width="200" ItemsSource="{Binding LightingModes.Keys, Mode=OneTime}" Text="{Binding SelectedLightingMode, Mode=TwoWay}">
|
||||
<ComboBox.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<TextBlock Text="{Binding Path=., Converter={StaticResource EnumNameConverter}}" />
|
||||
</DataTemplate>
|
||||
</ComboBox.ItemTemplate>
|
||||
</ComboBox>
|
||||
</controls:OptionControl>
|
||||
|
||||
<controls:OptionControl
|
||||
Header="{x:Static resources:Strings.Menu_FastFlags_Presets_FixDisplayScaling_Title}"
|
||||
Description="{x:Static resources:Strings.Menu_FastFlags_Presets_FixDisplayScaling_Description}"
|
||||
HelpLink="https://github.com/pizzaboxer/bloxstrap/wiki/A-guide-to-FastFlags#dpi-scaling-fixes">
|
||||
<ui:ToggleSwitch IsChecked="{Binding FixDisplayScaling, Mode=TwoWay}" />
|
||||
</controls:OptionControl>
|
||||
|
||||
<controls:OptionControl
|
||||
Header="{x:Static resources:Strings.Menu_FastFlags_Presets_RenderingMode_Title}">
|
||||
<ComboBox Margin="5,0,0,0" Padding="10,5,10,5" Width="200" ItemsSource="{Binding RenderingModes.Keys, Mode=OneTime}" Text="{Binding SelectedRenderingMode, Mode=TwoWay}">
|
||||
<ComboBox.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<TextBlock Text="{Binding Path=., Converter={StaticResource EnumNameConverter}}" />
|
||||
</DataTemplate>
|
||||
</ComboBox.ItemTemplate>
|
||||
</ComboBox>
|
||||
</controls:OptionControl>
|
||||
|
||||
<controls:OptionControl
|
||||
Header="{x:Static resources:Strings.Menu_FastFlags_Presets_TextureQuality_Title}">
|
||||
<ComboBox Margin="5,0,0,0" Padding="10,5,10,5" Width="200" ItemsSource="{Binding TextureQualities.Keys, Mode=OneTime}" Text="{Binding SelectedTextureQuality, Mode=TwoWay}">
|
||||
<ComboBox.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<TextBlock Text="{Binding Path=., Converter={StaticResource EnumNameConverter}}" />
|
||||
</DataTemplate>
|
||||
</ComboBox.ItemTemplate>
|
||||
</ComboBox>
|
||||
</controls:OptionControl>
|
||||
|
||||
<TextBlock Text="{x:Static resources:Strings.Menu_FastFlags_Presets_Categories_UserInterface}" FontSize="16" FontWeight="Medium" Margin="0,16,0,0" />
|
||||
|
||||
<controls:OptionControl
|
||||
Header="{x:Static resources:Strings.Menu_FastFlags_Presets_FullscreenTitlebar_Title}"
|
||||
Description="{x:Static resources:Strings.Menu_FastFlags_Presets_FullscreenTitlebar_Description}">
|
||||
<ui:ToggleSwitch IsChecked="{Binding FullscreenTitlebarDisabled, Mode=TwoWay}" />
|
||||
</controls:OptionControl>
|
||||
|
||||
<controls:OptionControl
|
||||
Header="{x:Static resources:Strings.Menu_FastFlags_Presets_HideGuis_Title}"
|
||||
Description="{Binding Source={x:Static resources:Strings.Menu_FastFlags_Presets_HideGuis_Description}, Converter={StaticResource StringFormatConverter}, ConverterParameter='https://github.com/pizzaboxer/bloxstrap/wiki/A-guide-to-FastFlags#gui-hiding|https://www.roblox.com/groups/32380007/Bloxstrap'}"
|
||||
HelpLink="https://github.com/pizzaboxer/bloxstrap/wiki/A-guide-to-FastFlags#gui-hiding">
|
||||
<ui:ToggleSwitch IsChecked="{Binding GuiHidingEnabled, Mode=TwoWay}" />
|
||||
</controls:OptionControl>
|
||||
|
||||
<controls:OptionControl
|
||||
x:Name="FontPaddingOption"
|
||||
Header="{x:Static resources:Strings.Menu_FastFlags_Presets_FontPadding_Title}"
|
||||
Description="{Binding Source={x:Static resources:Strings.Menu_FastFlags_Presets_FontPadding_Description}, Converter={StaticResource StringFormatConverter}, ConverterParameter='https://github.com/pizzaboxer/bloxstrap/wiki/A-guide-to-FastFlags#gui-hiding|https://www.roblox.com/groups/32380007/Bloxstrap'}">
|
||||
<ui:TextBox Width="200" Padding="10,5,10,5" Text="{Binding FontSize, Mode=TwoWay}" PreviewTextInput="ValidateInt32" />
|
||||
</controls:OptionControl>
|
||||
|
||||
<controls:OptionControl
|
||||
Header="{x:Static resources:Strings.Menu_FastFlags_Presets_EscapeMenuVersion_Title}"
|
||||
HelpLink="https://github.com/pizzaboxer/bloxstrap/wiki/A-guide-to-FastFlags#escape-menu-version">
|
||||
<ComboBox Margin="5,0,0,0" Padding="10,5,10,5" Width="200" ItemsSource="{Binding IGMenuVersions.Keys, Mode=OneTime}" Text="{Binding SelectedIGMenuVersion, Mode=TwoWay}">
|
||||
<ComboBox.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<TextBlock Text="{Binding Path=., Converter={StaticResource EnumNameConverter}}" />
|
||||
</DataTemplate>
|
||||
</ComboBox.ItemTemplate>
|
||||
</ComboBox>
|
||||
</controls:OptionControl>
|
||||
<!-- TextBox type -->
|
||||
<ui:TextBox Margin="5,0,0,0" Padding="10,5,10,5" Width="200" Text="{Binding TextBoxValue, Mode=TwoWay}">
|
||||
<ui:TextBox.Style>
|
||||
<Style TargetType="ui:TextBox" BasedOn="{StaticResource {x:Type ui:TextBox}}">
|
||||
<Style.Triggers>
|
||||
<DataTrigger Binding="{Binding Type}" Value="TextBox">
|
||||
<Setter Property="Visibility" Value="Visible" />
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
<Setter Property="Visibility" Value="Collapsed" />
|
||||
</Style>
|
||||
</ui:TextBox.Style>
|
||||
</ui:TextBox>
|
||||
</StackPanel>
|
||||
</controls:OptionControl>
|
||||
</DataTemplate>
|
||||
</ListView.ItemTemplate>
|
||||
</ListView>
|
||||
</StackPanel>
|
||||
</DataTemplate>
|
||||
</ListView.ItemTemplate>
|
||||
</ListView>
|
||||
|
||||
<ui:CardAction Margin="0,24,0,0" Icon="EditSettings24" Command="{Binding OpenFastFlagEditorCommand}">
|
||||
<StackPanel>
|
||||
|
@ -7,7 +7,6 @@ using Wpf.Ui.Mvvm.Contracts;
|
||||
using CommunityToolkit.Mvvm.Input;
|
||||
|
||||
using Bloxstrap.UI.Elements.Settings.Pages;
|
||||
using Bloxstrap.Enums.FlagPresets;
|
||||
|
||||
namespace Bloxstrap.UI.ViewModels.Settings
|
||||
{
|
||||
@ -15,6 +14,16 @@ namespace Bloxstrap.UI.ViewModels.Settings
|
||||
{
|
||||
private readonly Page _page;
|
||||
|
||||
public ICommand OpenFastFlagEditorCommand => new RelayCommand(OpenFastFlagEditor);
|
||||
|
||||
public bool UseFastFlagManager
|
||||
{
|
||||
get => App.Settings.Prop.UseFastFlagManager;
|
||||
set => App.Settings.Prop.UseFastFlagManager = value;
|
||||
}
|
||||
|
||||
public Dictionary<string, List<FFlagPreset>> Presets => App.FastFlags.PresetConfig.Presets;
|
||||
|
||||
public FastFlagsViewModel(Page page)
|
||||
{
|
||||
_page = page;
|
||||
@ -30,167 +39,5 @@ namespace Bloxstrap.UI.ViewModels.Settings
|
||||
window.Navigate(typeof(FastFlagEditorPage));
|
||||
}
|
||||
}
|
||||
|
||||
public ICommand OpenFastFlagEditorCommand => new RelayCommand(OpenFastFlagEditor);
|
||||
|
||||
#if DEBUG
|
||||
public Visibility ShowDebugFlags => Visibility.Visible;
|
||||
#else
|
||||
public Visibility ShowDebugFlags => Visibility.Collapsed;
|
||||
#endif
|
||||
|
||||
public bool UseFastFlagManager
|
||||
{
|
||||
get => App.Settings.Prop.UseFastFlagManager;
|
||||
set => App.Settings.Prop.UseFastFlagManager = value;
|
||||
}
|
||||
|
||||
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 : 0;
|
||||
set => App.FastFlags.SetPreset("Rendering.Framerate", value == 0 ? null : value);
|
||||
}
|
||||
|
||||
public IReadOnlyDictionary<MSAAMode, string?> MSAALevels => FastFlagManager.MSAAModes;
|
||||
|
||||
public MSAAMode SelectedMSAALevel
|
||||
{
|
||||
get => MSAALevels.FirstOrDefault(x => x.Value == App.FastFlags.GetPreset("Rendering.MSAA")).Key;
|
||||
set => App.FastFlags.SetPreset("Rendering.MSAA", MSAALevels[value]);
|
||||
}
|
||||
|
||||
public IReadOnlyDictionary<RenderingMode, string> RenderingModes => FastFlagManager.RenderingModes;
|
||||
|
||||
public RenderingMode SelectedRenderingMode
|
||||
{
|
||||
get => App.FastFlags.GetPresetEnum(RenderingModes, "Rendering.Mode", "True");
|
||||
set => App.FastFlags.SetPresetEnum("Rendering.Mode", RenderingModes[value], "True");
|
||||
}
|
||||
|
||||
public bool FixDisplayScaling
|
||||
{
|
||||
get => App.FastFlags.GetPreset("Rendering.DisableScaling") == "True";
|
||||
set => App.FastFlags.SetPreset("Rendering.DisableScaling", value ? "True" : null);
|
||||
}
|
||||
|
||||
public IReadOnlyDictionary<InGameMenuVersion, Dictionary<string, string?>> IGMenuVersions => FastFlagManager.IGMenuVersions;
|
||||
|
||||
public InGameMenuVersion 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<LightingMode, string> LightingModes => FastFlagManager.LightingModes;
|
||||
|
||||
public LightingMode SelectedLightingMode
|
||||
{
|
||||
get => App.FastFlags.GetPresetEnum(LightingModes, "Rendering.Lighting", "True");
|
||||
set => App.FastFlags.SetPresetEnum("Rendering.Lighting", LightingModes[value], "True");
|
||||
}
|
||||
|
||||
public bool FullscreenTitlebarDisabled
|
||||
{
|
||||
get => int.TryParse(App.FastFlags.GetPreset("UI.FullscreenTitlebarDelay"), out int x) && x > 5000;
|
||||
set => App.FastFlags.SetPreset("UI.FullscreenTitlebarDelay", value ? "3600000" : null);
|
||||
}
|
||||
|
||||
public bool GuiHidingEnabled
|
||||
{
|
||||
get => App.FastFlags.GetPreset("UI.Hide") == "32380007";
|
||||
set => App.FastFlags.SetPreset("UI.Hide", value ? "32380007" : null);
|
||||
}
|
||||
|
||||
public IReadOnlyDictionary<TextureQuality, string?> TextureQualities => FastFlagManager.TextureQualityLevels;
|
||||
|
||||
public TextureQuality SelectedTextureQuality
|
||||
{
|
||||
get => TextureQualities.Where(x => x.Value == App.FastFlags.GetPreset("Rendering.TextureQuality.Level")).FirstOrDefault().Key;
|
||||
set
|
||||
{
|
||||
if (value == TextureQuality.Default)
|
||||
{
|
||||
App.FastFlags.SetPreset("Rendering.TextureQuality", null);
|
||||
}
|
||||
else
|
||||
{
|
||||
App.FastFlags.SetPreset("Rendering.TextureQuality.OverrideEnabled", "True");
|
||||
App.FastFlags.SetPreset("Rendering.TextureQuality.Level", TextureQualities[value]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public bool DisablePostFX
|
||||
{
|
||||
get => App.FastFlags.GetPreset("Rendering.DisablePostFX") == "True";
|
||||
set => App.FastFlags.SetPreset("Rendering.DisablePostFX", value ? "True" : null);
|
||||
}
|
||||
|
||||
public bool DisablePlayerShadows
|
||||
{
|
||||
get => App.FastFlags.GetPreset("Rendering.ShadowIntensity") == "0";
|
||||
set => App.FastFlags.SetPreset("Rendering.ShadowIntensity", value ? "0" : null);
|
||||
}
|
||||
|
||||
public int? FontSize
|
||||
{
|
||||
get => int.TryParse(App.FastFlags.GetPreset("UI.FontSize"), out int x) ? x : 1;
|
||||
set => App.FastFlags.SetPreset("UI.FontSize", value == 1 ? null : value);
|
||||
}
|
||||
|
||||
public bool DisableTerrainTextures
|
||||
{
|
||||
get => App.FastFlags.GetPreset("Rendering.TerrainTextureQuality") == "0";
|
||||
set => App.FastFlags.SetPreset("Rendering.TerrainTextureQuality", value ? "0" : null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user