View Issue Details
| ID | Project | Category | View Status | Date Submitted | Last Update |
|---|---|---|---|---|---|
| 0005177 | NoesisGUI | Unity | public | 2026-08-20 19:23 | 2026-08-21 20:24 |
| Reporter | stonstad | Assigned To | jsantos | ||
| Priority | normal | Severity | major | ||
| Status | resolved | Resolution | fixed | ||
| Product Version | 4.0 | ||||
| Fixed in Version | 4.0 | ||||
| Summary | 0005177: 4.0 RC5. AssetDependency Fails After Subsequent Stop/Play Cycle | ||||
| Description | I am seeing AssetDependency attribute resolution fail after Unity playback stops and is restarted. 1) Play -> Stop -> Play generates XAML errors. Note that first time playback works and no XAML errors are generated on Unity import. These are runtime errors that occur on second playback only.
Unity 6.5.7f1. | ||||
| Attached Files | TitleScreen.xaml (6,445 bytes)
<UserControl
x:Class="StellarConquest.Presentation.Unity.UI.TitleScreen"
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" mc:Ignorable="d"
xmlns:noesis="clr-namespace:NoesisGUIExtensions"
xmlns:b="http://schemas.microsoft.com/xaml/behaviors"
xmlns:local="clr-namespace:StellarConquest.Presentation.Unity.UI"
d:DesignWidth="1280" d:DesignHeight="720">
<Grid>
<Viewbox x:Name="LoginScreenViewBox">
<local:ViewboxGridControl x:Name="_LayoutRoot">
<Grid>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="1*"/>
<RowDefinition Height="6*"/>
<RowDefinition Height="1*"/>
</Grid.RowDefinitions>
<StackPanel x:Name="_LoginStackPanel" Orientation="Horizontal" Grid.Row="1" HorizontalAlignment="Center" VerticalAlignment="Center">
<local:ButtonPanelControl x:Name="_ButtonPanelControl" VerticalAlignment="Center" Margin="0, -35, 20, 0"/>
<StackPanel x:Name="_NewsStackPanel1" Orientation="Vertical" VerticalAlignment="Center">
<local:NewsControl x:Name="_NewsControl1" Margin="0, 0, 0, 20"/>
<local:SocialMediaPanelControl x:Name="_SocialMediaPanelControl"/>
</StackPanel>
<StackPanel x:Name="_NewsStackPanel2" Orientation="Vertical" VerticalAlignment="Center" Visibility="Collapsed">
<local:NewsControl x:Name="_NewsControl2" Margin="0, 0, 0, 20"/>
<Grid Height="50"/>
</StackPanel>
</StackPanel>
<TextBlock x:Name="_Handle" Grid.Row="2" HorizontalAlignment="Right" FontFamily="{StaticResource Teko}" FontSize="35" VerticalAlignment="Bottom" Foreground="White" Opacity="0.9" Margin="0, 0, 60, 35"/>
<TextBlock x:Name="_VersionTextBlock" Grid.Row="2" HorizontalAlignment="Center" FontFamily="{StaticResource Teko}" FontSize="22" VerticalAlignment="Bottom" Foreground="White" Opacity="0.7" Margin="0, 0, 0, 40"/>
</Grid>
<StackPanel x:Name="_SecondaryScreenStackPanel" HorizontalAlignment="Center" VerticalAlignment="Center"/>
<Grid x:Name="_PreviewGrid" Background="Transparent" Opacity="0" Visibility="Collapsed">
<Grid Background="#99000000" HorizontalAlignment="Stretch" VerticalAlignment="Stretch"/>
<Grid HorizontalAlignment="Center" VerticalAlignment="Stretch">
<Border HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<b:Interaction.Behaviors>
<noesis:BackgroundEffectBehavior Source="{DynamicResource BaseBlurSource}">
<BlurEffect Radius="{Binding Radius, Source={StaticResource TopBlurRadius}}"/>
</noesis:BackgroundEffectBehavior>
</b:Interaction.Behaviors>
</Border>
<Grid Background="#AA000000" HorizontalAlignment="Stretch" VerticalAlignment="Stretch"/>
<Rectangle Fill="#66777777" Width="2" HorizontalAlignment="Left" VerticalAlignment="Stretch"/>
<Rectangle Fill="#66777777" Width="2" HorizontalAlignment="Right" VerticalAlignment="Stretch"/>
<StackPanel Orientation="Vertical" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="50, -50, 50, 50">
<Viewbox Width="600" Margin="-10, 0, -10, 15">
<Grid>
<Grid.Effect>
<DropShadowEffect BlurRadius="10" ShadowDepth="3" Opacity="1"/>
</Grid.Effect>
<Image x:Name="_LogoEllipse" Source="{StaticResource ellipse}" Width="550" Stretch="Uniform" Margin="0, 0, 0, 100"/>
<TextBlock x:Name="_LogoText" HorizontalAlignment="Center" FontFamily="{StaticResource Agency}" FontSize="95" VerticalAlignment="Bottom" Margin="0, 0, 0, 0" Foreground="White" Opacity="0.9" noesis:Text.CharacterSpacing="350" Text="STELLAR CONQUEST"/>
</Grid>
</Viewbox>
<StackPanel Orientation="Vertical" MaxWidth="500" Effect="{StaticResource UIDropShadow}">
<TextBlock FontFamily="{StaticResource Teko}" FontSize="40" FontWeight="Normal" HorizontalAlignment="Center" Margin="0, 0, 0, 95">PREVIEW</TextBlock>
<TextBlock FontFamily="{StaticResource DefaultFontFamily}" FontSize="30" FontWeight="Normal" HorizontalAlignment="Center" TextAlignment="Center" TextWrapping="Wrap" Margin="0, 0, 0, 35">This is an unfinished version of the game. You might encounter broken or missing parts.</TextBlock>
<TextBlock FontFamily="{StaticResource DefaultFontFamily}" FontSize="30" FontWeight="Normal" HorizontalAlignment="Center" TextAlignment="Center" TextWrapping="Wrap" Margin="0, 0, 0, 35">Saved galaxies won't work with the final release version.</TextBlock>
<TextBlock FontFamily="{StaticResource HeadingFontFamily}" FontSize="30" FontWeight="Bold" HorizontalAlignment="Center" TextAlignment="Center" TextWrapping="Wrap" Margin="0, 0, 0, 0">Press any key or button to start</TextBlock>
</StackPanel>
</StackPanel>
</Grid>
</Grid>
</Grid>
</local:ViewboxGridControl>
</Viewbox>
</Grid>
</UserControl> TitleScreen.xaml.cs (15,733 bytes)
using Noesis;
using StellarConquest.Model.Actions;
using StellarConquest.Model.Authentication;
using StellarConquest.Model.Core;
using StellarConquest.Model.Performance;
using StellarConquest.Model.Platform;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using UnityEngine;
using EventArgs = Noesis.EventArgs;
using Grid = Noesis.Grid;
using GUI = Noesis.GUI;
using Task = System.Threading.Tasks.Task;
namespace StellarConquest.Presentation.Unity.UI
{
[AssetDependency]
public partial class TitleScreen : UserControl, IGameScreenPrimary, IGameScreenInputProvider
{
private bool _IsPlayerServerError = false;
private bool _IsGameServerError = false;
private bool _IsSystemServerError = false;
private bool _IsServiceAuthenticationError = false;
private string _GameNews;
private Statistics _Statistics = new Statistics();
public List<AuthenticatedPlayer> _Players = null;
private FrameworkElement _Root;
private Grid _LayoutRoot;
private StackPanel _NewsStackPanel1;
private NewsControl _NewsControl1;
private StackPanel _NewsStackPanel2;
private NewsControl _NewsControl2;
private StackPanel _SecondaryScreenStackPanel;
private ServerControl _ServerControl;
private ServerListControl _ServerListControl;
private LocalizationControl _LocalizationControl;
private ButtonPanelControl _ButtonPanelControl;
private TextBlock _VersionTextBlock;
private TextBlock _Handle;
public bool IsCursorOverUI { get { return false; } }
private Grid _PreviewGrid;
private static bool _PreviewGridShown = false;
public TitleScreen()
{
Initialized += OnInitialized;
InitializeComponent();
}
private void InitializeComponent()
{
GUI.LoadComponent(this, "Assets/User Interface/Screens/Title/TitleScreen.xaml");
_Root = Content as FrameworkElement;
_LayoutRoot = _Root.FindName(nameof(_LayoutRoot)) as Grid;
_NewsStackPanel1 = _Root.FindName(nameof(_NewsStackPanel1)) as StackPanel;
_NewsControl1 = _Root.FindName(nameof(_NewsControl1)) as NewsControl;
_NewsStackPanel2 = _Root.FindName(nameof(_NewsStackPanel2)) as StackPanel;
_NewsControl2 = _Root.FindName(nameof(_NewsControl2)) as NewsControl;
_SecondaryScreenStackPanel = _Root.FindName(nameof(_SecondaryScreenStackPanel)) as StackPanel;
_ButtonPanelControl = _Root.FindName(nameof(_ButtonPanelControl)) as ButtonPanelControl;
_VersionTextBlock = _Root.FindName(nameof(_VersionTextBlock)) as TextBlock;
_Handle = _Root.FindName(nameof(_Handle)) as TextBlock;
_PreviewGrid = _Root.FindName(nameof(_PreviewGrid)) as Grid;
_LayoutRoot.Visibility = Visibility.Collapsed;
}
private void OnInitialized(object sender, EventArgs args)
{
if (!Application.isPlaying)
return;
RegisterEvents();
// TODO: enable and test account id caching feature when Steam is down.
//var result = PlayerPreferences.Instance.GetPreviousAccount();
//if (result.Item1 != null && result.Item2.HasValue)
//{
// SessionState.Instance.AuthenticationToken = new AuthenticationToken(result.Item1);
// SessionState.Instance.AccountId = result.Item2.Value;
//}
_ = Initialize(PlayerPreferences.Instance.ConquestEnvironment, Application.isEditor);
//https://howtomarketagame.com/2021/06/21/neat-ideas-for-your-games-demo/
//TutorialControl tutorialControl = new TutorialControl();
//string text = "Thank you for playing this alpha build of Stellar Conquest. Please join us on our Discord channel for news about the next play test. See you for the next update!" + Environment.NewLine + Environment.NewLine;
//tutorialControl.SetText("Build Expired", false, text);
//tutorialControl.Show();
if (!_PreviewGridShown)
{
_PreviewGrid.Visibility = Visibility.Visible;
_PreviewGrid.FadeInScreen(this);
_PreviewGridShown = true;
}
}
public async Task Initialize(EnvironmentType cloudEnvironment, bool isEditor)
{
UnityDispatcher.Instance.Invoke(() =>
{
_Handle.Text = string.Empty;
ChatBuffer.Instance.Execute(new ChatAction() { Clear = true });
});
_IsSystemServerError = false;
_IsGameServerError = false;
try
{
await NetworkClient.Instance.Initialize(cloudEnvironment, true, isEditor);
_IsSystemServerError = !await NetworkClient.Instance.TestSystemServerHttpConnection(GameStateMachine.Instance.CancellationTokenSource.Token);
if (!_IsSystemServerError)
{
var taskA = GameServices.Instance.InitializeGameService(); // initialize Steam or XBL and create Stellar Conquest authorization token
var taskB = GetGameServerVersion();
var taskC = GetGameNewsAsync();
// initialize game services
await taskA;
_IsServiceAuthenticationError = !taskA.Result;
if (!_IsServiceAuthenticationError && !_IsSystemServerError)
{
var taskD = GetCloudLicenseAsync(); // get license using game service authorization token
await taskD;
}
if (taskB != null)
await taskB;
if (taskC != null)
await taskC;
}
UnityDispatcher.Instance.Invoke(() => FadeInUI());
}
catch (TaskCanceledException)
{
}
catch (Exception e)
{
Debug.LogError(e);
_IsSystemServerError = true;
}
#if (UNITY_STANDALONE_WIN)
if (!Application.isEditor && Constants.System.Build == "Debug")
UIStateMachine.Instance.UIShowMessage("Build Error", "Warning: DEBUG library detected in RELEASE build.");
#endif
if (_IsServiceAuthenticationError)
{
UnityDispatcher.Instance.Invoke(() =>
{
#if(UNITY_STANDALONE_WIN)
_NewsControl1.ShowError("Please launch Steam before playing Stellar Conquest and ensure you have access to this game.");
#else
_NewsControl1.ShowError("A problem occurred while authenticating your account Xbox Live.");
#endif
_ButtonPanelControl.SetPlayButtonText("RETRY");
});
}
else if (_IsSystemServerError)
{
UnityDispatcher.Instance.Invoke(() =>
{
FadeInUI();
_NewsControl1.ShowError($"Stellar Conquest ({PlayerPreferences.Instance.ConquestEnvironment}) " +
"is down for maintenance and will be back up shortly. Please retry again.");
_ButtonPanelControl.SetPlayButtonText("RETRY");
});
}
else if (!_IsSystemServerError)
{
UnityDispatcher.Instance.Invoke(() =>
{
_NewsControl1.Update(_Statistics, _GameNews, null);
if (SessionState.Instance.ClientVersion == SessionState.Instance.ServerVersion)
_ButtonPanelControl.SetConquestButtonEnabled(SessionState.Instance.HasLicense && !_IsSystemServerError && !_IsGameServerError);
else
_ButtonPanelControl.SetConquestButtonEnabled(false);
});
}
}
private async Task Login()
{
CheckedResponse<List<AuthenticatedPlayer>> result = null;
try
{
// get players
result = await NetworkClient.Instance.GetPlayers();
// get price list
_ = GetPriceListAsync();
}
catch (Exception e)
{
Debug.LogError(e);
result = new CheckedResponse<List<AuthenticatedPlayer>>(null, e.Message);
}
UnityDispatcher.Instance.Invoke(() =>
{
PlayerPreferences.Instance.FPSLogin = Mathf.RoundToInt(GameState.Instance.FrameRateCounter.FPS);
PlayerPreferences.Instance.SavePreferences();
if (result != null && result.Result != null)
{
SessionState.Instance.AuthenticatedPlayers = result.Result;
if (result.Result.Count == 0)
GameStateMachine.Instance.SetState(GameStateType.CharacterCreation);
else
GameStateMachine.Instance.SetState(GameStateType.CharacterSelection);
RuntimeSettings.Instance.SendTelemetry();
}
else if (result == null || result.Result == null || !string.IsNullOrEmpty(result.Error))
{
ShowPlayOptions();
if (result != null && !string.IsNullOrEmpty(result.Error))
_NewsControl2.ShowError("Login Error: " + result.Error);
else
_NewsControl2.ShowError("Login Error: unable to access account.");
}
});
}
private void ShowPlayOptions()
{
UIStateMachine.Instance.TransitionLayer.ShowLoadingImage(false, false);
_ServerControl = null;
_ServerListControl = null;
_LocalizationControl = null;
_SecondaryScreenStackPanel.Children.Clear();
_ButtonPanelControl.SetPlayButtonEnabled(true);
_ButtonPanelControl.SetPlayButtonText("PLAY");
_NewsStackPanel1.Visibility = Visibility.Collapsed;
_NewsStackPanel2.Visibility = Visibility.Visible;
_ButtonPanelControl.Visibility = Visibility.Visible;
_ButtonPanelControl.ShowPlayOptions();
_Handle.Visibility = Visibility.Collapsed;
_VersionTextBlock.Visibility = Visibility.Collapsed;
}
private void ShowTitleOptions()
{
UIStateMachine.Instance.TransitionLayer.ShowLoadingImage(false, false);
_NewsStackPanel1.Visibility = Visibility.Visible;
_NewsStackPanel2.Visibility = Visibility.Collapsed;
_ButtonPanelControl.Visibility = Visibility.Visible;
if (_ServerControl != null)
_ServerControl.Visibility = Visibility.Collapsed;
if (_ServerListControl != null)
_ServerListControl.Visibility = Visibility.Collapsed;
_ButtonPanelControl.ShowTitleOptions();
_Handle.Visibility = Visibility.Visible;
_VersionTextBlock.Visibility = Visibility.Visible;
}
private void FadeInUI()
{
if (_LayoutRoot.Visibility == Visibility.Collapsed)
{
_LayoutRoot.Visibility = Visibility.Visible;
_LayoutRoot.FadeInScreen(this);
}
}
private void Shutdown()
{
if (!Application.isEditor)
{
IsHitTestVisible = false;
_ = Task.Run(async () =>
{
try
{
await GameServices.Instance.ShutdownGameService();
if (ServerBootstrap.Instance.IsServerRunning && !ServerBootstrap.Instance.IsDedicatedServer)
await NetworkClient.Instance.GracefulPlayerServerShutdown();
ServerBootstrap.Instance.StopServer(false);
}
catch (Exception e)
{
Debug.Log(e);
}
finally
{
UnityDispatcher.Instance.Invoke(() => Application.Quit());
}
});
}
}
public void UpdateInput()
{
if (_PreviewGrid.Visibility == Visibility.Visible)
if (Input.anyKeyDown || Input.GetMouseButtonDown(0) || Input.GetButton(InputNames.GamePad.A) || Input.GetButton(InputNames.GamePad.B))
{
if (_PreviewGrid.Visibility == Visibility.Visible)
{
_PreviewGrid.FadeOutScreen(this, () => _PreviewGrid.Visibility = Visibility.Collapsed);
return;
}
}
if (Input.GetKeyDown(KeyCode.Escape))
{
if (GameServerCancellationTokenSource != null)
GameServerCancellationTokenSource.Cancel(false);
else
{
if (_ServerControl != null)
{
_SecondaryScreenStackPanel.Children.Remove(_ServerControl);
_ServerControl = null;
ShowPlayOptions();
}
else if (_ServerListControl != null)
{
_SecondaryScreenStackPanel.Children.Remove(_ServerListControl);
_ServerListControl = null;
ShowPlayOptions();
}
else if (_LocalizationControl != null)
{
_SecondaryScreenStackPanel.Children.Remove(_LocalizationControl);
_LocalizationControl = null;
ShowPlayOptions();
}
else if (_ButtonPanelControl.Visibility == Visibility.Visible && _NewsStackPanel2.Visibility == Visibility.Visible)
{
ShowTitleOptions();
}
else
{
InputControl inputControl = new InputControl("Quit", "Quit Stellar Conquest?", null, InputControlButtonTypes.Yes | InputControlButtonTypes.No);
inputControl.Hidden += (sender, e) =>
{
if (inputControl.Response == InputControlButtonTypes.Yes)
Shutdown();
else
this.FadeInScreen(this);
};
this.FadeOutScreen(this);
inputControl.Show();
}
}
}
#if (UNITY_GAMECORE_XBOXSERIES)
if (Input.GetKeyDown(KeyCode.Alpha1))
_ = Login();
#endif
}
public void UpdateUserInterface()
{
}
}
}
| ||||
| Platform | Any | ||||
|
It is strange. I get these XAML not found errors for two files (TitleScreen and SettingsControl). I can't seem to determine what causes the errors to persist versus go away. Restarting Unity and/or reloading the assets via Import does not resolve the behavior. Second Error: SettingsControl.xaml (64,271 bytes)
<UserControl
x:Class="StellarConquest.Presentation.Unity.UI.SettingsControl"
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" mc:Ignorable="d"
xmlns:local="clr-namespace:StellarConquest.Presentation.Unity.UI">
<UserControl.Resources>
<Thickness x:Key="GroupMargin">0, 20, 0, 0</Thickness>
<Thickness x:Key="ScrollViewerMargin">15, 8, 15, 15</Thickness>
<SolidColorBrush x:Key="HeadingBrush" Color="#AAFFFFFF"/>
</UserControl.Resources>
<Grid x:Name="_LayoutRoot">
<local:BorderControlTitle x:Name="_BorderControl" HorizontalAlignment="Center" VerticalAlignment="Center" TitleText="Settings" BlurLayer="{DynamicResource OverlayBlurSource}">
<TabControl x:Name="_TabControl" MinWidth="700" Height="600" Background="#00000000" BorderBrush="#00000000" Margin="30, 20, 25, 20">
<TabItem>
<TabItem.Header>
<TextBlock Style="{StaticResource Heading2Primary}" Text="GAMEPLAY" FontSize="20" Margin="5"/>
</TabItem.Header>
<ScrollViewer>
<StackPanel Margin="{StaticResource ScrollViewerMargin}" >
<TextBlock Style="{StaticResource Heading3Primary}" HorizontalAlignment="Left" VerticalAlignment="Center" Padding="3" Margin="0, 0, 0, 12" MinWidth="625"
Foreground="Black" Background="{StaticResource HeadingBrush}" Text="Gameplay Assistance"/>
<StackPanel Orientation="Horizontal" Margin="0, 0, 0, 12">
<CheckBox x:Name="_GameHelpUIEnabled" Margin="0, 0, 5, 0" VerticalAlignment="Center">
<CheckBox.LayoutTransform>
<ScaleTransform ScaleX="1.5" ScaleY="1.5"/>
</CheckBox.LayoutTransform>
</CheckBox>
<TextBlock Style="{StaticResource Heading4Primary}" HorizontalAlignment="Left" VerticalAlignment="Center" Text="Show Game Help"/>
</StackPanel>
<StackPanel Orientation="Horizontal" Margin="0, 0, 0, 12">
<CheckBox x:Name="_DesignerHelpUIEnabled" Margin="0, 0, 5, 0" VerticalAlignment="Center">
<CheckBox.LayoutTransform>
<ScaleTransform ScaleX="1.5" ScaleY="1.5"/>
</CheckBox.LayoutTransform>
</CheckBox>
<TextBlock Style="{StaticResource Heading4Primary}" HorizontalAlignment="Left" VerticalAlignment="Center" Text="Show Designer Help"/>
</StackPanel>
<StackPanel Margin="{StaticResource GroupMargin}" Visibility="Collapsed"/>
<TextBlock Style="{StaticResource Heading3Primary}" HorizontalAlignment="Left" VerticalAlignment="Center" Padding="3" Margin="0, 0, 0, 12" MinWidth="625"
Foreground="Black" Background="{StaticResource HeadingBrush}" Text="Notifications" Visibility="Collapsed"/>
<StackPanel Orientation="Horizontal" Margin="0, 0, 0, 12" Visibility="Collapsed">
<CheckBox x:Name="_WarnSafeParkingEnabled" Margin="0, 0, 5, 0" VerticalAlignment="Center">
<CheckBox.LayoutTransform>
<ScaleTransform ScaleX="1.5" ScaleY="1.5"/>
</CheckBox.LayoutTransform>
</CheckBox>
<TextBlock Style="{StaticResource Heading4Primary}" HorizontalAlignment="Left" VerticalAlignment="Center" Text="Warn if Parking Unsafe"/>
</StackPanel>
<StackPanel Orientation="Horizontal" Margin="0, 0, 0, 12" Visibility="Collapsed">
<CheckBox x:Name="_WarnEvilEnabled" Margin="0, 0, 5, 0" VerticalAlignment="Center">
<CheckBox.LayoutTransform>
<ScaleTransform ScaleX="1.5" ScaleY="1.5"/>
</CheckBox.LayoutTransform>
</CheckBox>
<TextBlock Style="{StaticResource Heading4Primary}" HorizontalAlignment="Left" VerticalAlignment="Center" Text="Warn if Committing Evil"/>
</StackPanel>
<StackPanel Margin="{StaticResource GroupMargin}" Visibility="Visible"/>
<StackPanel x:Name="_GenerativeAIStackPanel">
<TextBlock Style="{StaticResource Heading3Primary}" HorizontalAlignment="Left" VerticalAlignment="Center" Padding="3" Margin="0, 0, 0, 12" MinWidth="625"
Foreground="Black" Background="{StaticResource HeadingBrush}" Text="Generative AI"/>
<StackPanel Orientation="Horizontal" Margin="0, 0, 0, 12">
<CheckBox x:Name="_GenerativeTextDialogue" Margin="0, 0, 5, 0" VerticalAlignment="Center">
<CheckBox.LayoutTransform>
<ScaleTransform ScaleX="1.5" ScaleY="1.5"/>
</CheckBox.LayoutTransform>
</CheckBox>
<TextBlock Style="{StaticResource Heading4Primary}" HorizontalAlignment="Left" VerticalAlignment="Center" Text="Generative Text Dialogue"/>
</StackPanel>
<StackPanel Orientation="Horizontal" Margin="0, 0, 0, 12">
<CheckBox x:Name="_GenerativeAudioDialogue" Margin="0, 0, 5, 0" VerticalAlignment="Center">
<CheckBox.LayoutTransform>
<ScaleTransform ScaleX="1.5" ScaleY="1.5"/>
</CheckBox.LayoutTransform>
</CheckBox>
<TextBlock Style="{StaticResource Heading4Primary}" HorizontalAlignment="Left" VerticalAlignment="Center" Text="Generative Audio Dialogue"/>
</StackPanel>
</StackPanel>
<StackPanel Margin="{StaticResource GroupMargin}" Visibility="Visible"/>
<StackPanel x:Name="_UnitsStackPanel">
<TextBlock Style="{StaticResource Heading3Primary}" HorizontalAlignment="Left" VerticalAlignment="Center" Padding="3" Margin="0, 0, 0, 12" MinWidth="625"
Foreground="Black" Background="{StaticResource HeadingBrush}" Text="Measurement Units"/>
<StackPanel Orientation="Horizontal" Margin="0, 0, 0, 12">
<TextBlock Style="{StaticResource Heading4Primary}" HorizontalAlignment="Right" VerticalAlignment="Center" Width="140" Margin="0, 0, 5, 0" Text="Temperature"/>
<ComboBox x:Name="_TemperatureUnits" Width="210">
<ComboBoxItem>Celsius</ComboBoxItem>
<ComboBoxItem>Fahrenheit</ComboBoxItem>
</ComboBox>
</StackPanel>
</StackPanel>
</StackPanel>
</ScrollViewer>
</TabItem>
<TabItem>
<TabItem.Header>
<TextBlock Style="{StaticResource Heading2Primary}" Text="INPUT" FontSize="20" Margin="5"/>
</TabItem.Header>
<ScrollViewer VerticalScrollBarVisibility="Visible">
<StackPanel Margin="{StaticResource ScrollViewerMargin}">
<StackPanel x:Name="_DevicesStackPanel">
<TextBlock Style="{StaticResource Heading3Primary}" HorizontalAlignment="Left" VerticalAlignment="Center" Padding="3" Margin="0, 0, 0, 12" MinWidth="625"
Foreground="Black" Background="{StaticResource HeadingBrush}" Text="Devices"/>
<StackPanel Orientation="Horizontal" Margin="0, 0, 0, 12">
<CheckBox x:Name="_GamepadEnabled" Margin="0, 0, 5, 0" VerticalAlignment="Center">
<CheckBox.LayoutTransform>
<ScaleTransform ScaleX="1.5" ScaleY="1.5"/>
</CheckBox.LayoutTransform>
</CheckBox>
<TextBlock Style="{StaticResource Heading4Primary}" HorizontalAlignment="Left" VerticalAlignment="Center" Text="Gamepad Enabled"/>
</StackPanel>
<StackPanel Orientation="Horizontal" Margin="0, 0, 0, 12">
<CheckBox x:Name="_MouseConfined" Margin="0, 0, 5, 0" VerticalAlignment="Center">
<CheckBox.LayoutTransform>
<ScaleTransform ScaleX="1.5" ScaleY="1.5"/>
</CheckBox.LayoutTransform>
</CheckBox>
<TextBlock Style="{StaticResource Heading4Primary}" HorizontalAlignment="Left" VerticalAlignment="Center" Text="Confine Mouse"/>
</StackPanel>
<StackPanel Margin="{StaticResource GroupMargin}"/>
</StackPanel>
<TextBlock Style="{StaticResource Heading3Primary}" HorizontalAlignment="Left" VerticalAlignment="Center" Padding="3" Margin="0, 0, 0, 12" MinWidth="625"
Foreground="Black" Background="{StaticResource HeadingBrush}" Text="Character"/>
<StackPanel Orientation="Horizontal" Margin="0, 0, 0, 12">
<TextBlock Style="{StaticResource Heading4Primary}" HorizontalAlignment="Right" VerticalAlignment="Center" Width="160" Margin="0, 0, 5, 0" Text="Camera Control"/>
<ComboBox x:Name="_CharacterControl" Width="210">
<ComboBoxItem>Default</ComboBoxItem>
<ComboBoxItem>Pivot</ComboBoxItem>
<ComboBoxItem>Cinematic</ComboBoxItem>
</ComboBox>
</StackPanel>
<StackPanel Orientation="Horizontal" Margin="0, 0, 0, 12">
<TextBlock Style="{StaticResource Heading4Primary}" HorizontalAlignment="Right" VerticalAlignment="Center" Width="160" Margin="0, 0, 5, 0" Text="Interior Camera"/>
<ComboBox x:Name="_InteriorCamera" Width="210">
<ComboBoxItem>Over the Shoulder</ComboBoxItem>
<ComboBoxItem>First Person</ComboBoxItem>
</ComboBox>
</StackPanel>
<StackPanel Orientation="Horizontal" Margin="0, 0, 0, 12">
<CheckBox x:Name="_CharacterInvertUpEnabled" Margin="0, 0, 5, 0" VerticalAlignment="Center">
<CheckBox.LayoutTransform>
<ScaleTransform ScaleX="1.5" ScaleY="1.5"/>
</CheckBox.LayoutTransform>
</CheckBox>
<TextBlock Style="{StaticResource Heading4Primary}" HorizontalAlignment="Left" VerticalAlignment="Center" Text="Character Invert Up"/>
</StackPanel>
<StackPanel Orientation="Vertical" Margin="0, 0, 0, 12">
<TextBlock Style="{StaticResource Heading4Primary}" HorizontalAlignment="Left" Text="Look Sensitivity"/>
<StackPanel Orientation="Horizontal" Margin="0, 0, 10, 0">
<StackPanel.LayoutTransform>
<ScaleTransform ScaleX="1.5" ScaleY="1.5"/>
</StackPanel.LayoutTransform>
<Slider x:Name="_CharacterLookSensitivity" Minimum="0.2" Maximum="1.8" IsSnapToTickEnabled="False" IsMoveToPointEnabled="True" TickFrequency="0.2" TickPlacement="BottomRight" Width="420" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="0, 0, 0, 0"/>
</StackPanel>
</StackPanel>
<StackPanel Margin="{StaticResource GroupMargin}"/>
<TextBlock Style="{StaticResource Heading3Primary}" HorizontalAlignment="Left" VerticalAlignment="Center" Padding="3" Margin="0, 0, 0, 12" MinWidth="625"
Foreground="Black" Background="{StaticResource HeadingBrush}" Text="Starship"/>
<StackPanel Orientation="Horizontal" Margin="0, 0, 0, 12">
<CheckBox x:Name="_ShipInvertUpEnabled" Margin="0, 0, 5, 0" VerticalAlignment="Center">
<CheckBox.LayoutTransform>
<ScaleTransform ScaleX="1.5" ScaleY="1.5"/>
</CheckBox.LayoutTransform>
</CheckBox>
<TextBlock Style="{StaticResource Heading4Primary}" HorizontalAlignment="Left" VerticalAlignment="Center" Text="Starship Invert Up"/>
</StackPanel>
<StackPanel Margin="{StaticResource GroupMargin}"/>
</StackPanel>
</ScrollViewer>
</TabItem>
<TabItem>
<TabItem.Header>
<TextBlock Style="{StaticResource Heading2Primary}" Text="DISPLAY" FontSize="20" Margin="5"/>
</TabItem.Header>
<ScrollViewer>
<StackPanel Orientation="Vertical" Margin="{StaticResource ScrollViewerMargin}">
<StackPanel x:Name="_ResolutionStackPanel">
<TextBlock Style="{StaticResource Heading3Primary}" HorizontalAlignment="Left" VerticalAlignment="Center" Padding="3" Margin="0, 0, 0, 12" MinWidth="625"
Foreground="Black" Background="{StaticResource HeadingBrush}" Text="Resolution"/>
<StackPanel Orientation="Horizontal" Margin="0, 0, 0, 12">
<TextBlock Style="{StaticResource Heading4Primary}" HorizontalAlignment="Right" VerticalAlignment="Center" Width="160" Margin="0, 0, 5, 0" Text="Display"/>
<ComboBox x:Name="_Displays" Width="220"/>
</StackPanel>
<StackPanel Orientation="Horizontal" Margin="0, 0, 0, 12">
<TextBlock Style="{StaticResource Heading4Primary}" HorizontalAlignment="Right" VerticalAlignment="Center" Width="160" Margin="0, 0, 5, 0" Text="Resolution"/>
<ComboBox x:Name="_WindowMode" Width="220">
<ComboBoxItem>Fullscreen Exclusive</ComboBoxItem>
<ComboBoxItem>Fullscreen Windowed</ComboBoxItem>
<ComboBoxItem Visibility="Collapsed">Windowed Maximized</ComboBoxItem>
<!-- MacOS -->
<ComboBoxItem>Windowed</ComboBoxItem>
</ComboBox>
<StackPanel x:Name="_DisplayResolutionStackPanel" Width="220" Margin="15, 0, 0, 0">
<ComboBox x:Name="_DisplayResolution"/>
</StackPanel>
</StackPanel>
<StackPanel Orientation="Horizontal" Margin="0, 0, 0, 12">
<TextBlock Style="{StaticResource Heading4Primary}" HorizontalAlignment="Right" VerticalAlignment="Center" Width="160" Margin="0, 0, 5, 0" Text="Upscaling"/>
<ComboBox x:Name="_ResolutionUpscaler" Width="220">
<ComboBoxItem>Off</ComboBoxItem>
<ComboBoxItem>DLSS</ComboBoxItem>
<ComboBoxItem>FSR 3</ComboBoxItem>
<ComboBoxItem>XeSS</ComboBoxItem>
</ComboBox>
<StackPanel x:Name="_UpscalerQualityStackPanel" Width="220" Margin="15, 0, 0, 0">
<ComboBox x:Name="_ResolutionUpscalerQuality" Width="220">
<ComboBoxItem>Ultra Quality</ComboBoxItem>
<ComboBoxItem>Quality</ComboBoxItem>
<ComboBoxItem>Balanced</ComboBoxItem>
<ComboBoxItem>Performance</ComboBoxItem>
<ComboBoxItem>Ultra Performance</ComboBoxItem>
</ComboBox>
</StackPanel>
</StackPanel>
<StackPanel Orientation="Horizontal" Margin="0, 0, 0, 12">
<TextBlock Style="{StaticResource Heading4Primary}" HorizontalAlignment="Right" VerticalAlignment="Center" Width="160" Margin="0, 0, 5, 0" Text="Frame Rate Limit"/>
<ComboBox x:Name="_VSync" Width="220">
<ComboBoxItem>Monitor vSync Off</ComboBoxItem>
<ComboBoxItem>Monitor vSync On</ComboBoxItem>
</ComboBox>
<ComboBox x:Name="_FrameRateLimit" Width="220" Margin="15, 0, 0, 0">
<ComboBoxItem>Unlimited</ComboBoxItem>
<ComboBoxItem>60 FPS</ComboBoxItem>
<ComboBoxItem>120 FPS</ComboBoxItem>
</ComboBox>
</StackPanel>
<StackPanel Orientation="Horizontal" Margin="0, 0, 0, 12" Visibility="Collapsed">
<TextBlock Style="{StaticResource Heading4Primary}" HorizontalAlignment="Right" VerticalAlignment="Center" Width="160" Margin="0, 0, 5, 0" Text="Motion Blur"/>
<ComboBox x:Name="_MotionBlur" Width="80">
<ComboBoxItem>Off</ComboBoxItem>
<ComboBoxItem>On</ComboBoxItem>
</ComboBox>
</StackPanel>
<StackPanel Orientation="Horizontal" Margin="0, 0, 0, 12">
<TextBlock Style="{StaticResource Heading4Primary}" HorizontalAlignment="Right" VerticalAlignment="Center" Width="160" Margin="0, 0, 5, 0" Text="Show FPS"/>
<ComboBox x:Name="_ShowFPS" Width="80">
<ComboBoxItem>Off</ComboBoxItem>
<ComboBoxItem>On</ComboBoxItem>
</ComboBox>
</StackPanel>
<StackPanel Margin="{StaticResource GroupMargin}"/>
</StackPanel>
<StackPanel x:Name="_QualityStackPanel">
<TextBlock Style="{StaticResource Heading3Primary}" HorizontalAlignment="Left" VerticalAlignment="Center" Padding="3" Margin="0, 0, 0, 12" MinWidth="625"
Foreground="Black" Background="{StaticResource HeadingBrush}" Text="Quality"/>
<StackPanel Orientation="Horizontal" Margin="0, 0, 0, 12" VerticalAlignment="Center">
<TextBlock Style="{StaticResource Heading4Primary}" HorizontalAlignment="Right" VerticalAlignment="Center" Width="160" Margin="0, 0, 5, 0" Text="Preset"/>
<ToggleButton x:Name="_QualityLow" Content="Low"/>
<ToggleButton x:Name="_QualityMedium" Content="Medium"/>
<ToggleButton x:Name="_QualityHigh" Content="High"/>
<ToggleButton x:Name="_QualityEpic" Content="Epic"/>
<ToggleButton x:Name="_QualityAuto" Content="Auto" Visibility="Collapsed"/>
</StackPanel>
<StackPanel Orientation="Horizontal" Margin="0, 0, 0, 12" VerticalAlignment="Center">
<TextBlock Style="{StaticResource Heading4Primary}" HorizontalAlignment="Right" VerticalAlignment="Center" Width="145" Margin="15, 0, 5, 0" Text="View Distance"/>
<ToggleButton x:Name="_ViewNear" Content="Near"/>
<ToggleButton x:Name="_ViewMedium" Content="Medium"/>
<ToggleButton x:Name="_ViewFar" Content="Far"/>
<ToggleButton x:Name="_ViewEpic" Content="Epic"/>
</StackPanel>
<StackPanel Orientation="Horizontal" Margin="0, 0, 0, 12" VerticalAlignment="Center">
<TextBlock Style="{StaticResource Heading4Primary}" HorizontalAlignment="Right" VerticalAlignment="Center" Width="145" Margin="15, 0, 5, 0" Text="Shadow Quality"/>
<ToggleButton x:Name="_ShadowsLow" Content="Low"/>
<ToggleButton x:Name="_ShadowsMedium" Content="Medium"/>
<ToggleButton x:Name="_ShadowsHigh" Content="High"/>
<ToggleButton x:Name="_ShadowsEpic" Content="Epic"/>
</StackPanel>
<StackPanel Orientation="Horizontal" Margin="0, 0, 0, 12" VerticalAlignment="Center">
<TextBlock Style="{StaticResource Heading4Primary}" HorizontalAlignment="Right" VerticalAlignment="Center" Width="145" Margin="15, 0, 5, 0" Text="Shadow Distance"/>
<ToggleButton x:Name="_ShadowDistanceNear" Content="Near"/>
<ToggleButton x:Name="_ShadowDistanceMedium" Content="Medium"/>
<ToggleButton x:Name="_ShadowDistanceFar" Content="Far"/>
<ToggleButton x:Name="_ShadowDistanceEpic" Content="Epic"/>
</StackPanel>
<StackPanel Orientation="Horizontal" Margin="0, 0, 0, 12" VerticalAlignment="Center">
<TextBlock Style="{StaticResource Heading4Primary}" HorizontalAlignment="Right" VerticalAlignment="Center" Width="145" Margin="15, 0, 5, 0" Text="Textures"/>
<ToggleButton x:Name="_TexturesLow" Content="Low"/>
<ToggleButton x:Name="_TexturesMedium" Content="Medium"/>
<ToggleButton x:Name="_TexturesHigh" Content="High"/>
<ToggleButton x:Name="_TexturesEpic" Content="Epic"/>
</StackPanel>
<StackPanel Orientation="Horizontal" Margin="0, 0, 0, 12" VerticalAlignment="Center">
<TextBlock Style="{StaticResource Heading4Primary}" HorizontalAlignment="Right" VerticalAlignment="Center" Width="145" Margin="15, 0, 5, 0" Text="Reflections"/>
<ToggleButton x:Name="_ReflectionsOff" Content="Off"/>
<ToggleButton x:Name="_ReflectionsMedium" Content="Medium"/>
<ToggleButton x:Name="_ReflectionsHigh" Content="High"/>
<ToggleButton x:Name="_ReflectionsEpic" Content="Epic"/>
</StackPanel>
<StackPanel Orientation="Horizontal" Margin="0, 0, 0, 12" VerticalAlignment="Center">
<TextBlock Style="{StaticResource Heading4Primary}" HorizontalAlignment="Right" VerticalAlignment="Center" Width="145" Margin="15, 0, 5, 0" Text="Detail"/>
<ToggleButton x:Name="_DetailLow" Content="Low"/>
<ToggleButton x:Name="_DetailMedium" Content="Medium"/>
<ToggleButton x:Name="_DetailHigh" Content="High"/>
<ToggleButton x:Name="_DetailEpic" Content="Epic"/>
</StackPanel>
<StackPanel Orientation="Horizontal" Margin="0, 0, 0, 12" VerticalAlignment="Center">
<TextBlock Style="{StaticResource Heading4Primary}" HorizontalAlignment="Right" VerticalAlignment="Center" Width="145" Margin="15, 0, 5, 0" Text="Post Processing"/>
<ToggleButton x:Name="_PostProcessingLow" Content="Low"/>
<ToggleButton x:Name="_PostProcessingMedium" Content="Medium"/>
<ToggleButton x:Name="_PostProcessingHigh" Content="High"/>
<ToggleButton x:Name="_PostProcessingEpic" Content="Epic"/>
</StackPanel>
<StackPanel Margin="{StaticResource GroupMargin}"/>
</StackPanel>
<StackPanel x:Name="_FieldOfViewStackPanel">
<TextBlock Style="{StaticResource Heading3Primary}" HorizontalAlignment="Left" VerticalAlignment="Center" Padding="3" Margin="0, 0, 0, 12" MinWidth="625"
Foreground="Black" Background="{StaticResource HeadingBrush}" Text="Field of View"/>
<StackPanel Orientation="Vertical" Margin="0, 0, 0, 12">
<TextBlock Style="{StaticResource Heading4Primary}" HorizontalAlignment="Left" Text="Character"/>
<StackPanel Orientation="Horizontal" Margin="0, 0, 10, 0">
<StackPanel.LayoutTransform>
<ScaleTransform ScaleX="1.5" ScaleY="1.5"/>
</StackPanel.LayoutTransform>
<Slider x:Name="_CharacterFieldOfView" Minimum="40" Maximum="120" IsSnapToTickEnabled="False" IsMoveToPointEnabled="True" TickFrequency="10" TickPlacement="BottomRight" Width="420" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="0, 0, 0, 0"/>
</StackPanel>
</StackPanel>
<StackPanel Orientation="Vertical" Margin="0, 0, 0, 12">
<TextBlock Style="{StaticResource Heading4Primary}" HorizontalAlignment="Left" Text="Starship Cockpit"/>
<StackPanel Orientation="Horizontal" Margin="0, 0, 10, 0">
<StackPanel.LayoutTransform>
<ScaleTransform ScaleX="1.5" ScaleY="1.5"/>
</StackPanel.LayoutTransform>
<Slider x:Name="_CockpitFieldOfView" Minimum="40" Maximum="120" IsSnapToTickEnabled="False" IsMoveToPointEnabled="True" TickFrequency="10" TickPlacement="BottomRight" Width="420" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="0, 0, 0, 0"/>
</StackPanel>
</StackPanel>
<StackPanel Orientation="Vertical" Margin="0, 0, 0, 12">
<TextBlock Style="{StaticResource Heading4Primary}" HorizontalAlignment="Left" Text="Starship External"/>
<StackPanel Orientation="Horizontal" Margin="0, 0, 10, 0">
<StackPanel.LayoutTransform>
<ScaleTransform ScaleX="1.5" ScaleY="1.5"/>
</StackPanel.LayoutTransform>
<Slider x:Name="_ExternalFieldOfView" Minimum="40" Maximum="120" IsSnapToTickEnabled="False" IsMoveToPointEnabled="True" TickFrequency="10" TickPlacement="BottomRight" Width="420" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="0, 0, 0, 0"/>
</StackPanel>
</StackPanel>
<StackPanel Orientation="Vertical" Margin="5, 0, 0, 12">
<Button x:Name="_ResetFieldOfViewButton" HorizontalAlignment="Left">
<TextBlock Style="{StaticResource Heading3Primary}">Reset</TextBlock>
</Button>
</StackPanel>
<StackPanel Margin="{StaticResource GroupMargin}"/>
</StackPanel>
<StackPanel x:Name="_ColorCorrectionStackPanel">
<TextBlock Style="{StaticResource Heading3Primary}" HorizontalAlignment="Left" VerticalAlignment="Center" Padding="3" Margin="0, 0, 0, 12" MinWidth="625"
Foreground="Black" Background="{StaticResource HeadingBrush}" Text="Color Correction"/>
<StackPanel Orientation="Vertical" Margin="0, 0, 0, 12">
<TextBlock Style="{StaticResource Heading4Primary}" HorizontalAlignment="Left" Text="Brightness"/>
<StackPanel Orientation="Horizontal" Margin="0, 0, 10, 0">
<StackPanel.LayoutTransform>
<ScaleTransform ScaleX="1.5" ScaleY="1.5"/>
</StackPanel.LayoutTransform>
<Slider x:Name="_BrightnessSlider" Minimum="-50" Maximum="50" IsSnapToTickEnabled="False" IsMoveToPointEnabled="True" TickFrequency="20" TickPlacement="BottomRight" Width="420" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="0, 0, 0, 0"/>
</StackPanel>
</StackPanel>
<StackPanel Orientation="Vertical" Margin="0, 0, 0, 12">
<TextBlock Style="{StaticResource Heading4Primary}" HorizontalAlignment="Left" Text="Contrast"/>
<StackPanel Orientation="Horizontal" Margin="0, 0, 10, 0">
<StackPanel.LayoutTransform>
<ScaleTransform ScaleX="1.5" ScaleY="1.5"/>
</StackPanel.LayoutTransform>
<Slider x:Name="_ContrastSlider" Minimum="-50" Maximum="50" IsSnapToTickEnabled="False" IsMoveToPointEnabled="True" TickFrequency="20" TickPlacement="BottomRight" Width="420" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="0, 0, 0, 0"/>
</StackPanel>
</StackPanel>
<StackPanel Orientation="Vertical" Margin="5, 0, 0, 12">
<Button x:Name="_ResetColorCorrectionButton" HorizontalAlignment="Left">
<TextBlock Style="{StaticResource Heading3Primary}">Reset</TextBlock>
</Button>
</StackPanel>
</StackPanel>
</StackPanel>
</ScrollViewer>
</TabItem>
<TabItem>
<TabItem.Header>
<TextBlock Style="{StaticResource Heading2Primary}" Text="UI" FontSize="20" Margin="5"/>
</TabItem.Header>
<ScrollViewer>
<StackPanel Orientation="Vertical" Margin="{StaticResource ScrollViewerMargin}">
<TextBlock Style="{StaticResource Heading3Primary}" HorizontalAlignment="Left" VerticalAlignment="Center" Padding="3" Margin="0, 0, 0, 12" MinWidth="625"
Foreground="Black" Background="{StaticResource HeadingBrush}" Text="Configuration"/>
<StackPanel Orientation="Horizontal" Margin="0, 0, 0, 12">
<CheckBox x:Name="_UIEnabled" Margin="0, 0, 5, 0" VerticalAlignment="Center">
<CheckBox.LayoutTransform>
<ScaleTransform ScaleX="1.5" ScaleY="1.5"/>
</CheckBox.LayoutTransform>
</CheckBox>
<TextBlock Style="{StaticResource Heading4Primary}" HorizontalAlignment="Left" VerticalAlignment="Center" Text="Show User Interface"/>
</StackPanel>
<StackPanel Orientation="Horizontal" Margin="0, 0, 0, 12">
<CheckBox x:Name="_GameMenuEnabled" Margin="0, 0, 5, 0" VerticalAlignment="Center">
<CheckBox.LayoutTransform>
<ScaleTransform ScaleX="1.5" ScaleY="1.5"/>
</CheckBox.LayoutTransform>
</CheckBox>
<TextBlock Style="{StaticResource Heading4Primary}" HorizontalAlignment="Left" VerticalAlignment="Center" Text="Show Game Menu"/>
</StackPanel>
<StackPanel Orientation="Horizontal" Margin="0, 0, 0, 12">
<CheckBox x:Name="_WindowDragEnabled" Margin="0, 0, 5, 0" VerticalAlignment="Center">
<CheckBox.LayoutTransform>
<ScaleTransform ScaleX="1.5" ScaleY="1.5"/>
</CheckBox.LayoutTransform>
</CheckBox>
<TextBlock Style="{StaticResource Heading4Primary}" HorizontalAlignment="Left" VerticalAlignment="Center" Text="Allow Window Dragging"/>
</StackPanel>
<StackPanel Orientation="Horizontal" Margin="0, 0, 0, 12">
<CheckBox x:Name="_TargetingEnabled" Margin="0, 0, 5, 0" VerticalAlignment="Center">
<CheckBox.LayoutTransform>
<ScaleTransform ScaleX="1.5" ScaleY="1.5"/>
</CheckBox.LayoutTransform>
</CheckBox>
<TextBlock Style="{StaticResource Heading4Primary}" HorizontalAlignment="Left" VerticalAlignment="Center" Text="Show Targeting"/>
</StackPanel>
<StackPanel Margin="{StaticResource GroupMargin}"/>
<TextBlock Style="{StaticResource Heading3Primary}" HorizontalAlignment="Left" VerticalAlignment="Center" Padding="3" Margin="0, 0, 0, 12" MinWidth="625"
Foreground="Black" Background="{StaticResource HeadingBrush}" Text="Scale"/>
<StackPanel Orientation="Horizontal" Margin="0, 0, 0, 12" VerticalAlignment="Center">
<TextBlock Style="{StaticResource Heading4Primary}" HorizontalAlignment="Right" VerticalAlignment="Center" Width="160" Margin="0, 0, 5, 0" Text="User Interface"/>
<ToggleButton x:Name="_UISmallest" Content="Smallest"/>
<ToggleButton x:Name="_UISmaller" Content="Smaller"/>
<ToggleButton x:Name="_UINormal" Content="Normal"/>
<ToggleButton x:Name="_UILarger" Content="Larger"/>
<ToggleButton x:Name="_UILargest" Content="Largest"/>
</StackPanel>
<StackPanel Margin="{StaticResource GroupMargin}"/>
<TextBlock Style="{StaticResource Heading3Primary}" HorizontalAlignment="Left" VerticalAlignment="Center" Padding="3" Margin="0, 0, 0, 12" MinWidth="625"
Foreground="Black" Background="{StaticResource HeadingBrush}" Text="Effects"/>
<StackPanel Orientation="Vertical" Margin="0, 0, 0, 12">
<TextBlock Style="{StaticResource Heading4Primary}" HorizontalAlignment="Left" Text="Blur Effects"/>
<StackPanel Orientation="Horizontal" Margin="0, 0, 10, 0">
<StackPanel.LayoutTransform>
<ScaleTransform ScaleX="1.5" ScaleY="1.5"/>
</StackPanel.LayoutTransform>
<CheckBox x:Name="_BlurEffectsEnabled" Margin="0, 0, 5, 0" VerticalAlignment="Center"/>
</StackPanel>
</StackPanel>
<StackPanel Orientation="Vertical" Margin="0, 0, 0, 12">
<TextBlock Style="{StaticResource Heading4Primary}" HorizontalAlignment="Left" Text="Top Blur"/>
<StackPanel Orientation="Horizontal" Margin="0, 0, 10, 0">
<StackPanel.LayoutTransform>
<ScaleTransform ScaleX="1.5" ScaleY="1.5"/>
</StackPanel.LayoutTransform>
<Slider x:Name="_TopBlurSlider" Minimum="0" Maximum="100" IsSnapToTickEnabled="False" IsMoveToPointEnabled="True" TickFrequency="20" TickPlacement="BottomRight" Width="420" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="0, 0, 0, 0"/>
</StackPanel>
</StackPanel>
<StackPanel Orientation="Vertical" Margin="0, 0, 0, 12">
<TextBlock Style="{StaticResource Heading4Primary}" HorizontalAlignment="Left" Text="Bottom Blur"/>
<StackPanel Orientation="Horizontal" Margin="0, 0, 10, 0">
<StackPanel.LayoutTransform>
<ScaleTransform ScaleX="1.5" ScaleY="1.5"/>
</StackPanel.LayoutTransform>
<Slider x:Name="_BottomBlurSlider" Minimum="0" Maximum="100" IsSnapToTickEnabled="False" IsMoveToPointEnabled="True" TickFrequency="20" TickPlacement="BottomRight" Width="420" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="0, 0, 0, 0"/>
</StackPanel>
</StackPanel>
</StackPanel>
</ScrollViewer>
</TabItem>
<TabItem>
<TabItem.Header>
<TextBlock Style="{StaticResource Heading2Primary}" Text="AUDIO" FontSize="20" Margin="5"/>
</TabItem.Header>
<ScrollViewer>
<StackPanel Orientation="Vertical" Margin="{StaticResource ScrollViewerMargin}">
<TextBlock Style="{StaticResource Heading3Primary}" HorizontalAlignment="Left" VerticalAlignment="Center" Padding="3" Margin="0, 0, 0, 12" MinWidth="625"
Foreground="Black" Background="{StaticResource HeadingBrush}" Text="Master"/>
<StackPanel Orientation="Vertical" Margin="0, 0, 0, 12">
<TextBlock Style="{StaticResource Heading4Primary}" HorizontalAlignment="Left" Text="Volume"/>
<StackPanel Orientation="Horizontal" Margin="0, 0, 10, 0">
<StackPanel.LayoutTransform>
<ScaleTransform ScaleX="1.5" ScaleY="1.5"/>
</StackPanel.LayoutTransform>
<CheckBox x:Name="_MasterVolumeEnabled" Margin="0, 0, 5, 0" VerticalAlignment="Center" Width="35"/>
<Slider x:Name="_MasterVolumeSlider" Minimum="0" Maximum="100" IsSnapToTickEnabled="False" IsMoveToPointEnabled="True" TickFrequency="25" TickPlacement="BottomRight" Width="380" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="0, 0, 0, 0"/>
</StackPanel>
</StackPanel>
<StackPanel Margin="{StaticResource GroupMargin}"/>
<TextBlock Style="{StaticResource Heading3Primary}" HorizontalAlignment="Left" VerticalAlignment="Center" Padding="3" Margin="0, 0, 0, 12" MinWidth="625"
Foreground="Black" Background="{StaticResource HeadingBrush}" Text="Mixer"/>
<StackPanel Orientation="Vertical" Margin="0, 0, 0, 12">
<TextBlock Style="{StaticResource Heading4Primary}" HorizontalAlignment="Left" Text="Music"/>
<StackPanel Orientation="Horizontal" Margin="0, 0, 10, 0">
<StackPanel.LayoutTransform>
<ScaleTransform ScaleX="1.5" ScaleY="1.5"/>
</StackPanel.LayoutTransform>
<CheckBox x:Name="_MusicVolumeEnabled" Margin="0, 0, 5, 0" VerticalAlignment="Center" Width="35"/>
<Slider x:Name="_MusicVolumeSlider" Minimum="0" Maximum="100" IsSnapToTickEnabled="False" IsMoveToPointEnabled="True" TickFrequency="25" TickPlacement="BottomRight" Width="380" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="0, 0, 0, 0"/>
</StackPanel>
</StackPanel>
<StackPanel Orientation="Vertical" Margin="0, 0, 0, 12">
<TextBlock Style="{StaticResource Heading4Primary}" HorizontalAlignment="Left" Text="Effects"/>
<StackPanel Orientation="Horizontal" Margin="0, 0, 10, 0">
<StackPanel.LayoutTransform>
<ScaleTransform ScaleX="1.5" ScaleY="1.5"/>
</StackPanel.LayoutTransform>
<CheckBox x:Name="_EffectsVolumeEnabled" Margin="0, 0, 5, 0" VerticalAlignment="Center" Width="35"/>
<Slider x:Name="_EffectsVolumeSlider" Minimum="0" Maximum="100" IsSnapToTickEnabled="False" IsMoveToPointEnabled="True" TickFrequency="25" TickPlacement="BottomRight" Width="380" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="0, 0, 0, 0"/>
</StackPanel>
</StackPanel>
<StackPanel Orientation="Vertical" Margin="0, 0, 0, 12">
<TextBlock Style="{StaticResource Heading4Primary}" HorizontalAlignment="Left" Text="Voice"/>
<StackPanel Orientation="Horizontal" Margin="0, 0, 10, 0">
<StackPanel.LayoutTransform>
<ScaleTransform ScaleX="1.5" ScaleY="1.5"/>
</StackPanel.LayoutTransform>
<CheckBox x:Name="_VoiceVolumeEnabled" Margin="0, 0, 5, 0" VerticalAlignment="Center" Width="35"/>
<Slider x:Name="_VoiceVolumeSlider" Minimum="0" Maximum="100" IsSnapToTickEnabled="False" IsMoveToPointEnabled="True" TickFrequency="25" TickPlacement="BottomRight" Width="380" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="0, 0, 0, 0"/>
</StackPanel>
</StackPanel>
<StackPanel Orientation="Vertical" Margin="0, 0, 0, 12">
<TextBlock Style="{StaticResource Heading4Primary}" HorizontalAlignment="Left" Text="User Interface"/>
<StackPanel Orientation="Horizontal" Margin="0, 0, 10, 0">
<StackPanel.LayoutTransform>
<ScaleTransform ScaleX="1.5" ScaleY="1.5"/>
</StackPanel.LayoutTransform>
<CheckBox x:Name="_UIVolumeEnabled" Margin="0, 0, 5, 0" VerticalAlignment="Center" Width="35"/>
<Slider x:Name="_UIVolumeSlider" Minimum="0" Maximum="100" IsSnapToTickEnabled="False" IsMoveToPointEnabled="True" TickFrequency="25" TickPlacement="BottomRight" Width="380" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="0, 0, 0, 0"/>
</StackPanel>
</StackPanel>
<StackPanel Orientation="Vertical" Margin="0, 0, 0, 12">
<TextBlock Style="{StaticResource Heading4Primary}" HorizontalAlignment="Left" Text="Ambient"/>
<StackPanel Orientation="Horizontal" Margin="0, 0, 10, 0">
<StackPanel.LayoutTransform>
<ScaleTransform ScaleX="1.5" ScaleY="1.5"/>
</StackPanel.LayoutTransform>
<CheckBox x:Name="_AmbientVolumeEnabled" Margin="0, 0, 5, 0" VerticalAlignment="Center" Width="35"/>
<Slider x:Name="_AmbientVolumeSlider" Minimum="0" Maximum="100" IsSnapToTickEnabled="False" IsMoveToPointEnabled="True" TickFrequency="25" TickPlacement="BottomRight" Width="380" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="0, 0, 0, 0"/>
</StackPanel>
</StackPanel>
</StackPanel>
</ScrollViewer>
</TabItem>
<TabItem x:Name="_NetworkTab">
<TabItem.Header>
<TextBlock Style="{StaticResource Heading2Primary}" Text="NETWORK" FontSize="20" Margin="5"/>
</TabItem.Header>
<ScrollViewer>
<StackPanel Orientation="Vertical" Margin="{StaticResource ScrollViewerMargin}">
<TextBlock Style="{StaticResource Heading3Primary}" HorizontalAlignment="Left" VerticalAlignment="Center" Padding="3" Margin="0, 0, 0, 12" MinWidth="625"
Foreground="Black" Background="{StaticResource HeadingBrush}" Text="Environment"/>
<StackPanel Orientation="Horizontal" Margin="0, 0, 0, 12">
<TextBlock Style="{StaticResource Heading4Primary}" HorizontalAlignment="Right" VerticalAlignment="Center" Width="160" Margin="0, 0, 5, 0" Text="Conquest Server"/>
<ComboBox x:Name="_Environment">
<ComboBoxItem>Developer</ComboBoxItem>
<ComboBoxItem>Preview</ComboBoxItem>
<ComboBoxItem>Release</ComboBoxItem>
</ComboBox>
</StackPanel>
<StackPanel Margin="{StaticResource GroupMargin}"/>
<TextBlock Style="{StaticResource Heading3Primary}" HorizontalAlignment="Left" VerticalAlignment="Center" Padding="3" Margin="0, 0, 0, 12" MinWidth="625"
Foreground="Black" Background="{StaticResource HeadingBrush}" Text="Update Rate"/>
<StackPanel>
<StackPanel Orientation="Vertical" Margin="0, 0, 0, 12">
<TextBlock x:Name="_ClientToServerRateTextBlock" Style="{StaticResource Heading4Primary}" HorizontalAlignment="Left" Margin="0, 0, 0, 2" Text="Client"/>
<StackPanel Orientation="Horizontal" Margin="0, 0, 10, 0">
<StackPanel.LayoutTransform>
<ScaleTransform ScaleX="1.5" ScaleY="1.5"/>
</StackPanel.LayoutTransform>
<Slider x:Name="_ClientToServerSlider" Minimum="0.0" Maximum="1.0" IsSnapToTickEnabled="true" IsMoveToPointEnabled="True" TickFrequency="0.05" TickPlacement="BottomRight" Width="420" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="0, 0, 0, 0"/>
</StackPanel>
</StackPanel>
<StackPanel Orientation="Vertical" Margin="0, 0, 0, 12">
<TextBlock x:Name="_ServerToClientRateTextBlock" Style="{StaticResource Heading4Primary}" HorizontalAlignment="Left" Margin="0, 0, 0, 2" Text="Server"/>
<StackPanel Orientation="Horizontal" Margin="0, 0, 10, 0">
<StackPanel.LayoutTransform>
<ScaleTransform ScaleX="1.5" ScaleY="1.5"/>
</StackPanel.LayoutTransform>
<Slider x:Name="_ServerToClientSlider" Minimum="0.0" Maximum="1.0" IsSnapToTickEnabled="true" IsMoveToPointEnabled="True" TickFrequency="0.05" TickPlacement="BottomRight" Width="420" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="0, 0, 0, 0"/>
</StackPanel>
</StackPanel>
</StackPanel>
</StackPanel>
</ScrollViewer>
</TabItem>
<TabItem x:Name="_CorsairTab">
<TabItem.Header>
<TextBlock Style="{StaticResource Heading2Primary}" Text="CORSAIR" FontSize="20" Margin="5"/>
</TabItem.Header>
<ScrollViewer>
<StackPanel Orientation="Vertical" Margin="{StaticResource ScrollViewerMargin}">
<TextBlock Style="{StaticResource Heading3Primary}" HorizontalAlignment="Left" VerticalAlignment="Center" Padding="3" Margin="0, 0, 0, 12" MinWidth="625"
Foreground="Black" Background="{StaticResource HeadingBrush}" Text="Corsair Lighting"/>
<StackPanel Orientation="Horizontal" Margin="0, 0, 0, 12">
<CheckBox x:Name="_RGBLightingEnabled" Margin="0, 0, 5, 0" VerticalAlignment="Center">
<CheckBox.LayoutTransform>
<ScaleTransform ScaleX="1.5" ScaleY="1.5"/>
</CheckBox.LayoutTransform>
</CheckBox>
<TextBlock Style="{StaticResource Heading4Primary}" HorizontalAlignment="Left" VerticalAlignment="Center" Text="RGB Lighting Enabled"/>
</StackPanel>
<TextBlock x:Name="_CorsairNotFoundTextBlock" Margin="0, 16, 0, 0" Style="{StaticResource Heading3Primary}"
Visibility="Collapsed" HorizontalAlignment="Left" Width="625" TextWrapping="Wrap">
Corsair devices could not be detected. Please ensure that iCUE is running and that both iCUE and Game SDK control is enabled.
</TextBlock>
<StackPanel x:Name="_RGBStackPanel">
<StackPanel Margin="{StaticResource GroupMargin}"/>
<TextBlock Style="{StaticResource Heading3Primary}" HorizontalAlignment="Left" VerticalAlignment="Center" Padding="3" Margin="0, 0, 0, 12" MinWidth="625"
Foreground="Black" Background="{StaticResource HeadingBrush}" Text="Keyboard"/>
<StackPanel Orientation="Horizontal" Margin="0, 0, 0, 12">
<CheckBox x:Name="_TutorialKeysEnabled" Margin="0, 0, 5, 0" VerticalAlignment="Center">
<CheckBox.LayoutTransform>
<ScaleTransform ScaleX="1.5" ScaleY="1.5"/>
</CheckBox.LayoutTransform>
</CheckBox>
<TextBlock Style="{StaticResource Heading4Primary}" HorizontalAlignment="Left" VerticalAlignment="Center" Text="Show Tutorial Keys"/>
</StackPanel>
<StackPanel Orientation="Horizontal" Margin="0, 0, 0, 12">
<CheckBox x:Name="_InputKeysEnabled" Margin="0, 0, 5, 0" VerticalAlignment="Center">
<CheckBox.LayoutTransform>
<ScaleTransform ScaleX="1.5" ScaleY="1.5"/>
</CheckBox.LayoutTransform>
</CheckBox>
<TextBlock Style="{StaticResource Heading4Primary}" HorizontalAlignment="Left" VerticalAlignment="Center" Text="Show Input Keys"/>
</StackPanel>
<StackPanel Margin="{StaticResource GroupMargin}"/>
<TextBlock Style="{StaticResource Heading3Primary}" HorizontalAlignment="Left" VerticalAlignment="Center" Padding="3" Margin="0, 0, 0, 12" MinWidth="625"
Foreground="Black" Background="{StaticResource HeadingBrush}" Text="Assignment"/>
<StackPanel x:Name="_CorsairStackPanel" Orientation="Vertical" Margin="0, 0, 0, 0"/>
<StackPanel Margin="{StaticResource GroupMargin}"/>
<TextBlock Style="{StaticResource Heading3Primary}" HorizontalAlignment="Left" VerticalAlignment="Center" Padding="3" Margin="0, 0, 0, 12" MinWidth="625"
Foreground="Black" Background="{StaticResource HeadingBrush}" Text="Color Correction"/>
<StackPanel Orientation="Vertical" Margin="0, 0, 0, 12">
<TextBlock Style="{StaticResource Heading4Primary}" HorizontalAlignment="Left" Margin="0, 0, 0, 2" Text="Hue"/>
<StackPanel Orientation="Horizontal" Margin="0, 0, 10, 0">
<StackPanel.LayoutTransform>
<ScaleTransform ScaleX="1.5" ScaleY="1.5"/>
</StackPanel.LayoutTransform>
<Slider x:Name="_RGBHueSlider" Minimum="-180" Maximum="180" IsSnapToTickEnabled="false" IsMoveToPointEnabled="True" TickFrequency="20" TickPlacement="BottomRight" Width="420" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="0, 0, 0, 0"/>
</StackPanel>
</StackPanel>
<StackPanel Orientation="Vertical" Margin="0, 0, 0, 12">
<TextBlock Style="{StaticResource Heading4Primary}" HorizontalAlignment="Left" Margin="0, 0, 0, 2" Text="Saturation"/>
<StackPanel Orientation="Horizontal" Margin="0, 0, 10, 0">
<StackPanel.LayoutTransform>
<ScaleTransform ScaleX="1.5" ScaleY="1.5"/>
</StackPanel.LayoutTransform>
<Slider x:Name="_RGBSaturationSlider" Minimum="-100" Maximum="100" IsSnapToTickEnabled="false" IsMoveToPointEnabled="True" TickFrequency="20" TickPlacement="BottomRight" Width="420" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="0, 0, 0, 0"/>
</StackPanel>
</StackPanel>
<StackPanel Orientation="Vertical" Margin="0, 0, 0, 12">
<TextBlock Style="{StaticResource Heading4Primary}" HorizontalAlignment="Left" Margin="0, 0, 0, 2" Text="Brightness"/>
<StackPanel Orientation="Horizontal" Margin="0, 0, 10, 0">
<StackPanel.LayoutTransform>
<ScaleTransform ScaleX="1.5" ScaleY="1.5"/>
</StackPanel.LayoutTransform>
<Slider x:Name="_RGBBrightnessSlider" Minimum="-100" Maximum="100" IsSnapToTickEnabled="false" IsMoveToPointEnabled="True" TickFrequency="20" TickPlacement="BottomRight" Width="420" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="0, 0, 0, 0"/>
</StackPanel>
</StackPanel>
<StackPanel Orientation="Vertical" Margin="5, 0, 0, 12">
<Button x:Name="_ResetCorsairColorCorrectionButton" HorizontalAlignment="Left">
<TextBlock Style="{StaticResource Heading3Primary}">Reset</TextBlock>
</Button>
</StackPanel>
</StackPanel>
</StackPanel>
</ScrollViewer>
</TabItem>
<TabItem x:Name="AboutTab">
<TabItem.Header>
<TextBlock Style="{StaticResource Heading2Primary}" Text="ABOUT" FontSize="20" Margin="5"/>
</TabItem.Header>
<StackPanel Orientation="Vertical" Margin="{StaticResource ScrollViewerMargin}">
<TextBlock Style="{StaticResource Heading3Primary}" HorizontalAlignment="Left" VerticalAlignment="Center" Padding="3" Margin="0, 0, 0, 12" MinWidth="625"
Foreground="Black" Background="{StaticResource HeadingBrush}" Text="Version"/>
<TextBlock x:Name="_VersionTextBlock" Margin="0, 0, 0, 10" Style="{StaticResource Heading3Primary}"/>
<StackPanel Margin="{StaticResource GroupMargin}"/>
<TextBlock Style="{StaticResource Heading3Primary}" HorizontalAlignment="Left" VerticalAlignment="Center" Padding="3" Margin="0, 0, 0, 12" MinWidth="625"
Foreground="Black" Background="{StaticResource HeadingBrush}" Text="AI Notice"/>
<TextBlock Style="{StaticResource Heading3Primary}" HorizontalAlignment="Left" Width="625" TextWrapping="Wrap">
<Run>Stellar Conquest</Run>
<Run FontWeight="Bold">does not</Run>
<Run>use AI for art and music content. If enabled, generative AI is used to create NPC memories and dialogue.</Run>
</TextBlock>
<StackPanel Margin="{StaticResource GroupMargin}"/>
<TextBlock Style="{StaticResource Heading3Primary}" HorizontalAlignment="Left" VerticalAlignment="Center" Padding="3" Margin="0, 0, 0, 12" MinWidth="625"
Foreground="Black" Background="{StaticResource HeadingBrush}" Text="Legal Notice"/>
<TextBlock Style="{StaticResource Heading3Primary}">
<Run FontWeight="Bold">Stellar Conquest</Run>
<Run>© 2026 Stellar Studio</Run></TextBlock>
<TextBlock Margin="0, 16, 0, 0" Style="{StaticResource Heading3Primary}" HorizontalAlignment="Left" Width="625" TextWrapping="Wrap">
<Run>All trademarked names and copyrights are protected by law. The Stellar Conquest®</Run>
<Run>name and the Stellar Conquest Logo are registered trademarks and/or service brand names, slogans, logos and emblems of Shaun C Tonstad. All rights reserved.</Run></TextBlock>
<TextBlock Margin="0, 16, 0, 0">
<Hyperlink x:Name="_HyperLinkButton" FontSize="{StaticResource Heading3FontSize}">Third-Party Notices</Hyperlink>
</TextBlock>
</StackPanel>
</TabItem>
</TabControl>
</local:BorderControlTitle>
</Grid>
</UserControl> SettingsControl.xaml.cs (69,999 bytes)
using Noesis;
using StellarConquest.Model.Core;
using StellarConquest.Model.Platform;
using StellarConquest.RGB;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using UnityEngine;
using GUI = Noesis.GUI;
using NoesisEventArgs = Noesis.EventArgs;
namespace StellarConquest.Presentation.Unity.UI
{
[AssetDependency]
public partial class SettingsControl : OverlayControl
{
private FrameworkElement _Root;
private BorderControlTitle _BorderControl;
private TabControl _TabControl;
// gameplay
private CheckBox _WarnSafeParkingEnabled;
private CheckBox _WarnEvilEnabled;
private CheckBox _GameMenuEnabled;
private CheckBox _TargetingEnabled;
private CheckBox _WindowDragEnabled;
private CheckBox _UIEnabled;
private ComboBox _TemperatureUnits;
// control
private StackPanel _DevicesStackPanel;
private CheckBox _MouseConfined;
private CheckBox _GamepadEnabled;
private TextBlock _CockpitHeadingTextBlock;
private CheckBox _CharacterInvertUpEnabled;
private Slider _CharacterLookSensitivity;
private CheckBox _ShipInvertUpEnabled;
private ComboBox _CharacterControl;
private ComboBox _InteriorCamera;
// display
private bool _DisplayInitialized = false;
private StackPanel _ResolutionStackPanel;
private ComboBox _WindowMode;
private StackPanel _DisplayResolutionStackPanel;
private ComboBox _Displays;
private ComboBox _DisplayResolution;
private ComboBox _ResolutionUpscaler;
private ComboBox _ResolutionUpscalerQuality;
private ComboBox _FrameRateLimit;
private ComboBox _VSync;
private ComboBox _MotionBlur;
private ComboBox _ShowFPS;
private StackPanel _QualityStackPanel;
private ToggleButton _QualityLow;
private ToggleButton _QualityMedium;
private ToggleButton _QualityHigh;
private ToggleButton _QualityEpic;
private ToggleButton _QualityAuto;
private ToggleButton _ViewNear;
private ToggleButton _ViewMedium;
private ToggleButton _ViewFar;
private ToggleButton _ViewEpic;
private ToggleButton _ShadowsLow;
private ToggleButton _ShadowsMedium;
private ToggleButton _ShadowsHigh;
private ToggleButton _ShadowsEpic;
private ToggleButton _ShadowDistanceNear;
private ToggleButton _ShadowDistanceMedium;
private ToggleButton _ShadowDistanceFar;
private ToggleButton _ShadowDistanceEpic;
private ToggleButton _TexturesLow;
private ToggleButton _TexturesMedium;
private ToggleButton _TexturesHigh;
private ToggleButton _TexturesEpic;
private ToggleButton _ReflectionsOff;
private ToggleButton _ReflectionsMedium;
private ToggleButton _ReflectionsHigh;
private ToggleButton _ReflectionsEpic;
private ToggleButton _PostProcessingLow;
private ToggleButton _PostProcessingMedium;
private ToggleButton _PostProcessingHigh;
private ToggleButton _PostProcessingEpic;
private ToggleButton _DetailLow;
private ToggleButton _DetailMedium;
private ToggleButton _DetailHigh;
private ToggleButton _DetailEpic;
private StackPanel _FieldOfViewStackPanel;
private Slider _CharacterFieldOfView;
private Slider _CockpitFieldOfView;
private Slider _ExternalFieldOfView;
private Button _ResetFieldOfViewButton;
private Slider _BrightnessSlider;
private Slider _ContrastSlider;
private Button _ResetColorCorrectionButton;
// ui
private ToggleButton _UISmallest;
private ToggleButton _UISmaller;
private ToggleButton _UINormal;
private ToggleButton _UILarger;
private ToggleButton _UILargest;
private CheckBox _BlurEffectsEnabled;
private Slider _TopBlurSlider;
private Slider _BottomBlurSlider;
private CheckBox _DesignerHelpUIEnabled;
private CheckBox _GameHelpUIEnabled;
// sound
private CheckBox _MasterVolumeEnabled;
private Slider _MasterVolumeSlider;
private CheckBox _MusicVolumeEnabled;
private Slider _MusicVolumeSlider;
private CheckBox _EffectsVolumeEnabled;
private Slider _EffectsVolumeSlider;
private CheckBox _VoiceVolumeEnabled;
private Slider _VoiceVolumeSlider;
private CheckBox _UIVolumeEnabled;
private Slider _UIVolumeSlider;
private CheckBox _AmbientVolumeEnabled;
private Slider _AmbientVolumeSlider;
// network
private TabItem _NetworkTab;
private ComboBox _Environment;
private Slider _ClientToServerSlider;
private Slider _ServerToClientSlider;
private TextBlock _ClientToServerRateTextBlock;
private TextBlock _ServerToClientRateTextBlock;
// generative AI
private StackPanel _GenerativeAIStackPanel;
private CheckBox _GenerativeTextDialogue;
private CheckBox _GenerativeAudioDialogue;
// corsair
private TabItem _CorsairTab;
private StackPanel _RGBStackPanel;
private CheckBox _RGBLightingEnabled;
private CheckBox _TutorialKeysEnabled;
private CheckBox _InputKeysEnabled;
private Slider _RGBHueSlider;
private Slider _RGBSaturationSlider;
private Slider _RGBBrightnessSlider;
private Button _ResetCorsairColorCorrectionButton;
private StackPanel _CorsairStackPanel;
private TextBlock _CorsairNotFoundTextBlock;
// about
private Hyperlink _HyperlinkButton;
private TextBlock _VersionTextBlock;
private bool _ApplyEnabled = true;
private List<Resolution> _SupportedResolutions;
public SettingsControl()
{
Name = nameof(SettingsControl);
IsBlurEnabled = false;
IsDragAllowed = true;
Initialized += OnInitialized;
InitializeComponent();
}
protected override void InitializeComponent()
{
base.InitializeComponent();
GUI.LoadComponent(this, "Assets/User Interface/Screens/Game/Overlay/Settings/SettingsControl.xaml");
_Root = Content as FrameworkElement;
_TabControl = _Root.FindName("_TabControl") as TabControl;
_BorderControl = _Root.FindName("_BorderControl") as BorderControlTitle;
// bind controls: gameplay
_WarnSafeParkingEnabled = _Root.FindName("_WarnSafeParkingEnabled") as CheckBox;
_WarnEvilEnabled = _Root.FindName("_WarnEvilEnabled") as CheckBox;
_GameMenuEnabled = _Root.FindName("_GameMenuEnabled") as CheckBox;
_TargetingEnabled = _Root.FindName("_TargetingEnabled") as CheckBox;
_WindowDragEnabled = _Root.FindName("_WindowDragEnabled") as CheckBox;
_UIEnabled = _Root.FindName("_UIEnabled") as CheckBox;
_TemperatureUnits = _Root.FindName(nameof(_TemperatureUnits)) as ComboBox;
// bind controls: input
_DevicesStackPanel = _Root.FindName(nameof(_DevicesStackPanel)) as StackPanel;
_MouseConfined = _Root.FindName("_MouseConfined") as CheckBox;
_GamepadEnabled = _Root.FindName("_GamepadEnabled") as CheckBox;
_CockpitHeadingTextBlock = _Root.FindName("_CockpitHeadingTextBlock") as TextBlock;
_CharacterInvertUpEnabled = _Root.FindName("_CharacterInvertUpEnabled") as CheckBox;
_ShipInvertUpEnabled = _Root.FindName("_ShipInvertUpEnabled") as CheckBox;
_CharacterControl = _Root.FindName("_CharacterControl") as ComboBox;
_InteriorCamera = _Root.FindName("_InteriorCamera") as ComboBox;
_CharacterLookSensitivity = _Root.FindName("_CharacterLookSensitivity") as Slider;
// bind controls: video
_ResolutionStackPanel = _Root.FindName(nameof(_ResolutionStackPanel)) as StackPanel;
_WindowMode = _Root.FindName("_WindowMode") as ComboBox;
_DisplayResolutionStackPanel = _Root.FindName("_DisplayResolutionStackPanel") as StackPanel;
_Displays = _Root.FindName("_Displays") as ComboBox;
_DisplayResolution = _Root.FindName("_DisplayResolution") as ComboBox;
_ResolutionUpscaler = _Root.FindName(nameof(_ResolutionUpscaler)) as ComboBox;
_ResolutionUpscalerQuality = _Root.FindName(nameof(_ResolutionUpscalerQuality)) as ComboBox;
_FrameRateLimit = _Root.FindName("_FrameRateLimit") as ComboBox;
_VSync = _Root.FindName("_VSync") as ComboBox;
_MotionBlur = _Root.FindName("_MotionBlur") as ComboBox;
_ShowFPS = _Root.FindName("_ShowFPS") as ComboBox;
_QualityStackPanel = _Root.FindName(nameof(_QualityStackPanel)) as StackPanel;
_QualityLow = _Root.FindName("_QualityLow") as ToggleButton;
_QualityMedium = _Root.FindName("_QualityMedium") as ToggleButton;
_QualityHigh = _Root.FindName("_QualityHigh") as ToggleButton;
_QualityEpic = _Root.FindName("_QualityEpic") as ToggleButton;
_QualityAuto = _Root.FindName("_QualityAuto") as ToggleButton;
_ViewNear = _Root.FindName("_ViewNear") as ToggleButton;
_ViewMedium = _Root.FindName("_ViewMedium") as ToggleButton;
_ViewFar = _Root.FindName("_ViewFar") as ToggleButton;
_ViewEpic = _Root.FindName("_ViewEpic") as ToggleButton;
_ShadowsLow = _Root.FindName("_ShadowsLow") as ToggleButton;
_ShadowsMedium = _Root.FindName("_ShadowsMedium") as ToggleButton;
_ShadowsHigh = _Root.FindName("_ShadowsHigh") as ToggleButton;
_ShadowsEpic = _Root.FindName("_ShadowsEpic") as ToggleButton;
_ShadowDistanceNear = _Root.FindName("_ShadowDistanceNear") as ToggleButton;
_ShadowDistanceMedium = _Root.FindName("_ShadowDistanceMedium") as ToggleButton;
_ShadowDistanceFar = _Root.FindName("_ShadowDistanceFar") as ToggleButton;
_ShadowDistanceEpic = _Root.FindName("_ShadowDistanceEpic") as ToggleButton;
_TexturesLow = _Root.FindName("_TexturesLow") as ToggleButton;
_TexturesMedium = _Root.FindName("_TexturesMedium") as ToggleButton;
_TexturesHigh = _Root.FindName("_TexturesHigh") as ToggleButton;
_TexturesEpic = _Root.FindName("_TexturesEpic") as ToggleButton;
_ReflectionsOff = _Root.FindName("_ReflectionsOff") as ToggleButton;
_ReflectionsMedium = _Root.FindName("_ReflectionsMedium") as ToggleButton;
_ReflectionsHigh = _Root.FindName("_ReflectionsHigh") as ToggleButton;
_ReflectionsEpic = _Root.FindName("_ReflectionsEpic") as ToggleButton;
_PostProcessingLow = _Root.FindName("_PostProcessingLow") as ToggleButton;
_PostProcessingMedium = _Root.FindName("_PostProcessingMedium") as ToggleButton;
_PostProcessingHigh = _Root.FindName("_PostProcessingHigh") as ToggleButton;
_PostProcessingEpic = _Root.FindName("_PostProcessingEpic") as ToggleButton;
_DetailLow = _Root.FindName("_DetailLow") as ToggleButton;
_DetailMedium = _Root.FindName("_DetailMedium") as ToggleButton;
_DetailHigh = _Root.FindName("_DetailHigh") as ToggleButton;
_DetailEpic = _Root.FindName("_DetailEpic") as ToggleButton;
_FieldOfViewStackPanel = _Root.FindName(nameof(_FieldOfViewStackPanel)) as StackPanel;
_CharacterFieldOfView = _Root.FindName("_CharacterFieldOfView") as Slider;
_CockpitFieldOfView = _Root.FindName("_CockpitFieldOfView") as Slider;
_ExternalFieldOfView = _Root.FindName("_ExternalFieldOfView") as Slider;
_ResetFieldOfViewButton = _Root.FindName("_ResetFieldOfViewButton") as Button;
_BrightnessSlider = _Root.FindName("_BrightnessSlider") as Slider;
_ContrastSlider = _Root.FindName("_ContrastSlider") as Slider;
_ResetColorCorrectionButton = _Root.FindName("_ResetColorCorrectionButton") as Button;
// UI
_UISmallest = _Root.FindName("_UISmallest") as ToggleButton;
_UISmaller = _Root.FindName("_UISmaller") as ToggleButton;
_UINormal = _Root.FindName("_UINormal") as ToggleButton;
_UILarger = _Root.FindName("_UILarger") as ToggleButton;
_UILargest = _Root.FindName("_UILargest") as ToggleButton;
_BlurEffectsEnabled = _Root.FindName("_BlurEffectsEnabled") as CheckBox;
_TopBlurSlider = _Root.FindName("_TopBlurSlider") as Slider;
_BottomBlurSlider = _Root.FindName("_BottomBlurSlider") as Slider;
_DesignerHelpUIEnabled = _Root.FindName("_DesignerHelpUIEnabled") as CheckBox;
_GameHelpUIEnabled = _Root.FindName("_GameHelpUIEnabled") as CheckBox;
// bind controls: audio
_MasterVolumeEnabled = _Root.FindName("_MasterVolumeEnabled") as CheckBox;
_MasterVolumeSlider = _Root.FindName("_MasterVolumeSlider") as Slider;
_MusicVolumeEnabled = _Root.FindName("_MusicVolumeEnabled") as CheckBox;
_MusicVolumeSlider = _Root.FindName("_MusicVolumeSlider") as Slider;
_EffectsVolumeEnabled = _Root.FindName("_EffectsVolumeEnabled") as CheckBox;
_EffectsVolumeSlider = _Root.FindName("_EffectsVolumeSlider") as Slider;
_VoiceVolumeEnabled = _Root.FindName("_VoiceVolumeEnabled") as CheckBox;
_VoiceVolumeSlider = _Root.FindName("_VoiceVolumeSlider") as Slider;
_UIVolumeEnabled = _Root.FindName("_UIVolumeEnabled") as CheckBox;
_UIVolumeSlider = _Root.FindName("_UIVolumeSlider") as Slider;
_AmbientVolumeEnabled = _Root.FindName("_AmbientVolumeEnabled") as CheckBox;
_AmbientVolumeSlider = _Root.FindName("_AmbientVolumeSlider") as Slider;
// network
_NetworkTab = _Root.FindName("_NetworkTab") as TabItem;
_Environment = _Root.FindName("_Environment") as ComboBox;
_ClientToServerSlider = _Root.FindName("_ClientToServerSlider") as Slider;
_ServerToClientSlider = _Root.FindName("_ServerToClientSlider") as Slider;
_ClientToServerRateTextBlock = _Root.FindName(nameof(_ClientToServerRateTextBlock)) as TextBlock;
_ServerToClientRateTextBlock = _Root.FindName(nameof(_ServerToClientRateTextBlock)) as TextBlock;
// generative AI
_GenerativeAIStackPanel = _Root.FindName(nameof(_GenerativeAIStackPanel)) as StackPanel;
_GenerativeTextDialogue = _Root.FindName(nameof(_GenerativeTextDialogue)) as CheckBox;
_GenerativeAudioDialogue = _Root.FindName(nameof(_GenerativeAudioDialogue)) as CheckBox;
// corsair
_CorsairTab = _Root.FindName(nameof(_CorsairTab)) as TabItem;
_RGBStackPanel = _Root.FindName(nameof(_RGBStackPanel)) as StackPanel;
_RGBLightingEnabled = _Root.FindName(nameof(_RGBLightingEnabled)) as CheckBox;
_TutorialKeysEnabled = _Root.FindName("_TutorialKeysEnabled") as CheckBox;
_InputKeysEnabled = _Root.FindName("_InputKeysEnabled") as CheckBox;
_RGBHueSlider = _Root.FindName("_RGBHueSlider") as Slider;
_RGBSaturationSlider = _Root.FindName("_RGBSaturationSlider") as Slider;
_RGBBrightnessSlider = _Root.FindName("_RGBBrightnessSlider") as Slider;
_ResetCorsairColorCorrectionButton = _Root.FindName("_ResetCorsairColorCorrectionButton") as Button;
_CorsairStackPanel = _Root.FindName("_CorsairStackPanel") as StackPanel;
_CorsairNotFoundTextBlock = _Root.FindName("_CorsairNotFoundTextBlock") as TextBlock;
// about
_HyperlinkButton = _Root.FindName("_HyperLinkButton") as Hyperlink;
_VersionTextBlock = _Root.FindName("_VersionTextBlock") as TextBlock;
}
private void WireEvents(Action<int> action, int defaultIndex, params ToggleButton[] buttons)
{
buttons[defaultIndex].IsChecked = true;
foreach (ToggleButton button in buttons)
{
button.Checked += (sender, e) =>
{
int index = 0;
for (int i = 0; i < buttons.Length; i++)
{
if (buttons[i].Equals(sender))
index = i;
else if (!buttons[i].Equals(sender))
buttons[i].IsChecked = false;
}
action?.Invoke(index);
};
}
}
protected override void OnInitialized(object sender, NoesisEventArgs args)
{
base.OnInitialized(sender, args);
if (!Application.isPlaying)
return;
if (PlayerPreferences.Instance == null)
return;
Update(true);
}
public void Update(bool wireEvents)
{
_ApplyEnabled = false;
// initialize values: gameplay
_WarnSafeParkingEnabled.IsChecked = PlayerPreferences.Instance.WarnSafeParkingEnabled;
_WarnEvilEnabled.IsChecked = PlayerPreferences.Instance.WarnEvilEnabled;
// initialize values: controls
_MouseConfined.IsChecked = PlayerPreferences.Instance.MouseConfined;
_GamepadEnabled.IsChecked = PlayerPreferences.Instance.GamepadEnabled;
_CharacterInvertUpEnabled.IsChecked = PlayerPreferences.Instance.CharacterInvertUpEnabled;
_ShipInvertUpEnabled.IsChecked = PlayerPreferences.Instance.ShipInvertUpEnabled;
_CharacterControl.SelectedIndex = (int)PlayerPreferences.Instance.CharacterControl;
_InteriorCamera.SelectedIndex = (int)PlayerPreferences.Instance.DefaultInteriorCamera;
_CharacterLookSensitivity.Value = PlayerPreferences.Instance.CharacterLookSensitivity;
// initialize values: display
_WindowMode.SelectedIndex = (int)PlayerPreferences.Instance.FullScreenMode;
_FrameRateLimit.SelectedIndex = (int)PlayerPreferences.Instance.FrameRateLimit;
_VSync.SelectedIndex = (int)PlayerPreferences.Instance.VSync;
_MotionBlur.SelectedIndex = (int)PlayerPreferences.Instance.MotionBlur;
_ShowFPS.SelectedIndex = PlayerPreferences.Instance.ShowFPS ? 1 : 0;
// diplays
List<DisplayInfo> displays = new List<DisplayInfo>();
Screen.GetDisplayLayout(displays);
string FilterName(string displayName)
{
if (string.IsNullOrEmpty(displayName))
return string.Empty;
return displayName.Replace("\\", string.Empty);
}
for (int i = 0; i < displays.Count; i++)
{
DisplayInfo displayInfo = displays[i];
ComboBoxItem comboBoxItem = new ComboBoxItem();
comboBoxItem.Content = $"{i + 1}: {FilterName(displayInfo.name)}";
comboBoxItem.Tag = displayInfo;
_Displays.Items.Add(comboBoxItem);
}
_Displays.SelectedIndex = PlayerPreferences.Instance.SelectedDisplayIndex;
UpdateScreeenResolutions(false);
switch (PlayerPreferences.Instance.ResolutionUpscaler)
{
case ResolutionUpscalerType.DLSS:
_ResolutionUpscaler.SelectedIndex = 1;
break;
case ResolutionUpscalerType.FSR:
_ResolutionUpscaler.SelectedIndex = 2;
break;
case ResolutionUpscalerType.XeSS:
_ResolutionUpscaler.SelectedIndex = 3;
break;
case ResolutionUpscalerType.TAA:
case ResolutionUpscalerType.None:
default:
_ResolutionUpscaler.SelectedIndex = 0;
break;
}
_ResolutionUpscalerQuality.SelectedIndex = (int)(PlayerPreferences.Instance.ResolutionUpscalerQuality - 2);
_CharacterFieldOfView.Value = PlayerPreferences.Instance.CharacterFieldOfView;
_CockpitFieldOfView.Value = PlayerPreferences.Instance.CockpitFieldOfView;
_ExternalFieldOfView.Value = PlayerPreferences.Instance.ExternalFieldOfView;
_BrightnessSlider.Value = PlayerPreferences.Instance.Brightness;
_ContrastSlider.Value = PlayerPreferences.Instance.Contrast;
// initialize values: ui
_BlurEffectsEnabled.IsChecked = PlayerPreferences.Instance.BlurEffectsEnabled;
_TopBlurSlider.Value = PlayerPreferences.Instance.TopBlurRadius;
_BottomBlurSlider.Value = PlayerPreferences.Instance.BottomBlurRadius;
_GameMenuEnabled.IsChecked = PlayerPreferences.Instance.GameMenuEnabled;
_TargetingEnabled.IsChecked = PlayerPreferences.Instance.TargetingEnabled;
_WindowDragEnabled.IsChecked = PlayerPreferences.Instance.WindowDragEnabled;
_UIEnabled.IsChecked = PlayerPreferences.Instance.UIEnabled;
_DesignerHelpUIEnabled.IsChecked = PlayerPreferences.Instance.DesignerHelpUIEnabled;
_GameHelpUIEnabled.IsChecked = PlayerPreferences.Instance.GameHelpUIEnabled;
_TemperatureUnits.SelectedIndex = (int)PlayerPreferences.Instance.TemperatureUnits;
// initialize values: sound
_MasterVolumeEnabled.IsChecked = PlayerPreferences.Instance.MasterVolumeEnabled;
_MasterVolumeSlider.Value = PlayerPreferences.Instance.MasterVolume * 100.0f;
_MusicVolumeEnabled.IsChecked = PlayerPreferences.Instance.MusicVolumeEnabled;
_MusicVolumeSlider.Value = PlayerPreferences.Instance.MusicVolume * 100.0f;
_EffectsVolumeEnabled.IsChecked = PlayerPreferences.Instance.EffectsVolumeEnabled;
_EffectsVolumeSlider.Value = PlayerPreferences.Instance.EffectsVolume * 100.0f;
_VoiceVolumeEnabled.IsChecked = PlayerPreferences.Instance.VoiceVolumeEnabled;
_VoiceVolumeSlider.Value = PlayerPreferences.Instance.VoiceVolume * 100.0f;
_UIVolumeEnabled.IsChecked = PlayerPreferences.Instance.UIVolumeEnabled;
_UIVolumeSlider.Value = PlayerPreferences.Instance.UIVolume * 100.0f;
_AmbientVolumeEnabled.IsChecked = PlayerPreferences.Instance.AmbientVolumeEnabled;
_AmbientVolumeSlider.Value = PlayerPreferences.Instance.AmbientVolume * 100.0f;
// generative ai
_GenerativeTextDialogue.IsChecked = PlayerPreferences.Instance.GenerativeTextDialogue;
_GenerativeAudioDialogue.IsChecked = PlayerPreferences.Instance.GenerativeAudioDialogue;
// initialize values: rgb
_RGBLightingEnabled.IsChecked = PlayerPreferences.Instance.RGBLightingEnabled;
_TutorialKeysEnabled.IsChecked = PlayerPreferences.Instance.RGBConfiguration.TutorialKeysEnabled;
_InputKeysEnabled.IsChecked = PlayerPreferences.Instance.RGBConfiguration.InputKeysEnabled;
_Environment.SelectedIndex = (int)PlayerPreferences.Instance.ConquestEnvironment;
_ClientToServerSlider.Value = PlayerPreferences.Instance.ClientToServerNetworkUpdateRate;
_ServerToClientSlider.Value = PlayerPreferences.Instance.ServerToClientNetworkUpdateRate;
_RGBHueSlider.Value = PlayerPreferences.Instance.RGBConfiguration.Hue * 100.0f;
_RGBSaturationSlider.Value = PlayerPreferences.Instance.RGBConfiguration.Saturation * 100.0f;
_RGBBrightnessSlider.Value = PlayerPreferences.Instance.RGBConfiguration.Brightness * 100.0f;
// about
_VersionTextBlock.Text = $"Version {VersionUtility.GetVersion()}{Environment.NewLine}{VersionUtility.GetBuildDate()}";
if (!wireEvents)
{
_ApplyEnabled = true;
return;
}
// events: gameplay
_WarnSafeParkingEnabled.Checked += (sender2, e2) => PlayerPreferences.Instance.WarnSafeParkingEnabled = true;
_WarnSafeParkingEnabled.Unchecked += (sender2, e2) => PlayerPreferences.Instance.WarnSafeParkingEnabled = false;
_WarnEvilEnabled.Checked += (sender2, e2) => PlayerPreferences.Instance.WarnEvilEnabled = true;
_WarnEvilEnabled.Unchecked += (sender2, e2) => PlayerPreferences.Instance.WarnEvilEnabled = false;
_GameMenuEnabled.Checked += (sender2, e2) =>
{
PlayerPreferences.Instance.GameMenuEnabled = true;
Apply();
};
_GameMenuEnabled.Unchecked += (sender2, e2) =>
{
PlayerPreferences.Instance.GameMenuEnabled = false;
Apply();
};
_TargetingEnabled.Checked += (sender2, e2) =>
{
PlayerPreferences.Instance.TargetingEnabled = true;
Apply();
};
_TargetingEnabled.Unchecked += (sender2, e2) =>
{
PlayerPreferences.Instance.TargetingEnabled = false;
Apply();
};
// UI
_WindowDragEnabled.Checked += (sender2, e2) =>
{
PlayerPreferences.Instance.WindowDragEnabled = true;
Apply();
UpdateWindowDragBehavior();
};
_WindowDragEnabled.Unchecked += (sender2, e2) =>
{
PlayerPreferences.Instance.WindowDragEnabled = false;
Apply();
UpdateWindowDragBehavior();
};
_TemperatureUnits.SelectionChanged += (sender2, e2) =>
{
PlayerPreferences.Instance.TemperatureUnits = (TemperatureUnitType)_TemperatureUnits.SelectedIndex;
};
_UIEnabled.Checked += (sender2, e2) =>
{
PlayerPreferences.Instance.UIEnabled = true;
Apply();
};
_UIEnabled.Unchecked += (sender2, e2) =>
{
PlayerPreferences.Instance.UIEnabled = false;
Apply();
};
_DesignerHelpUIEnabled.Checked += (sender2, e2) =>
{
PlayerPreferences.Instance.DesignerHelpUIEnabled = true;
Apply();
};
_DesignerHelpUIEnabled.Unchecked += (sender2, e2) =>
{
PlayerPreferences.Instance.DesignerHelpUIEnabled = false;
Apply();
};
_GameHelpUIEnabled.Checked += (sender2, e2) =>
{
PlayerPreferences.Instance.GameHelpUIEnabled = true;
Apply();
};
_GameHelpUIEnabled.Unchecked += (sender2, e2) =>
{
PlayerPreferences.Instance.GameHelpUIEnabled = false;
Apply();
};
// events: input
_MouseConfined.Checked += (sender2, e2) =>
{
PlayerPreferences.Instance.MouseConfined = true;
};
_MouseConfined.Unchecked += (sender2, e2) =>
{
PlayerPreferences.Instance.MouseConfined = false;
};
_GamepadEnabled.Checked += (sender2, e2) =>
{
PlayerPreferences.Instance.GamepadEnabled = true;
};
_GamepadEnabled.Unchecked += (sender2, e2) =>
{
PlayerPreferences.Instance.GamepadEnabled = false;
};
_CharacterInvertUpEnabled.Checked += (sender2, e2) =>
{
PlayerPreferences.Instance.CharacterInvertUpEnabled = true;
};
_CharacterInvertUpEnabled.Unchecked += (sender2, e2) =>
{
PlayerPreferences.Instance.CharacterInvertUpEnabled = false;
};
_ShipInvertUpEnabled.Checked += (sender2, e2) =>
{
PlayerPreferences.Instance.ShipInvertUpEnabled = true;
};
_ShipInvertUpEnabled.Unchecked += (sender2, e2) =>
{
PlayerPreferences.Instance.ShipInvertUpEnabled = false;
};
_CharacterControl.SelectionChanged += (sender2, e2) =>
{
PlayerPreferences.Instance.CharacterControl = (CharacterControlType)_CharacterControl.SelectedIndex;
};
_InteriorCamera.SelectionChanged += (sender2, e2) =>
{
PlayerPreferences.Instance.DefaultInteriorCamera = (DefaultInteriorCameraType)_InteriorCamera.SelectedIndex;
};
_CharacterLookSensitivity.ValueChanged += (sender2, e2) =>
{
PlayerPreferences.Instance.CharacterLookSensitivity = e2.NewValue;
};
// events: sound
// master
_MasterVolumeEnabled.Checked += (sender2, e2) =>
{
PlayerPreferences.Instance.MasterVolumeEnabled = true;
Apply(updateUI: false, updateAudio: true, updateDisplay: false);
UpdateButtonVisibility();
};
_MasterVolumeEnabled.Unchecked += (sender2, e2) =>
{
PlayerPreferences.Instance.MasterVolumeEnabled = false;
Apply(updateUI: false, updateAudio: true, updateDisplay: false);
UpdateButtonVisibility();
};
_MasterVolumeSlider.ValueChanged += (sender2, e2) =>
{
PlayerPreferences.Instance.MasterVolume = e2.NewValue / 100.0f;
Apply(updateUI: false, updateAudio: true, updateDisplay: false);
};
// music
_MusicVolumeEnabled.Checked += (sender2, e2) =>
{
PlayerPreferences.Instance.MusicVolumeEnabled = true;
Apply(updateUI: false, updateAudio: true, updateDisplay: false);
UpdateButtonVisibility();
};
_MusicVolumeEnabled.Unchecked += (sender2, e2) =>
{
PlayerPreferences.Instance.MusicVolumeEnabled = false;
Apply(updateUI: false, updateAudio: true, updateDisplay: false);
UpdateButtonVisibility();
};
_MusicVolumeSlider.ValueChanged += (sender2, e2) =>
{
PlayerPreferences.Instance.MusicVolume = e2.NewValue / 100.0f;
Apply(updateUI: false, updateAudio: true, updateDisplay: false);
};
// effects
_EffectsVolumeEnabled.Checked += (sender2, e2) =>
{
PlayerPreferences.Instance.EffectsVolumeEnabled = true;
Apply(updateUI: false, updateAudio: true, updateDisplay: false);
UpdateButtonVisibility();
};
_EffectsVolumeEnabled.Unchecked += (sender2, e2) =>
{
PlayerPreferences.Instance.EffectsVolumeEnabled = false;
Apply(updateUI: false, updateAudio: true, updateDisplay: false);
UpdateButtonVisibility();
};
_EffectsVolumeSlider.ValueChanged += (sender2, e2) =>
{
PlayerPreferences.Instance.EffectsVolume = e2.NewValue / 100.0f;
Apply(updateUI: false, updateAudio: true, updateDisplay: false);
};
// ambient
_AmbientVolumeEnabled.Checked += (sender2, e2) =>
{
PlayerPreferences.Instance.AmbientVolumeEnabled = true;
Apply(updateUI: false, updateAudio: true, updateDisplay: false);
UpdateButtonVisibility();
};
_AmbientVolumeEnabled.Unchecked += (sender2, e2) =>
{
PlayerPreferences.Instance.AmbientVolumeEnabled = false;
Apply(updateUI: false, updateAudio: true, updateDisplay: false);
UpdateButtonVisibility();
};
_AmbientVolumeSlider.ValueChanged += (sender2, e2) =>
{
PlayerPreferences.Instance.AmbientVolume = e2.NewValue / 100.0f;
Apply(updateUI: false, updateAudio: true, updateDisplay: false);
};
// voice
_VoiceVolumeEnabled.Checked += (sender2, e2) =>
{
PlayerPreferences.Instance.VoiceVolumeEnabled = true;
Apply(updateUI: false, updateAudio: true, updateDisplay: false);
UpdateButtonVisibility();
};
_VoiceVolumeEnabled.Unchecked += (sender2, e2) =>
{
PlayerPreferences.Instance.VoiceVolumeEnabled = false;
Apply(updateUI: false, updateAudio: true, updateDisplay: false);
UpdateButtonVisibility();
};
_VoiceVolumeSlider.ValueChanged += (sender2, e2) =>
{
PlayerPreferences.Instance.VoiceVolume = e2.NewValue / 100.0f;
Apply(updateUI: false, updateAudio: true, updateDisplay: false);
};
// ui
_UIVolumeEnabled.Checked += (sender2, e2) =>
{
PlayerPreferences.Instance.UIVolumeEnabled = true;
Apply(updateUI: false, updateAudio: true, updateDisplay: false);
UpdateButtonVisibility();
};
_UIVolumeEnabled.Unchecked += (sender2, e2) =>
{
PlayerPreferences.Instance.UIVolumeEnabled = false;
Apply(updateUI: false, updateAudio: true, updateDisplay: false);
UpdateButtonVisibility();
};
_UIVolumeSlider.ValueChanged += (sender2, e2) =>
{
PlayerPreferences.Instance.UIVolume = e2.NewValue / 100.0f;
Apply(updateUI: false, updateAudio: true, updateDisplay: false);
};
void OnResolutionChanged()
{
if (!_ApplyEnabled)
return;
if (_DisplayResolution.SelectedIndex == -1)
return;
Resolution selectedResolution = _SupportedResolutions[_DisplayResolution.SelectedIndex];
if (PlayerPreferences.Instance.FullScreenMode == FullScreenMode.Windowed)
{
// use system (window) resolution and system refresh rate
PlayerPreferences.Instance.DisplayResolution = new Vector2Int(Screen.width, Screen.height); // causes maximized screen to reset to screen width and height?
//PlayerPreferences.Instance.DisplayResolution = new Vector2Int(selectedResolution.width, selectedResolution.height);
PlayerPreferences.Instance.DisplayRefreshRate = (float)Screen.currentResolution.refreshRateRatio.value; // ignore selected refreshrate
}
else if (PlayerPreferences.Instance.FullScreenMode == FullScreenMode.FullScreenWindow)
{
// use selected resolution and system refresh rate
PlayerPreferences.Instance.DisplayResolution = new Vector2Int(selectedResolution.width, selectedResolution.height);
PlayerPreferences.Instance.DisplayRefreshRate = (float)Screen.currentResolution.refreshRateRatio.value; // ignore selected refreshrate
}
else if (PlayerPreferences.Instance.FullScreenMode == FullScreenMode.ExclusiveFullScreen)
{
// use selected resolution and selected refresh rate
PlayerPreferences.Instance.DisplayResolution = new Vector2Int(selectedResolution.width, selectedResolution.height);
PlayerPreferences.Instance.DisplayRefreshRate = (float)Math.Round(selectedResolution.refreshRateRatio.value, 2);
}
Apply(updateDisplay: true);
}
void OnFullScreenModeChanged()
{
PlayerPreferences.Instance.FullScreenMode = (FullScreenMode)_WindowMode.SelectedIndex;
UpdateScreeenResolutions(true);
if (_ApplyEnabled)
{
UpdateButtonVisibility();
if (PlayerPreferences.Instance.FullScreenMode == FullScreenMode.FullScreenWindow || PlayerPreferences.Instance.FullScreenMode == FullScreenMode.ExclusiveFullScreen)
{
_DisplayResolution.SelectedIndex = 0;
OnResolutionChanged(); // will invoke Apply()
}
else
Apply(updateDisplay: true);
}
}
void OnDisplayChanged()
{
PlayerPreferences.Instance.SelectedDisplayIndex = _Displays.SelectedIndex;
if (_ApplyEnabled)
{
Apply(updateDisplay: true, completed: () =>
{
UpdateScreeenResolutions(resetSelection: true); // updates display and resets Resolutions combobox
Apply(updateDisplay: true); // applies resolution ^1
});
}
}
_Displays.SelectionChanged += (sender, e) => OnDisplayChanged();
_WindowMode.SelectionChanged += (sender, e) => OnFullScreenModeChanged();
_DisplayResolution.SelectionChanged += (sender2, e2) => OnResolutionChanged();
_ResolutionUpscaler.SelectionChanged += (sender2, e2) =>
{
if (_ResolutionUpscaler.SelectedIndex == 0)
PlayerPreferences.Instance.ResolutionUpscaler = ResolutionUpscalerType.TAA;
else if (_ResolutionUpscaler.SelectedIndex == 1)
PlayerPreferences.Instance.ResolutionUpscaler = ResolutionUpscalerType.DLSS;
else if (_ResolutionUpscaler.SelectedIndex == 2)
PlayerPreferences.Instance.ResolutionUpscaler = ResolutionUpscalerType.FSR;
else if (_ResolutionUpscaler.SelectedIndex == 3)
PlayerPreferences.Instance.ResolutionUpscaler = ResolutionUpscalerType.XeSS;
else
throw new ArgumentOutOfRangeException();
Apply(updateDisplay: true);
};
_ResolutionUpscalerQuality.SelectionChanged += (sender2, e2) =>
{
PlayerPreferences.Instance.ResolutionUpscalerQuality = (ResolutionUpscalerQualityType)_ResolutionUpscalerQuality.SelectedIndex + 2;
Apply(updateDisplay: true);
};
_VSync.SelectionChanged += (sender2, e2) =>
{
PlayerPreferences.Instance.VSync = (VSyncType)_VSync.SelectedIndex;
if (PlayerPreferences.Instance.VSync == VSyncType.On)
_FrameRateLimit.Visibility = Visibility.Collapsed;
else
_FrameRateLimit.Visibility = Visibility.Visible;
Apply();
};
if (PlayerPreferences.Instance.VSync == VSyncType.On)
_FrameRateLimit.Visibility = Visibility.Collapsed;
else
_FrameRateLimit.Visibility = Visibility.Visible;
_FrameRateLimit.SelectionChanged += (sender2, e2) =>
{
PlayerPreferences.Instance.FrameRateLimit = (FrameRateLimitType)_FrameRateLimit.SelectedIndex;
Apply();
};
// motion blur
_MotionBlur.SelectionChanged += (sender2, e2) =>
{
PlayerPreferences.Instance.MotionBlur = (MotionBlurType)_MotionBlur.SelectedIndex;
Apply();
};
// show FPS
_ShowFPS.SelectionChanged += (sender2, e2) =>
{
PlayerPreferences.Instance.ShowFPS = _ShowFPS.SelectedIndex == 1;
Apply();
};
// quality
Action<int> updateAction = null;
updateAction = new Action<int>((value) =>
{
PlayerPreferences.Instance.Quality = (QualityType)value;
if (_DisplayInitialized)
ApplyQualitySetting(PlayerPreferences.Instance.Quality);
});
WireEvents(updateAction, (int)PlayerPreferences.Instance.Quality, _QualityLow, _QualityMedium, _QualityHigh, _QualityEpic, _QualityAuto);
// view distance
updateAction = new Action<int>((value) =>
{
PlayerPreferences.Instance.ViewDistance = (ViewDistanceType)value;
Apply();
});
WireEvents(updateAction, (int)PlayerPreferences.Instance.ViewDistance, _ViewNear, _ViewMedium, _ViewFar, _ViewEpic);
// shadows
updateAction = new Action<int>((value) =>
{
PlayerPreferences.Instance.Shadows = (ShadowsQualityType)value;
Apply();
});
WireEvents(updateAction, (int)PlayerPreferences.Instance.Shadows, _ShadowsLow, _ShadowsMedium, _ShadowsHigh, _ShadowsEpic);
// shadow distance
updateAction = new Action<int>((value) =>
{
PlayerPreferences.Instance.ShadowDistance = (ShadowDistanceType)value;
Apply();
});
WireEvents(updateAction, (int)PlayerPreferences.Instance.ShadowDistance, _ShadowDistanceNear, _ShadowDistanceMedium, _ShadowDistanceFar, _ShadowDistanceEpic);
// textures
updateAction = new Action<int>((value) =>
{
PlayerPreferences.Instance.Textures = (TexturesType)value;
Apply();
});
WireEvents(updateAction, (int)PlayerPreferences.Instance.Textures, _TexturesLow, _TexturesMedium, _TexturesHigh, _TexturesEpic);
// reflections
updateAction = new Action<int>((value) =>
{
PlayerPreferences.Instance.Reflections = (ReflectionsType)value;
Apply();
});
WireEvents(updateAction, (int)PlayerPreferences.Instance.Reflections, _ReflectionsOff, _ReflectionsMedium, _ReflectionsHigh, _ReflectionsEpic);
// post processing
updateAction = new Action<int>((value) =>
{
PlayerPreferences.Instance.PostProcessing = (PostProcessingType)value;
Apply();
});
WireEvents(updateAction, (int)PlayerPreferences.Instance.PostProcessing, _PostProcessingLow, _PostProcessingMedium, _PostProcessingHigh, _PostProcessingEpic);
// detail
updateAction = new Action<int>((value) =>
{
PlayerPreferences.Instance.Detail = (DetailType)value;
Apply();
});
WireEvents(updateAction, (int)PlayerPreferences.Instance.Detail, _DetailLow, _DetailMedium, _DetailHigh, _DetailEpic);
// field of view
_CharacterFieldOfView.ValueChanged += (sender2, e2) =>
{
PlayerPreferences.Instance.CharacterFieldOfView = (int)e2.NewValue;
Apply();
};
_CockpitFieldOfView.ValueChanged += (sender2, e2) =>
{
PlayerPreferences.Instance.CockpitFieldOfView = (int)e2.NewValue;
Apply();
};
_ExternalFieldOfView.ValueChanged += (sender2, e2) =>
{
PlayerPreferences.Instance.ExternalFieldOfView = (int)e2.NewValue;
Apply();
};
_ResetFieldOfViewButton.Click += (sender2, e2) =>
{
_CockpitFieldOfView.Value = 60;
_CharacterFieldOfView.Value = 60;
_ExternalFieldOfView.Value = 40;
};
_BrightnessSlider.ValueChanged += (sender2, e2) =>
{
PlayerPreferences.Instance.Brightness = (int)e2.NewValue;
Apply();
};
_ContrastSlider.ValueChanged += (sender2, e2) =>
{
PlayerPreferences.Instance.Contrast = (int)e2.NewValue;
Apply();
};
_ResetColorCorrectionButton.Click += (sender2, e2) =>
{
_BrightnessSlider.Value = 0;
_ContrastSlider.Value = 0;
};
// ui
// UI size
updateAction = new Action<int>((value) =>
{
PlayerPreferences.Instance.UserInterfaceSize = AspectRatioUtility.DefaultAspectRatioIndex - 2 + value;
Apply();
});
WireEvents(updateAction, PlayerPreferences.Instance.UserInterfaceSize, _UISmallest, _UISmaller, _UINormal, _UILarger, _UILargest);
_BlurEffectsEnabled.Unchecked += (sender2, e2) =>
{
PlayerPreferences.Instance.BlurEffectsEnabled = _BlurEffectsEnabled.IsChecked.Value;
Apply();
};
_BlurEffectsEnabled.Checked += (sender2, e2) =>
{
PlayerPreferences.Instance.BlurEffectsEnabled = _BlurEffectsEnabled.IsChecked.Value;
Apply();
};
_TopBlurSlider.ValueChanged += (sender2, e2) =>
{
PlayerPreferences.Instance.TopBlurRadius = (int)e2.NewValue;
Apply();
};
_BottomBlurSlider.ValueChanged += (sender2, e2) =>
{
PlayerPreferences.Instance.BottomBlurRadius = (int)e2.NewValue;
Apply();
};
// generative AI
_GenerativeTextDialogue.Checked += (sender2, e2) =>
{
PlayerPreferences.Instance.GenerativeTextDialogue = true;
};
_GenerativeTextDialogue.Unchecked += (sender2, e2) =>
{
PlayerPreferences.Instance.GenerativeTextDialogue = false;
};
_GenerativeAudioDialogue.Checked += (sender2, e2) =>
{
PlayerPreferences.Instance.GenerativeAudioDialogue = true;
};
_GenerativeAudioDialogue.Unchecked += (sender2, e2) =>
{
PlayerPreferences.Instance.GenerativeAudioDialogue = false;
};
// corsair
_RGBLightingEnabled.Checked += (sender2, e2) =>
{
PlayerPreferences.Instance.RGBLightingEnabled = true;
Apply(updateUI: false, updateAudio: false, updateDisplay: false, updateRGB: true);
UpdateButtonVisibility();
};
_RGBLightingEnabled.Unchecked += (sender2, e2) =>
{
PlayerPreferences.Instance.RGBLightingEnabled = false;
Apply(updateUI: false, updateAudio: false, updateDisplay: false, updateRGB: true);
UpdateButtonVisibility();
};
_TutorialKeysEnabled.Checked += (sender2, e2) =>
{
PlayerPreferences.Instance.RGBConfiguration.TutorialKeysEnabled = true;
Apply(updateUI: false, updateAudio: false, updateDisplay: false, updateRGB: true);
};
_TutorialKeysEnabled.Unchecked += (sender2, e2) =>
{
PlayerPreferences.Instance.RGBConfiguration.TutorialKeysEnabled = false;
Apply(updateUI: false, updateAudio: false, updateDisplay: false, updateRGB: true);
};
_InputKeysEnabled.Checked += (sender2, e2) =>
{
PlayerPreferences.Instance.RGBConfiguration.InputKeysEnabled = true;
Apply(updateUI: false, updateAudio: false, updateDisplay: false, updateRGB: true);
};
_InputKeysEnabled.Unchecked += (sender2, e2) =>
{
PlayerPreferences.Instance.RGBConfiguration.InputKeysEnabled = false;
Apply(updateUI: false, updateAudio: false, updateDisplay: false, updateRGB: true);
};
_RGBHueSlider.ValueChanged += (sender2, e2) =>
{
float value = e2.NewValue / 180.0f;
if (value < 0)
value = 1 - value;
PlayerPreferences.Instance.RGBConfiguration.Hue = value;
RGBBehavior.Instance.SetDirty(true, true);
};
_RGBSaturationSlider.ValueChanged += (sender2, e2) =>
{
PlayerPreferences.Instance.RGBConfiguration.Saturation = e2.NewValue / 100.0f;
RGBBehavior.Instance.SetDirty(true, true);
};
_RGBBrightnessSlider.ValueChanged += (sender2, e2) =>
{
PlayerPreferences.Instance.RGBConfiguration.Brightness = e2.NewValue / 100.0f;
RGBBehavior.Instance.SetDirty(true, true);
};
_ResetCorsairColorCorrectionButton.Click += (sender2, e2) =>
{
_RGBHueSlider.Value = 0;
_RGBSaturationSlider.Value = 0;
_RGBBrightnessSlider.Value = 0;
};
if (PlayerPreferences.Instance.RGBLightingEnabled && RGBBehavior.Instance.IsAvailable)
CreateRGBLightingUI();
_DisplayInitialized = true;
// global
UpdateButtonVisibility();
// network
_Environment.SelectionChanged += (sender2, e2) =>
{
PlayerPreferences.Instance.ConquestEnvironment = (EnvironmentType)_Environment.SelectedIndex;
};
_ClientToServerRateTextBlock.Text = $"Client ({(int)(1000 / Mathf.Lerp(Constants.Network.SpatialUpdateDelayMaxMS, Constants.Network.SpatialUpdateDelayMinMS, PlayerPreferences.Instance.ClientToServerNetworkUpdateRate))} Hz)";
_ServerToClientRateTextBlock.Text = $"Server ({(int)(1000 / Mathf.Lerp(Constants.Network.SpatialUpdateDelayMaxMS, Constants.Network.SpatialUpdateDelayMinMS, PlayerPreferences.Instance.ServerToClientNetworkUpdateRate))} Hz)";
_ClientToServerSlider.ValueChanged += (sender2, e2) =>
{
_ClientToServerRateTextBlock.Text = $"Client ({(int)(1000 / Mathf.Lerp(Constants.Network.SpatialUpdateDelayMaxMS, Constants.Network.SpatialUpdateDelayMinMS, e2.NewValue))} Hz)";
};
_ServerToClientSlider.ValueChanged += (sender2, e2) =>
{
_ServerToClientRateTextBlock.Text = $"Server ({(int)(1000 / Mathf.Lerp(Constants.Network.SpatialUpdateDelayMaxMS, Constants.Network.SpatialUpdateDelayMinMS, e2.NewValue))} Hz)";
};
// about
_HyperlinkButton.Click += (sender2, e2) => ShowSoftwareLicenseAttribution();
_ApplyEnabled = true;
}
private void UpdateScreeenResolutions(bool resetSelection)
{
bool applyEnabled = _ApplyEnabled;
_ApplyEnabled = false;
void AddResolution(List<Resolution> resolutions, float scalar)
{
Resolution resolution = new Resolution()
{
width = Mathf.RoundToInt(resolutions[0].width * scalar),
height = Mathf.RoundToInt(resolutions[0].height * scalar),
refreshRateRatio = resolutions[0].refreshRateRatio
};
if (!resolutions.Where(a => a.width == resolution.width && a.height == resolution.height).Any())
resolutions.Add(resolution);
}
List<Resolution> resolutions = Screen.resolutions
.Where(a => a.width >= 1024 && a.height >= 1024 && a.refreshRateRatio.value >= 50)
.OrderByDescending(a => a.width)
.ThenByDescending(a => a.height)
.ThenByDescending(a => a.refreshRateRatio.value).ToList();
if (PlayerPreferences.Instance.FullScreenMode == FullScreenMode.FullScreenWindow)
{
AddResolution(resolutions, 0.90f);
AddResolution(resolutions, 0.80f);
AddResolution(resolutions, 0.70f);
AddResolution(resolutions, 0.60f);
AddResolution(resolutions, 0.50f);
}
_SupportedResolutions = resolutions
.OrderByDescending(a => a.width)
.ThenByDescending(a => a.height)
.ThenByDescending(a => a.refreshRateRatio.value)
.ToList();
Resolution highestScreenResolution = _SupportedResolutions[0];
var nativeAspectRatio = UIUtility.GetAspectRatio(highestScreenResolution.width, highestScreenResolution.height);
_DisplayResolution.Items.Clear();
foreach (Resolution resolution in _SupportedResolutions)
{
var selectedAspectRatio = UIUtility.GetAspectRatio(resolution.width, resolution.height);
ComboBoxItem i = new ComboBoxItem();
if (selectedAspectRatio == nativeAspectRatio)
{
i.Content = $"{resolution.width,4} x {resolution.height,-4} @ {Math.Round(resolution.refreshRateRatio.value, 2)}Hz 📐 ";
i.FontFamily = FindResource("HeadingFontFamily") as FontFamily;
}
else
i.Content = $"{resolution.width,4} x {resolution.height,-4} @ {Math.Round(resolution.refreshRateRatio.value, 2)}Hz";
i.Tag = resolution;
_DisplayResolution.Items.Add(i);
}
if (resetSelection)
_DisplayResolution.SelectedIndex = 0;
else
{
int selectedResolutionIndex = -1;
for (int i = 0; i < _SupportedResolutions.Count; i++)
if (_SupportedResolutions[i].width == PlayerPreferences.Instance.DisplayResolution.x &&
_SupportedResolutions[i].height == PlayerPreferences.Instance.DisplayResolution.y &&
(PlayerPreferences.Instance.FullScreenMode != FullScreenMode.ExclusiveFullScreen ||
(Math.Round(_SupportedResolutions[i].refreshRateRatio.value, 2) == Math.Round(PlayerPreferences.Instance.DisplayRefreshRate, 2))))
{
selectedResolutionIndex = i;
break;
}
int currentScreenResolutionIndex = -1;
for (int i = 0; i < _SupportedResolutions.Count; i++)
{
if (_SupportedResolutions[i].width == Screen.currentResolution.width &&
_SupportedResolutions[i].height == Screen.currentResolution.height &&
(PlayerPreferences.Instance.FullScreenMode != FullScreenMode.ExclusiveFullScreen ||
(_SupportedResolutions[i].refreshRateRatio.numerator == Screen.currentResolution.refreshRateRatio.numerator &&
_SupportedResolutions[i].refreshRateRatio.denominator == Screen.currentResolution.refreshRateRatio.denominator)))
{
currentScreenResolutionIndex = i;
break;
}
}
if (selectedResolutionIndex != -1)
_DisplayResolution.SelectedIndex = selectedResolutionIndex;
else if (currentScreenResolutionIndex != -1)
_DisplayResolution.SelectedIndex = currentScreenResolutionIndex;
else
_DisplayResolution.SelectedIndex = 0;
}
_ApplyEnabled = applyEnabled;
}
private void ApplyQualitySetting(QualityType value)
{
_ApplyEnabled = false;
switch (value)
{
case QualityType.Low:
_ViewNear.IsChecked = true;
_ShadowsMedium.IsChecked = true;
_ShadowDistanceMedium.IsChecked = true;
_TexturesLow.IsChecked = true;
_ReflectionsMedium.IsChecked = true;
_PostProcessingLow.IsChecked = true;
_DetailLow.IsChecked = true;
break;
case QualityType.Medium:
_ViewMedium.IsChecked = true;
_ShadowsMedium.IsChecked = true;
_ShadowDistanceMedium.IsChecked = true;
_TexturesMedium.IsChecked = true;
_ReflectionsMedium.IsChecked = true;
_PostProcessingMedium.IsChecked = true;
_DetailMedium.IsChecked = true;
break;
case QualityType.High:
_ViewFar.IsChecked = true;
_ShadowsHigh.IsChecked = true;
_ShadowDistanceFar.IsChecked = true;
_TexturesHigh.IsChecked = true;
_ReflectionsMedium.IsChecked = true;
_PostProcessingHigh.IsChecked = true;
_DetailHigh.IsChecked = true;
break;
case QualityType.Epic:
_ViewEpic.IsChecked = true;
_ShadowsEpic.IsChecked = true;
_ShadowDistanceEpic.IsChecked = true;
_TexturesHigh.IsChecked = true;
_ReflectionsHigh.IsChecked = true;
_PostProcessingEpic.IsChecked = true;
_DetailEpic.IsChecked = true;
break;
case QualityType.Auto:
PlayerPreferences.Instance.VSync = 0;
UnityDispatcher.Instance.Invoke(TimeSpan.FromMilliseconds(250), () =>
{
float fps = GameState.Instance.FrameRateCounter.FPS;
PlayerPreferences.Instance.VSync = (VSyncType)_VSync.SelectedIndex;
if (fps > 125)
ApplyQualitySetting(QualityType.Epic);
else if (fps > 100)
ApplyQualitySetting(QualityType.High);
else if (fps > 75)
ApplyQualitySetting(QualityType.Medium);
else
ApplyQualitySetting(QualityType.Low);
});
return;
default:
break;
}
_ApplyEnabled = true;
Apply();
}
public override void Show()
{
base.Show();
if (Application.isEditor || RuntimeSettings.Instance.IsDeveloperMode || PlayerPreferences.Instance.ConquestEnvironment == EnvironmentType.LocalDevelopment)
_NetworkTab.Visibility = Visibility.Visible;
else
_NetworkTab.Visibility = Visibility.Collapsed;
#if (UNITY_GAMECORE)
_CorsairTab.Visibility = Visibility.Collapsed;
_DevicesStackPanel.Visibility = Visibility.Collapsed;
_ResolutionStackPanel.Visibility = Visibility.Collapsed;
_QualityStackPanel.Visibility = Visibility.Collapsed;
_FieldOfViewStackPanel.Visibility = Visibility.Collapsed;
_WindowDragEnabled.Parent.Visibility = Visibility.Collapsed;
_UIEnabled.Parent.Visibility = Visibility.Collapsed;
_GameMenuEnabled.Parent.Visibility = Visibility.Collapsed;
_GenerativeAIStackPanel.Visibility = Visibility.Collapsed;
#endif
InputHelpManager.Instance.UpdateRGBKeysForUI();
}
public override void Hide()
{
base.Hide();
// update preferences that should change only once, upon save
PlayerPreferences.Instance.ClientToServerNetworkUpdateRate = _ClientToServerSlider.Value;
PlayerPreferences.Instance.ServerToClientNetworkUpdateRate = _ServerToClientSlider.Value;
// save preferences
PlayerPreferences.Instance.SaveRGB();
PlayerPreferences.Instance.SavePreferences();
}
public void Apply(bool updateUI = true, bool updateAudio = true, bool updateDisplay = true, bool updateRGB = true, bool updateWorld = true, Action completed = null)
{
if (_ApplyEnabled)
{
if (updateRGB)
{
// RGB state
if (_RGBLightingEnabled.IsChecked.Value)
{
// create device UI if it does not exist, and Corsair RGB is ready
if (_CorsairStackPanel.Children.Count == 0)
UnityDispatcher.Instance.Invoke(async () =>
{
int tries = 0;
while (tries++ < 4)
{
if (RGBBehavior.Instance.IsAvailable)
{
CreateRGBLightingUI();
break;
}
else
await Task.Delay(50);
}
if (RGBBehavior.Instance.IsAvailable)
{
_RGBStackPanel.Visibility = Visibility.Visible;
_CorsairNotFoundTextBlock.Visibility = Visibility.Collapsed;
}
else
{
_RGBStackPanel.Visibility = Visibility.Collapsed;
_CorsairNotFoundTextBlock.Visibility = Visibility.Visible;
}
});
}
else
{
_RGBStackPanel.Visibility = Visibility.Collapsed;
_CorsairNotFoundTextBlock.Visibility = Visibility.Collapsed;
_CorsairStackPanel.Children.Clear();
}
}
PlayerPreferences.Instance.Apply(updateUI, updateAudio, updateDisplay, updateRGB, updateWorld, completed);
if (RGBBehavior.Instance.IsAvailable && updateRGB)
RGBBehavior.Instance.LoadDevices();
}
}
private void UpdateButtonVisibility()
{
if (_MasterVolumeEnabled.IsChecked.Value)
{
_MasterVolumeSlider.IsEnabled = true;
_MasterVolumeSlider.Opacity = 1.0f;
}
else
{
_MasterVolumeSlider.IsEnabled = false;
_MasterVolumeSlider.Opacity = 0.5f;
}
if (_MusicVolumeEnabled.IsChecked.Value)
{
_MusicVolumeSlider.IsEnabled = true;
_MusicVolumeSlider.Opacity = 1.0f;
}
else
{
_MusicVolumeSlider.IsEnabled = false;
_MusicVolumeSlider.Opacity = 0.5f;
}
if (_EffectsVolumeEnabled.IsChecked.Value)
{
_EffectsVolumeSlider.IsEnabled = true;
_EffectsVolumeSlider.Opacity = 1.0f;
}
else
{
_EffectsVolumeSlider.IsEnabled = false;
_EffectsVolumeSlider.Opacity = 0.5f;
}
if (_AmbientVolumeEnabled.IsChecked.Value)
{
_AmbientVolumeSlider.IsEnabled = true;
_AmbientVolumeSlider.Opacity = 1.0f;
}
else
{
_AmbientVolumeSlider.IsEnabled = false;
_AmbientVolumeSlider.Opacity = 0.5f;
}
if (!_RGBLightingEnabled.IsChecked.Value)
{
_RGBStackPanel.Visibility = Visibility.Collapsed;
_CorsairNotFoundTextBlock.Visibility = Visibility.Collapsed;
}
if (_WindowMode.SelectedIndex == (int)FullScreenMode.ExclusiveFullScreen || _WindowMode.SelectedIndex == (int)FullScreenMode.FullScreenWindow)
_DisplayResolutionStackPanel.Visibility = Visibility.Visible;
else
_DisplayResolutionStackPanel.Visibility = Visibility.Hidden;
}
private void CreateRGBLightingUI()
{
if (RGBBehavior.Instance.IsAvailable)
foreach (RGBDeviceMetadata metadata in RGBBehavior.Instance.Devices)
{
string deviceName = RGBConfiguration.SantitizeDeviceName(metadata.Device.DeviceInfo.DeviceName);
StackPanel stackPanel = new StackPanel();
stackPanel.Orientation = Orientation.Horizontal;
stackPanel.Margin = new Thickness(0, 0, 0, 12);
_CorsairStackPanel.Children.Add(stackPanel);
TextBlock textBlock = new TextBlock();
textBlock.Style = (Style)_Root.FindResource("Heading4Primary");
textBlock.HorizontalAlignment = HorizontalAlignment.Right;
textBlock.VerticalAlignment = VerticalAlignment.Center;
textBlock.Width = 250;
textBlock.Margin = new Thickness(0, 0, 5, 0);
textBlock.Text = deviceName;
ToolTipService.SetToolTip(textBlock, textBlock.Text);
stackPanel.Children.Add(textBlock);
ComboBox comboBox = new ComboBox();
comboBox.Width = 315;
stackPanel.Children.Add(comboBox);
Array values = Enum.GetValues(typeof(LightingAssignmentType));
for (int i = 0; i < values.Length; i++)
{
LightingAssignmentType lightingAssignmentType = (LightingAssignmentType)i;
ComboBoxItem comboBoxItem = new ComboBoxItem();
comboBoxItem.Tag = lightingAssignmentType;
comboBoxItem.Content = lightingAssignmentType.ToString().Replace("_", " ");
comboBox.Items.Add(comboBoxItem);
}
comboBox.SelectedIndex = (int)metadata.Binding.Assignment;
comboBox.SelectionChanged += (sender, e) =>
{
ComboBoxItem selectedItem = (ComboBoxItem)e.AddedItems[0];
LightingAssignmentType assignment = (LightingAssignmentType)selectedItem.Tag;
metadata.Binding.Assignment = assignment;
Apply(updateUI: false, updateAudio: false, updateDisplay: false, updateRGB: true);
};
}
}
private void ShowSoftwareLicenseAttribution()
{
Hide();
LicenseAttributionControl control = new LicenseAttributionControl();
control.Hidden += (sender, e) => Show();
control.Show();
}
public override void UpdateInput()
{
if (OpenFrame != Time.frameCount)
{
if (Input.GetKeyDown(KeyCode.Escape) ||
Input.GetButtonDown(InputNames.GamePad.B) ||
Input.GetButtonDown(InputNames.GamePad.Start) ||
Input.GetKeyDown(KeyCode.F1))
{
Hide();
}
}
}
}
} OverlayControl.cs (9,635 bytes)
using Noesis;
using Noesis.Interactivity;
using System;
using UnityEngine;
using Color = Noesis.Color;
using Grid = Noesis.Grid;
using NoesisEventArgs = Noesis.EventArgs;
namespace StellarConquest.Presentation.Unity.UI
{
public enum HideReasonType
{
None,
Programmatic,
LightDismiss,
}
[AssetDependency]
public partial class OverlayControl : UserControl, IGameScreenInputProvider
{
public event EventHandler<NoesisEventArgs> Shown;
public event EventHandler<NoesisEventArgs> Hidden;
public bool IsOverlayVisible { get; private set; }
public bool IsLightDismissExteriorEnabled { get; set; } = true;
public bool IsLightDismissInteriorEnabled { get; set; } = false;
public bool IsBlurEnabled { get; set; } = false;
public bool IsBackgroundSourceBlendEnabled { get; set; } = true;
public bool IsModal { get; set; } = true;
public bool IsFadeEnabled { get; set; } = true;
public bool IsUnscaled { get; set; } = false;
public bool IsAnimatedShow { get; set; } = false;
public bool IsAlternateKeyToCloseEnabled { get; set; } = false;
public KeyCode AlternateCloseKey { get; set; } = KeyCode.F;
public bool IsDragAllowed { get; set; } = false;
public bool IsDragEnabled { get; set; } = false;
public bool IsEscapeToCloseEnabled { get; set; } = false;
public OverlayLayerType Layer { get; set; } = OverlayLayerType.Primary;
public HorizontalAlignment ParentHorizontalAlignment { get; set; } = HorizontalAlignment.Center;
public VerticalAlignment ParentVerticalAlignment { get; set; } = VerticalAlignment.Center;
public HideReasonType HideReason { get; private set; } = HideReasonType.None;
public bool AllowSubsequentPopupDelay { get; protected set; } = true;
private Grid _ParentGrid;
private OverlayLayer _OverlayLayer;
public int OpenFrame { get; private set; } = -1;
public int CloseFrame { get; private set; } = -1;
public static int CloseFrameGlobal { get; private set; } = -1;
public bool UseKeyUpEvent;
public OverlayControl()
{
}
protected virtual void InitializeComponent()
{
if (!Application.isPlaying)
return;
_OverlayLayer = UIStateMachine.Instance.OverlayLayer;
_ParentGrid = new Grid();
_ParentGrid.Name = Name + "_ParentGrid";
_ParentGrid.HorizontalAlignment = HorizontalAlignment.Stretch;
_ParentGrid.VerticalAlignment = VerticalAlignment.Stretch;
if (IsModal)
_ParentGrid.Background = new SolidColorBrush(Color.FromArgb(0, 0, 0, 0)); // transparent but interactive
else
_ParentGrid.Background = null;
_ParentGrid.Children.Add(this);
}
protected virtual void OnInitialized(object sender, NoesisEventArgs args)
{
if (!Application.isPlaying)
return;
UpdateLightDismiss();
}
public virtual void Show()
{
_OverlayLayer.Tag = this;
PickingManager.Instance.InteractionFired = true;
OpenFrame = Time.frameCount;
HideReason = HideReasonType.None;
if (IsUnscaled)
_OverlayLayer.ShowUnscaled(_ParentGrid, Layer, IsBlurEnabled, IsBackgroundSourceBlendEnabled, IsFadeEnabled, IsModal, ParentHorizontalAlignment, ParentVerticalAlignment);
else
_OverlayLayer.Show(_ParentGrid, Layer, IsBlurEnabled, IsBackgroundSourceBlendEnabled, IsFadeEnabled, IsModal, ParentHorizontalAlignment, ParentVerticalAlignment);
if (IsAnimatedShow)
this.Grow(_OverlayLayer, TimeSpan.FromMilliseconds(160));
if (Layer == OverlayLayerType.Primary)
{
IsOverlayVisible = true;
UIStateMachine.Instance.AddInputProvider(this);
}
UpdateWindowDragBehavior();
Shown?.Invoke(this, NoesisEventArgs.Empty);
}
public virtual void Hide()
{
_OverlayLayer.Tag = null;
PickingManager.Instance.InteractionFired = true;
CloseFrame = Time.frameCount;
CloseFrameGlobal = CloseFrame;
if (HideReason == HideReasonType.None)
HideReason = HideReasonType.Programmatic;
if (IsUnscaled)
_OverlayLayer.HideUnscaled(_ParentGrid, Layer);
else
_OverlayLayer.Hide(_ParentGrid, Layer, AllowSubsequentPopupDelay);
if (Layer == OverlayLayerType.Primary)
{
IsOverlayVisible = false;
UIStateMachine.Instance.RemoveInputProvider(this);
}
if (UIStateMachine.Instance.IsGameScreenOpen)
{
if (this == UIStateMachine.Instance.GameScreen.TargetingControl.SelectedTargetMenu)
UIStateMachine.Instance.GameScreen.TargetingControl.SelectedTargetMenu = null;
}
Hidden?.Invoke(this, NoesisEventArgs.Empty);
}
public bool Toggle()
{
if (IsOverlayVisible)
{
Hide();
return false;
}
else
{
Show();
return true;
}
}
protected void UpdateWindowDragBehavior()
{
if (IsDragAllowed && PlayerPreferences.Instance.WindowDragEnabled || IsDragEnabled)
{
if (Interaction.GetBehaviors(this).Count == 0)
{
ParentHorizontalAlignment = HorizontalAlignment.Stretch;
ParentVerticalAlignment = VerticalAlignment.Stretch;
HorizontalAlignment = HorizontalAlignment.Center;
VerticalAlignment = VerticalAlignment.Center;
MouseDragElementBehavior dragBehavior = new MouseDragElementBehavior();
dragBehavior.ConstrainToParentBounds = true;
Interaction.GetBehaviors(this).Add(dragBehavior);
}
}
else
{
if (Interaction.GetBehaviors(this).Count > 0)
Interaction.GetBehaviors(this).Clear();
}
}
public Vector2 GetViewboxScale()
{
return _OverlayLayer.GetViewboxScale();
}
protected void UpdateLightDismiss()
{
// Noesis MouseUp event processing runs independent of PickingManager MouseDown processing. The Show() method
// is invoked from InteractionEventManager. For this reason, it is possible for PickingManager to request Show() AND
// for _ParentGrid.MouseUp to fire immediately thereafter. Variable _InteractionFrame tracks the frame for Show(), and
// subsequently ignores mouse events occuring on this same frame. While unfortunate, this is necessary logic to accomodate
// parallel threads which have access to the same data structure. The alternative, using Noesis for all UI or Unity for all UI
// (ray casting), is not tennable due to the inherent disconnect between 2D (Noesis) and 3D (Picking).
_ParentGrid.MouseLeftButtonUp -= LightDismissExteriorMouseUp;
if (IsLightDismissExteriorEnabled)
_ParentGrid.MouseLeftButtonUp += LightDismissExteriorMouseUp;
MouseLeftButtonUp -= LightDismissInteriorMouseUp;
if (!IsLightDismissInteriorEnabled)
MouseLeftButtonUp += LightDismissInteriorMouseUp;
}
private void LightDismissExteriorMouseUp(object sender, MouseButtonEventArgs args)
{
if (OpenFrame != Time.frameCount && !PickingManager.Instance.InteractionFired)
{
HideReason = HideReasonType.LightDismiss;
Hide();
}
}
private void LightDismissInteriorMouseUp(object sender, MouseButtonEventArgs args)
{
if (OpenFrame != Time.frameCount && !PickingManager.Instance.InteractionFired)
args.Handled = true;
}
public virtual void UpdateInput()
{
if (OpenFrame != Time.frameCount)
if (!PickingManager.Instance.InteractionFired)
if (IsLightDismissExteriorEnabled || IsLightDismissInteriorEnabled || IsEscapeToCloseEnabled)
{
if (UseKeyUpEvent)
{
if (Input.GetButtonUp(InputNames.GamePad.B) || Input.GetKeyUp(KeyCode.Escape) ||
(IsAlternateKeyToCloseEnabled && Input.GetKeyDown(AlternateCloseKey)))
Hide();
}
else
{
if (Input.GetButtonDown(InputNames.GamePad.B) || Input.GetKeyDown(KeyCode.Escape) ||
(IsAlternateKeyToCloseEnabled && Input.GetKeyDown(AlternateCloseKey)))
Hide();
}
}
}
}
} |
|
|
Edited initial issue above to note that the behavior manifests after every edit to a CS file. |
|
|
OK, I likely misunderstood our previous issue. I thought adding [AssetDependency] was sufficient to resolve dependencies. I have learned that I need to either define asset dependencies in code using the attribute or in XAML using the deprecated Dependencies tag. I am now using the Dependencies tag in XAML and the above behaviors are resolved. Candidate for closure. Thanks! |
|
|
The final 4.0.0 fixed a minor issue related to this, that could explain a few of your errors. |
|
| Date Modified | Username | Field | Change |
|---|---|---|---|
| 2026-08-20 19:23 | stonstad | New Issue | |
| 2026-08-20 19:23 | stonstad | File Added: TitleScreen.xaml | |
| 2026-08-20 19:23 | stonstad | File Added: TitleScreen.xaml.cs | |
| 2026-08-20 19:23 | stonstad | Summary | AssetDependency Fails After Subsequent Stop/Play Cycle => 4.0 RC5. AssetDependency Fails After Subsequent Stop/Play Cycle |
| 2026-08-20 19:28 | stonstad | Description Updated | |
| 2026-08-20 19:43 | stonstad | Note Added: 0012538 | |
| 2026-08-20 19:43 | stonstad | File Added: SettingsControl.xaml | |
| 2026-08-20 19:43 | stonstad | File Added: SettingsControl.xaml.cs | |
| 2026-08-20 19:43 | stonstad | File Added: OverlayControl.cs | |
| 2026-08-20 19:45 | stonstad | Description Updated | |
| 2026-08-20 19:46 | stonstad | Note Added: 0012539 | |
| 2026-08-20 19:47 | stonstad | Note Edited: 0012539 | |
| 2026-08-20 20:16 | stonstad | Note Added: 0012540 | |
| 2026-08-20 20:16 | stonstad | Note Edited: 0012540 | |
| 2026-08-21 20:22 | jsantos | Assigned To | => jsantos |
| 2026-08-21 20:22 | jsantos | Status | new => assigned |
| 2026-08-21 20:23 | jsantos | Description Updated | |
| 2026-08-21 20:24 | jsantos | Note Added: 0012554 | |
| 2026-08-21 20:24 | jsantos | Status | assigned => resolved |
| 2026-08-21 20:24 | jsantos | Resolution | open => fixed |
| 2026-08-21 20:24 | jsantos | Fixed in Version | => 4.0 |