Unstable 0.17.0.0
This commit is contained in:
@@ -0,0 +1,13 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
public class CreatureMetrics
|
||||
{
|
||||
public readonly HashSet<Identifier> RecentlyEncountered = new HashSet<Identifier>();
|
||||
public readonly HashSet<Identifier> Encountered = new HashSet<Identifier>();
|
||||
public readonly HashSet<Identifier> Killed = new HashSet<Identifier>();
|
||||
|
||||
public readonly static CreatureMetrics Instance = new CreatureMetrics();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,562 @@
|
||||
#nullable enable
|
||||
using Barotrauma.Extensions;
|
||||
using Microsoft.Xna.Framework;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Xml.Linq;
|
||||
using Barotrauma.IO;
|
||||
#if CLIENT
|
||||
using Barotrauma.ClientSource.Settings;
|
||||
using Microsoft.Xna.Framework.Input;
|
||||
#endif
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
public enum WindowMode
|
||||
{
|
||||
Windowed, Fullscreen, BorderlessWindowed
|
||||
}
|
||||
|
||||
public enum LosMode
|
||||
{
|
||||
None = 0,
|
||||
Transparent = 1,
|
||||
Opaque = 2
|
||||
}
|
||||
|
||||
public enum VoiceMode
|
||||
{
|
||||
Disabled,
|
||||
PushToTalk,
|
||||
Activity
|
||||
}
|
||||
|
||||
public static class GameSettings
|
||||
{
|
||||
public struct Config
|
||||
{
|
||||
public static Config GetDefault()
|
||||
{
|
||||
Config config = new Config
|
||||
{
|
||||
Language = LanguageIdentifier.None,
|
||||
SubEditorUndoBuffer = 32,
|
||||
MaxAutoSaves = 8,
|
||||
AutoSaveIntervalSeconds = 300,
|
||||
SubEditorBackground = new Color(13, 37, 69, 255),
|
||||
EnableSplashScreen = true,
|
||||
PauseOnFocusLost = true,
|
||||
AimAssistAmount = 0.5f,
|
||||
EnableMouseLook = true,
|
||||
ChatOpen = true,
|
||||
CrewMenuOpen = true,
|
||||
CampaignDisclaimerShown = false,
|
||||
EditorDisclaimerShown = false,
|
||||
ShowOffensiveServerPrompt = true,
|
||||
TutorialSkipWarning = true,
|
||||
CorpseDespawnDelay = 600,
|
||||
CorpsesPerSubDespawnThreshold = 5,
|
||||
#if OSX
|
||||
UseDualModeSockets = false,
|
||||
#else
|
||||
UseDualModeSockets = true,
|
||||
#endif
|
||||
DisableInGameHints = false,
|
||||
EnableSubmarineAutoSave = true,
|
||||
Graphics = GraphicsSettings.GetDefault(),
|
||||
Audio = AudioSettings.GetDefault(),
|
||||
#if CLIENT
|
||||
KeyMap = KeyMapping.GetDefault(),
|
||||
InventoryKeyMap = InventoryKeyMapping.GetDefault()
|
||||
#endif
|
||||
|
||||
};
|
||||
#if DEBUG
|
||||
config.UseSteamMatchmaking = true;
|
||||
config.QuickStartSub = "Humpback".ToIdentifier();
|
||||
config.RequireSteamAuthentication = true;
|
||||
config.AutomaticQuickStartEnabled = false;
|
||||
config.AutomaticCampaignLoadEnabled = false;
|
||||
config.TextManagerDebugModeEnabled = false;
|
||||
config.ModBreakerMode = false;
|
||||
#endif
|
||||
return config;
|
||||
}
|
||||
|
||||
public static Config FromFile(string configFile, in Config? fallback = null)
|
||||
{
|
||||
XDocument doc = XMLExtensions.TryLoadXml(configFile);
|
||||
|
||||
return FromElement(doc.Root ?? throw new InvalidOperationException("Unable to load config file: XML document is null."), fallback);
|
||||
}
|
||||
|
||||
public static Config FromElement(XElement element, in Config? fallback = null)
|
||||
{
|
||||
Config retVal = fallback ?? GetDefault();
|
||||
|
||||
retVal.DeserializeElement(element);
|
||||
|
||||
retVal.Graphics = GraphicsSettings.FromElements(element.GetChildElements("graphicsmode", "graphicssettings"), retVal.Graphics);
|
||||
retVal.Audio = AudioSettings.FromElements(element.GetChildElements("audio"), retVal.Audio);
|
||||
#if CLIENT
|
||||
retVal.KeyMap = new KeyMapping(element.GetChildElements("keymapping"), retVal.KeyMap);
|
||||
retVal.InventoryKeyMap = new InventoryKeyMapping(element.GetChildElements("inventorykeymapping"), retVal.InventoryKeyMap);
|
||||
#endif
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
public LanguageIdentifier Language;
|
||||
public bool VerboseLogging;
|
||||
public bool SaveDebugConsoleLogs;
|
||||
public int SubEditorUndoBuffer;
|
||||
public int MaxAutoSaves;
|
||||
public int AutoSaveIntervalSeconds;
|
||||
public Color SubEditorBackground;
|
||||
public bool EnableSplashScreen;
|
||||
public bool PauseOnFocusLost;
|
||||
public float AimAssistAmount;
|
||||
public bool EnableMouseLook;
|
||||
public bool ChatOpen;
|
||||
public bool CrewMenuOpen;
|
||||
public bool CampaignDisclaimerShown;
|
||||
public bool EditorDisclaimerShown;
|
||||
public bool ShowOffensiveServerPrompt;
|
||||
public bool TutorialSkipWarning;
|
||||
public int CorpseDespawnDelay;
|
||||
public int CorpsesPerSubDespawnThreshold;
|
||||
public bool UseDualModeSockets;
|
||||
public bool DisableInGameHints;
|
||||
public bool EnableSubmarineAutoSave;
|
||||
public Identifier QuickStartSub;
|
||||
#if DEBUG
|
||||
public bool UseSteamMatchmaking;
|
||||
public bool RequireSteamAuthentication;
|
||||
public bool AutomaticQuickStartEnabled;
|
||||
public bool AutomaticCampaignLoadEnabled;
|
||||
public bool TestScreenEnabled;
|
||||
public bool TextManagerDebugModeEnabled;
|
||||
public bool ModBreakerMode;
|
||||
#else
|
||||
public bool UseSteamMatchmaking => true;
|
||||
public bool RequireSteamAuthentication => true;
|
||||
#endif
|
||||
|
||||
public struct GraphicsSettings
|
||||
{
|
||||
public static GraphicsSettings GetDefault()
|
||||
{
|
||||
GraphicsSettings gfxSettings = new GraphicsSettings
|
||||
{
|
||||
RadialDistortion = true,
|
||||
InventoryScale = 1.0f,
|
||||
LightMapScale = 1.0f,
|
||||
TextScale = 1.0f,
|
||||
HUDScale = 1.0f,
|
||||
Specularity = true,
|
||||
ChromaticAberration = true,
|
||||
ParticleLimit = 1500,
|
||||
LosMode = LosMode.Transparent
|
||||
};
|
||||
gfxSettings.RadialDistortion = true;
|
||||
gfxSettings.CompressTextures = true;
|
||||
gfxSettings.FrameLimit = 300;
|
||||
gfxSettings.VSync = true;
|
||||
#if DEBUG
|
||||
gfxSettings.DisplayMode = WindowMode.Windowed;
|
||||
#else
|
||||
gfxSettings.DisplayMode = WindowMode.BorderlessWindowed;
|
||||
#endif
|
||||
return gfxSettings;
|
||||
}
|
||||
|
||||
public static GraphicsSettings FromElements(IEnumerable<XElement> elements, in GraphicsSettings? fallback = null)
|
||||
{
|
||||
GraphicsSettings retVal = fallback ?? GetDefault();
|
||||
elements.ForEach(element => retVal.DeserializeElement(element));
|
||||
return retVal;
|
||||
}
|
||||
|
||||
public int Width;
|
||||
public int Height;
|
||||
public bool VSync;
|
||||
public bool CompressTextures;
|
||||
public int FrameLimit;
|
||||
public WindowMode DisplayMode;
|
||||
public int ParticleLimit;
|
||||
public bool Specularity;
|
||||
public bool ChromaticAberration;
|
||||
public LosMode LosMode;
|
||||
public float HUDScale;
|
||||
public float InventoryScale;
|
||||
public float LightMapScale;
|
||||
public float TextScale;
|
||||
public bool RadialDistortion;
|
||||
}
|
||||
|
||||
[StructSerialization.Skip]
|
||||
public GraphicsSettings Graphics;
|
||||
|
||||
public struct AudioSettings
|
||||
{
|
||||
public static class DeviceNameHandler
|
||||
{
|
||||
public static string Read(string s)
|
||||
=> System.Xml.XmlConvert.DecodeName(s)!;
|
||||
|
||||
public static string Write(string s)
|
||||
=> System.Xml.XmlConvert.EncodeName(s)!;
|
||||
}
|
||||
|
||||
public static AudioSettings GetDefault()
|
||||
{
|
||||
AudioSettings audioSettings = new AudioSettings
|
||||
{
|
||||
MusicVolume = 0.3f,
|
||||
SoundVolume = 0.5f,
|
||||
VoiceChatVolume = 0.5f,
|
||||
VoiceChatCutoffPrevention = 0,
|
||||
MicrophoneVolume = 5,
|
||||
MuteOnFocusLost = false,
|
||||
DynamicRangeCompressionEnabled = true,
|
||||
UseDirectionalVoiceChat = true,
|
||||
VoipAttenuationEnabled = true,
|
||||
VoiceSetting = VoiceMode.PushToTalk,
|
||||
UseLocalVoiceByDefault = false,
|
||||
DisableVoiceChatFilters = false
|
||||
};
|
||||
return audioSettings;
|
||||
}
|
||||
|
||||
public static AudioSettings FromElements(IEnumerable<XElement> elements, in AudioSettings? fallback = null)
|
||||
{
|
||||
AudioSettings retVal = fallback ?? GetDefault();
|
||||
elements.ForEach(element => retVal.DeserializeElement(element));
|
||||
return retVal;
|
||||
}
|
||||
|
||||
public float MusicVolume;
|
||||
public float SoundVolume;
|
||||
public float VoiceChatVolume;
|
||||
public int VoiceChatCutoffPrevention;
|
||||
public float MicrophoneVolume;
|
||||
public bool MuteOnFocusLost;
|
||||
public bool DynamicRangeCompressionEnabled;
|
||||
public bool UseDirectionalVoiceChat;
|
||||
public bool VoipAttenuationEnabled;
|
||||
public VoiceMode VoiceSetting;
|
||||
|
||||
[StructSerialization.Handler(typeof(DeviceNameHandler))]
|
||||
public string AudioOutputDevice;
|
||||
[StructSerialization.Handler(typeof(DeviceNameHandler))]
|
||||
public string VoiceCaptureDevice;
|
||||
|
||||
public float NoiseGateThreshold;
|
||||
public bool UseLocalVoiceByDefault;
|
||||
public bool DisableVoiceChatFilters;
|
||||
}
|
||||
|
||||
[StructSerialization.Skip]
|
||||
public AudioSettings Audio;
|
||||
|
||||
#if CLIENT
|
||||
public struct KeyMapping
|
||||
{
|
||||
private readonly static ImmutableDictionary<InputType, KeyOrMouse> DefaultsQwerty =
|
||||
new Dictionary<InputType, KeyOrMouse>()
|
||||
{
|
||||
{ InputType.Run, Keys.LeftShift },
|
||||
{ InputType.Attack, Keys.R },
|
||||
{ InputType.Crouch, Keys.LeftControl },
|
||||
{ InputType.Grab, Keys.G },
|
||||
{ InputType.Health, Keys.H },
|
||||
{ InputType.Ragdoll, Keys.Space },
|
||||
{ InputType.Aim, MouseButton.SecondaryMouse },
|
||||
|
||||
{ InputType.InfoTab, Keys.Tab },
|
||||
{ InputType.Chat, Keys.T },
|
||||
{ InputType.RadioChat, Keys.R },
|
||||
{ InputType.CrewOrders, Keys.C },
|
||||
|
||||
{ InputType.Voice, Keys.V },
|
||||
{ InputType.LocalVoice, Keys.B },
|
||||
{ InputType.Command, MouseButton.MiddleMouse },
|
||||
{ InputType.PreviousFireMode, MouseButton.MouseWheelDown },
|
||||
{ InputType.NextFireMode, MouseButton.MouseWheelUp },
|
||||
|
||||
{ InputType.TakeHalfFromInventorySlot, Keys.LeftShift },
|
||||
{ InputType.TakeOneFromInventorySlot, Keys.LeftControl },
|
||||
|
||||
{ InputType.Up, Keys.W },
|
||||
{ InputType.Down, Keys.S },
|
||||
{ InputType.Left, Keys.A },
|
||||
{ InputType.Right, Keys.D },
|
||||
{ InputType.ToggleInventory, Keys.Q },
|
||||
|
||||
{ InputType.SelectNextCharacter, Keys.Z },
|
||||
{ InputType.SelectPreviousCharacter, Keys.X },
|
||||
|
||||
{ InputType.Use, Keys.E },
|
||||
{ InputType.Select, MouseButton.PrimaryMouse },
|
||||
{ InputType.Deselect, MouseButton.SecondaryMouse },
|
||||
{ InputType.Shoot, MouseButton.PrimaryMouse }
|
||||
}.ToImmutableDictionary();
|
||||
|
||||
public static KeyMapping GetDefault() => new KeyMapping
|
||||
{
|
||||
Bindings = DefaultsQwerty
|
||||
.Select(kvp =>
|
||||
(kvp.Key, kvp.Value.MouseButton == MouseButton.None
|
||||
? (KeyOrMouse)Keyboard.QwertyToCurrentLayout(kvp.Value.Key)
|
||||
: (KeyOrMouse)kvp.Value.MouseButton))
|
||||
.ToImmutableDictionary()
|
||||
};
|
||||
|
||||
public KeyMapping(IEnumerable<XElement> elements, in KeyMapping? fallback)
|
||||
{
|
||||
var defaultBindings = GetDefault().Bindings;
|
||||
Dictionary<InputType, KeyOrMouse> bindings = fallback?.Bindings?.ToMutable() ?? defaultBindings.ToMutable();
|
||||
foreach (InputType inputType in (InputType[])Enum.GetValues(typeof(InputType)))
|
||||
{
|
||||
if (!bindings.ContainsKey(inputType)) { bindings.Add(inputType, defaultBindings[inputType]); }
|
||||
}
|
||||
|
||||
foreach (XElement element in elements)
|
||||
{
|
||||
foreach (XAttribute attribute in element.Attributes())
|
||||
{
|
||||
if (Enum.TryParse(attribute.Name.LocalName, out InputType result))
|
||||
{
|
||||
bindings[result] = element.GetAttributeKeyOrMouse(attribute.Name.LocalName, bindings[result]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Bindings = bindings.ToImmutableDictionary();
|
||||
}
|
||||
|
||||
public KeyMapping WithBinding(InputType type, KeyOrMouse bind)
|
||||
{
|
||||
KeyMapping newMapping = this;
|
||||
newMapping.Bindings = newMapping.Bindings
|
||||
.Select(kvp =>
|
||||
kvp.Key == type
|
||||
? (type, bind)
|
||||
: (kvp.Key, kvp.Value))
|
||||
.ToImmutableDictionary();
|
||||
return newMapping;
|
||||
}
|
||||
|
||||
public ImmutableDictionary<InputType, KeyOrMouse> Bindings;
|
||||
|
||||
public LocalizedString KeyBindText(InputType inputType) => Bindings[inputType].Name;
|
||||
}
|
||||
|
||||
[StructSerialization.Skip]
|
||||
public KeyMapping KeyMap;
|
||||
|
||||
public struct InventoryKeyMapping
|
||||
{
|
||||
public ImmutableArray<KeyOrMouse> Bindings;
|
||||
|
||||
public static InventoryKeyMapping GetDefault() => new InventoryKeyMapping
|
||||
{
|
||||
Bindings = new KeyOrMouse[]
|
||||
{
|
||||
Keys.D1,
|
||||
Keys.D2,
|
||||
Keys.D3,
|
||||
Keys.D4,
|
||||
Keys.D5,
|
||||
Keys.D6,
|
||||
Keys.D7,
|
||||
Keys.D8,
|
||||
Keys.D9,
|
||||
Keys.D0,
|
||||
}.ToImmutableArray()
|
||||
};
|
||||
|
||||
public InventoryKeyMapping WithBinding(int index, KeyOrMouse keyOrMouse)
|
||||
{
|
||||
var thisBindings = Bindings;
|
||||
return new InventoryKeyMapping()
|
||||
{
|
||||
Bindings = Enumerable.Range(0, thisBindings.Length)
|
||||
.Select(i => i == index ? keyOrMouse : thisBindings[i])
|
||||
.ToImmutableArray()
|
||||
};
|
||||
}
|
||||
|
||||
public InventoryKeyMapping(IEnumerable<XElement> elements, InventoryKeyMapping? fallback)
|
||||
{
|
||||
var bindings = (fallback?.Bindings ?? GetDefault().Bindings).ToArray();
|
||||
foreach (XElement element in elements)
|
||||
{
|
||||
for (int i = 0; i < bindings.Length; i++)
|
||||
{
|
||||
bindings[i] = element.GetAttributeKeyOrMouse($"slot{i}", bindings[i]);
|
||||
}
|
||||
}
|
||||
Bindings = bindings.ToImmutableArray();
|
||||
}
|
||||
}
|
||||
|
||||
[StructSerialization.Skip]
|
||||
public InventoryKeyMapping InventoryKeyMap;
|
||||
#endif
|
||||
}
|
||||
|
||||
public const string PlayerConfigPath = "config_player.xml";
|
||||
|
||||
private static Config currentConfig;
|
||||
public static ref readonly Config CurrentConfig => ref currentConfig;
|
||||
|
||||
public static void Init()
|
||||
{
|
||||
XDocument? currentConfigDoc = null;
|
||||
|
||||
if (File.Exists(PlayerConfigPath))
|
||||
{
|
||||
currentConfigDoc = XMLExtensions.TryLoadXml(PlayerConfigPath);
|
||||
}
|
||||
|
||||
if (currentConfigDoc != null)
|
||||
{
|
||||
currentConfig = Config.FromElement(currentConfigDoc.Root ?? throw new NullReferenceException("Config XML element is invalid: document is null."));
|
||||
#if CLIENT
|
||||
ServerListFilters.Init(currentConfigDoc.Root.GetChildElement("serverfilters"));
|
||||
MultiplayerPreferences.Init(
|
||||
currentConfigDoc.Root.GetChildElement("player"),
|
||||
currentConfigDoc.Root.GetChildElement("gameplay")?.GetChildElement("jobpreferences"));
|
||||
IgnoredHints.Init(currentConfigDoc.Root.GetChildElement("ignoredhints"));
|
||||
DebugConsoleMapping.Init(currentConfigDoc.Root.GetChildElement("debugconsolemapping"));
|
||||
CompletedTutorials.Init(currentConfigDoc.Root.GetChildElement("tutorials"));
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
currentConfig = Config.GetDefault();
|
||||
SaveCurrentConfig();
|
||||
}
|
||||
}
|
||||
|
||||
public static void SetCurrentConfig(in Config newConfig)
|
||||
{
|
||||
bool setGraphicsMode =
|
||||
currentConfig.Graphics.Width != newConfig.Graphics.Width
|
||||
|| currentConfig.Graphics.Height != newConfig.Graphics.Height
|
||||
|| currentConfig.Graphics.VSync != newConfig.Graphics.VSync
|
||||
|| currentConfig.Graphics.DisplayMode != newConfig.Graphics.DisplayMode;
|
||||
|
||||
bool languageChanged = currentConfig.Language != newConfig.Language;
|
||||
|
||||
currentConfig = newConfig;
|
||||
#warning TODO: Implement program state updates;
|
||||
|
||||
#if CLIENT
|
||||
if (setGraphicsMode)
|
||||
{
|
||||
GameMain.Instance.ApplyGraphicsSettings();
|
||||
}
|
||||
|
||||
GameMain.SoundManager?.ApplySettings();
|
||||
#endif
|
||||
if (languageChanged) { TextManager.ClearCache(); }
|
||||
}
|
||||
|
||||
public static void SaveCurrentConfig()
|
||||
{
|
||||
XDocument configDoc = new XDocument();
|
||||
XElement root = new XElement("config"); configDoc.Add(root);
|
||||
currentConfig.SerializeElement(root);
|
||||
|
||||
XElement graphicsElement = new XElement("graphicssettings"); root.Add(graphicsElement);
|
||||
currentConfig.Graphics.SerializeElement(graphicsElement);
|
||||
|
||||
#region Backwards compatibility crap
|
||||
#warning TODO: remove once modding refactor ships in a stable release
|
||||
XElement backwardsCompatibilityGraphicsMode = new XElement(graphicsElement); root.Add(backwardsCompatibilityGraphicsMode);
|
||||
backwardsCompatibilityGraphicsMode.Name = "graphicsmode";
|
||||
#endregion
|
||||
|
||||
XElement audioElement = new XElement("audio"); root.Add(audioElement);
|
||||
currentConfig.Audio.SerializeElement(audioElement);
|
||||
|
||||
XElement contentPackagesElement = new XElement("contentpackages"); root.Add(contentPackagesElement);
|
||||
#region More backwards compatibility crap
|
||||
XComment backwardsCompatibleComment = new XComment("Backwards compatibility"); contentPackagesElement.Add(backwardsCompatibleComment);
|
||||
#warning TODO: remove once modding refactor ships in a stable release
|
||||
XElement backwardsCompatibleCoreElement = new XElement("core"); contentPackagesElement.Add(backwardsCompatibleCoreElement);
|
||||
backwardsCompatibleCoreElement.SetAttributeValue("name", "Vanilla 0.9");
|
||||
#endregion
|
||||
XComment corePackageComment = new XComment(ContentPackageManager.EnabledPackages.Core?.Name ?? "Vanilla"); contentPackagesElement.Add(corePackageComment);
|
||||
XElement corePackageElement = new XElement(ContentPackageManager.CorePackageElementName); contentPackagesElement.Add(corePackageElement);
|
||||
corePackageElement.SetAttributeValue("path", ContentPackageManager.EnabledPackages.Core?.Path ?? ContentPackageManager.VanillaFileList);
|
||||
|
||||
XElement regularPackagesElement = new XElement(ContentPackageManager.RegularPackagesElementName); contentPackagesElement.Add(regularPackagesElement);
|
||||
foreach (var regularPackage in ContentPackageManager.EnabledPackages.Regular)
|
||||
{
|
||||
XComment packageComment = new XComment(regularPackage.Name); regularPackagesElement.Add(packageComment);
|
||||
XElement packageElement = new XElement(ContentPackageManager.RegularPackagesSubElementName); regularPackagesElement.Add(packageElement);
|
||||
packageElement.SetAttributeValue("path", regularPackage.Path);
|
||||
}
|
||||
|
||||
#if CLIENT
|
||||
XElement serverFiltersElement = new XElement("serverfilters"); root.Add(serverFiltersElement);
|
||||
ServerListFilters.Instance.SaveTo(serverFiltersElement);
|
||||
|
||||
XElement characterElement = new XElement("player"); root.Add(characterElement);
|
||||
MultiplayerPreferences.Instance.SaveTo(characterElement);
|
||||
|
||||
XElement ignoredHintsElement = new XElement("ignoredhints"); root.Add(ignoredHintsElement);
|
||||
IgnoredHints.Instance.SaveTo(ignoredHintsElement);
|
||||
|
||||
XElement debugConsoleMappingElement = new XElement("debugconsolemapping"); root.Add(debugConsoleMappingElement);
|
||||
DebugConsoleMapping.Instance.SaveTo(debugConsoleMappingElement);
|
||||
|
||||
XElement tutorialsElement = new XElement("tutorials"); root.Add(tutorialsElement);
|
||||
CompletedTutorials.Instance.SaveTo(tutorialsElement);
|
||||
|
||||
XElement keyMappingElement = new XElement("keymapping",
|
||||
currentConfig.KeyMap.Bindings.Select(kvp
|
||||
=> new XAttribute(kvp.Key.ToString(), kvp.Value.ToString())));
|
||||
root.Add(keyMappingElement);
|
||||
|
||||
XElement inventoryKeyMappingElement = new XElement("inventorykeymapping",
|
||||
Enumerable.Range(0, currentConfig.InventoryKeyMap.Bindings.Length)
|
||||
.Zip(currentConfig.InventoryKeyMap.Bindings)
|
||||
.Cast<(int Index, KeyOrMouse Bind)>()
|
||||
.Select(kvp
|
||||
=> new XAttribute($"slot{kvp.Index.ToString(CultureInfo.InvariantCulture)}", kvp.Bind.ToString())));
|
||||
root.Add(inventoryKeyMappingElement);
|
||||
#endif
|
||||
|
||||
configDoc.SaveSafe(PlayerConfigPath);
|
||||
|
||||
System.Xml.XmlWriterSettings settings = new System.Xml.XmlWriterSettings
|
||||
{
|
||||
Indent = true,
|
||||
OmitXmlDeclaration = true,
|
||||
NewLineOnAttributes = true
|
||||
};
|
||||
|
||||
try
|
||||
{
|
||||
using (var writer = XmlWriter.Create(PlayerConfigPath, settings))
|
||||
{
|
||||
configDoc.WriteTo(writer);
|
||||
writer.Flush();
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
DebugConsole.ThrowError("Saving game settings failed.", e);
|
||||
GameAnalyticsManager.AddErrorEventOnce("GameSettings.Save:SaveFailed", GameAnalyticsManager.ErrorSeverity.Error,
|
||||
"Saving game settings failed.\n" + e.Message + "\n" + e.StackTrace.CleanupStackTrace());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user