3 using System.Collections.Generic;
4 using System.Collections.Immutable;
5 using System.Globalization;
12 using Microsoft.Xna.Framework;
13 using Microsoft.Xna.Framework.Graphics;
14 using Microsoft.Xna.Framework.Input;
34 private GameSettings.Config unsavedConfig;
39 private readonly
GUIFrame contentFrame;
44 private static readonly ImmutableHashSet<InputType> LegacyInputTypes =
new List<InputType>()
50 }.ToImmutableHashSet();
61 unsavedConfig = GameSettings.CurrentConfig;
66 isHorizontal:
false, childAnchor:
Anchor.TopRight);
69 font: GUIStyle.LargeFont);
78 tabber =
new GUILayoutGroup(
new RectTransform((0.06f, 1.0f), tabberAndContentLayout.RectTransform), isHorizontal:
false) { AbsoluteSpacing = GUI.IntScale(5f) };
80 tabContents =
new Dictionary<Tab, (GUIButton Button, GUIFrame Content)>();
82 contentFrame =
new GUIFrame(
new RectTransform((0.92f, 1.0f), tabberAndContentLayout.RectTransform),
85 bottom =
new GUILayoutGroup(
new RectTransform((contentFrame.RectTransform.RelativeSize.X, 0.04f), mainLayout.RectTransform), isHorizontal:
true) { Stretch =
true, RelativeSpacing = 0.01f };
88 CreateAudioAndVCTab();
93 CreateBottomButtons();
100 private void SwitchContent(GUIFrame newContent)
102 contentFrame.Children.ForEach(c => c.Visible =
false);
103 newContent.Visible =
true;
106 private readonly Dictionary<
Tab, (GUIButton Button, GUIFrame Content)> tabContents;
111 SwitchContent(tabContents[tab].Content);
112 tabber.Children.ForEach(c =>
114 if (c is
GUIButton btn) { btn.Selected = btn == tabContents[tab].Button; }
118 private void AddButtonToTabber(
Tab tab,
GUIFrame content)
122 ToolTip = TextManager.Get($
"SettingsTab.{tab}"),
123 OnClicked = (b, _) =>
129 button.RectTransform.MaxSize = RectTransform.MaxPoint;
130 button.Children.ForEach(c => c.RectTransform.MaxSize = RectTransform.MaxPoint);
132 tabContents.Add(tab, (button, content));
135 private GUIFrame CreateNewContentFrame(
Tab tab)
137 var content =
new GUIFrame(
new RectTransform(Vector2.One * 0.95f, contentFrame.RectTransform,
Anchor.Center,
Pivot.Center), style:
null);
138 AddButtonToTabber(tab, content);
142 private static (GUILayoutGroup Left, GUILayoutGroup Right) CreateSidebars(GUIFrame parent,
bool split =
false)
144 GUILayoutGroup layout =
new GUILayoutGroup(
new RectTransform(Vector2.One, parent.RectTransform), isHorizontal:
true);
145 GUILayoutGroup left =
new GUILayoutGroup(
new RectTransform((0.4875f, 1.0f), layout.RectTransform), isHorizontal:
false);
146 var centerFrame =
new GUIFrame(
new RectTransform((0.025f, 1.0f), layout.RectTransform), style:
null);
149 new GUICustomComponent(
new RectTransform(Vector2.One, centerFrame.RectTransform),
152 sb.DrawLine((c.Rect.Center.X, c.Rect.Top),(c.Rect.Center.X, c.Rect.Bottom), GUIStyle.TextColorDim, 2f);
155 GUILayoutGroup right =
new GUILayoutGroup(
new RectTransform((0.4875f, 1.0f), layout.RectTransform), isHorizontal:
false);
156 return (left, right);
159 private static GUILayoutGroup CreateCenterLayout(GUIFrame parent)
161 return new GUILayoutGroup(
new RectTransform((0.5f, 1.0f), parent.RectTransform,
Anchor.TopCenter,
Pivot.TopCenter)) { ChildAnchor =
Anchor.TopCenter };
164 private static RectTransform NewItemRectT(GUILayoutGroup parent)
165 =>
new RectTransform((1.0f, 0.06f), parent.RectTransform,
Anchor.CenterLeft);
167 private static void Spacer(GUILayoutGroup parent)
169 new GUIFrame(
new RectTransform((1.0f, 0.03f), parent.RectTransform,
Anchor.CenterLeft), style:
null);
172 private static GUITextBlock Label(GUILayoutGroup parent, LocalizedString str, GUIFont font)
174 return new GUITextBlock(NewItemRectT(parent), str, font: font);
177 private static void DropdownEnum<T>(GUILayoutGroup parent, Func<T, LocalizedString> textFunc, Func<T, LocalizedString>? tooltipFunc, T currentValue,
178 Action<T> setter) where T : Enum
179 => Dropdown(parent, textFunc, tooltipFunc, (T[])Enum.GetValues(typeof(T)), currentValue, setter);
181 private static GUIDropDown Dropdown<T>(GUILayoutGroup parent, Func<T, LocalizedString> textFunc, Func<T, LocalizedString>? tooltipFunc, IReadOnlyList<T> values, T currentValue, Action<T> setter)
183 var dropdown =
new GUIDropDown(NewItemRectT(parent));
184 values.ForEach(v => dropdown.AddItem(text: textFunc(v), userData: v, toolTip: tooltipFunc?.Invoke(v) ??
null));
185 int childIndex = values.IndexOf(currentValue);
186 dropdown.Select(childIndex);
187 dropdown.ListBox.ForceLayoutRecalculation();
188 dropdown.ListBox.ScrollToElement(dropdown.ListBox.Content.GetChild(childIndex));
189 dropdown.OnSelected = (dd, obj) =>
197 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)
199 var layout =
new GUILayoutGroup(NewItemRectT(parent), isHorizontal:
true);
200 var slider =
new GUIScrollBar(
new RectTransform((0.72f, 1.0f), layout.RectTransform), style:
"GUISlider")
203 BarScrollValue = currentValue,
204 Step = 1.0f / (float)(steps - 1),
205 BarSize = 1.0f / steps
209 slider.ToolTip = tooltip;
211 var label =
new GUITextBlock(
new RectTransform((0.28f, 1.0f), layout.RectTransform),
212 labelFunc(currentValue), wrap:
false, textAlignment: Alignment.Center);
213 slider.OnMoved = (sb, val) =>
215 label.Text = labelFunc(sb.BarScrollValue);
216 setter(sb.BarScrollValue);
219 return (slider, label);
222 private static GUITickBox Tickbox(GUILayoutGroup parent, LocalizedString label, LocalizedString tooltip,
bool currentValue, Action<bool> setter)
224 return new GUITickBox(NewItemRectT(parent), label)
236 private string Percentage(
float v) => ToolBox.GetFormattedPercentage(v);
238 private static int Round(
float v) => MathUtils.RoundToInt(v);
240 private void CreateGraphicsTab()
242 GUIFrame content = CreateNewContentFrame(
Tab.Graphics);
244 var (left, right) = CreateSidebars(content);
246 List<(
int Width,
int Height)> supportedResolutions =
247 GameMain.GraphicsDeviceManager.GraphicsDevice.Adapter.SupportedDisplayModes
248 .Where(m => m.Format == SurfaceFormat.Color)
249 .Select(m => (m.Width, m.Height))
250 .Where(m => m.Width >= GameSettings.Config.GraphicsSettings.MinSupportedResolution.X
251 && m.Height >= GameSettings.Config.GraphicsSettings.MinSupportedResolution.Y)
253 var currentResolution = (unsavedConfig.Graphics.Width, unsavedConfig.Graphics.Height);
254 if (!supportedResolutions.Contains(currentResolution))
256 supportedResolutions.Add(currentResolution);
259 Label(left, TextManager.Get(
"Resolution"), GUIStyle.SubHeadingFont);
260 Dropdown(left, (m) => $
"{m.Width}x{m.Height}",
null, supportedResolutions, currentResolution,
263 unsavedConfig.Graphics.Width = res.Width;
264 unsavedConfig.Graphics.Height = res.Height;
268 Label(left, TextManager.Get(
"DisplayMode"), GUIStyle.SubHeadingFont);
269 DropdownEnum(left, (m) => TextManager.Get($
"{m}"),
null, unsavedConfig.Graphics.DisplayMode, v => unsavedConfig.Graphics.DisplayMode = v);
272 Tickbox(left, TextManager.Get(
"EnableVSync"), TextManager.Get(
"EnableVSyncTooltip"), unsavedConfig.Graphics.VSync, v => unsavedConfig.Graphics.VSync = v);
273 Tickbox(left, TextManager.Get(
"EnableTextureCompression"), TextManager.Get(
"EnableTextureCompressionTooltip"), unsavedConfig.Graphics.CompressTextures, v => unsavedConfig.Graphics.CompressTextures = v);
276 Label(right, TextManager.Get(
"LOSEffect"), GUIStyle.SubHeadingFont);
277 DropdownEnum(right, (m) => TextManager.Get($
"LosMode{m}"),
null, unsavedConfig.Graphics.LosMode, v => unsavedConfig.Graphics.LosMode = v);
280 Label(right, TextManager.Get(
"LightMapScale"), GUIStyle.SubHeadingFont);
281 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"));
284 Label(right, TextManager.Get(
"VisibleLightLimit"), GUIStyle.SubHeadingFont);
285 Slider(right, (10, 510), 21, v => v > 500 ? TextManager.Get(
"unlimited").Value : Round(v).ToString(), unsavedConfig.Graphics.VisibleLightLimit,
286 v => unsavedConfig.Graphics.VisibleLightLimit = v > 500 ?
int.MaxValue : Round(v), TextManager.Get(
"VisibleLightLimitTooltip"));
289 Tickbox(right, TextManager.Get(
"RadialDistortion"), TextManager.Get(
"RadialDistortionTooltip"), unsavedConfig.Graphics.RadialDistortion, v => unsavedConfig.Graphics.RadialDistortion = v);
290 Tickbox(right, TextManager.Get(
"ChromaticAberration"), TextManager.Get(
"ChromaticAberrationTooltip"), unsavedConfig.Graphics.ChromaticAberration, v => unsavedConfig.Graphics.ChromaticAberration = v);
292 Label(right, TextManager.Get(
"ParticleLimit"), GUIStyle.SubHeadingFont);
293 Slider(right, (100, 1500), 15, v => Round(v).ToString(), unsavedConfig.Graphics.ParticleLimit, v => unsavedConfig.Graphics.ParticleLimit = Round(v));
297 private static string TrimAudioDeviceName(
string name)
299 if (
string.IsNullOrWhiteSpace(name)) {
return string.Empty; }
300 string[] prefixes = {
"OpenAL Soft on " };
301 foreach (
string prefix
in prefixes)
303 if (name.StartsWith(prefix, StringComparison.OrdinalIgnoreCase))
305 return name.Remove(0, prefix.Length);
311 private static int HandleAlErrors(
string message)
316 DebugConsole.ThrowError($
"{message}: ALC error {Alc.GetErrorString(alcError)}");
323 DebugConsole.ThrowError($
"{message}: AL error {Al.GetErrorString(alError)}");
330 private static void GetAudioDevices(
int listSpecifier,
int defaultSpecifier, out IReadOnlyList<string> list, ref
string current)
332 list = Array.Empty<
string>();
335 if (HandleAlErrors(
"Alc.GetStringList failed") !=
Al.
NoError) {
return; }
338 if (
string.IsNullOrEmpty(current))
341 if (HandleAlErrors(
"Alc.GetString failed") !=
Al.
NoError) {
return; }
344 string currentVal = current;
345 if (list.Any() && !list.Any(n => n.Equals(currentVal, StringComparison.OrdinalIgnoreCase)))
351 private void CreateAudioAndVCTab()
353 if (GameMain.Client ==
null
356 string currDevice = unsavedConfig.Audio.VoiceCaptureDevice;
359 if (deviceList.Any())
365 unsavedConfig.Audio.VoiceSetting =
VoiceMode.Disabled;
369 GUIFrame content = CreateNewContentFrame(
Tab.AudioAndVC);
371 var (audio, voiceChat) = CreateSidebars(content, split:
true);
373 static void audioDeviceElement(
374 GUILayoutGroup parent,
375 Action<string> setter,
377 int defaultSpecifier,
378 ref
string currentDevice)
387 var deviceNameContainerElement =
new GUIFrame(NewItemRectT(parent), style:
"GUITextBoxNoIcon");
388 var deviceNameElement =
new GUITextBlock(
new RectTransform(Vector2.One, deviceNameContainerElement.RectTransform), currentDevice, textAlignment: Alignment.CenterLeft);
389 new GUICustomComponent(
new RectTransform(Vector2.Zero, deviceNameElement.RectTransform), onUpdate:
390 (deltaTime, component) =>
392 deviceNameElement.Text = Alc.GetString(IntPtr.Zero, listSpecifier);
395 GetAudioDevices(listSpecifier, defaultSpecifier, out var devices, ref currentDevice);
396 Dropdown(parent, v => TrimAudioDeviceName(v),
null, devices, currentDevice, setter);
400 Label(audio, TextManager.Get(
"AudioOutputDevice"), GUIStyle.SubHeadingFont);
402 string currentOutputDevice = unsavedConfig.Audio.AudioOutputDevice;
406 Label(audio, TextManager.Get(
"SoundVolume"), GUIStyle.SubHeadingFont);
407 Slider(audio, (0, 1), 101, Percentage, unsavedConfig.Audio.SoundVolume, v =>
409 unsavedConfig.Audio.SoundVolume = v;
410 GameMain.SoundManager.SetCategoryGainMultiplier(SoundManager.SoundCategoryDefault, v);
411 GameMain.SoundManager.SetCategoryGainMultiplier(SoundManager.SoundCategoryWaterAmbience, v);
414 Label(audio, TextManager.Get(
"MusicVolume"), GUIStyle.SubHeadingFont);
415 Slider(audio, (0, 1), 101, Percentage, unsavedConfig.Audio.MusicVolume, v =>
417 unsavedConfig.Audio.MusicVolume = v;
418 GameMain.SoundManager.SetCategoryGainMultiplier(SoundManager.SoundCategoryMusic, v);
421 Label(audio, TextManager.Get(
"UiSoundVolume"), GUIStyle.SubHeadingFont);
422 Slider(audio, (0, 1), 101, Percentage, unsavedConfig.Audio.UiVolume, v =>
424 unsavedConfig.Audio.UiVolume = v;
425 GameMain.SoundManager.SetCategoryGainMultiplier(SoundManager.SoundCategoryUi, v);
428 Tickbox(audio, TextManager.Get(
"MuteOnFocusLost"), TextManager.Get(
"MuteOnFocusLostTooltip"), unsavedConfig.Audio.MuteOnFocusLost, v => unsavedConfig.Audio.MuteOnFocusLost = v);
429 Tickbox(audio, TextManager.Get(
"DynamicRangeCompression"), TextManager.Get(
"DynamicRangeCompressionTooltip"), unsavedConfig.Audio.DynamicRangeCompressionEnabled, v => unsavedConfig.Audio.DynamicRangeCompressionEnabled = v);
432 Label(audio, TextManager.Get(
"VoiceChatVolume"), GUIStyle.SubHeadingFont);
433 Slider(audio, (0, 2), 201, Percentage, unsavedConfig.Audio.VoiceChatVolume, v =>
435 unsavedConfig.Audio.VoiceChatVolume = v;
436 GameMain.SoundManager.SetCategoryGainMultiplier(SoundManager.SoundCategoryVoip, v);
439 Tickbox(audio, TextManager.Get(
"DirectionalVoiceChat"), TextManager.Get(
"DirectionalVoiceChatTooltip"), unsavedConfig.Audio.UseDirectionalVoiceChat, v => unsavedConfig.Audio.UseDirectionalVoiceChat = v);
440 Tickbox(audio, TextManager.Get(
"VoipAttenuation"), TextManager.Get(
"VoipAttenuationTooltip"), unsavedConfig.Audio.VoipAttenuationEnabled, v => unsavedConfig.Audio.VoipAttenuationEnabled = v);
442 Label(voiceChat, TextManager.Get(
"AudioInputDevice"), GUIStyle.SubHeadingFont);
444 string currentInputDevice = unsavedConfig.Audio.VoiceCaptureDevice;
448 Label(voiceChat, TextManager.Get(
"VCInputMode"), GUIStyle.SubHeadingFont);
449 DropdownEnum(voiceChat, v => TextManager.Get($
"VoiceMode.{v}"), v => TextManager.Get($
"VoiceMode.{v}Tooltip"), unsavedConfig.Audio.VoiceSetting, v => unsavedConfig.Audio.VoiceSetting = v);
452 var noiseGateThresholdLabel = Label(voiceChat, TextManager.Get(
"NoiseGateThreshold"), GUIStyle.SubHeadingFont);
453 var dbMeter =
new GUIProgressBar(NewItemRectT(voiceChat), 0.0f, Color.Lime);
454 dbMeter.ProgressGetter = () =>
458 dbMeter.Color = unsavedConfig.Audio.VoiceSetting
switch
466 return scrollVal * scrollVal;
468 var noiseGateSlider =
new GUIScrollBar(
new RectTransform(Vector2.One, dbMeter.RectTransform,
Anchor.Center), color: Color.White,
469 style:
"GUISlider", barSize: 0.03f);
470 noiseGateSlider.Frame.Visible =
false;
471 noiseGateSlider.Step = 0.01f;
472 noiseGateSlider.Range =
new Vector2(-100.0f, 0.0f);
473 noiseGateSlider.BarScroll = MathUtils.InverseLerp(-100.0f, 0.0f, unsavedConfig.Audio.NoiseGateThreshold);
474 noiseGateSlider.BarScroll *= noiseGateSlider.BarScroll;
475 noiseGateSlider.OnMoved = (scrollBar, barScroll) =>
477 unsavedConfig.Audio.NoiseGateThreshold = MathHelper.Lerp(-100.0f, 0.0f, (
float)Math.Sqrt(scrollBar.BarScroll));
480 new GUICustomComponent(
new RectTransform(Vector2.Zero, voiceChat.RectTransform), onUpdate:
481 (deltaTime, component) =>
483 noiseGateThresholdLabel.Visible = unsavedConfig.Audio.VoiceSetting == VoiceMode.Activity;
484 noiseGateSlider.Visible = unsavedConfig.Audio.VoiceSetting == VoiceMode.Activity;
488 Label(voiceChat, TextManager.Get(
"MicrophoneVolume"), GUIStyle.SubHeadingFont);
489 Slider(voiceChat, (0, 10), 101, Percentage, unsavedConfig.Audio.MicrophoneVolume, v => unsavedConfig.Audio.MicrophoneVolume = v);
492 Label(voiceChat, TextManager.Get(
"CutoffPrevention"), GUIStyle.SubHeadingFont);
493 Slider(voiceChat, (0, 500), 26, v => $
"{Round(v)} ms", unsavedConfig.Audio.VoiceChatCutoffPrevention, v => unsavedConfig.Audio.VoiceChatCutoffPrevention = Round(v), TextManager.Get(
"CutoffPreventionTooltip"));
496 private readonly Dictionary<GUIButton, Func<LocalizedString>> inputButtonValueNameGetters =
new Dictionary<GUIButton, Func<LocalizedString>>();
497 private bool inputBoxSelectedThisFrame =
false;
499 private void CreateControlsTab()
501 GUIFrame content = CreateNewContentFrame(
Tab.Controls);
503 GUILayoutGroup layout = CreateCenterLayout(content);
505 Label(layout, TextManager.Get(
"AimAssist"), GUIStyle.SubHeadingFont);
507 var aimAssistSlider = Slider(layout, (0, 1), 101, Percentage, unsavedConfig.AimAssistAmount, v => unsavedConfig.AimAssistAmount = v, TextManager.Get(
"AimAssistTooltip"));
508 Tickbox(layout, TextManager.Get(
"EnableMouseLook"), TextManager.Get(
"EnableMouseLookTooltip"), unsavedConfig.EnableMouseLook, v => unsavedConfig.EnableMouseLook = v);
512 GUIListBox keyMapList =
513 new GUIListBox(
new RectTransform((2.0f, 0.7f),
514 layout.RectTransform))
516 CanBeFocused =
false,
517 OnSelected = (_, __) =>
false
521 GUILayoutGroup createInputRowLayout()
522 =>
new GUILayoutGroup(
new RectTransform((1.0f, 0.1f), keyMapList.Content.RectTransform), isHorizontal:
true);
524 inputButtonValueNameGetters.Clear();
525 Action<KeyOrMouse>? currentSetter =
null;
526 void addInputToRow(GUILayoutGroup currRow, LocalizedString labelText, Func<LocalizedString> valueNameGetter, Action<KeyOrMouse> valueSetter,
bool isLegacyBind =
false)
528 var inputFrame =
new GUIFrame(
new RectTransform((0.5f, 1.0f), currRow.RectTransform),
532 labelText = TextManager.GetWithVariable(
"legacyitemformat",
"[name]", labelText);
534 var label =
new GUITextBlock(
new RectTransform((0.6f, 1.0f), inputFrame.RectTransform), labelText,
536 var inputBox =
new GUIButton(
537 new RectTransform((0.4f, 1.0f), inputFrame.RectTransform,
Anchor.TopRight,
Pivot.TopRight),
538 valueNameGetter(), style:
"GUITextBoxNoIcon")
540 OnClicked = (btn, obj) =>
542 inputButtonValueNameGetters.Keys.ForEach(b =>
544 if (b != btn) { b.Selected =
false; }
546 bool willBeSelected = !btn.Selected;
549 inputBoxSelectedThisFrame =
true;
553 btn.Text = valueNameGetter();
557 btn.Selected = willBeSelected;
563 label.TextColor = Color.Lerp(label.TextColor, label.DisabledTextColor, 0.5f);
564 inputBox.Color = Color.Lerp(inputBox.Color, inputBox.DisabledColor, 0.5f);
565 inputBox.TextColor = Color.Lerp(inputBox.TextColor, label.DisabledTextColor, 0.5f);
567 inputButtonValueNameGetters.Add(inputBox, valueNameGetter);
570 var inputListener =
new GUICustomComponent(
new RectTransform(Vector2.Zero, layout.RectTransform), onUpdate: (deltaTime, component) =>
572 if (currentSetter is null) { return; }
574 if (PlayerInput.PrimaryMouseButtonClicked() && inputBoxSelectedThisFrame)
576 inputBoxSelectedThisFrame = false;
582 currentSetter =
null;
583 inputButtonValueNameGetters.Keys.ForEach(b => b.Selected =
false);
586 void callSetter(KeyOrMouse v)
588 currentSetter?.Invoke(v);
592 var pressedKeys = PlayerInput.GetKeyboardState.GetPressedKeys();
593 if (pressedKeys?.
Any() ??
false)
595 if (pressedKeys.Contains(Keys.Escape))
601 callSetter(pressedKeys.First());
604 else if (PlayerInput.PrimaryMouseButtonClicked() &&
605 (GUI.MouseOn ==
null || !(GUI.MouseOn is GUIButton) || GUI.MouseOn.IsChildOf(keyMapList.Content)))
609 else if (PlayerInput.SecondaryMouseButtonClicked())
613 else if (PlayerInput.MidButtonClicked())
617 else if (PlayerInput.Mouse4ButtonClicked())
621 else if (PlayerInput.Mouse5ButtonClicked())
625 else if (PlayerInput.MouseWheelUpClicked())
629 else if (PlayerInput.MouseWheelDownClicked())
638 inputTypes.Take(inputTypes.Length - (inputTypes.Length / 2)).ToArray(),
639 inputTypes.TakeLast(inputTypes.Length / 2).ToArray()
641 for (
int i = 0; i < inputTypes.Length; i+=2)
643 var currRow = createInputRowLayout();
644 for (
int j = 0; j < 2; j++)
646 var column = inputTypeColumns[j];
647 if (i / 2 >= column.Length) {
break; }
648 var input = column[i / 2];
651 TextManager.Get($
"InputType.{input}"),
652 () => unsavedConfig.KeyMap.Bindings[input].Name,
653 v => unsavedConfig.KeyMap = unsavedConfig.KeyMap.WithBinding(input, v),
654 LegacyInputTypes.Contains(input));
658 for (
int i = 0; i < unsavedConfig.InventoryKeyMap.Bindings.Length; i += 2)
660 var currRow = createInputRowLayout();
661 for (
int j = 0; j < 2; j++)
663 int currIndex = i + j;
664 if (currIndex >= unsavedConfig.InventoryKeyMap.Bindings.Length) {
break; }
666 var input = unsavedConfig.InventoryKeyMap.Bindings[currIndex];
669 TextManager.GetWithVariable(
"inventoryslotkeybind",
"[slotnumber]", (currIndex + 1).ToString(CultureInfo.InvariantCulture)),
670 () => unsavedConfig.InventoryKeyMap.Bindings[currIndex].Name,
671 v => unsavedConfig.InventoryKeyMap = unsavedConfig.InventoryKeyMap.WithBinding(currIndex, v));
675 GUILayoutGroup resetControlsHolder =
676 new GUILayoutGroup(
new RectTransform((1.75f, 0.1f), layout.RectTransform), isHorizontal:
true, childAnchor:
Anchor.Center)
678 RelativeSpacing = 0.1f
681 var defaultBindingsButton =
682 new GUIButton(
new RectTransform(
new Vector2(0.45f, 1.0f), resetControlsHolder.RectTransform),
683 TextManager.Get(
"Reset"), style:
"GUIButtonSmall")
685 ToolTip = TextManager.Get(
"SetDefaultBindingsTooltip"),
686 OnClicked = (_, userdata) =>
688 unsavedConfig.InventoryKeyMap = GameSettings.Config.InventoryKeyMapping.GetDefault();
689 unsavedConfig.KeyMap = GameSettings.Config.KeyMapping.GetDefault();
690 aimAssistSlider.slider.BarScrollValue = GameSettings.Config.DefaultAimAssist;
691 aimAssistSlider.label.Text = Percentage(GameSettings.Config.DefaultAimAssist);
692 foreach (var btn
in inputButtonValueNameGetters.Keys)
694 btn.Text = inputButtonValueNameGetters[btn]();
702 private void CreateGameplayTab()
704 GUIFrame content = CreateNewContentFrame(Tab.Gameplay);
706 var (leftColumn, rightColumn) = CreateSidebars(content, split:
true);
708 var languages = TextManager.AvailableLanguages
709 .OrderBy(l => TextManager.GetTranslatedLanguageName(l).ToIdentifier())
711 Label(leftColumn, TextManager.Get(
"Language"), GUIStyle.SubHeadingFont);
712 Dropdown(leftColumn, v => TextManager.GetTranslatedLanguageName(v),
null, languages, unsavedConfig.Language, v => unsavedConfig.Language = v);
715 Tickbox(leftColumn, TextManager.Get(
"PauseOnFocusLost"), TextManager.Get(
"PauseOnFocusLostTooltip"), unsavedConfig.PauseOnFocusLost, v => unsavedConfig.PauseOnFocusLost = v);
718 Tickbox(leftColumn, TextManager.Get(
"DisableInGameHints"), TextManager.Get(
"DisableInGameHintsTooltip"), unsavedConfig.DisableInGameHints, v => unsavedConfig.DisableInGameHints = v);
719 var resetInGameHintsButton =
720 new GUIButton(
new RectTransform(
new Vector2(1.0f, 1.0f), leftColumn.RectTransform),
721 TextManager.Get(
"ResetInGameHints"), style:
"GUIButtonSmall")
723 OnClicked = (button, o) =>
725 var msgBox =
new GUIMessageBox(TextManager.Get(
"ResetInGameHints"),
726 TextManager.Get(
"ResetInGameHintsTooltip"),
727 buttons:
new[] { TextManager.Get(
"Yes"), TextManager.Get(
"No") });
728 msgBox.Buttons[0].OnClicked = (guiButton, o1) =>
730 IgnoredHints.Instance.Clear();
734 msgBox.Buttons[1].OnClicked = msgBox.Close;
741 Tickbox(leftColumn, TextManager.Get(
"ChatSpeechBubbles"), TextManager.Get(
"ChatSpeechBubbles.Tooltip"), unsavedConfig.ChatSpeechBubbles, v => unsavedConfig.ChatSpeechBubbles = v);
743 Label(leftColumn, TextManager.Get(
"ShowEnemyHealthBars"), GUIStyle.SubHeadingFont);
744 DropdownEnum(leftColumn, v => TextManager.Get($
"ShowEnemyHealthBars.{v}"),
null, unsavedConfig.ShowEnemyHealthBars, v => unsavedConfig.ShowEnemyHealthBars = v);
746 Label(leftColumn, TextManager.Get(
"InteractionLabels"), GUIStyle.SubHeadingFont);
747 DropdownEnum(leftColumn, v => TextManager.Get($
"InteractionLabels.{v}"),
null, unsavedConfig.InteractionLabelDisplayMode, v => unsavedConfig.InteractionLabelDisplayMode = v);
749 Label(rightColumn, TextManager.Get(
"HUDScale"), GUIStyle.SubHeadingFont);
750 Slider(rightColumn, (0.75f, 1.25f), 51, Percentage, unsavedConfig.Graphics.HUDScale, v => unsavedConfig.Graphics.HUDScale = v);
751 Label(rightColumn, TextManager.Get(
"InventoryScale"), GUIStyle.SubHeadingFont);
752 Slider(rightColumn, (0.75f, 1.25f), 51, Percentage, unsavedConfig.Graphics.InventoryScale, v => unsavedConfig.Graphics.InventoryScale = v);
753 Label(rightColumn, TextManager.Get(
"TextScale"), GUIStyle.SubHeadingFont);
754 Slider(rightColumn, (0.75f, 1.25f), 51, Percentage, unsavedConfig.Graphics.TextScale, v => unsavedConfig.Graphics.TextScale = v);
756 var resetSpamListFilter =
757 new GUIButton(
new RectTransform(
new Vector2(1.0f, 1.0f), rightColumn.RectTransform),
758 TextManager.Get(
"clearserverlistfilters"), style:
"GUIButtonSmall")
760 OnClicked =
static (_, _) =>
762 GUI.AskForConfirmation(
763 header: TextManager.Get(
"clearserverlistfilters"),
764 body: TextManager.Get(
"clearserverlistfiltersconfirmation"),
765 onConfirm: SpamServerFilters.ClearLocalSpamFilter);
772 var statisticsTickBox =
new GUITickBox(NewItemRectT(rightColumn), TextManager.Get(
"statisticsconsenttickbox"))
774 OnSelected = tickBox =>
776 GUIMessageBox? loadingBox =
null;
777 if (!tickBox.Selected)
779 loadingBox = GUIMessageBox.CreateLoadingBox(TextManager.Get(
"PleaseWait"));
781 GameAnalyticsManager.SetConsent(
783 ? GameAnalyticsManager.Consent.Ask
784 : GameAnalyticsManager.Consent.No,
785 onAnswerSent: () => loadingBox?.Close());
790 statisticsTickBox.Enabled =
false;
792 void updateGATickBoxToolTip()
793 => statisticsTickBox.ToolTip = TextManager.Get($
"GameAnalyticsStatus.{GameAnalyticsManager.UserConsented}");
794 updateGATickBoxToolTip();
796 var cachedConsent = GameAnalyticsManager.Consent.Unknown;
797 var statisticsTickBoxUpdater =
new GUICustomComponent(
798 new RectTransform(Vector2.Zero, statisticsTickBox.RectTransform),
799 onUpdate: (deltaTime, component) =>
801 bool shouldTickBoxBeSelected = GameAnalyticsManager.UserConsented == GameAnalyticsManager.Consent.Yes;
803 bool shouldUpdateTickBoxState = cachedConsent != GameAnalyticsManager.UserConsented
804 || statisticsTickBox.Selected != shouldTickBoxBeSelected;
806 if (!shouldUpdateTickBoxState) { return; }
808 updateGATickBoxToolTip();
809 cachedConsent = GameAnalyticsManager.UserConsented;
810 GUITickBox.OnSelectedHandler prevHandler = statisticsTickBox.OnSelected;
811 statisticsTickBox.OnSelected =
null;
812 statisticsTickBox.Selected = shouldTickBoxBeSelected;
813 statisticsTickBox.OnSelected = prevHandler;
814 statisticsTickBox.Enabled &= GameAnalyticsManager.UserConsented != GameAnalyticsManager.Consent.Error;
818 if (SteamManager.IsInitialized)
820 bool shouldCrossplayBeEnabled = unsavedConfig.CrossplayChoice is Eos.EosSteamPrimaryLogin.CrossplayChoice.Enabled;
821 var crossplayTickBox = Tickbox(rightColumn, TextManager.Get(
"EosAllowCrossplay"), TextManager.Get(
"EosAllowCrossplayTooltip"), shouldCrossplayBeEnabled, v =>
823 unsavedConfig.CrossplayChoice = v
824 ? Eos.EosSteamPrimaryLogin.CrossplayChoice.Enabled
825 : Eos.EosSteamPrimaryLogin.CrossplayChoice.Disabled;
827 if (GameMain.NetworkMember !=
null)
829 crossplayTickBox.Enabled =
false;
830 crossplayTickBox.ToolTip = TextManager.Get(
"CantAccessEOSSettingsInMP");
835 private void CreateModsTab(out
WorkshopMenu workshopMenu)
837 GUIFrame content = CreateNewContentFrame(Tab.Mods);
838 content.RectTransform.RelativeSize = Vector2.One;
840 workshopMenu = Screen.Selected is MainMenuScreen
844 GameMain.MainMenuScreen.ResetModUpdateButton();
847 private void CreateBottomButtons()
849 new GUIButton(
new RectTransform(
new Vector2(1.0f, 1.0f), bottom.RectTransform), text: TextManager.Get(
"Cancel"))
851 OnClicked = (btn, obj) =>
854 GameMain.SoundManager?.ApplySettings();
859 new GUIButton(
new RectTransform(
new Vector2(1.0f, 1.0f), bottom.RectTransform), text: TextManager.Get(
"applysettingsbutton"))
861 OnClicked = (btn, obj) =>
863 ApplyInstalledModChanges();
864 mainFrame.Flash(color: GUIStyle.Green);
867 OnAddedToGUIUpdateList = (GUIComponent component) =>
870 CurrentTab != Tab.Mods ||
878 EosSteamPrimaryLogin.HandleCrossplayChoiceChange(unsavedConfig.CrossplayChoice);
879 GameSettings.SetCurrentConfig(unsavedConfig);
882 mutableWorkshopMenu.Apply();
884 GameSettings.SaveCurrentConfig();
893 mainFrame.Parent.RemoveChild(mainFrame);
894 if (Instance ==
this) { Instance =
null; }
896 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)