3 using System.Collections.Generic;
4 using System.Collections.Immutable;
5 using System.Globalization;
11 using Microsoft.Xna.Framework;
12 using Microsoft.Xna.Framework.Graphics;
13 using Microsoft.Xna.Framework.Input;
33 private GameSettings.Config unsavedConfig;
38 private readonly
GUIFrame contentFrame;
43 private static readonly ImmutableHashSet<InputType> LegacyInputTypes =
new List<InputType>()
49 }.ToImmutableHashSet();
60 unsavedConfig = GameSettings.CurrentConfig;
65 isHorizontal:
false, childAnchor:
Anchor.TopRight);
68 font: GUIStyle.LargeFont);
77 tabber =
new GUILayoutGroup(
new RectTransform((0.06f, 1.0f), tabberAndContentLayout.RectTransform), isHorizontal:
false) { AbsoluteSpacing = GUI.IntScale(5f) };
79 tabContents =
new Dictionary<Tab, (GUIButton Button, GUIFrame Content)>();
81 contentFrame =
new GUIFrame(
new RectTransform((0.92f, 1.0f), tabberAndContentLayout.RectTransform),
84 bottom =
new GUILayoutGroup(
new RectTransform((contentFrame.RectTransform.RelativeSize.X, 0.04f), mainLayout.RectTransform), isHorizontal:
true) { Stretch =
true, RelativeSpacing = 0.01f };
87 CreateAudioAndVCTab();
92 CreateBottomButtons();
99 private void SwitchContent(GUIFrame newContent)
101 contentFrame.Children.ForEach(c => c.Visible =
false);
102 newContent.Visible =
true;
105 private readonly Dictionary<
Tab, (GUIButton Button, GUIFrame Content)> tabContents;
110 SwitchContent(tabContents[tab].Content);
111 tabber.Children.ForEach(c =>
113 if (c is
GUIButton btn) { btn.Selected = btn == tabContents[tab].Button; }
117 private void AddButtonToTabber(
Tab tab,
GUIFrame content)
121 ToolTip = TextManager.Get($
"SettingsTab.{tab}"),
122 OnClicked = (b, _) =>
128 button.RectTransform.MaxSize = RectTransform.MaxPoint;
129 button.Children.ForEach(c => c.RectTransform.MaxSize = RectTransform.MaxPoint);
131 tabContents.Add(tab, (button, content));
134 private GUIFrame CreateNewContentFrame(
Tab tab)
136 var content =
new GUIFrame(
new RectTransform(Vector2.One * 0.95f, contentFrame.RectTransform,
Anchor.Center,
Pivot.Center), style:
null);
137 AddButtonToTabber(tab, content);
141 private static (GUILayoutGroup Left, GUILayoutGroup Right) CreateSidebars(GUIFrame parent,
bool split =
false)
143 GUILayoutGroup layout =
new GUILayoutGroup(
new RectTransform(Vector2.One, parent.RectTransform), isHorizontal:
true);
144 GUILayoutGroup left =
new GUILayoutGroup(
new RectTransform((0.4875f, 1.0f), layout.RectTransform), isHorizontal:
false);
145 var centerFrame =
new GUIFrame(
new RectTransform((0.025f, 1.0f), layout.RectTransform), style:
null);
148 new GUICustomComponent(
new RectTransform(Vector2.One, centerFrame.RectTransform),
151 sb.DrawLine((c.Rect.Center.X, c.Rect.Top),(c.Rect.Center.X, c.Rect.Bottom), GUIStyle.TextColorDim, 2f);
154 GUILayoutGroup right =
new GUILayoutGroup(
new RectTransform((0.4875f, 1.0f), layout.RectTransform), isHorizontal:
false);
155 return (left, right);
158 private static GUILayoutGroup CreateCenterLayout(GUIFrame parent)
160 return new GUILayoutGroup(
new RectTransform((0.5f, 1.0f), parent.RectTransform,
Anchor.TopCenter,
Pivot.TopCenter)) { ChildAnchor =
Anchor.TopCenter };
163 private static RectTransform NewItemRectT(GUILayoutGroup parent)
164 =>
new RectTransform((1.0f, 0.06f), parent.RectTransform,
Anchor.CenterLeft);
166 private static void Spacer(GUILayoutGroup parent)
168 new GUIFrame(
new RectTransform((1.0f, 0.03f), parent.RectTransform,
Anchor.CenterLeft), style:
null);
171 private static GUITextBlock Label(GUILayoutGroup parent, LocalizedString str, GUIFont font)
173 return new GUITextBlock(NewItemRectT(parent), str, font: font);
176 private static void DropdownEnum<T>(GUILayoutGroup parent, Func<T, LocalizedString> textFunc, Func<T, LocalizedString>? tooltipFunc, T currentValue,
177 Action<T> setter) where T : Enum
178 => Dropdown(parent, textFunc, tooltipFunc, (T[])Enum.GetValues(typeof(T)), currentValue, setter);
180 private static GUIDropDown Dropdown<T>(GUILayoutGroup parent, Func<T, LocalizedString> textFunc, Func<T, LocalizedString>? tooltipFunc, IReadOnlyList<T> values, T currentValue, Action<T> setter)
182 var dropdown =
new GUIDropDown(NewItemRectT(parent));
183 values.ForEach(v => dropdown.AddItem(text: textFunc(v), userData: v, toolTip: tooltipFunc?.Invoke(v) ??
null));
184 int childIndex = values.IndexOf(currentValue);
185 dropdown.Select(childIndex);
186 dropdown.ListBox.ForceLayoutRecalculation();
187 dropdown.ListBox.ScrollToElement(dropdown.ListBox.Content.GetChild(childIndex));
188 dropdown.OnSelected = (dd, obj) =>
196 private static (GUIScrollBar slider, GUITextBlock label) Slider(GUILayoutGroup parent, Vector2 range,
int steps, Func<float, string> labelFunc,
float currentValue, Action<float> setter, LocalizedString? tooltip =
null)
198 var layout =
new GUILayoutGroup(NewItemRectT(parent), isHorizontal:
true);
199 var slider =
new GUIScrollBar(
new RectTransform((0.72f, 1.0f), layout.RectTransform), style:
"GUISlider")
202 BarScrollValue = currentValue,
203 Step = 1.0f / (float)(steps - 1),
204 BarSize = 1.0f / steps
208 slider.ToolTip = tooltip;
210 var label =
new GUITextBlock(
new RectTransform((0.28f, 1.0f), layout.RectTransform),
211 labelFunc(currentValue), wrap:
false, textAlignment: Alignment.Center);
212 slider.OnMoved = (sb, val) =>
214 label.Text = labelFunc(sb.BarScrollValue);
215 setter(sb.BarScrollValue);
218 return (slider, label);
221 private static GUITickBox Tickbox(GUILayoutGroup parent, LocalizedString label, LocalizedString tooltip,
bool currentValue, Action<bool> setter)
223 return new GUITickBox(NewItemRectT(parent), label)
235 private string Percentage(
float v) => ToolBox.GetFormattedPercentage(v);
237 private static int Round(
float v) => MathUtils.RoundToInt(v);
239 private void CreateGraphicsTab()
241 GUIFrame content = CreateNewContentFrame(
Tab.Graphics);
243 var (left, right) = CreateSidebars(content);
245 List<(
int Width,
int Height)> supportedResolutions =
246 GameMain.GraphicsDeviceManager.GraphicsDevice.Adapter.SupportedDisplayModes
247 .Where(m => m.Format == SurfaceFormat.Color)
248 .Select(m => (m.Width, m.Height))
249 .Where(m => m.Width >= GameSettings.Config.GraphicsSettings.MinSupportedResolution.X
250 && m.Height >= GameSettings.Config.GraphicsSettings.MinSupportedResolution.Y)
252 var currentResolution = (unsavedConfig.Graphics.Width, unsavedConfig.Graphics.Height);
253 if (!supportedResolutions.Contains(currentResolution))
255 supportedResolutions.Add(currentResolution);
258 Label(left, TextManager.Get(
"Resolution"), GUIStyle.SubHeadingFont);
259 Dropdown(left, (m) => $
"{m.Width}x{m.Height}",
null, supportedResolutions, currentResolution,
262 unsavedConfig.Graphics.Width = res.Width;
263 unsavedConfig.Graphics.Height = res.Height;
267 Label(left, TextManager.Get(
"DisplayMode"), GUIStyle.SubHeadingFont);
268 DropdownEnum(left, (m) => TextManager.Get($
"{m}"),
null, unsavedConfig.Graphics.DisplayMode, v => unsavedConfig.Graphics.DisplayMode = v);
271 Tickbox(left, TextManager.Get(
"EnableVSync"), TextManager.Get(
"EnableVSyncTooltip"), unsavedConfig.Graphics.VSync, v => unsavedConfig.Graphics.VSync = v);
272 Tickbox(left, TextManager.Get(
"EnableTextureCompression"), TextManager.Get(
"EnableTextureCompressionTooltip"), unsavedConfig.Graphics.CompressTextures, v => unsavedConfig.Graphics.CompressTextures = v);
275 Label(right, TextManager.Get(
"LOSEffect"), GUIStyle.SubHeadingFont);
276 DropdownEnum(right, (m) => TextManager.Get($
"LosMode{m}"),
null, unsavedConfig.Graphics.LosMode, v => unsavedConfig.Graphics.LosMode = v);
279 Label(right, TextManager.Get(
"LightMapScale"), GUIStyle.SubHeadingFont);
280 Slider(right, (0.5f, 1.0f), 11, v => TextManager.GetWithVariable(
"percentageformat",
"[value]", Round(v * 100).ToString()).Value, unsavedConfig.Graphics.LightMapScale, v => unsavedConfig.Graphics.LightMapScale = v, TextManager.Get(
"LightMapScaleTooltip"));
283 Label(right, TextManager.Get(
"VisibleLightLimit"), GUIStyle.SubHeadingFont);
284 Slider(right, (10, 210), 21, v => v > 200 ? TextManager.Get(
"unlimited").Value : Round(v).ToString(), unsavedConfig.Graphics.VisibleLightLimit,
285 v => unsavedConfig.Graphics.VisibleLightLimit = v > 200 ?
int.MaxValue : Round(v), TextManager.Get(
"VisibleLightLimitTooltip"));
288 Tickbox(right, TextManager.Get(
"RadialDistortion"), TextManager.Get(
"RadialDistortionTooltip"), unsavedConfig.Graphics.RadialDistortion, v => unsavedConfig.Graphics.RadialDistortion = v);
289 Tickbox(right, TextManager.Get(
"ChromaticAberration"), TextManager.Get(
"ChromaticAberrationTooltip"), unsavedConfig.Graphics.ChromaticAberration, v => unsavedConfig.Graphics.ChromaticAberration = v);
291 Label(right, TextManager.Get(
"ParticleLimit"), GUIStyle.SubHeadingFont);
292 Slider(right, (100, 1500), 15, v => Round(v).ToString(), unsavedConfig.Graphics.ParticleLimit, v => unsavedConfig.Graphics.ParticleLimit = Round(v));
296 private static string TrimAudioDeviceName(
string name)
298 if (
string.IsNullOrWhiteSpace(name)) {
return string.Empty; }
299 string[] prefixes = {
"OpenAL Soft on " };
300 foreach (
string prefix
in prefixes)
302 if (name.StartsWith(prefix, StringComparison.OrdinalIgnoreCase))
304 return name.Remove(0, prefix.Length);
310 private static int HandleAlErrors(
string message)
315 DebugConsole.ThrowError($
"{message}: ALC error {Alc.GetErrorString(alcError)}");
322 DebugConsole.ThrowError($
"{message}: AL error {Al.GetErrorString(alError)}");
329 private static void GetAudioDevices(
int listSpecifier,
int defaultSpecifier, out IReadOnlyList<string> list, ref
string current)
331 list = Array.Empty<
string>();
334 if (HandleAlErrors(
"Alc.GetStringList failed") !=
Al.
NoError) {
return; }
337 if (
string.IsNullOrEmpty(current))
340 if (HandleAlErrors(
"Alc.GetString failed") !=
Al.
NoError) {
return; }
343 string currentVal = current;
344 if (list.Any() && !list.Any(n => n.Equals(currentVal, StringComparison.OrdinalIgnoreCase)))
350 private void CreateAudioAndVCTab()
352 if (GameMain.Client ==
null
355 string currDevice = unsavedConfig.Audio.VoiceCaptureDevice;
358 if (deviceList.Any())
364 unsavedConfig.Audio.VoiceSetting =
VoiceMode.Disabled;
368 GUIFrame content = CreateNewContentFrame(
Tab.AudioAndVC);
370 var (audio, voiceChat) = CreateSidebars(content, split:
true);
372 static void audioDeviceElement(
373 GUILayoutGroup parent,
374 Action<string> setter,
376 int defaultSpecifier,
377 ref
string currentDevice)
386 var deviceNameContainerElement =
new GUIFrame(NewItemRectT(parent), style:
"GUITextBoxNoIcon");
387 var deviceNameElement =
new GUITextBlock(
new RectTransform(Vector2.One, deviceNameContainerElement.RectTransform), currentDevice, textAlignment: Alignment.CenterLeft);
388 new GUICustomComponent(
new RectTransform(Vector2.Zero, deviceNameElement.RectTransform), onUpdate:
389 (deltaTime, component) =>
391 deviceNameElement.Text = Alc.GetString(IntPtr.Zero, listSpecifier);
394 GetAudioDevices(listSpecifier, defaultSpecifier, out var devices, ref currentDevice);
395 Dropdown(parent, v => TrimAudioDeviceName(v),
null, devices, currentDevice, setter);
399 Label(audio, TextManager.Get(
"AudioOutputDevice"), GUIStyle.SubHeadingFont);
401 string currentOutputDevice = unsavedConfig.Audio.AudioOutputDevice;
405 Label(audio, TextManager.Get(
"SoundVolume"), GUIStyle.SubHeadingFont);
406 Slider(audio, (0, 1), 101, Percentage, unsavedConfig.Audio.SoundVolume, v => unsavedConfig.Audio.SoundVolume = v);
408 Label(audio, TextManager.Get(
"MusicVolume"), GUIStyle.SubHeadingFont);
409 Slider(audio, (0, 1), 101, Percentage, unsavedConfig.Audio.MusicVolume, v => unsavedConfig.Audio.MusicVolume = v);
411 Label(audio, TextManager.Get(
"UiSoundVolume"), GUIStyle.SubHeadingFont);
412 Slider(audio, (0, 1), 101, Percentage, unsavedConfig.Audio.UiVolume, v => unsavedConfig.Audio.UiVolume = v);
414 Tickbox(audio, TextManager.Get(
"MuteOnFocusLost"), TextManager.Get(
"MuteOnFocusLostTooltip"), unsavedConfig.Audio.MuteOnFocusLost, v => unsavedConfig.Audio.MuteOnFocusLost = v);
415 Tickbox(audio, TextManager.Get(
"DynamicRangeCompression"), TextManager.Get(
"DynamicRangeCompressionTooltip"), unsavedConfig.Audio.DynamicRangeCompressionEnabled, v => unsavedConfig.Audio.DynamicRangeCompressionEnabled = v);
418 Label(audio, TextManager.Get(
"VoiceChatVolume"), GUIStyle.SubHeadingFont);
419 Slider(audio, (0, 2), 201, Percentage, unsavedConfig.Audio.VoiceChatVolume, v => unsavedConfig.Audio.VoiceChatVolume = v);
421 Tickbox(audio, TextManager.Get(
"DirectionalVoiceChat"), TextManager.Get(
"DirectionalVoiceChatTooltip"), unsavedConfig.Audio.UseDirectionalVoiceChat, v => unsavedConfig.Audio.UseDirectionalVoiceChat = v);
422 Tickbox(audio, TextManager.Get(
"VoipAttenuation"), TextManager.Get(
"VoipAttenuationTooltip"), unsavedConfig.Audio.VoipAttenuationEnabled, v => unsavedConfig.Audio.VoipAttenuationEnabled = v);
424 Label(voiceChat, TextManager.Get(
"AudioInputDevice"), GUIStyle.SubHeadingFont);
426 string currentInputDevice = unsavedConfig.Audio.VoiceCaptureDevice;
430 Label(voiceChat, TextManager.Get(
"VCInputMode"), GUIStyle.SubHeadingFont);
431 DropdownEnum(voiceChat, v => TextManager.Get($
"VoiceMode.{v}"), v => TextManager.Get($
"VoiceMode.{v}Tooltip"), unsavedConfig.Audio.VoiceSetting, v => unsavedConfig.Audio.VoiceSetting = v);
434 var noiseGateThresholdLabel = Label(voiceChat, TextManager.Get(
"NoiseGateThreshold"), GUIStyle.SubHeadingFont);
435 var dbMeter =
new GUIProgressBar(NewItemRectT(voiceChat), 0.0f, Color.Lime);
436 dbMeter.ProgressGetter = () =>
440 dbMeter.Color = unsavedConfig.Audio.VoiceSetting
switch
448 return scrollVal * scrollVal;
450 var noiseGateSlider =
new GUIScrollBar(
new RectTransform(Vector2.One, dbMeter.RectTransform,
Anchor.Center), color: Color.White,
451 style:
"GUISlider", barSize: 0.03f);
452 noiseGateSlider.Frame.Visible =
false;
453 noiseGateSlider.Step = 0.01f;
454 noiseGateSlider.Range =
new Vector2(-100.0f, 0.0f);
455 noiseGateSlider.BarScroll = MathUtils.InverseLerp(-100.0f, 0.0f, unsavedConfig.Audio.NoiseGateThreshold);
456 noiseGateSlider.BarScroll *= noiseGateSlider.BarScroll;
457 noiseGateSlider.OnMoved = (scrollBar, barScroll) =>
459 unsavedConfig.Audio.NoiseGateThreshold = MathHelper.Lerp(-100.0f, 0.0f, (
float)Math.Sqrt(scrollBar.BarScroll));
462 new GUICustomComponent(
new RectTransform(Vector2.Zero, voiceChat.RectTransform), onUpdate:
463 (deltaTime, component) =>
465 noiseGateThresholdLabel.Visible = unsavedConfig.Audio.VoiceSetting == VoiceMode.Activity;
466 noiseGateSlider.Visible = unsavedConfig.Audio.VoiceSetting == VoiceMode.Activity;
470 Label(voiceChat, TextManager.Get(
"MicrophoneVolume"), GUIStyle.SubHeadingFont);
471 Slider(voiceChat, (0, 10), 101, Percentage, unsavedConfig.Audio.MicrophoneVolume, v => unsavedConfig.Audio.MicrophoneVolume = v);
474 Label(voiceChat, TextManager.Get(
"CutoffPrevention"), GUIStyle.SubHeadingFont);
475 Slider(voiceChat, (0, 500), 26, v => $
"{Round(v)} ms", unsavedConfig.Audio.VoiceChatCutoffPrevention, v => unsavedConfig.Audio.VoiceChatCutoffPrevention = Round(v), TextManager.Get(
"CutoffPreventionTooltip"));
478 private readonly Dictionary<GUIButton, Func<LocalizedString>> inputButtonValueNameGetters =
new Dictionary<GUIButton, Func<LocalizedString>>();
479 private bool inputBoxSelectedThisFrame =
false;
481 private void CreateControlsTab()
483 GUIFrame content = CreateNewContentFrame(
Tab.Controls);
485 GUILayoutGroup layout = CreateCenterLayout(content);
487 Label(layout, TextManager.Get(
"AimAssist"), GUIStyle.SubHeadingFont);
489 var aimAssistSlider = Slider(layout, (0, 1), 101, Percentage, unsavedConfig.AimAssistAmount, v => unsavedConfig.AimAssistAmount = v, TextManager.Get(
"AimAssistTooltip"));
490 Tickbox(layout, TextManager.Get(
"EnableMouseLook"), TextManager.Get(
"EnableMouseLookTooltip"), unsavedConfig.EnableMouseLook, v => unsavedConfig.EnableMouseLook = v);
494 GUIListBox keyMapList =
495 new GUIListBox(
new RectTransform((2.0f, 0.7f),
496 layout.RectTransform))
498 CanBeFocused =
false,
499 OnSelected = (_, __) =>
false
503 GUILayoutGroup createInputRowLayout()
504 =>
new GUILayoutGroup(
new RectTransform((1.0f, 0.1f), keyMapList.Content.RectTransform), isHorizontal:
true);
506 inputButtonValueNameGetters.Clear();
507 Action<KeyOrMouse>? currentSetter =
null;
508 void addInputToRow(GUILayoutGroup currRow, LocalizedString labelText, Func<LocalizedString> valueNameGetter, Action<KeyOrMouse> valueSetter,
bool isLegacyBind =
false)
510 var inputFrame =
new GUIFrame(
new RectTransform((0.5f, 1.0f), currRow.RectTransform),
514 labelText = TextManager.GetWithVariable(
"legacyitemformat",
"[name]", labelText);
516 var label =
new GUITextBlock(
new RectTransform((0.6f, 1.0f), inputFrame.RectTransform), labelText,
518 var inputBox =
new GUIButton(
519 new RectTransform((0.4f, 1.0f), inputFrame.RectTransform,
Anchor.TopRight,
Pivot.TopRight),
520 valueNameGetter(), style:
"GUITextBoxNoIcon")
522 OnClicked = (btn, obj) =>
524 inputButtonValueNameGetters.Keys.ForEach(b =>
526 if (b != btn) { b.Selected =
false; }
528 bool willBeSelected = !btn.Selected;
531 inputBoxSelectedThisFrame =
true;
535 btn.Text = valueNameGetter();
539 btn.Selected = willBeSelected;
545 label.TextColor = Color.Lerp(label.TextColor, label.DisabledTextColor, 0.5f);
546 inputBox.Color = Color.Lerp(inputBox.Color, inputBox.DisabledColor, 0.5f);
547 inputBox.TextColor = Color.Lerp(inputBox.TextColor, label.DisabledTextColor, 0.5f);
549 inputButtonValueNameGetters.Add(inputBox, valueNameGetter);
552 var inputListener =
new GUICustomComponent(
new RectTransform(Vector2.Zero, layout.RectTransform), onUpdate: (deltaTime, component) =>
554 if (currentSetter is null) { return; }
556 if (PlayerInput.PrimaryMouseButtonClicked() && inputBoxSelectedThisFrame)
558 inputBoxSelectedThisFrame = false;
564 currentSetter =
null;
565 inputButtonValueNameGetters.Keys.ForEach(b => b.Selected =
false);
568 void callSetter(KeyOrMouse v)
570 currentSetter?.Invoke(v);
574 var pressedKeys = PlayerInput.GetKeyboardState.GetPressedKeys();
575 if (pressedKeys?.
Any() ??
false)
577 if (pressedKeys.Contains(Keys.Escape))
583 callSetter(pressedKeys.First());
586 else if (PlayerInput.PrimaryMouseButtonClicked() &&
587 (GUI.MouseOn ==
null || !(GUI.MouseOn is GUIButton) || GUI.MouseOn.IsChildOf(keyMapList.Content)))
591 else if (PlayerInput.SecondaryMouseButtonClicked())
595 else if (PlayerInput.MidButtonClicked())
599 else if (PlayerInput.Mouse4ButtonClicked())
603 else if (PlayerInput.Mouse5ButtonClicked())
607 else if (PlayerInput.MouseWheelUpClicked())
611 else if (PlayerInput.MouseWheelDownClicked())
620 inputTypes.Take(inputTypes.Length - (inputTypes.Length / 2)).ToArray(),
621 inputTypes.TakeLast(inputTypes.Length / 2).ToArray()
623 for (
int i = 0; i < inputTypes.Length; i+=2)
625 var currRow = createInputRowLayout();
626 for (
int j = 0; j < 2; j++)
628 var column = inputTypeColumns[j];
629 if (i / 2 >= column.Length) {
break; }
630 var input = column[i / 2];
633 TextManager.Get($
"InputType.{input}"),
634 () => unsavedConfig.KeyMap.Bindings[input].Name,
635 v => unsavedConfig.KeyMap = unsavedConfig.KeyMap.WithBinding(input, v),
636 LegacyInputTypes.Contains(input));
640 for (
int i = 0; i < unsavedConfig.InventoryKeyMap.Bindings.Length; i += 2)
642 var currRow = createInputRowLayout();
643 for (
int j = 0; j < 2; j++)
645 int currIndex = i + j;
646 if (currIndex >= unsavedConfig.InventoryKeyMap.Bindings.Length) {
break; }
648 var input = unsavedConfig.InventoryKeyMap.Bindings[currIndex];
651 TextManager.GetWithVariable(
"inventoryslotkeybind",
"[slotnumber]", (currIndex + 1).ToString(CultureInfo.InvariantCulture)),
652 () => unsavedConfig.InventoryKeyMap.Bindings[currIndex].Name,
653 v => unsavedConfig.InventoryKeyMap = unsavedConfig.InventoryKeyMap.WithBinding(currIndex, v));
657 GUILayoutGroup resetControlsHolder =
658 new GUILayoutGroup(
new RectTransform((1.75f, 0.1f), layout.RectTransform), isHorizontal:
true, childAnchor:
Anchor.Center)
660 RelativeSpacing = 0.1f
663 var defaultBindingsButton =
664 new GUIButton(
new RectTransform(
new Vector2(0.45f, 1.0f), resetControlsHolder.RectTransform),
665 TextManager.Get(
"Reset"), style:
"GUIButtonSmall")
667 ToolTip = TextManager.Get(
"SetDefaultBindingsTooltip"),
668 OnClicked = (_, userdata) =>
670 unsavedConfig.InventoryKeyMap = GameSettings.Config.InventoryKeyMapping.GetDefault();
671 unsavedConfig.KeyMap = GameSettings.Config.KeyMapping.GetDefault();
672 aimAssistSlider.slider.BarScrollValue = GameSettings.Config.DefaultAimAssist;
673 aimAssistSlider.label.Text = Percentage(GameSettings.Config.DefaultAimAssist);
674 foreach (var btn
in inputButtonValueNameGetters.Keys)
676 btn.Text = inputButtonValueNameGetters[btn]();
684 private void CreateGameplayTab()
686 GUIFrame content = CreateNewContentFrame(Tab.Gameplay);
688 var (leftColumn, rightColumn) = CreateSidebars(content, split:
true);
690 var languages = TextManager.AvailableLanguages
691 .OrderBy(l => TextManager.GetTranslatedLanguageName(l).ToIdentifier())
693 Label(leftColumn, TextManager.Get(
"Language"), GUIStyle.SubHeadingFont);
694 Dropdown(leftColumn, v => TextManager.GetTranslatedLanguageName(v),
null, languages, unsavedConfig.Language, v => unsavedConfig.Language = v);
697 Tickbox(leftColumn, TextManager.Get(
"PauseOnFocusLost"), TextManager.Get(
"PauseOnFocusLostTooltip"), unsavedConfig.PauseOnFocusLost, v => unsavedConfig.PauseOnFocusLost = v);
700 Tickbox(leftColumn, TextManager.Get(
"DisableInGameHints"), TextManager.Get(
"DisableInGameHintsTooltip"), unsavedConfig.DisableInGameHints, v => unsavedConfig.DisableInGameHints = v);
701 var resetInGameHintsButton =
702 new GUIButton(
new RectTransform(
new Vector2(1.0f, 1.0f), leftColumn.RectTransform),
703 TextManager.Get(
"ResetInGameHints"), style:
"GUIButtonSmall")
705 OnClicked = (button, o) =>
707 var msgBox =
new GUIMessageBox(TextManager.Get(
"ResetInGameHints"),
708 TextManager.Get(
"ResetInGameHintsTooltip"),
709 buttons:
new[] { TextManager.Get(
"Yes"), TextManager.Get(
"No") });
710 msgBox.Buttons[0].OnClicked = (guiButton, o1) =>
712 IgnoredHints.Instance.Clear();
716 msgBox.Buttons[1].OnClicked = msgBox.Close;
723 Tickbox(leftColumn, TextManager.Get(
"ChatSpeechBubbles"), TextManager.Get(
"ChatSpeechBubbles.Tooltip"), unsavedConfig.ChatSpeechBubbles, v => unsavedConfig.ChatSpeechBubbles = v);
725 Label(leftColumn, TextManager.Get(
"ShowEnemyHealthBars"), GUIStyle.SubHeadingFont);
726 DropdownEnum(leftColumn, v => TextManager.Get($
"ShowEnemyHealthBars.{v}"),
null, unsavedConfig.ShowEnemyHealthBars, v => unsavedConfig.ShowEnemyHealthBars = v);
728 Label(leftColumn, TextManager.Get(
"InteractionLabels"), GUIStyle.SubHeadingFont);
729 DropdownEnum(leftColumn, v => TextManager.Get($
"InteractionLabels.{v}"),
null, unsavedConfig.InteractionLabelDisplayMode, v => unsavedConfig.InteractionLabelDisplayMode = v);
731 Label(rightColumn, TextManager.Get(
"HUDScale"), GUIStyle.SubHeadingFont);
732 Slider(rightColumn, (0.75f, 1.25f), 51, Percentage, unsavedConfig.Graphics.HUDScale, v => unsavedConfig.Graphics.HUDScale = v);
733 Label(rightColumn, TextManager.Get(
"InventoryScale"), GUIStyle.SubHeadingFont);
734 Slider(rightColumn, (0.75f, 1.25f), 51, Percentage, unsavedConfig.Graphics.InventoryScale, v => unsavedConfig.Graphics.InventoryScale = v);
735 Label(rightColumn, TextManager.Get(
"TextScale"), GUIStyle.SubHeadingFont);
736 Slider(rightColumn, (0.75f, 1.25f), 51, Percentage, unsavedConfig.Graphics.TextScale, v => unsavedConfig.Graphics.TextScale = v);
738 var resetSpamListFilter =
739 new GUIButton(
new RectTransform(
new Vector2(1.0f, 1.0f), rightColumn.RectTransform),
740 TextManager.Get(
"clearserverlistfilters"), style:
"GUIButtonSmall")
742 OnClicked =
static (_, _) =>
744 GUI.AskForConfirmation(
745 header: TextManager.Get(
"clearserverlistfilters"),
746 body: TextManager.Get(
"clearserverlistfiltersconfirmation"),
747 onConfirm: SpamServerFilters.ClearLocalSpamFilter);
754 var statisticsTickBox =
new GUITickBox(NewItemRectT(rightColumn), TextManager.Get(
"statisticsconsenttickbox"))
756 OnSelected = tickBox =>
758 GUIMessageBox? loadingBox =
null;
759 if (!tickBox.Selected)
761 loadingBox = GUIMessageBox.CreateLoadingBox(TextManager.Get(
"PleaseWait"));
763 GameAnalyticsManager.SetConsent(
765 ? GameAnalyticsManager.Consent.Ask
766 : GameAnalyticsManager.Consent.No,
767 onAnswerSent: () => loadingBox?.Close());
772 statisticsTickBox.Enabled =
false;
774 void updateGATickBoxToolTip()
775 => statisticsTickBox.ToolTip = TextManager.Get($
"GameAnalyticsStatus.{GameAnalyticsManager.UserConsented}");
776 updateGATickBoxToolTip();
778 var cachedConsent = GameAnalyticsManager.Consent.Unknown;
779 var statisticsTickBoxUpdater =
new GUICustomComponent(
780 new RectTransform(Vector2.Zero, statisticsTickBox.RectTransform),
781 onUpdate: (deltaTime, component) =>
783 bool shouldTickBoxBeSelected = GameAnalyticsManager.UserConsented == GameAnalyticsManager.Consent.Yes;
785 bool shouldUpdateTickBoxState = cachedConsent != GameAnalyticsManager.UserConsented
786 || statisticsTickBox.Selected != shouldTickBoxBeSelected;
788 if (!shouldUpdateTickBoxState) { return; }
790 updateGATickBoxToolTip();
791 cachedConsent = GameAnalyticsManager.UserConsented;
792 GUITickBox.OnSelectedHandler prevHandler = statisticsTickBox.OnSelected;
793 statisticsTickBox.OnSelected =
null;
794 statisticsTickBox.Selected = shouldTickBoxBeSelected;
795 statisticsTickBox.OnSelected = prevHandler;
796 statisticsTickBox.Enabled &= GameAnalyticsManager.UserConsented != GameAnalyticsManager.Consent.Error;
800 if (SteamManager.IsInitialized)
802 bool shouldCrossplayBeEnabled = unsavedConfig.CrossplayChoice is Eos.EosSteamPrimaryLogin.CrossplayChoice.Enabled;
803 var crossplayTickBox = Tickbox(rightColumn, TextManager.Get(
"EosAllowCrossplay"), TextManager.Get(
"EosAllowCrossplayTooltip"), shouldCrossplayBeEnabled, v =>
805 unsavedConfig.CrossplayChoice = v
806 ? Eos.EosSteamPrimaryLogin.CrossplayChoice.Enabled
807 : Eos.EosSteamPrimaryLogin.CrossplayChoice.Disabled;
809 if (GameMain.NetworkMember !=
null)
811 crossplayTickBox.Enabled =
false;
812 crossplayTickBox.ToolTip = TextManager.Get(
"CantAccessEOSSettingsInMP");
817 private void CreateModsTab(out
WorkshopMenu workshopMenu)
819 GUIFrame content = CreateNewContentFrame(Tab.Mods);
820 content.RectTransform.RelativeSize = Vector2.One;
822 workshopMenu = Screen.Selected is MainMenuScreen
826 GameMain.MainMenuScreen.ResetModUpdateButton();
829 private void CreateBottomButtons()
831 new GUIButton(
new RectTransform(
new Vector2(1.0f, 1.0f), bottom.RectTransform), text: TextManager.Get(
"Cancel"))
833 OnClicked = (btn, obj) =>
839 new GUIButton(
new RectTransform(
new Vector2(1.0f, 1.0f), bottom.RectTransform), text: TextManager.Get(
"applysettingsbutton"))
841 OnClicked = (btn, obj) =>
843 ApplyInstalledModChanges();
844 mainFrame.Flash(color: GUIStyle.Green);
847 OnAddedToGUIUpdateList = (GUIComponent component) =>
850 CurrentTab != Tab.Mods ||
858 EosSteamPrimaryLogin.HandleCrossplayChoiceChange(unsavedConfig.CrossplayChoice);
859 GameSettings.SetCurrentConfig(unsavedConfig);
862 mutableWorkshopMenu.Apply();
864 GameSettings.SaveCurrentConfig();
873 mainFrame.Parent.RemoveChild(mainFrame);
874 if (Instance ==
this) { Instance =
null; }
876 GUI.SettingsMenuOpen =
false;
static void Create(string deviceName, UInt16? storedBufferID=null)
static VoipCapture Instance
const int CaptureDeviceSpecifier
static IReadOnlyList< string > GetStringList(IntPtr device, int param)
static int GetError(IntPtr device)
const int DefaultDeviceSpecifier
const int CaptureDefaultDeviceSpecifier
const int OutputDevicesSpecifier
static string GetString(IntPtr device, int param)