diff --git a/Barotrauma/BarotraumaShared/SharedSource/LuaCs/Data/SettingList.cs b/Barotrauma/BarotraumaShared/SharedSource/LuaCs/Data/SettingList.cs new file mode 100644 index 000000000..ad4c89665 --- /dev/null +++ b/Barotrauma/BarotraumaShared/SharedSource/LuaCs/Data/SettingList.cs @@ -0,0 +1,98 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Linq; +using System.Xml.Linq; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.Toolkit.Diagnostics; + +namespace Barotrauma.LuaCs.Data; + +public class SettingList : SettingEntry, ISettingList where T : IEquatable, IConvertible +{ + public class LFactory : ISettingBase.IFactory> + { + public ISettingList CreateInstance(IConfigInfo configInfo, Func, bool> valueChangePredicate) + { + Guard.IsNotNull(configInfo, nameof(configInfo)); + return new SettingList(configInfo, valueChangePredicate); + } + } + + public SettingList(IConfigInfo configInfo, Func, bool> valueChangePredicate) : base(configInfo, valueChangePredicate) + { + if (!( + typeof(T).IsEnum || + typeof(T).IsPrimitive || + typeof(T) == typeof(string))) + { + ThrowHelper.ThrowArgumentException($"{nameof(ISettingBase)}: The type of {nameof(T)} is not an allowed type."); + } + ValueChangePredicate = valueChangePredicate; + + var valuesElements = ConfigInfo.Element.GetChildElement("Values")?.GetChildElements("Value")?.ToImmutableArray(); + + Guard.IsNotNull(valuesElements, this.InternalName); + if (valuesElements.Value.IsEmpty) + { + ThrowHelper.ThrowArgumentNullException($"{this.InternalName}: Could not find any values in list!"); + } + + foreach (var element in valuesElements.Value) + { + if (!TryConvert(element, out var v1)) + { + ThrowHelper.ThrowArgumentException($"{this.InternalName}: Error while parsing list values"); + } + _valuesList.Add(v1); + } + + if (TryConvert(ConfigInfo.Element, out var v) && _valuesList.Contains(v)) + { + Value = v; + DefaultValue = v; + } + else + { + Value = _valuesList[0]; + DefaultValue = _valuesList[0]; + } + + + bool TryConvert(XElement element, out T value) + { + try + { + value = (T)Convert.ChangeType(element.GetAttributeString("Value", null), typeof(T)); + return true; + } + catch (Exception e) when (e is InvalidCastException or ArgumentNullException) + { + value = default(T); + return false; + } + } + } + + private readonly List _valuesList = new(); + + public override bool TrySetValue(T value) + { + if (!_valuesList.Contains(value)) + { + return false; + } + + return base.TrySetValue(value); + } + + public bool TrySetValueByIndex(int index) + { + throw new NotImplementedException(); + } + + public IReadOnlyList Options => _valuesList.AsReadOnly(); + + public IReadOnlyList StringOptions => _valuesList.Select(e => e.ToString()).ToImmutableArray(); +} diff --git a/Barotrauma/BarotraumaShared/SharedSource/LuaCs/Data/SettingsFactoryRegistrationProvider.cs b/Barotrauma/BarotraumaShared/SharedSource/LuaCs/Data/SettingsFactoryRegistrationProvider.cs index 31d85e8b0..883699e8b 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/LuaCs/Data/SettingsFactoryRegistrationProvider.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/LuaCs/Data/SettingsFactoryRegistrationProvider.cs @@ -22,8 +22,6 @@ public class SettingsEntryRegistrar : ISettingsRegistrationProvider public void RegisterTypeProviders(IConfigService configService, Func, bool> valueChangePredicate) { - // TODO: Replace this with a proper IFactory lookup pattern. - // ISettingBase RegisterSettingEntry(configService, "bool", valueChangePredicate); RegisterSettingEntry(configService, "byte", valueChangePredicate); RegisterSettingEntry(configService, "sbyte", valueChangePredicate); @@ -58,8 +56,31 @@ public class SettingsEntryRegistrar : ISettingsRegistrationProvider IsValueChangeAllowed(cfgInfo.Info, val, valueChangePredicate)); }); #endif + + RegisterSettingList(configService, "listBool", valueChangePredicate); + RegisterSettingList(configService, "listByte", valueChangePredicate); + RegisterSettingList(configService, "listSbyte", valueChangePredicate); + RegisterSettingList(configService, "listShort", valueChangePredicate); + RegisterSettingList(configService, "listUshort", valueChangePredicate); + RegisterSettingList(configService, "listInt", valueChangePredicate); + RegisterSettingList(configService, "listUint", valueChangePredicate); + RegisterSettingList(configService, "listLong", valueChangePredicate); + RegisterSettingList(configService, "listUlong", valueChangePredicate); + RegisterSettingList(configService, "listString", valueChangePredicate); + RegisterSettingList(configService, "listFloat", valueChangePredicate); + RegisterSettingList(configService, "listSingle", valueChangePredicate); + RegisterSettingList(configService, "listDouble", valueChangePredicate); } + private void RegisterSettingList(IConfigService configService, string typeName, Func, bool> valueChangePredicate) where T : IEquatable, IConvertible + { + configService.RegisterSettingTypeInitializer(typeName, cfgInfo => + { + return new SettingList.LFactory().CreateInstance(cfgInfo.Info, (val) => + IsValueChangeAllowed(cfgInfo.Info, val, valueChangePredicate)); + }); + } + private void RegisterSettingEntry(IConfigService configService, string typeName, Func, bool> valueChangePredicate) where T : IEquatable, IConvertible { configService.RegisterSettingTypeInitializer(typeName, cfgInfo =>