Unstable 0.17.0.0
This commit is contained in:
@@ -0,0 +1,45 @@
|
||||
#nullable enable
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
using System.Linq;
|
||||
using System.Xml.Linq;
|
||||
using Barotrauma.Extensions;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
public class CompletedTutorials
|
||||
{
|
||||
private readonly HashSet<Identifier> identifiers = new HashSet<Identifier>();
|
||||
|
||||
private CompletedTutorials() { }
|
||||
|
||||
private CompletedTutorials(XElement element)
|
||||
{
|
||||
foreach (XElement subElement in element.Elements())
|
||||
{
|
||||
identifiers.Add(subElement.GetAttributeIdentifier("name", Identifier.Empty));
|
||||
}
|
||||
}
|
||||
|
||||
public static void Init(XElement? element)
|
||||
{
|
||||
if (element is null) { return; }
|
||||
|
||||
Instance = new CompletedTutorials(element);
|
||||
}
|
||||
|
||||
public void SaveTo(XElement element)
|
||||
{
|
||||
identifiers.ForEach(id => new XElement("Tutorial", new XAttribute("name", id.Value)));
|
||||
}
|
||||
|
||||
public bool Contains(Identifier identifier) => identifiers.Contains(identifier);
|
||||
|
||||
public void Add(Identifier identifier) => identifiers.Add(identifier);
|
||||
|
||||
public void Remove(Identifier identifier) => identifiers.Remove(identifier);
|
||||
|
||||
public static CompletedTutorials Instance { get; private set; } = new CompletedTutorials();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
#nullable enable
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Xml.Linq;
|
||||
using Barotrauma.Extensions;
|
||||
|
||||
namespace Barotrauma.ClientSource.Settings
|
||||
{
|
||||
public class DebugConsoleMapping
|
||||
{
|
||||
private readonly Dictionary<KeyOrMouse, string> bindings = new Dictionary<KeyOrMouse, string>();
|
||||
public IReadOnlyDictionary<KeyOrMouse, string> Bindings => bindings;
|
||||
|
||||
private DebugConsoleMapping() { }
|
||||
|
||||
private DebugConsoleMapping(XElement element)
|
||||
{
|
||||
var bindings = new Dictionary<KeyOrMouse, string>();
|
||||
foreach (var subElement in element.Elements())
|
||||
{
|
||||
KeyOrMouse keyOrMouse = subElement.GetAttributeKeyOrMouse("key", MouseButton.None);
|
||||
if (keyOrMouse == MouseButton.None) { continue; }
|
||||
string command = subElement.GetAttributeString("command", "");
|
||||
if (command.IsNullOrWhiteSpace()) { continue; }
|
||||
bindings[keyOrMouse] = command;
|
||||
}
|
||||
|
||||
this.bindings = bindings;
|
||||
}
|
||||
|
||||
public static void Init(XElement? element)
|
||||
{
|
||||
if (element is null) { return; }
|
||||
|
||||
Instance = new DebugConsoleMapping(element);
|
||||
}
|
||||
|
||||
public void SaveTo(XElement element)
|
||||
{
|
||||
Bindings
|
||||
.ForEach(kvp => element.Add(
|
||||
new XElement("Keybind",
|
||||
new XAttribute("key", kvp.Key),
|
||||
new XAttribute("command", kvp.Value))));
|
||||
}
|
||||
|
||||
public void Set(KeyOrMouse key, string command)
|
||||
=> bindings[key] = command;
|
||||
|
||||
public void Remove(KeyOrMouse key)
|
||||
=> bindings.Remove(key);
|
||||
|
||||
public static DebugConsoleMapping Instance { get; private set; } = new DebugConsoleMapping();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
#nullable enable
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
using System.Linq;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
public class IgnoredHints
|
||||
{
|
||||
private readonly HashSet<Identifier> identifiers = new HashSet<Identifier>();
|
||||
|
||||
private IgnoredHints() { }
|
||||
|
||||
private IgnoredHints(XElement element)
|
||||
{
|
||||
identifiers = element.GetAttributeIdentifierArray("identifiers", Array.Empty<Identifier>())
|
||||
.ToHashSet();
|
||||
}
|
||||
|
||||
public static void Init(XElement? element)
|
||||
{
|
||||
if (element is null) { return; }
|
||||
|
||||
Instance = new IgnoredHints(element);
|
||||
}
|
||||
|
||||
public void SaveTo(XElement element)
|
||||
{
|
||||
element.SetAttributeValue("identifiers", string.Join(",", identifiers));
|
||||
}
|
||||
|
||||
public bool Contains(Identifier identifier) => identifiers.Contains(identifier);
|
||||
|
||||
public void Add(Identifier identifier) => identifiers.Add(identifier);
|
||||
|
||||
public void Remove(Identifier identifier) => identifiers.Remove(identifier);
|
||||
|
||||
public static IgnoredHints Instance { get; private set; } = new IgnoredHints();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,112 @@
|
||||
#nullable enable
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Xml.Linq;
|
||||
using Barotrauma.Extensions;
|
||||
using Microsoft.Xna.Framework;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
class MultiplayerPreferences
|
||||
{
|
||||
public readonly struct JobPreference
|
||||
{
|
||||
public JobPreference(Identifier jobIdentifier, int variant)
|
||||
{
|
||||
JobIdentifier = jobIdentifier;
|
||||
Variant = variant;
|
||||
}
|
||||
|
||||
public JobPreference(XElement element) : this(
|
||||
element.GetAttributeIdentifier("identifier", Identifier.Empty),
|
||||
element.GetAttributeInt("variant", -1)) { }
|
||||
|
||||
public readonly Identifier JobIdentifier;
|
||||
public readonly int Variant;
|
||||
|
||||
public static bool operator ==(JobPreference a, JobPreference b)
|
||||
=> a.JobIdentifier == b.JobIdentifier && a.Variant == b.Variant;
|
||||
|
||||
public static bool operator !=(JobPreference a, JobPreference b) => !(a == b);
|
||||
|
||||
public override bool Equals(object? obj)
|
||||
=> obj is JobPreference jp && jp == this;
|
||||
|
||||
public bool Equals(JobPreference other) => other == this;
|
||||
|
||||
public override int GetHashCode() => HashCode.Combine(JobIdentifier, Variant);
|
||||
}
|
||||
|
||||
public readonly List<JobPreference> JobPreferences = new List<JobPreference>();
|
||||
public CharacterTeamType TeamPreference;
|
||||
public string PlayerName = string.Empty;
|
||||
|
||||
public readonly HashSet<Identifier> TagSet = new HashSet<Identifier>();
|
||||
public int HairIndex = -1;
|
||||
public int BeardIndex = -1;
|
||||
public int MoustacheIndex = -1;
|
||||
public int FaceAttachmentIndex = -1;
|
||||
public Color HairColor = Color.Black;
|
||||
public Color FacialHairColor = Color.Black;
|
||||
public Color SkinColor = Color.Black;
|
||||
|
||||
public static MultiplayerPreferences Instance { get; private set; } = new MultiplayerPreferences();
|
||||
|
||||
private MultiplayerPreferences() { }
|
||||
|
||||
private MultiplayerPreferences(IEnumerable<XElement> elements)
|
||||
{
|
||||
foreach (var element in elements)
|
||||
{
|
||||
PlayerName = element.GetAttributeString("name", PlayerName);
|
||||
|
||||
TagSet.UnionWith(element.GetAttributeIdentifierArray("tags", Array.Empty<Identifier>()));
|
||||
HairIndex = element.GetAttributeInt(nameof(HairIndex), HairIndex);
|
||||
BeardIndex = element.GetAttributeInt(nameof(BeardIndex), BeardIndex);
|
||||
MoustacheIndex = element.GetAttributeInt(nameof(MoustacheIndex), MoustacheIndex);
|
||||
FaceAttachmentIndex = element.GetAttributeInt(nameof(FaceAttachmentIndex), FaceAttachmentIndex);
|
||||
|
||||
HairColor = element.GetAttributeColor(nameof(HairColor), HairColor);
|
||||
FacialHairColor = element.GetAttributeColor(nameof(FacialHairColor), FacialHairColor);
|
||||
SkinColor = element.GetAttributeColor(nameof(SkinColor), SkinColor);
|
||||
|
||||
foreach (var subElement in element.GetChildElements("job"))
|
||||
{
|
||||
JobPreferences.Add(new JobPreference(subElement));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void Init(params XElement?[] elements)
|
||||
{
|
||||
Instance = new MultiplayerPreferences(elements.Where(e => e != null)!);
|
||||
}
|
||||
|
||||
public void SaveTo(XElement element)
|
||||
{
|
||||
element.SetAttributeValue("name", PlayerName);
|
||||
|
||||
element.SetAttributeValue("tags", string.Join(",", TagSet));
|
||||
element.SetAttributeValue(nameof(HairIndex), HairIndex);
|
||||
element.SetAttributeValue(nameof(BeardIndex), BeardIndex);
|
||||
element.SetAttributeValue(nameof(MoustacheIndex), MoustacheIndex);
|
||||
element.SetAttributeValue(nameof(FaceAttachmentIndex), FaceAttachmentIndex);
|
||||
|
||||
element.SetAttributeValue(nameof(HairColor), HairColor.ToStringHex());
|
||||
element.SetAttributeValue(nameof(FacialHairColor), FacialHairColor.ToStringHex());
|
||||
element.SetAttributeValue(nameof(SkinColor), SkinColor.ToStringHex());
|
||||
|
||||
foreach (var jobPreference in JobPreferences)
|
||||
{
|
||||
element.Add(new XElement("job",
|
||||
new XAttribute("identifier", jobPreference.JobIdentifier.Value),
|
||||
new XAttribute("variant", jobPreference.Variant.ToString(CultureInfo.InvariantCulture))));
|
||||
}
|
||||
}
|
||||
|
||||
public bool AreJobPreferencesEqual(IReadOnlyList<JobPreference> other)
|
||||
=> JobPreferences.SequenceEqual(other);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
#nullable enable
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
#warning TODO: implement properly
|
||||
public class ServerListFilters
|
||||
{
|
||||
private readonly Dictionary<Identifier, string> attributes = new Dictionary<Identifier, string>();
|
||||
|
||||
private ServerListFilters() { }
|
||||
|
||||
private ServerListFilters(XElement elem)
|
||||
{
|
||||
if (elem == null) { return; }
|
||||
foreach (var attr in elem.Attributes())
|
||||
{
|
||||
attributes.Add(attr.NameAsIdentifier(), attr.Value);
|
||||
}
|
||||
}
|
||||
|
||||
public static void Init(XElement? elem)
|
||||
{
|
||||
if (elem is null) { return; }
|
||||
|
||||
Instance = new ServerListFilters(elem);
|
||||
}
|
||||
|
||||
public void SaveTo(XElement elem)
|
||||
{
|
||||
foreach (var kvp in attributes)
|
||||
{
|
||||
elem.Add(new XAttribute(kvp.Key.Value, kvp.Value));
|
||||
}
|
||||
}
|
||||
|
||||
public bool GetAttributeBool(Identifier key, bool def)
|
||||
{
|
||||
if (attributes.TryGetValue(key, out string? val))
|
||||
{
|
||||
if (bool.TryParse(val, out bool result)) { return result; }
|
||||
}
|
||||
|
||||
return def;
|
||||
}
|
||||
|
||||
public T GetAttributeEnum<T>(Identifier key, T def) where T : struct, Enum
|
||||
{
|
||||
if (attributes.TryGetValue(key, out string? val))
|
||||
{
|
||||
if (Enum.TryParse(val, out T result)) { return result; }
|
||||
}
|
||||
|
||||
return def;
|
||||
}
|
||||
|
||||
public void SetAttribute(Identifier key, string val)
|
||||
{
|
||||
attributes[key] = val;
|
||||
}
|
||||
|
||||
public static ServerListFilters Instance { get; private set; } = new ServerListFilters();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,752 @@
|
||||
#nullable enable
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using Barotrauma.Extensions;
|
||||
using Barotrauma.Networking;
|
||||
using Barotrauma.Steam;
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
using Microsoft.Xna.Framework.Input;
|
||||
using OpenAL;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
public class SettingsMenu
|
||||
{
|
||||
public static SettingsMenu? Instance { get; private set; }
|
||||
|
||||
public enum Tab
|
||||
{
|
||||
Graphics,
|
||||
AudioAndVC,
|
||||
Controls,
|
||||
Gameplay,
|
||||
Mods
|
||||
}
|
||||
|
||||
private GameSettings.Config unsavedConfig;
|
||||
|
||||
private readonly GUIFrame mainFrame;
|
||||
|
||||
private readonly GUILayoutGroup tabber;
|
||||
private readonly GUIFrame contentFrame;
|
||||
private readonly GUILayoutGroup bottom;
|
||||
|
||||
public readonly WorkshopMenu WorkshopMenu;
|
||||
|
||||
public static SettingsMenu Create(RectTransform mainParent)
|
||||
{
|
||||
Instance?.Close();
|
||||
Instance = new SettingsMenu(mainParent);
|
||||
return Instance;
|
||||
}
|
||||
|
||||
private SettingsMenu(RectTransform mainParent)
|
||||
{
|
||||
unsavedConfig = GameSettings.CurrentConfig;
|
||||
|
||||
mainFrame = new GUIFrame(new RectTransform(Vector2.One, mainParent));
|
||||
|
||||
var mainLayout = new GUILayoutGroup(new RectTransform(Vector2.One * 0.95f, mainFrame.RectTransform, Anchor.Center, Pivot.Center),
|
||||
isHorizontal: false, childAnchor: Anchor.TopRight);
|
||||
|
||||
new GUITextBlock(new RectTransform((1.0f, 0.07f), mainLayout.RectTransform), TextManager.Get("Settings"),
|
||||
font: GUIStyle.LargeFont);
|
||||
|
||||
var tabberAndContentLayout = new GUILayoutGroup(new RectTransform((1.0f, 0.86f), mainLayout.RectTransform),
|
||||
isHorizontal: true);
|
||||
|
||||
void tabberPadding()
|
||||
=> new GUIFrame(new RectTransform((0.01f, 1.0f), tabberAndContentLayout.RectTransform), style: null);
|
||||
|
||||
tabberPadding();
|
||||
tabber = new GUILayoutGroup(new RectTransform((0.06f, 1.0f), tabberAndContentLayout.RectTransform), isHorizontal: false) { AbsoluteSpacing = GUI.IntScale(5f) };
|
||||
tabberPadding();
|
||||
tabContents = new Dictionary<Tab, (GUIButton Button, GUIFrame Content)>();
|
||||
|
||||
contentFrame = new GUIFrame(new RectTransform((0.92f, 1.0f), tabberAndContentLayout.RectTransform),
|
||||
style: "InnerFrame");
|
||||
|
||||
bottom = new GUILayoutGroup(new RectTransform((contentFrame.RectTransform.RelativeSize.X, 0.04f), mainLayout.RectTransform), isHorizontal: true) { Stretch = true, RelativeSpacing = 0.01f };
|
||||
|
||||
CreateGraphicsTab();
|
||||
CreateAudioAndVCTab();
|
||||
CreateControlsTab();
|
||||
CreateGameplayTab();
|
||||
CreateModsTab(out WorkshopMenu);
|
||||
|
||||
CreateBottomButtons();
|
||||
|
||||
SelectTab(Tab.Graphics);
|
||||
|
||||
tabber.Recalculate();
|
||||
}
|
||||
|
||||
private void SwitchContent(GUIFrame newContent)
|
||||
{
|
||||
contentFrame.Children.ForEach(c => c.Visible = false);
|
||||
newContent.Visible = true;
|
||||
}
|
||||
|
||||
private readonly Dictionary<Tab, (GUIButton Button, GUIFrame Content)> tabContents;
|
||||
|
||||
public void SelectTab(Tab tab)
|
||||
{
|
||||
SwitchContent(tabContents[tab].Content);
|
||||
tabber.Children.ForEach(c =>
|
||||
{
|
||||
if (c is GUIButton btn) { btn.Selected = btn == tabContents[tab].Button; }
|
||||
});
|
||||
}
|
||||
|
||||
private void AddButtonToTabber(Tab tab, GUIFrame content)
|
||||
{
|
||||
var button = new GUIButton(new RectTransform(Vector2.One, tabber.RectTransform, Anchor.TopLeft, Pivot.TopLeft, scaleBasis: ScaleBasis.Smallest), "", style: $"SettingsMenuTab.{tab}")
|
||||
{
|
||||
ToolTip = TextManager.Get($"SettingsTab.{tab}"),
|
||||
OnClicked = (b, _) =>
|
||||
{
|
||||
SelectTab(tab);
|
||||
return false;
|
||||
}
|
||||
};
|
||||
button.RectTransform.MaxSize = RectTransform.MaxPoint;
|
||||
button.Children.ForEach(c => c.RectTransform.MaxSize = RectTransform.MaxPoint);
|
||||
|
||||
tabContents.Add(tab, (button, content));
|
||||
}
|
||||
|
||||
private GUIFrame CreateNewContentFrame(Tab tab)
|
||||
{
|
||||
var content = new GUIFrame(new RectTransform(Vector2.One * 0.95f, contentFrame.RectTransform, Anchor.Center, Pivot.Center), style: null);
|
||||
AddButtonToTabber(tab, content);
|
||||
return content;
|
||||
}
|
||||
|
||||
private static (GUILayoutGroup Left, GUILayoutGroup Right) CreateSidebars(GUIFrame parent, bool split = false)
|
||||
{
|
||||
GUILayoutGroup layout = new GUILayoutGroup(new RectTransform(Vector2.One, parent.RectTransform), isHorizontal: true);
|
||||
GUILayoutGroup left = new GUILayoutGroup(new RectTransform((0.4875f, 1.0f), layout.RectTransform), isHorizontal: false);
|
||||
var centerFrame = new GUIFrame(new RectTransform((0.025f, 1.0f), layout.RectTransform), style: null);
|
||||
if (split)
|
||||
{
|
||||
new GUICustomComponent(new RectTransform(Vector2.One, centerFrame.RectTransform),
|
||||
onDraw: (sb, c) =>
|
||||
{
|
||||
sb.DrawLine((c.Rect.Center.X, c.Rect.Top),(c.Rect.Center.X, c.Rect.Bottom), GUIStyle.TextColorDim, 2f);
|
||||
});
|
||||
}
|
||||
GUILayoutGroup right = new GUILayoutGroup(new RectTransform((0.4875f, 1.0f), layout.RectTransform), isHorizontal: false);
|
||||
return (left, right);
|
||||
}
|
||||
|
||||
private static GUILayoutGroup CreateCenterLayout(GUIFrame parent)
|
||||
{
|
||||
return new GUILayoutGroup(new RectTransform((0.5f, 1.0f), parent.RectTransform, Anchor.TopCenter, Pivot.TopCenter)) { ChildAnchor = Anchor.TopCenter };
|
||||
}
|
||||
|
||||
private static RectTransform NewItemRectT(GUILayoutGroup parent)
|
||||
=> new RectTransform((1.0f, 0.06f), parent.RectTransform, Anchor.CenterLeft);
|
||||
|
||||
private static void Spacer(GUILayoutGroup parent)
|
||||
{
|
||||
new GUIFrame(new RectTransform((1.0f, 0.03f), parent.RectTransform, Anchor.CenterLeft), style: null);
|
||||
}
|
||||
|
||||
private static GUITextBlock Label(GUILayoutGroup parent, LocalizedString str, GUIFont font)
|
||||
{
|
||||
return new GUITextBlock(NewItemRectT(parent), str, font: font);
|
||||
}
|
||||
|
||||
private static void DropdownEnum<T>(GUILayoutGroup parent, Func<T, LocalizedString> textFunc, Func<T, LocalizedString>? tooltipFunc, T currentValue,
|
||||
Action<T> setter) where T : Enum
|
||||
=> Dropdown(parent, textFunc, tooltipFunc, (T[])Enum.GetValues(typeof(T)), currentValue, setter);
|
||||
|
||||
private static void Dropdown<T>(GUILayoutGroup parent, Func<T, LocalizedString> textFunc, Func<T, LocalizedString>? tooltipFunc, IReadOnlyList<T> values, T currentValue, Action<T> setter)
|
||||
{
|
||||
var dropdown = new GUIDropDown(NewItemRectT(parent));
|
||||
values.ForEach(v => dropdown.AddItem(text: textFunc(v), userData: v, toolTip: tooltipFunc?.Invoke(v) ?? null));
|
||||
dropdown.Select(values.IndexOf(currentValue));
|
||||
dropdown.OnSelected = (dd, obj) =>
|
||||
{
|
||||
setter((T)obj);
|
||||
return true;
|
||||
};
|
||||
}
|
||||
|
||||
private void Slider(GUILayoutGroup parent, Vector2 range, int steps, Func<float, string> labelFunc, float currentValue, Action<float> setter, LocalizedString? tooltip = null)
|
||||
{
|
||||
var layout = new GUILayoutGroup(NewItemRectT(parent), isHorizontal: true);
|
||||
var slider = new GUIScrollBar(new RectTransform((0.82f, 1.0f), layout.RectTransform), style: "GUISlider")
|
||||
{
|
||||
Range = range,
|
||||
BarScrollValue = currentValue,
|
||||
Step = 1.0f / (float)(steps - 1),
|
||||
BarSize = 1.0f / steps
|
||||
};
|
||||
if (tooltip != null)
|
||||
{
|
||||
slider.ToolTip = tooltip;
|
||||
}
|
||||
var label = new GUITextBlock(new RectTransform((0.18f, 1.0f), layout.RectTransform),
|
||||
labelFunc(currentValue), wrap: false, textAlignment: Alignment.Center);
|
||||
slider.OnMoved = (sb, val) =>
|
||||
{
|
||||
label.Text = labelFunc(sb.BarScrollValue);
|
||||
setter(sb.BarScrollValue);
|
||||
return true;
|
||||
};
|
||||
}
|
||||
|
||||
private void Tickbox(GUILayoutGroup parent, LocalizedString label, LocalizedString tooltip, bool currentValue, Action<bool> setter)
|
||||
{
|
||||
var tickbox = new GUITickBox(NewItemRectT(parent), label)
|
||||
{
|
||||
Selected = currentValue,
|
||||
ToolTip = tooltip,
|
||||
OnSelected = (tb) =>
|
||||
{
|
||||
setter(tb.Selected);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private string ScaleResolution(float scale) =>
|
||||
$"{Round(unsavedConfig.Graphics.Width * scale)}\nx\n{Round(unsavedConfig.Graphics.Height * scale)}";
|
||||
|
||||
private string Percentage(float v) => $"{Round(v * 100)}%";
|
||||
|
||||
private int Round(float v) => (int)MathF.Round(v);
|
||||
|
||||
private void CreateGraphicsTab()
|
||||
{
|
||||
GUIFrame content = CreateNewContentFrame(Tab.Graphics);
|
||||
|
||||
var (left, right) = CreateSidebars(content);
|
||||
|
||||
List<(int Width, int Height)> supportedResolutions =
|
||||
GameMain.GraphicsDeviceManager.GraphicsDevice.Adapter.SupportedDisplayModes
|
||||
.Where(m => m.Format == SurfaceFormat.Color)
|
||||
.Select(m => (m.Width, m.Height))
|
||||
.ToList();
|
||||
var currentResolution = (unsavedConfig.Graphics.Width, unsavedConfig.Graphics.Height);
|
||||
if (!supportedResolutions.Contains(currentResolution))
|
||||
{
|
||||
supportedResolutions.Add(currentResolution);
|
||||
}
|
||||
|
||||
Label(left, TextManager.Get("Resolution"), GUIStyle.SubHeadingFont);
|
||||
Dropdown(left, (m) => $"{m.Width}x{m.Height}", null, supportedResolutions, currentResolution,
|
||||
(res) =>
|
||||
{
|
||||
unsavedConfig.Graphics.Width = res.Width;
|
||||
unsavedConfig.Graphics.Height = res.Height;
|
||||
});
|
||||
Spacer(left);
|
||||
|
||||
Label(left, TextManager.Get("DisplayMode"), GUIStyle.SubHeadingFont);
|
||||
DropdownEnum(left, (m) => TextManager.Get($"{m}"), null, unsavedConfig.Graphics.DisplayMode, (v) => unsavedConfig.Graphics.DisplayMode = v);
|
||||
Spacer(left);
|
||||
|
||||
Tickbox(left, TextManager.Get("EnableVSync"), TextManager.Get("EnableVSyncTooltip"), unsavedConfig.Graphics.VSync, (v) => unsavedConfig.Graphics.VSync = v);
|
||||
Tickbox(left, TextManager.Get("EnableTextureCompression"), TextManager.Get("EnableTextureCompressionTooltip"), unsavedConfig.Graphics.CompressTextures, (v) => unsavedConfig.Graphics.CompressTextures = v);
|
||||
|
||||
Label(right, TextManager.Get("ParticleLimit"), GUIStyle.SubHeadingFont);
|
||||
Slider(right, (100, 1500), 15, (v) => Round(v).ToString(), unsavedConfig.Graphics.ParticleLimit, (v) => unsavedConfig.Graphics.ParticleLimit = Round(v));
|
||||
Spacer(right);
|
||||
|
||||
Label(right, TextManager.Get("LOSEffect"), GUIStyle.SubHeadingFont);
|
||||
DropdownEnum(right, (m) => TextManager.Get($"LosMode{m}"), null, unsavedConfig.Graphics.LosMode, (v) => unsavedConfig.Graphics.LosMode = v);
|
||||
Spacer(right);
|
||||
|
||||
Label(right, TextManager.Get("LightMapScale"), GUIStyle.SubHeadingFont);
|
||||
Slider(right, (0.5f, 1.0f), 10, ScaleResolution, unsavedConfig.Graphics.LightMapScale, (v) => unsavedConfig.Graphics.LightMapScale = v, TextManager.Get("LightMapScaleTooltip"));
|
||||
Spacer(right);
|
||||
|
||||
Tickbox(right, TextManager.Get("RadialDistortion"), TextManager.Get("RadialDistortionTooltip"), unsavedConfig.Graphics.RadialDistortion, (v) => unsavedConfig.Graphics.RadialDistortion = v);
|
||||
Tickbox(right, TextManager.Get("ChromaticAberration"), TextManager.Get("ChromaticAberrationTooltip"), unsavedConfig.Graphics.ChromaticAberration, (v) => unsavedConfig.Graphics.ChromaticAberration = v);
|
||||
}
|
||||
|
||||
private static string TrimAudioDeviceName(string name)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(name)) { return string.Empty; }
|
||||
string[] prefixes = { "OpenAL Soft on " };
|
||||
foreach (string prefix in prefixes)
|
||||
{
|
||||
if (name.StartsWith(prefix, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return name.Remove(0, prefix.Length);
|
||||
}
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
private static int HandleAlErrors(string message)
|
||||
{
|
||||
int alcError = Alc.GetError(IntPtr.Zero);
|
||||
if (alcError != Alc.NoError)
|
||||
{
|
||||
DebugConsole.ThrowError($"{message}: ALC error {Alc.GetErrorString(alcError)}");
|
||||
return alcError;
|
||||
}
|
||||
|
||||
int alError = Al.GetError();
|
||||
if (alError != Al.NoError)
|
||||
{
|
||||
DebugConsole.ThrowError($"{message}: AL error {Al.GetErrorString(alError)}");
|
||||
return alError;
|
||||
}
|
||||
|
||||
return Al.NoError;
|
||||
}
|
||||
|
||||
private static void GetAudioDevices(int listSpecifier, int defaultSpecifier, out IReadOnlyList<string> list, ref string current)
|
||||
{
|
||||
list = Array.Empty<string>();
|
||||
|
||||
var retVal = Alc.GetStringList(IntPtr.Zero, listSpecifier).ToList();
|
||||
if (HandleAlErrors("Alc.GetStringList failed") != Al.NoError) { return; }
|
||||
|
||||
list = retVal;
|
||||
if (string.IsNullOrEmpty(current))
|
||||
{
|
||||
current = Alc.GetString(IntPtr.Zero, defaultSpecifier);
|
||||
if (HandleAlErrors("Alc.GetString failed") != Al.NoError) { return; }
|
||||
}
|
||||
|
||||
string currentVal = current;
|
||||
if (list.Any() && !list.Any(n => n.Equals(currentVal, StringComparison.OrdinalIgnoreCase)))
|
||||
{
|
||||
current = list[0];
|
||||
}
|
||||
}
|
||||
|
||||
private void CreateAudioAndVCTab()
|
||||
{
|
||||
if (GameMain.Client == null
|
||||
&& VoipCapture.Instance == null)
|
||||
{
|
||||
string currDevice = unsavedConfig.Audio.VoiceCaptureDevice;
|
||||
GetAudioDevices(Alc.CaptureDeviceSpecifier, Alc.CaptureDefaultDeviceSpecifier, out var deviceList, ref currDevice);
|
||||
|
||||
if (deviceList.Any())
|
||||
{
|
||||
VoipCapture.Create(unsavedConfig.Audio.VoiceCaptureDevice);
|
||||
}
|
||||
if (VoipCapture.Instance == null)
|
||||
{
|
||||
unsavedConfig.Audio.VoiceSetting = VoiceMode.Disabled;
|
||||
}
|
||||
}
|
||||
|
||||
GUIFrame content = CreateNewContentFrame(Tab.AudioAndVC);
|
||||
|
||||
var (audio, voiceChat) = CreateSidebars(content, split: true);
|
||||
|
||||
static void audioDeviceElement(
|
||||
GUILayoutGroup parent,
|
||||
Action<string> setter,
|
||||
int listSpecifier,
|
||||
int defaultSpecifier,
|
||||
ref string currentDevice)
|
||||
{
|
||||
#if OSX
|
||||
//At the time of writing there are no OpenAL implementations
|
||||
//on macOS that return the list of available devices, or
|
||||
//allow selecting any other than the default one. I'm not
|
||||
//about to write my own OpenAL implementation to fix this
|
||||
//so here's a workaround instead, just a label that shows the
|
||||
//name of the current device.
|
||||
var deviceNameContainerElement = new GUIFrame(NewItemRectT(parent), style: "GUITextBoxNoIcon");
|
||||
var deviceNameElement = new GUITextBlock(new RectTransform(Vector2.One, deviceNameContainerElement.RectTransform), currentDevice, textAlignment: Alignment.CenterLeft);
|
||||
new GUICustomComponent(new RectTransform(Vector2.Zero, deviceNameElement.RectTransform), onUpdate:
|
||||
(deltaTime, component) =>
|
||||
{
|
||||
deviceNameElement.Text = Alc.GetString(IntPtr.Zero, listSpecifier);
|
||||
});
|
||||
#else
|
||||
GetAudioDevices(listSpecifier, defaultSpecifier, out var devices, ref currentDevice);
|
||||
Dropdown(parent, v => TrimAudioDeviceName(v), null, devices, currentDevice, setter);
|
||||
#endif
|
||||
}
|
||||
|
||||
Label(audio, TextManager.Get("AudioOutputDevice"), GUIStyle.SubHeadingFont);
|
||||
|
||||
string currentOutputDevice = unsavedConfig.Audio.AudioOutputDevice;
|
||||
audioDeviceElement(audio, v => unsavedConfig.Audio.AudioOutputDevice = v, Alc.OutputDevicesSpecifier, Alc.DefaultDeviceSpecifier, ref currentOutputDevice);
|
||||
Spacer(audio);
|
||||
|
||||
Label(audio, TextManager.Get("SoundVolume"), GUIStyle.SubHeadingFont);
|
||||
Slider(audio, (0, 1), 101, Percentage, unsavedConfig.Audio.SoundVolume, (v) => unsavedConfig.Audio.SoundVolume = v);
|
||||
|
||||
Label(audio, TextManager.Get("MusicVolume"), GUIStyle.SubHeadingFont);
|
||||
Slider(audio, (0, 1), 101, Percentage, unsavedConfig.Audio.MusicVolume, (v) => unsavedConfig.Audio.MusicVolume = v);
|
||||
|
||||
Tickbox(audio, TextManager.Get("MuteOnFocusLost"), TextManager.Get("MuteOnFocusLostTooltip"), unsavedConfig.Audio.MuteOnFocusLost, (v) => unsavedConfig.Audio.MuteOnFocusLost = v);
|
||||
Tickbox(audio, TextManager.Get("DynamicRangeCompression"), TextManager.Get("DynamicRangeCompressionTooltip"), unsavedConfig.Audio.DynamicRangeCompressionEnabled, (v) => unsavedConfig.Audio.DynamicRangeCompressionEnabled = v);
|
||||
Spacer(audio);
|
||||
|
||||
Label(audio, TextManager.Get("VoiceChatVolume"), GUIStyle.SubHeadingFont);
|
||||
Slider(audio, (0, 2), 201, Percentage, unsavedConfig.Audio.VoiceChatVolume, (v) => unsavedConfig.Audio.VoiceChatVolume = v);
|
||||
|
||||
Tickbox(audio, TextManager.Get("DirectionalVoiceChat"), TextManager.Get("DirectionalVoiceChatTooltip"), unsavedConfig.Audio.UseDirectionalVoiceChat, (v) => unsavedConfig.Audio.UseDirectionalVoiceChat = v);
|
||||
Tickbox(audio, TextManager.Get("VoipAttenuation"), TextManager.Get("VoipAttenuationTooltip"), unsavedConfig.Audio.VoipAttenuationEnabled, (v) => unsavedConfig.Audio.VoipAttenuationEnabled = v);
|
||||
|
||||
Label(voiceChat, TextManager.Get("AudioInputDevice"), GUIStyle.SubHeadingFont);
|
||||
|
||||
string currentInputDevice = unsavedConfig.Audio.VoiceCaptureDevice;
|
||||
audioDeviceElement(voiceChat, v => unsavedConfig.Audio.VoiceCaptureDevice = v, Alc.CaptureDeviceSpecifier, Alc.CaptureDefaultDeviceSpecifier, ref currentInputDevice);
|
||||
Spacer(voiceChat);
|
||||
|
||||
Label(voiceChat, TextManager.Get("VCInputMode"), GUIStyle.SubHeadingFont);
|
||||
DropdownEnum(voiceChat, (v) => TextManager.Get($"VoiceMode.{v}"), (v) => TextManager.Get($"VoiceMode.{v}Tooltip"), unsavedConfig.Audio.VoiceSetting, (v) => unsavedConfig.Audio.VoiceSetting = v);
|
||||
Spacer(voiceChat);
|
||||
|
||||
var noiseGateThresholdLabel = Label(voiceChat, TextManager.Get("NoiseGateThreshold"), GUIStyle.SubHeadingFont);
|
||||
var dbMeter = new GUIProgressBar(NewItemRectT(voiceChat), 0.0f, Color.Lime);
|
||||
dbMeter.ProgressGetter = () =>
|
||||
{
|
||||
if (VoipCapture.Instance == null) { return 0.0f; }
|
||||
|
||||
dbMeter.Color = unsavedConfig.Audio.VoiceSetting switch
|
||||
{
|
||||
VoiceMode.Activity => VoipCapture.Instance.LastdB > unsavedConfig.Audio.NoiseGateThreshold ? GUIStyle.Green : GUIStyle.Orange,
|
||||
VoiceMode.PushToTalk => GUIStyle.Green,
|
||||
VoiceMode.Disabled => Color.LightGray
|
||||
};
|
||||
|
||||
float scrollVal = double.IsNegativeInfinity(VoipCapture.Instance.LastdB) ? 0.0f : ((float)VoipCapture.Instance.LastdB + 100.0f) / 100.0f;
|
||||
return scrollVal * scrollVal;
|
||||
};
|
||||
var noiseGateSlider = new GUIScrollBar(new RectTransform(Vector2.One, dbMeter.RectTransform, Anchor.Center), color: Color.White,
|
||||
style: "GUISlider", barSize: 0.03f);
|
||||
noiseGateSlider.Frame.Visible = false;
|
||||
noiseGateSlider.Step = 0.01f;
|
||||
noiseGateSlider.Range = new Vector2(-100.0f, 0.0f);
|
||||
noiseGateSlider.BarScroll = MathUtils.InverseLerp(-100.0f, 0.0f, unsavedConfig.Audio.NoiseGateThreshold);
|
||||
noiseGateSlider.BarScroll *= noiseGateSlider.BarScroll;
|
||||
noiseGateSlider.OnMoved = (scrollBar, barScroll) =>
|
||||
{
|
||||
unsavedConfig.Audio.NoiseGateThreshold = MathHelper.Lerp(-100.0f, 0.0f, (float)Math.Sqrt(scrollBar.BarScroll));
|
||||
return true;
|
||||
};
|
||||
new GUICustomComponent(new RectTransform(Vector2.Zero, voiceChat.RectTransform), onUpdate:
|
||||
(deltaTime, component) =>
|
||||
{
|
||||
noiseGateThresholdLabel.Visible = unsavedConfig.Audio.VoiceSetting == VoiceMode.Activity;
|
||||
noiseGateSlider.Visible = unsavedConfig.Audio.VoiceSetting == VoiceMode.Activity;
|
||||
});
|
||||
Spacer(voiceChat);
|
||||
|
||||
Label(voiceChat, TextManager.Get("MicrophoneVolume"), GUIStyle.SubHeadingFont);
|
||||
Slider(voiceChat, (0, 10), 101, Percentage, unsavedConfig.Audio.MicrophoneVolume, (v) => unsavedConfig.Audio.MicrophoneVolume = v);
|
||||
Spacer(voiceChat);
|
||||
|
||||
Label(voiceChat, TextManager.Get("CutoffPrevention"), GUIStyle.SubHeadingFont);
|
||||
Slider(voiceChat, (0, 500), 26, (v) => $"{Round(v)} ms", unsavedConfig.Audio.VoiceChatCutoffPrevention, (v) => unsavedConfig.Audio.VoiceChatCutoffPrevention = Round(v), TextManager.Get("CutoffPreventionTooltip"));
|
||||
}
|
||||
|
||||
private void CreateControlsTab()
|
||||
{
|
||||
GUIFrame content = CreateNewContentFrame(Tab.Controls);
|
||||
|
||||
GUILayoutGroup layout = CreateCenterLayout(content);
|
||||
|
||||
Label(layout, TextManager.Get("AimAssist"), GUIStyle.SubHeadingFont);
|
||||
Slider(layout, (0, 1), 101, Percentage, unsavedConfig.AimAssistAmount, (v) => unsavedConfig.AimAssistAmount = v, TextManager.Get("AimAssistTooltip"));
|
||||
Tickbox(layout, TextManager.Get("EnableMouseLook"), TextManager.Get("EnableMouseLookTooltip"), unsavedConfig.EnableMouseLook, (v) => unsavedConfig.EnableMouseLook = v);
|
||||
Spacer(layout);
|
||||
|
||||
GUIListBox keyMapList =
|
||||
new GUIListBox(new RectTransform((2.0f, 0.7f),
|
||||
layout.RectTransform))
|
||||
{
|
||||
CanBeFocused = false,
|
||||
OnSelected = (_, __) => false
|
||||
};
|
||||
Spacer(layout);
|
||||
|
||||
GUILayoutGroup createInputRowLayout()
|
||||
=> new GUILayoutGroup(new RectTransform((1.0f, 0.1f), keyMapList.Content.RectTransform), isHorizontal: true);
|
||||
|
||||
HashSet<GUIButton> inputButtons = new HashSet<GUIButton>();
|
||||
Action<KeyOrMouse>? currentSetter = null;
|
||||
void addInputToRow(GUILayoutGroup currRow, LocalizedString labelText, Func<LocalizedString> valueNameGetter, Action<KeyOrMouse> valueSetter)
|
||||
{
|
||||
var inputFrame = new GUIFrame(new RectTransform((0.5f, 1.0f), currRow.RectTransform),
|
||||
style: null);
|
||||
var label = new GUITextBlock(new RectTransform((0.6f, 1.0f), inputFrame.RectTransform), labelText,
|
||||
font: GUIStyle.SmallFont) {ForceUpperCase = ForceUpperCase.Yes};
|
||||
var inputBox = new GUIButton(
|
||||
new RectTransform((0.4f, 1.0f), inputFrame.RectTransform, Anchor.TopRight, Pivot.TopRight),
|
||||
valueNameGetter(), style: "GUITextBoxNoIcon")
|
||||
{
|
||||
OnClicked = (btn, obj) =>
|
||||
{
|
||||
inputButtons.ForEach(b =>
|
||||
{
|
||||
if (b != btn) { b.Selected = false; }
|
||||
});
|
||||
bool willBeSelected = !btn.Selected;
|
||||
if (willBeSelected)
|
||||
{
|
||||
currentSetter = (v) =>
|
||||
{
|
||||
valueSetter(v);
|
||||
btn.Text = valueNameGetter();
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
currentSetter = null;
|
||||
}
|
||||
|
||||
btn.Selected = willBeSelected;
|
||||
return true;
|
||||
}
|
||||
};
|
||||
inputButtons.Add(inputBox);
|
||||
}
|
||||
|
||||
var inputListener = new GUICustomComponent(new RectTransform(Vector2.Zero, layout.RectTransform), onUpdate: (deltaTime, component) =>
|
||||
{
|
||||
if (currentSetter is null) { return; }
|
||||
|
||||
void clearSetter()
|
||||
{
|
||||
currentSetter = null;
|
||||
inputButtons.ForEach(b => b.Selected = false);
|
||||
}
|
||||
|
||||
void callSetter(KeyOrMouse v)
|
||||
{
|
||||
currentSetter?.Invoke(v);
|
||||
clearSetter();
|
||||
}
|
||||
|
||||
var pressedKeys = PlayerInput.GetKeyboardState.GetPressedKeys();
|
||||
if ((pressedKeys?.Any() ?? false))
|
||||
{
|
||||
if (pressedKeys.Contains(Keys.Escape))
|
||||
{
|
||||
clearSetter();
|
||||
}
|
||||
else
|
||||
{
|
||||
callSetter(pressedKeys.First());
|
||||
}
|
||||
}
|
||||
else if (PlayerInput.PrimaryMouseButtonClicked() && !(GUI.MouseOn is GUIButton))
|
||||
{
|
||||
callSetter(MouseButton.PrimaryMouse);
|
||||
}
|
||||
else if (PlayerInput.SecondaryMouseButtonClicked())
|
||||
{
|
||||
callSetter(MouseButton.SecondaryMouse);
|
||||
}
|
||||
else if (PlayerInput.MidButtonClicked())
|
||||
{
|
||||
callSetter(MouseButton.MiddleMouse);
|
||||
}
|
||||
else if (PlayerInput.Mouse4ButtonClicked())
|
||||
{
|
||||
callSetter(MouseButton.MouseButton4);
|
||||
}
|
||||
else if (PlayerInput.Mouse5ButtonClicked())
|
||||
{
|
||||
callSetter(MouseButton.MouseButton5);
|
||||
}
|
||||
else if (PlayerInput.MouseWheelUpClicked())
|
||||
{
|
||||
callSetter(MouseButton.MouseWheelUp);
|
||||
}
|
||||
else if (PlayerInput.MouseWheelDownClicked())
|
||||
{
|
||||
callSetter(MouseButton.MouseWheelDown);
|
||||
}
|
||||
});
|
||||
|
||||
InputType[] inputTypes = (InputType[])Enum.GetValues(typeof(InputType));
|
||||
InputType[][] inputTypeColumns =
|
||||
{
|
||||
inputTypes.Take(inputTypes.Length - (inputTypes.Length / 2)).ToArray(),
|
||||
inputTypes.TakeLast(inputTypes.Length / 2).ToArray()
|
||||
};
|
||||
for (int i = 0; i < inputTypes.Length; i+=2)
|
||||
{
|
||||
var currRow = createInputRowLayout();
|
||||
for (int j = 0; j < 2; j++)
|
||||
{
|
||||
var column = inputTypeColumns[j];
|
||||
if (i / 2 >= column.Length) { break; }
|
||||
var input = column[i / 2];
|
||||
addInputToRow(
|
||||
currRow,
|
||||
TextManager.Get($"InputType.{input}"),
|
||||
() => unsavedConfig.KeyMap.Bindings[input].Name,
|
||||
(v) => unsavedConfig.KeyMap = unsavedConfig.KeyMap.WithBinding(input, v));
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < unsavedConfig.InventoryKeyMap.Bindings.Length; i += 2)
|
||||
{
|
||||
var currRow = createInputRowLayout();
|
||||
for (int j = 0; j < 2; j++)
|
||||
{
|
||||
int currIndex = i + j;
|
||||
if (currIndex >= unsavedConfig.InventoryKeyMap.Bindings.Length) { break; }
|
||||
|
||||
var input = unsavedConfig.InventoryKeyMap.Bindings[currIndex];
|
||||
addInputToRow(
|
||||
currRow,
|
||||
TextManager.GetWithVariable("inventoryslotkeybind", "[slotnumber]", (currIndex+1).ToString(CultureInfo.InvariantCulture)),
|
||||
() => unsavedConfig.InventoryKeyMap.Bindings[currIndex].Name,
|
||||
(v) => unsavedConfig.InventoryKeyMap = unsavedConfig.InventoryKeyMap.WithBinding(currIndex, v));
|
||||
}
|
||||
}
|
||||
|
||||
GUILayoutGroup resetControlsHolder =
|
||||
new GUILayoutGroup(new RectTransform((1.75f, 0.1f), layout.RectTransform), isHorizontal: true)
|
||||
{
|
||||
RelativeSpacing = 0.1f
|
||||
};
|
||||
|
||||
var defaultBindingsButton =
|
||||
new GUIButton(new RectTransform(new Vector2(0.45f, 1.0f), resetControlsHolder.RectTransform),
|
||||
TextManager.Get("SetDefaultBindings"), style: "GUIButtonSmall")
|
||||
{
|
||||
ToolTip = TextManager.Get("SetDefaultBindingsTooltip")
|
||||
};
|
||||
|
||||
var legacyBindingsButton =
|
||||
new GUIButton(new RectTransform(new Vector2(0.45f, 1.0f), resetControlsHolder.RectTransform),
|
||||
TextManager.Get("SetLegacyBindings"), style: "GUIButtonSmall")
|
||||
{
|
||||
ToolTip = TextManager.Get("SetLegacyBindingsTooltip")
|
||||
};
|
||||
}
|
||||
|
||||
private void CreateGameplayTab()
|
||||
{
|
||||
GUIFrame content = CreateNewContentFrame(Tab.Gameplay);
|
||||
|
||||
GUILayoutGroup layout = CreateCenterLayout(content);
|
||||
|
||||
var languages = TextManager.AvailableLanguages
|
||||
.OrderBy(l => TextManager.GetTranslatedLanguageName(l).ToIdentifier())
|
||||
.ToArray();
|
||||
Label(layout, TextManager.Get("Language"), GUIStyle.SubHeadingFont);
|
||||
Dropdown(layout, (v) => TextManager.GetTranslatedLanguageName(v), null, languages, unsavedConfig.Language, (v) => unsavedConfig.Language = v);
|
||||
Spacer(layout);
|
||||
|
||||
Tickbox(layout, TextManager.Get("PauseOnFocusLost"), TextManager.Get("PauseOnFocusLostTooltip"), unsavedConfig.PauseOnFocusLost, (v) => unsavedConfig.PauseOnFocusLost = v);
|
||||
Spacer(layout);
|
||||
|
||||
Tickbox(layout, TextManager.Get("DisableInGameHints"), TextManager.Get("DisableInGameHintsTooltip"), unsavedConfig.DisableInGameHints, (v) => unsavedConfig.DisableInGameHints = v);
|
||||
var resetInGameHintsButton =
|
||||
new GUIButton(new RectTransform(new Vector2(1.0f, 1.0f), layout.RectTransform),
|
||||
TextManager.Get("ResetInGameHints"), style: "GUIButtonSmall")
|
||||
{
|
||||
ToolTip = TextManager.Get("ResetInGameHintsTooltip")
|
||||
};
|
||||
Spacer(layout);
|
||||
|
||||
Label(layout, TextManager.Get("HUDScale"), GUIStyle.SubHeadingFont);
|
||||
Slider(layout, (0.75f, 1.25f), 51, Percentage, unsavedConfig.Graphics.HUDScale, (v) => unsavedConfig.Graphics.HUDScale = v);
|
||||
Label(layout, TextManager.Get("InventoryScale"), GUIStyle.SubHeadingFont);
|
||||
Slider(layout, (0.75f, 1.25f), 51, Percentage, unsavedConfig.Graphics.InventoryScale, (v) => unsavedConfig.Graphics.InventoryScale = v);
|
||||
Label(layout, TextManager.Get("TextScale"), GUIStyle.SubHeadingFont);
|
||||
Slider(layout, (0.75f, 1.25f), 51, Percentage, unsavedConfig.Graphics.TextScale, (v) => unsavedConfig.Graphics.TextScale = v);
|
||||
|
||||
#if !OSX
|
||||
Spacer(layout);
|
||||
var statisticsTickBox = new GUITickBox(NewItemRectT(layout), TextManager.Get("statisticsconsenttickbox"))
|
||||
{
|
||||
OnSelected = tickBox =>
|
||||
{
|
||||
GameAnalyticsManager.SetConsent(
|
||||
tickBox.Selected
|
||||
? GameAnalyticsManager.Consent.Ask
|
||||
: GameAnalyticsManager.Consent.No);
|
||||
return false;
|
||||
}
|
||||
};
|
||||
#if DEBUG
|
||||
statisticsTickBox.Enabled = false;
|
||||
#endif
|
||||
void updateGATickBoxToolTip()
|
||||
=> statisticsTickBox.ToolTip = TextManager.Get($"GameAnalyticsStatus.{GameAnalyticsManager.UserConsented}");
|
||||
updateGATickBoxToolTip();
|
||||
|
||||
var cachedConsent = GameAnalyticsManager.Consent.Unknown;
|
||||
var statisticsTickBoxUpdater = new GUICustomComponent(
|
||||
new RectTransform(Vector2.Zero, statisticsTickBox.RectTransform),
|
||||
onUpdate: (deltaTime, component) =>
|
||||
{
|
||||
bool shouldTickBoxBeSelected = GameAnalyticsManager.UserConsented == GameAnalyticsManager.Consent.Yes;
|
||||
|
||||
bool shouldUpdateTickBoxState = cachedConsent != GameAnalyticsManager.UserConsented
|
||||
|| statisticsTickBox.Selected != shouldTickBoxBeSelected;
|
||||
|
||||
if (!shouldUpdateTickBoxState) { return; }
|
||||
|
||||
updateGATickBoxToolTip();
|
||||
cachedConsent = GameAnalyticsManager.UserConsented;
|
||||
GUITickBox.OnSelectedHandler prevHandler = statisticsTickBox.OnSelected;
|
||||
statisticsTickBox.OnSelected = null;
|
||||
statisticsTickBox.Selected = shouldTickBoxBeSelected;
|
||||
statisticsTickBox.OnSelected = prevHandler;
|
||||
statisticsTickBox.Enabled = GameAnalyticsManager.UserConsented != GameAnalyticsManager.Consent.Error;
|
||||
});
|
||||
#endif
|
||||
}
|
||||
|
||||
private void CreateModsTab(out WorkshopMenu workshopMenu)
|
||||
{
|
||||
GUIFrame content = CreateNewContentFrame(Tab.Mods);
|
||||
content.RectTransform.RelativeSize = Vector2.One;
|
||||
|
||||
workshopMenu = new WorkshopMenu(content);
|
||||
}
|
||||
|
||||
private void CreateBottomButtons()
|
||||
{
|
||||
GUIButton cancelButton =
|
||||
new GUIButton(new RectTransform(new Vector2(1.0f, 1.0f), bottom.RectTransform), text: "Cancel")
|
||||
{
|
||||
OnClicked = (btn, obj) =>
|
||||
{
|
||||
Close();
|
||||
return false;
|
||||
}
|
||||
};
|
||||
GUIButton applyButton =
|
||||
new GUIButton(new RectTransform(new Vector2(1.0f, 1.0f), bottom.RectTransform), text: "Apply")
|
||||
{
|
||||
OnClicked = (btn, obj) =>
|
||||
{
|
||||
GameSettings.SetCurrentConfig(unsavedConfig);
|
||||
WorkshopMenu.Apply();
|
||||
GameSettings.SaveCurrentConfig();
|
||||
mainFrame.Flash(color: GUIStyle.Green);
|
||||
return false;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public void Close()
|
||||
{
|
||||
if (GameMain.Client is null || GameSettings.CurrentConfig.Audio.VoiceSetting == VoiceMode.Disabled)
|
||||
{
|
||||
VoipCapture.Instance?.Dispose();
|
||||
}
|
||||
mainFrame.Parent.RemoveChild(mainFrame);
|
||||
if (Instance == this) { Instance = null; }
|
||||
|
||||
GUI.SettingsMenuOpen = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user