From 7e0e671539e6787c9e19ee1cb8d5a909cd2e100c Mon Sep 17 00:00:00 2001 From: MapleWheels Date: Thu, 22 Jan 2026 14:58:03 -0500 Subject: [PATCH] - ConfigService.cs alpha testing. --- .../{IConfigControl.cs => ISettingControl.cs} | 4 +- .../ClientSource/LuaCs/Data/IConfigInfo.cs | 6 +- .../ClientSource/LuaCs/LuaCsSetup.cs | 24 +- .../LuaCs/Services/ConfigService.cs | 2 +- .../LuaCs/Services/IConfigService.cs | 2 +- .../LuaCs/Configuration/ConfigEntry.cs | 103 ----- .../LuaCs/Configuration/ConfigList.cs | 111 ----- .../{IConfigBase.cs => ISettingBase.cs} | 7 +- .../{IConfigEntry.cs => ISettingEntry.cs} | 4 +- .../{IConfigEnum.cs => ISettingEnum.cs} | 2 +- .../{IConfigList.cs => ISettingList.cs} | 4 +- ...figRangeEntry.cs => ISettingRangeEntry.cs} | 2 +- .../LuaCs/Configuration/SettingEntry.cs | 85 ++++ .../LuaCs/Configuration/SettingList.cs | 94 ++++ .../Data/DataInterfaceImplementations.cs | 9 +- .../SharedSource/LuaCs/Data/IConfigInfo.cs | 18 +- .../LuaCs/Data/IConfigProfileInfo.cs | 2 +- .../SharedSource/LuaCs/IEvents.cs | 8 +- .../SharedSource/LuaCs/LuaCsSetup.cs | 36 +- .../LuaCs/Services/ConfigInitializers.cs | 106 ++--- .../LuaCs/Services/ConfigService.cs | 433 +++++++++++------- .../LuaCs/Services/EventService.cs | 3 + .../Processing/IHelperServiceDefinitions.cs | 5 + ...rvice.cs => ModConfigFileParserService.cs} | 4 +- .../Processing/SettingsFileParserService.cs | 212 +++++++++ .../LuaCs/Services/Safe/ILuaConfigService.cs | 24 +- .../Services/_Interfaces/IConfigService.cs | 31 +- 27 files changed, 795 insertions(+), 546 deletions(-) rename Barotrauma/BarotraumaClient/ClientSource/LuaCs/Configuration/{IConfigControl.cs => ISettingControl.cs} (68%) delete mode 100644 Barotrauma/BarotraumaShared/SharedSource/LuaCs/Configuration/ConfigEntry.cs delete mode 100644 Barotrauma/BarotraumaShared/SharedSource/LuaCs/Configuration/ConfigList.cs rename Barotrauma/BarotraumaShared/SharedSource/LuaCs/Configuration/{IConfigBase.cs => ISettingBase.cs} (61%) rename Barotrauma/BarotraumaShared/SharedSource/LuaCs/Configuration/{IConfigEntry.cs => ISettingEntry.cs} (55%) rename Barotrauma/BarotraumaShared/SharedSource/LuaCs/Configuration/{IConfigEnum.cs => ISettingEnum.cs} (61%) rename Barotrauma/BarotraumaShared/SharedSource/LuaCs/Configuration/{IConfigList.cs => ISettingList.cs} (52%) rename Barotrauma/BarotraumaShared/SharedSource/LuaCs/Configuration/{IConfigRangeEntry.cs => ISettingRangeEntry.cs} (66%) create mode 100644 Barotrauma/BarotraumaShared/SharedSource/LuaCs/Configuration/SettingEntry.cs create mode 100644 Barotrauma/BarotraumaShared/SharedSource/LuaCs/Configuration/SettingList.cs rename Barotrauma/BarotraumaShared/SharedSource/LuaCs/Services/Processing/{ConfigFileParserService.cs => ModConfigFileParserService.cs} (98%) create mode 100644 Barotrauma/BarotraumaShared/SharedSource/LuaCs/Services/Processing/SettingsFileParserService.cs diff --git a/Barotrauma/BarotraumaClient/ClientSource/LuaCs/Configuration/IConfigControl.cs b/Barotrauma/BarotraumaClient/ClientSource/LuaCs/Configuration/ISettingControl.cs similarity index 68% rename from Barotrauma/BarotraumaClient/ClientSource/LuaCs/Configuration/IConfigControl.cs rename to Barotrauma/BarotraumaClient/ClientSource/LuaCs/Configuration/ISettingControl.cs index 4e3afbd93..9907af9cc 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/LuaCs/Configuration/IConfigControl.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/LuaCs/Configuration/ISettingControl.cs @@ -2,9 +2,9 @@ namespace Barotrauma.LuaCs.Configuration; -public interface IConfigControl : IConfigBase +public interface ISettingControl : ISettingBase { - event Action OnDown; + event Action OnDown; KeyOrMouse Value { get; } bool IsAssignable(KeyOrMouse value); bool TrySetValue(KeyOrMouse value); diff --git a/Barotrauma/BarotraumaClient/ClientSource/LuaCs/Data/IConfigInfo.cs b/Barotrauma/BarotraumaClient/ClientSource/LuaCs/Data/IConfigInfo.cs index 801bc5ac4..1e26659a1 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/LuaCs/Data/IConfigInfo.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/LuaCs/Data/IConfigInfo.cs @@ -7,11 +7,11 @@ public partial interface IConfigInfo : IConfigDisplayInfo { } public interface IConfigDisplayInfo { /// - /// User-friendly name or Localization Token. + /// Localization Token for display name. /// string DisplayName { get; } /// - /// User-friendly description or Localization Token. + /// Localization Token for description. /// string Description { get; } /// @@ -29,5 +29,5 @@ public interface IConfigDisplayInfo /// /// Icon for display in menus, if available. /// - string ImageIconPath { get; } + ContentPath ImageIconPath { get; } } diff --git a/Barotrauma/BarotraumaClient/ClientSource/LuaCs/LuaCsSetup.cs b/Barotrauma/BarotraumaClient/ClientSource/LuaCs/LuaCsSetup.cs index a1c793843..4a30e21f4 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/LuaCs/LuaCsSetup.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/LuaCs/LuaCsSetup.cs @@ -21,8 +21,20 @@ namespace Barotrauma } } - public void CheckCsEnabled() + /// + /// + /// + /// Returns whether the IsCsEnabled has been changed to true/enabled. Returns false if already enabled. + public bool CheckCsEnabled() { + // fast exit if enabled or unavailable. + if (this.IsCsEnabled?.Value ?? true ) + { + return false; + } + + bool isCsValueChanged = false; + var csharpMods = PackageManagementService.GetLoadedAssemblyPackages(); StringBuilder sb = new StringBuilder(); @@ -38,7 +50,7 @@ namespace Barotrauma if (GameMain.Client == null || GameMain.Client.IsServerOwner) { new GUIMessageBox("", $"You have CSharp mods enabled but don't have the CSharp Scripting enabled, those mods might not work, go to the Main Menu, click on LuaCs Settings and check Enable CSharp Scripting.\n\n{sb}"); - return; + return false; } GUIMessageBox msg = new GUIMessageBox( @@ -49,6 +61,7 @@ namespace Barotrauma msg.Buttons[0].OnClicked = (GUIButton button, object obj) => { this.IsCsEnabled.TrySetValue(true); + isCsValueChanged = true; return true; }; @@ -57,6 +70,8 @@ namespace Barotrauma this.IsCsEnabled.TrySetValue(false); return true; }; + + return isCsValueChanged; } /// @@ -85,7 +100,10 @@ namespace Barotrauma case SpriteEditorScreen: case SubEditorScreen: case TestScreen: // notes: TestScreen is a Linux edge case editor screen and is deprecated. - CheckCsEnabled(); + if (CheckCsEnabled() && this.CurrentRunState >= RunState.Running) + { + SetRunState(RunState.LoadedNoExec); + } SetRunState(RunState.Running); break; default: diff --git a/Barotrauma/BarotraumaClient/ClientSource/LuaCs/Services/ConfigService.cs b/Barotrauma/BarotraumaClient/ClientSource/LuaCs/Services/ConfigService.cs index a628969b2..ab00224e5 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/LuaCs/Services/ConfigService.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/LuaCs/Services/ConfigService.cs @@ -19,7 +19,7 @@ public partial class ConfigService throw new NotImplementedException(); } - public Result AddConfigControl(IConfigInfo configInfo) + public Result AddConfigControl(IConfigInfo configInfo) { throw new NotImplementedException(); } diff --git a/Barotrauma/BarotraumaClient/ClientSource/LuaCs/Services/IConfigService.cs b/Barotrauma/BarotraumaClient/ClientSource/LuaCs/Services/IConfigService.cs index cbe7bf94d..7218ef2cc 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/LuaCs/Services/IConfigService.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/LuaCs/Services/IConfigService.cs @@ -13,5 +13,5 @@ public partial interface IConfigService ImmutableArray GetDisplayableConfigs(); ImmutableArray GetDisplayableConfigsForPackage(ContentPackage package); - FluentResults.Result AddConfigControl(IConfigInfo configInfo); + FluentResults.Result AddConfigControl(IConfigInfo configInfo); } diff --git a/Barotrauma/BarotraumaShared/SharedSource/LuaCs/Configuration/ConfigEntry.cs b/Barotrauma/BarotraumaShared/SharedSource/LuaCs/Configuration/ConfigEntry.cs deleted file mode 100644 index 4fd22a1cb..000000000 --- a/Barotrauma/BarotraumaShared/SharedSource/LuaCs/Configuration/ConfigEntry.cs +++ /dev/null @@ -1,103 +0,0 @@ -using System; -using System.Xml.Linq; -using Barotrauma.LuaCs.Data; -using Barotrauma.LuaCs.Services; -using Barotrauma.Networking; -using OneOf; - -namespace Barotrauma.LuaCs.Configuration; - -public class ConfigEntry : IConfigEntry where T : IEquatable -{ - - private readonly Action, INetReadMessage> _readMessageHandler; - private readonly Action, INetWriteMessage> _writeMessageHandler; - - public ConfigEntry(IConfigInfo configInfo, Action, INetReadMessage> readMessageHandler, - Action, INetWriteMessage> writeMessageHandler) - { - _readMessageHandler = readMessageHandler; - _writeMessageHandler = writeMessageHandler; - } - - public string InternalName { get; init; } - public ContentPackage OwnerPackage { get; init; } - - public bool Equals(IConfigBase other) - { - if (ReferenceEquals(this, other)) - return true; - throw new NotImplementedException(); - } - - public void Dispose() - { - throw new NotImplementedException(); - } - - public Type GetValueType() - { - throw new NotImplementedException(); - } - - public string GetValue() - { - throw new NotImplementedException(); - } - - public bool TrySetValue(OneOf value) - { - throw new NotImplementedException(); - } - - public bool IsAssignable(OneOf value) - { - throw new NotImplementedException(); - } - - private event Action> _onValueChanged; - public event Action> OnValueChanged - { - add => _onValueChanged += value; - remove => _onValueChanged -= value; - } - - event Action IConfigBase.OnValueChanged - { - add => _onValueChanged += value; - remove => _onValueChanged -= value; - } - - public OneOf GetSerializableValue() - { - throw new NotImplementedException(); - } - - public Guid InstanceId => throw new NotImplementedException(); - - public NetSync SyncType => throw new NotImplementedException(); - - public ClientPermissions WritePermissions => throw new NotImplementedException(); - - public void ReadNetMessage(INetReadMessage message) - { - throw new NotImplementedException(); - } - - public void WriteNetMessage(INetWriteMessage message) - { - throw new NotImplementedException(); - } - - public T Value => throw new NotImplementedException(); - - public bool TrySetValue(T value) - { - throw new NotImplementedException(); - } - - public bool IsAssignable(T value) - { - throw new NotImplementedException(); - } -} diff --git a/Barotrauma/BarotraumaShared/SharedSource/LuaCs/Configuration/ConfigList.cs b/Barotrauma/BarotraumaShared/SharedSource/LuaCs/Configuration/ConfigList.cs deleted file mode 100644 index d67d09e7d..000000000 --- a/Barotrauma/BarotraumaShared/SharedSource/LuaCs/Configuration/ConfigList.cs +++ /dev/null @@ -1,111 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Xml.Linq; -using Barotrauma.LuaCs.Data; -using Barotrauma.LuaCs.Services; -using Barotrauma.Networking; -using OneOf; - -namespace Barotrauma.LuaCs.Configuration; - -public class ConfigList : IConfigList where T : IEquatable -{ - private readonly Action, INetReadMessage> _readMessageHandler; - private readonly Action, INetWriteMessage> _writeMessageHandler; - - public ConfigList(IConfigInfo configInfo, Action, INetReadMessage> readMessageHandler, - Action, INetWriteMessage> writeMessageHandler) - { - _readMessageHandler = readMessageHandler; - _writeMessageHandler = writeMessageHandler; - } - - public string InternalName => throw new NotImplementedException(); - - public ContentPackage OwnerPackage => throw new NotImplementedException(); - - public bool Equals(IConfigBase other) - { - throw new NotImplementedException(); - } - - public void Dispose() - { - throw new NotImplementedException(); - } - - public Type GetValueType() - { - throw new NotImplementedException(); - } - - public string GetValue() - { - throw new NotImplementedException(); - } - - public bool TrySetValue(OneOf value) - { - throw new NotImplementedException(); - } - - public bool IsAssignable(OneOf value) - { - throw new NotImplementedException(); - } - - private event Action> _onValueChanged; - - public event Action> OnValueChanged - { - add => _onValueChanged += value; - remove => _onValueChanged -= value; - } - - event Action> IConfigEntry.OnValueChanged - { - add => _onValueChanged += value; - remove => _onValueChanged -= value; - } - - event Action IConfigBase.OnValueChanged - { - add => _onValueChanged += value; - remove => _onValueChanged -= value; - } - - public T Value => throw new NotImplementedException(); - - public bool TrySetValue(T value) - { - throw new NotImplementedException(); - } - - public bool IsAssignable(T value) - { - throw new NotImplementedException(); - } - - public OneOf GetSerializableValue() - { - throw new NotImplementedException(); - } - - public Guid InstanceId => throw new NotImplementedException(); - - public NetSync SyncType => throw new NotImplementedException(); - - public ClientPermissions WritePermissions => throw new NotImplementedException(); - - public void ReadNetMessage(INetReadMessage message) - { - throw new NotImplementedException(); - } - - public void WriteNetMessage(INetWriteMessage message) - { - throw new NotImplementedException(); - } - - public IReadOnlyList Options => throw new NotImplementedException(); -} diff --git a/Barotrauma/BarotraumaShared/SharedSource/LuaCs/Configuration/IConfigBase.cs b/Barotrauma/BarotraumaShared/SharedSource/LuaCs/Configuration/ISettingBase.cs similarity index 61% rename from Barotrauma/BarotraumaShared/SharedSource/LuaCs/Configuration/IConfigBase.cs rename to Barotrauma/BarotraumaShared/SharedSource/LuaCs/Configuration/ISettingBase.cs index 8e65f68b5..6adc49f31 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/LuaCs/Configuration/IConfigBase.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/LuaCs/Configuration/ISettingBase.cs @@ -6,12 +6,13 @@ using Barotrauma.Networking; namespace Barotrauma.LuaCs.Configuration; -public partial interface IConfigBase : IDataInfo, IEquatable, IDisposable +public partial interface ISettingBase : IDataInfo, IEquatable, IDisposable { Type GetValueType(); - string GetValue(); + string GetStringValue(); bool TrySetValue(OneOf.OneOf value); bool IsAssignable(OneOf.OneOf value); - event Action OnValueChanged; + event Func, bool> IsNewValueValid; + event Action OnValueChanged; OneOf.OneOf GetSerializableValue(); } diff --git a/Barotrauma/BarotraumaShared/SharedSource/LuaCs/Configuration/IConfigEntry.cs b/Barotrauma/BarotraumaShared/SharedSource/LuaCs/Configuration/ISettingEntry.cs similarity index 55% rename from Barotrauma/BarotraumaShared/SharedSource/LuaCs/Configuration/IConfigEntry.cs rename to Barotrauma/BarotraumaShared/SharedSource/LuaCs/Configuration/ISettingEntry.cs index 9b173233a..a6e545543 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/LuaCs/Configuration/IConfigEntry.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/LuaCs/Configuration/ISettingEntry.cs @@ -3,10 +3,10 @@ using Barotrauma.LuaCs.Services; namespace Barotrauma.LuaCs.Configuration; -public interface IConfigEntry : IConfigBase, INetworkSyncEntity where T : IEquatable +public interface ISettingEntry : ISettingBase, INetworkSyncEntity where T : IEquatable { T Value { get; } bool TrySetValue(T value); bool IsAssignable(T value); - new event Action> OnValueChanged; + new event Action> OnValueChanged; } diff --git a/Barotrauma/BarotraumaShared/SharedSource/LuaCs/Configuration/IConfigEnum.cs b/Barotrauma/BarotraumaShared/SharedSource/LuaCs/Configuration/ISettingEnum.cs similarity index 61% rename from Barotrauma/BarotraumaShared/SharedSource/LuaCs/Configuration/IConfigEnum.cs rename to Barotrauma/BarotraumaShared/SharedSource/LuaCs/Configuration/ISettingEnum.cs index 742f80a46..83e9604f0 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/LuaCs/Configuration/IConfigEnum.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/LuaCs/Configuration/ISettingEnum.cs @@ -3,7 +3,7 @@ using Barotrauma.LuaCs.Services; namespace Barotrauma.LuaCs.Configuration; -public interface IConfigEnum : IConfigBase, INetworkSyncEntity +public interface ISettingEnum : ISettingBase, INetworkSyncEntity { } diff --git a/Barotrauma/BarotraumaShared/SharedSource/LuaCs/Configuration/IConfigList.cs b/Barotrauma/BarotraumaShared/SharedSource/LuaCs/Configuration/ISettingList.cs similarity index 52% rename from Barotrauma/BarotraumaShared/SharedSource/LuaCs/Configuration/IConfigList.cs rename to Barotrauma/BarotraumaShared/SharedSource/LuaCs/Configuration/ISettingList.cs index d78b5779d..ee74412cb 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/LuaCs/Configuration/IConfigList.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/LuaCs/Configuration/ISettingList.cs @@ -4,8 +4,8 @@ using Barotrauma.LuaCs.Services; namespace Barotrauma.LuaCs.Configuration; -public interface IConfigList : IConfigEntry, INetworkSyncEntity where T : IEquatable +public interface ISettingList : ISettingEntry, INetworkSyncEntity where T : IEquatable { IReadOnlyList Options { get; } - new event Action> OnValueChanged; + new event Action> OnValueChanged; } diff --git a/Barotrauma/BarotraumaShared/SharedSource/LuaCs/Configuration/IConfigRangeEntry.cs b/Barotrauma/BarotraumaShared/SharedSource/LuaCs/Configuration/ISettingRangeEntry.cs similarity index 66% rename from Barotrauma/BarotraumaShared/SharedSource/LuaCs/Configuration/IConfigRangeEntry.cs rename to Barotrauma/BarotraumaShared/SharedSource/LuaCs/Configuration/ISettingRangeEntry.cs index 571bb1d3f..57eb47fab 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/LuaCs/Configuration/IConfigRangeEntry.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/LuaCs/Configuration/ISettingRangeEntry.cs @@ -2,7 +2,7 @@ using System; namespace Barotrauma.LuaCs.Configuration; -public interface IConfigRangeEntry : IConfigEntry where T : IConvertible, IEquatable +public interface ISettingRangeEntry : ISettingEntry where T : IConvertible, IEquatable { T MinValue { get; } T MaxValue { get; } diff --git a/Barotrauma/BarotraumaShared/SharedSource/LuaCs/Configuration/SettingEntry.cs b/Barotrauma/BarotraumaShared/SharedSource/LuaCs/Configuration/SettingEntry.cs new file mode 100644 index 000000000..37d7d5e9f --- /dev/null +++ b/Barotrauma/BarotraumaShared/SharedSource/LuaCs/Configuration/SettingEntry.cs @@ -0,0 +1,85 @@ +using System; +using System.Xml.Linq; +using Barotrauma.LuaCs.Data; +using Barotrauma.LuaCs.Services; +using Barotrauma.Networking; +using OneOf; + +namespace Barotrauma.LuaCs.Configuration; + +public class SettingEntry : ISettingEntry where T : IEquatable +{ + public string InternalName { get; } + public ContentPackage OwnerPackage { get; } + public bool Equals(ISettingBase other) + { + throw new NotImplementedException(); + } + + public void Dispose() + { + throw new NotImplementedException(); + } + + public Type GetValueType() + { + throw new NotImplementedException(); + } + + public string GetStringValue() + { + throw new NotImplementedException(); + } + + public bool TrySetValue(OneOf value) + { + throw new NotImplementedException(); + } + + public bool IsAssignable(OneOf value) + { + throw new NotImplementedException(); + } + + public event Func, bool> IsNewValueValid; + public T Value { get; } + public bool TrySetValue(T value) + { + throw new NotImplementedException(); + } + + public bool IsAssignable(T value) + { + throw new NotImplementedException(); + } + + event Action> ISettingEntry.OnValueChanged + { + add => throw new NotImplementedException(); + remove => throw new NotImplementedException(); + } + + event Action ISettingBase.OnValueChanged + { + add => throw new NotImplementedException(); + remove => throw new NotImplementedException(); + } + + public OneOf GetSerializableValue() + { + throw new NotImplementedException(); + } + + public Guid InstanceId { get; } + public NetSync SyncType { get; } + public ClientPermissions WritePermissions { get; } + public void ReadNetMessage(INetReadMessage message) + { + throw new NotImplementedException(); + } + + public void WriteNetMessage(INetWriteMessage message) + { + throw new NotImplementedException(); + } +} diff --git a/Barotrauma/BarotraumaShared/SharedSource/LuaCs/Configuration/SettingList.cs b/Barotrauma/BarotraumaShared/SharedSource/LuaCs/Configuration/SettingList.cs new file mode 100644 index 000000000..973a14abe --- /dev/null +++ b/Barotrauma/BarotraumaShared/SharedSource/LuaCs/Configuration/SettingList.cs @@ -0,0 +1,94 @@ +using System; +using System.Collections.Generic; +using System.Xml.Linq; +using Barotrauma.LuaCs.Data; +using Barotrauma.LuaCs.Services; +using Barotrauma.Networking; +using OneOf; + +namespace Barotrauma.LuaCs.Configuration; + +public class SettingList : ISettingList where T : IEquatable +{ + public string InternalName { get; } + public ContentPackage OwnerPackage { get; } + public bool Equals(ISettingBase other) + { + throw new NotImplementedException(); + } + + public void Dispose() + { + throw new NotImplementedException(); + } + + public Type GetValueType() + { + throw new NotImplementedException(); + } + + public string GetStringValue() + { + throw new NotImplementedException(); + } + + public bool TrySetValue(OneOf value) + { + throw new NotImplementedException(); + } + + public bool IsAssignable(OneOf value) + { + throw new NotImplementedException(); + } + + public event Func, bool> IsNewValueValid; + public T Value { get; } + public bool TrySetValue(T value) + { + throw new NotImplementedException(); + } + + public bool IsAssignable(T value) + { + throw new NotImplementedException(); + } + + event Action> ISettingList.OnValueChanged + { + add => throw new NotImplementedException(); + remove => throw new NotImplementedException(); + } + + public IReadOnlyList Options { get; } + + event Action> ISettingEntry.OnValueChanged + { + add => throw new NotImplementedException(); + remove => throw new NotImplementedException(); + } + + event Action ISettingBase.OnValueChanged + { + add => throw new NotImplementedException(); + remove => throw new NotImplementedException(); + } + + public OneOf GetSerializableValue() + { + throw new NotImplementedException(); + } + + public Guid InstanceId { get; } + public NetSync SyncType { get; } + public ClientPermissions WritePermissions { get; } + public void ReadNetMessage(INetReadMessage message) + { + throw new NotImplementedException(); + } + + public void WriteNetMessage(INetWriteMessage message) + { + throw new NotImplementedException(); + } +} diff --git a/Barotrauma/BarotraumaShared/SharedSource/LuaCs/Data/DataInterfaceImplementations.cs b/Barotrauma/BarotraumaShared/SharedSource/LuaCs/Data/DataInterfaceImplementations.cs index 3c2c84007..798e8734e 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/LuaCs/Data/DataInterfaceImplementations.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/LuaCs/Data/DataInterfaceImplementations.cs @@ -67,9 +67,8 @@ public record ConfigInfo : IConfigInfo { public string InternalName { get; init; } public ContentPackage OwnerPackage { get; init; } - public Type DataType { get; init; } - public OneOf DefaultValue { get; init; } - public OneOf Value { get; init; } + public string DataType { get; init; } + public XElement Element { get; init; } public RunState EditableStates { get; init; } public NetSync NetSync { get; init; } @@ -79,7 +78,7 @@ public record ConfigInfo : IConfigInfo public string DisplayCategory { get; init; } public bool ShowInMenus { get; init; } public string Tooltip { get; init; } - public string ImageIconPath { get; init; } + public ContentPath ImageIconPath { get; init; } #endif } @@ -87,7 +86,7 @@ public record ConfigProfileInfo : IConfigProfileInfo { public string InternalName { get; init; } public ContentPackage OwnerPackage { get; init; } - public IReadOnlyList<(string ConfigName, OneOf Value)> ProfileValues { get; init; } + public IReadOnlyList<(string ConfigName, XElement Element)> ProfileValues { get; init; } } #endregion diff --git a/Barotrauma/BarotraumaShared/SharedSource/LuaCs/Data/IConfigInfo.cs b/Barotrauma/BarotraumaShared/SharedSource/LuaCs/Data/IConfigInfo.cs index 4d8a5e5ea..164d37791 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/LuaCs/Data/IConfigInfo.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/LuaCs/Data/IConfigInfo.cs @@ -13,26 +13,18 @@ public partial interface IConfigInfo : IDataInfo /// /// Specifies the type initializer that will be used to instantiate the config var. /// - Type DataType { get; } + string DataType { get; } /// - /// The default value. + /// The 'Setting' XML element. /// - OneOf.OneOf DefaultValue { get; } - /// - /// The value the last time this config was saved. If not found, returns the default value. - ///
[If(Type='')]
- /// The value is from the 'Value' Attribute. Typically used for types with single/simple values, such as primitives. - ///
[If(Type='')]
- /// The value is from the first 'Value' child element. Typically used with complex config types, such as range and list. - ///
- OneOf.OneOf Value { get; } + XElement Element { get; } /// /// In what (s) is this config editable. Will be editable in the selected state, and lower value states. ///

/// [Important]
Setting this to value lower than 'Configuration` will render this config read-only. ///

Expected Behaviour: - ///
[|]: Read-Only. - ///
[]: Can only be changed at the Main Menu (not in a lobby). + ///
[|]: Read-Only. + ///
[]: Can only be changed at the Main Menu (not in a lobby). ///
[]: Can be changed at the Main Menu and while a lobby is active. ///
RunState EditableStates { get; } diff --git a/Barotrauma/BarotraumaShared/SharedSource/LuaCs/Data/IConfigProfileInfo.cs b/Barotrauma/BarotraumaShared/SharedSource/LuaCs/Data/IConfigProfileInfo.cs index d60fb2772..5d5f9065d 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/LuaCs/Data/IConfigProfileInfo.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/LuaCs/Data/IConfigProfileInfo.cs @@ -5,5 +5,5 @@ namespace Barotrauma.LuaCs.Data; public interface IConfigProfileInfo : IDataInfo { - IReadOnlyList<(string ConfigName, OneOf.OneOf Value)> ProfileValues { get; } + IReadOnlyList<(string ConfigName, XElement Element)> ProfileValues { get; } } diff --git a/Barotrauma/BarotraumaShared/SharedSource/LuaCs/IEvents.cs b/Barotrauma/BarotraumaShared/SharedSource/LuaCs/IEvents.cs index b3125f8b4..d3c6ac779 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/LuaCs/IEvents.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/LuaCs/IEvents.cs @@ -30,7 +30,7 @@ public interface IEvent : IEvent where T : IEvent } } -#region RuntimeEvents +#region RuntimeServiceEvents /// /// Called when the current (game state) changes. Upstream Type 'Screen' is internal. @@ -61,6 +61,12 @@ internal interface IEventReloadAllPackages : IEvent void OnReloadAllPackages(); } +internal interface IEventSettingInstanceLifetime : IEvent +{ + void OnSettingInstanceCreated(T configInstance) where T : ISettingBase; + void OnSettingInstanceDisposed(T configInstance) where T : ISettingBase; +} + #endregion #region GameEvents diff --git a/Barotrauma/BarotraumaShared/SharedSource/LuaCs/LuaCsSetup.cs b/Barotrauma/BarotraumaShared/SharedSource/LuaCs/LuaCsSetup.cs index 4a31ec71c..c0811c934 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/LuaCs/LuaCsSetup.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/LuaCs/LuaCsSetup.cs @@ -99,56 +99,56 @@ namespace Barotrauma /// /// Whether C# plugin code is enabled. /// - internal IConfigEntry IsCsEnabled { get; private set; } + internal ISettingEntry IsCsEnabled { get; private set; } /// /// Whether mods marked as 'forced' or 'always load' should only be loaded if they're in the enabled mods list. /// - internal IConfigEntry TreatForcedModsAsNormal { get; private set; } + internal ISettingEntry TreatForcedModsAsNormal { get; private set; } /// /// Whether the lua script runner from Workshop package should be used over the in-built version. /// - internal IConfigEntry PreferToUseWorkshopLuaSetup { get; private set; } + internal ISettingEntry PreferToUseWorkshopLuaSetup { get; private set; } /// /// Whether the popup error GUI should be hidden/suppressed. /// - internal IConfigEntry DisableErrorGUIOverlay { get; private set; } + internal ISettingEntry DisableErrorGUIOverlay { get; private set; } /// /// Whether usernames are anonymized or show in logs. /// - internal IConfigEntry HideUserNamesInLogs { get; private set; } + internal ISettingEntry HideUserNamesInLogs { get; private set; } /// /// The SteamId of the Workshop LuaCs CPackage in use, if available. /// - internal IConfigEntry LuaForBarotraumaSteamId { get; private set; } + internal ISettingEntry LuaForBarotraumaSteamId { get; private set; } /// /// TODO: @evilfactory@users.noreply.github.com /// - internal IConfigEntry RestrictMessageSize { get; private set; } + internal ISettingEntry RestrictMessageSize { get; private set; } /// /// The local save path for all local data storage for mods. /// - internal IConfigEntry LocalDataSavePath { get; private set; } + internal ISettingEntry LocalDataSavePath { get; private set; } void LoadLuaCsConfig() { - IsCsEnabled = ConfigService.TryGetConfig>(ContentPackageManager.VanillaCorePackage, "IsCsEnabled", out var val1) ? val1 + IsCsEnabled = ConfigService.TryGetConfig>(ContentPackageManager.VanillaCorePackage, "IsCsEnabled", out var val1) ? val1 : throw new NullReferenceException($"{nameof(IsCsEnabled)} cannot be loaded."); - TreatForcedModsAsNormal = ConfigService.TryGetConfig>(ContentPackageManager.VanillaCorePackage, "TreatForcedModsAsNormal", out var val2) ? val2 + TreatForcedModsAsNormal = ConfigService.TryGetConfig>(ContentPackageManager.VanillaCorePackage, "TreatForcedModsAsNormal", out var val2) ? val2 : throw new NullReferenceException($"{nameof(TreatForcedModsAsNormal)} cannot be loaded."); - DisableErrorGUIOverlay = ConfigService.TryGetConfig>(ContentPackageManager.VanillaCorePackage, "DisableErrorGUIOverlay", out var val3) ? val3 + DisableErrorGUIOverlay = ConfigService.TryGetConfig>(ContentPackageManager.VanillaCorePackage, "DisableErrorGUIOverlay", out var val3) ? val3 : throw new NullReferenceException($"{nameof(DisableErrorGUIOverlay)} cannot be loaded."); - HideUserNamesInLogs = ConfigService.TryGetConfig>(ContentPackageManager.VanillaCorePackage, "HideUserNamesInLogs", out var val4) ? val4 + HideUserNamesInLogs = ConfigService.TryGetConfig>(ContentPackageManager.VanillaCorePackage, "HideUserNamesInLogs", out var val4) ? val4 : throw new NullReferenceException($"{nameof(HideUserNamesInLogs)} cannot be loaded."); - LuaForBarotraumaSteamId = ConfigService.TryGetConfig>(ContentPackageManager.VanillaCorePackage, "LuaForBarotraumaSteamId", out var val5) ? val5 + LuaForBarotraumaSteamId = ConfigService.TryGetConfig>(ContentPackageManager.VanillaCorePackage, "LuaForBarotraumaSteamId", out var val5) ? val5 : throw new NullReferenceException($"{nameof(LuaForBarotraumaSteamId)} cannot be loaded."); - RestrictMessageSize = ConfigService.TryGetConfig>(ContentPackageManager.VanillaCorePackage, "RestrictMessageSize", out var val7) ? val7 + RestrictMessageSize = ConfigService.TryGetConfig>(ContentPackageManager.VanillaCorePackage, "RestrictMessageSize", out var val7) ? val7 : throw new NullReferenceException($"{nameof(RestrictMessageSize)} cannot be loaded."); } @@ -170,9 +170,11 @@ namespace Barotrauma // TODO: INetworkingService servicesProvider.RegisterServiceType(ServiceLifetime.Singleton); servicesProvider.RegisterServiceType(ServiceLifetime.Transient); - servicesProvider.RegisterServiceType, ConfigFileParserService>(ServiceLifetime.Transient); - servicesProvider.RegisterServiceType, ConfigFileParserService>(ServiceLifetime.Transient); - servicesProvider.RegisterServiceType, ConfigFileParserService>(ServiceLifetime.Transient); + servicesProvider.RegisterServiceType, ModConfigFileParserService>(ServiceLifetime.Transient); + servicesProvider.RegisterServiceType, ModConfigFileParserService>(ServiceLifetime.Transient); + servicesProvider.RegisterServiceType, ModConfigFileParserService>(ServiceLifetime.Transient); + servicesProvider.RegisterServiceType, SettingsFileParserService>(ServiceLifetime.Transient); + servicesProvider.RegisterServiceType, SettingsFileParserService>(ServiceLifetime.Transient); // service config data servicesProvider.RegisterServiceType(ServiceLifetime.Singleton); servicesProvider.RegisterServiceType(ServiceLifetime.Singleton); diff --git a/Barotrauma/BarotraumaShared/SharedSource/LuaCs/Services/ConfigInitializers.cs b/Barotrauma/BarotraumaShared/SharedSource/LuaCs/Services/ConfigInitializers.cs index d3bad9e9d..388923d64 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/LuaCs/Services/ConfigInitializers.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/LuaCs/Services/ConfigInitializers.cs @@ -26,37 +26,19 @@ public class ConfigInitializers : IService // stateless service public bool IsDisposed => false; - private Result> CreateConfigEntry(IConfigInfo configInfo, - Action, INetReadMessage> readHandler, - Action, INetWriteMessage> writeHandler) + private Result> CreateConfigEntry(IConfigInfo configInfo, + Action, INetReadMessage> readHandler, + Action, INetWriteMessage> writeHandler) where T : IEquatable { - try - { - var ice = new ConfigEntry(configInfo, readHandler, writeHandler); - return FluentResults.Result.Ok>(ice); - } - catch (Exception e) - { - return FluentResults.Result.Fail($"Error while initializing config var: {configInfo?.OwnerPackage} - {configInfo?.InternalName}") - .WithError(new ExceptionalError(e)); - } + throw new NotImplementedException(); } - private Result> CreateConfigList(IConfigInfo configInfo, - Action, INetReadMessage> readHandler, Action, INetWriteMessage> writeHandler) + private Result> CreateConfigList(IConfigInfo configInfo, + Action, INetReadMessage> readHandler, Action, INetWriteMessage> writeHandler) where T : IEquatable { - try - { - var icl = new ConfigList(configInfo, readHandler, writeHandler); - return FluentResults.Result.Ok>(icl); - } - catch (Exception e) - { - return FluentResults.Result.Fail($"Error while initializing config var: {configInfo?.OwnerPackage} - {configInfo?.InternalName}") - .WithError(new ExceptionalError(e)); - } + throw new NotImplementedException(); } public void RegisterTypeInitializers(IConfigService configService) @@ -64,30 +46,30 @@ public class ConfigInitializers : IService if (configService == null) throw new ArgumentNullException($"{nameof(RegisterTypeInitializers)}: {nameof(IConfigService)} is null."); - configService.RegisterTypeInitializer>(this.CreateConfigBool); - configService.RegisterTypeInitializer>(this.CreateConfigSbyte); - configService.RegisterTypeInitializer>(this.CreateConfigByte); - configService.RegisterTypeInitializer>(this.CreateConfigShort); - configService.RegisterTypeInitializer>(this.CreateConfigUShort); - configService.RegisterTypeInitializer>(this.CreateConfigInt32); - configService.RegisterTypeInitializer>(this.CreateConfigUInt32); - configService.RegisterTypeInitializer>(this.CreateConfigInt64); - configService.RegisterTypeInitializer>(this.CreateConfigUInt64); - configService.RegisterTypeInitializer>(this.CreateConfigFloat32); - configService.RegisterTypeInitializer>(this.CreateConfigFloat64); - configService.RegisterTypeInitializer>(this.CreateConfigFloat128); - configService.RegisterTypeInitializer>(this.CreateConfigChar); - configService.RegisterTypeInitializer>(this.CreateConfigString); - configService.RegisterTypeInitializer>(this.CreateConfigColor); - configService.RegisterTypeInitializer>(this.CreateConfigVector2); - configService.RegisterTypeInitializer>(this.CreateConfigVector3); - configService.RegisterTypeInitializer>(this.CreateConfigVector4); + /*configService.RegisterTypeInitializer>(this.CreateConfigBool); + configService.RegisterTypeInitializer>(this.CreateConfigSbyte); + configService.RegisterTypeInitializer>(this.CreateConfigByte); + configService.RegisterTypeInitializer>(this.CreateConfigShort); + configService.RegisterTypeInitializer>(this.CreateConfigUShort); + configService.RegisterTypeInitializer>(this.CreateConfigInt32); + configService.RegisterTypeInitializer>(this.CreateConfigUInt32); + configService.RegisterTypeInitializer>(this.CreateConfigInt64); + configService.RegisterTypeInitializer>(this.CreateConfigUInt64); + configService.RegisterTypeInitializer>(this.CreateConfigFloat32); + configService.RegisterTypeInitializer>(this.CreateConfigFloat64); + configService.RegisterTypeInitializer>(this.CreateConfigFloat128); + configService.RegisterTypeInitializer>(this.CreateConfigChar); + configService.RegisterTypeInitializer>(this.CreateConfigString); + configService.RegisterTypeInitializer>(this.CreateConfigColor); + configService.RegisterTypeInitializer>(this.CreateConfigVector2); + configService.RegisterTypeInitializer>(this.CreateConfigVector3); + configService.RegisterTypeInitializer>(this.CreateConfigVector4);*/ } #region InitializerWrappers_NetworkInjected - private void AssignValueConditional(T val, IConfigEntry inst) where T : IEquatable + private void AssignValueConditional(T val, ISettingEntry inst) where T : IEquatable { #if SERVER if (inst.SyncType is NetSync.None or NetSync.ServerAuthority) @@ -100,7 +82,7 @@ public class ConfigInitializers : IService #endif } - private Result> CreateConfigBool(IConfigInfo configInfo) + private Result> CreateConfigBool(IConfigInfo configInfo) { return CreateConfigEntry(configInfo, (inst, readMsg) => { @@ -112,7 +94,7 @@ public class ConfigInitializers : IService }); } - private Result> CreateConfigSbyte(IConfigInfo configInfo) + private Result> CreateConfigSbyte(IConfigInfo configInfo) { return CreateConfigEntry(configInfo, (inst, readMsg) => { @@ -124,7 +106,7 @@ public class ConfigInitializers : IService }); } - private Result> CreateConfigByte(IConfigInfo configInfo) + private Result> CreateConfigByte(IConfigInfo configInfo) { return CreateConfigEntry(configInfo, (inst, readMsg) => { @@ -136,7 +118,7 @@ public class ConfigInitializers : IService }); } - private Result> CreateConfigShort(IConfigInfo configInfo) + private Result> CreateConfigShort(IConfigInfo configInfo) { return CreateConfigEntry(configInfo, (inst, readMsg) => { @@ -148,7 +130,7 @@ public class ConfigInitializers : IService }); } - private Result> CreateConfigUShort(IConfigInfo configInfo) + private Result> CreateConfigUShort(IConfigInfo configInfo) { return CreateConfigEntry(configInfo, (inst, readMsg) => { @@ -160,7 +142,7 @@ public class ConfigInitializers : IService }); } - private Result> CreateConfigInt32(IConfigInfo configInfo) + private Result> CreateConfigInt32(IConfigInfo configInfo) { return CreateConfigEntry(configInfo, (inst, readMsg) => { @@ -172,7 +154,7 @@ public class ConfigInitializers : IService }); } - private Result> CreateConfigUInt32(IConfigInfo configInfo) + private Result> CreateConfigUInt32(IConfigInfo configInfo) { return CreateConfigEntry(configInfo, (inst, readMsg) => { @@ -184,7 +166,7 @@ public class ConfigInitializers : IService }); } - private Result> CreateConfigInt64(IConfigInfo configInfo) + private Result> CreateConfigInt64(IConfigInfo configInfo) { return CreateConfigEntry(configInfo, (inst, readMsg) => { @@ -196,7 +178,7 @@ public class ConfigInitializers : IService }); } - private Result> CreateConfigUInt64(IConfigInfo configInfo) + private Result> CreateConfigUInt64(IConfigInfo configInfo) { return CreateConfigEntry(configInfo, (inst, readMsg) => { @@ -208,7 +190,7 @@ public class ConfigInitializers : IService }); } - private Result> CreateConfigFloat32(IConfigInfo configInfo) + private Result> CreateConfigFloat32(IConfigInfo configInfo) { return CreateConfigEntry(configInfo, (inst, readMsg) => { @@ -220,7 +202,7 @@ public class ConfigInitializers : IService }); } - private Result> CreateConfigFloat64(IConfigInfo configInfo) + private Result> CreateConfigFloat64(IConfigInfo configInfo) { return CreateConfigEntry(configInfo, (inst, readMsg) => { @@ -232,7 +214,7 @@ public class ConfigInitializers : IService }); } - private Result> CreateConfigFloat128(IConfigInfo configInfo) + private Result> CreateConfigFloat128(IConfigInfo configInfo) { return CreateConfigEntry(configInfo, (inst, readMsg) => { @@ -253,7 +235,7 @@ public class ConfigInitializers : IService }); } - private Result> CreateConfigChar(IConfigInfo configInfo) + private Result> CreateConfigChar(IConfigInfo configInfo) { return CreateConfigEntry(configInfo, (inst, readMsg) => { @@ -265,7 +247,7 @@ public class ConfigInitializers : IService }); } - private Result> CreateConfigString(IConfigInfo configInfo) + private Result> CreateConfigString(IConfigInfo configInfo) { return CreateConfigEntry(configInfo, (inst, readMsg) => { @@ -277,7 +259,7 @@ public class ConfigInitializers : IService }); } - private Result> CreateConfigColor(IConfigInfo configInfo) + private Result> CreateConfigColor(IConfigInfo configInfo) { return CreateConfigEntry(configInfo, (inst, readMsg) => { @@ -289,7 +271,7 @@ public class ConfigInitializers : IService }); } - private Result> CreateConfigVector2(IConfigInfo configInfo) + private Result> CreateConfigVector2(IConfigInfo configInfo) { return CreateConfigEntry(configInfo, (inst, readMsg) => { @@ -302,7 +284,7 @@ public class ConfigInitializers : IService }); } - private Result> CreateConfigVector3(IConfigInfo configInfo) + private Result> CreateConfigVector3(IConfigInfo configInfo) { return CreateConfigEntry(configInfo, (inst, readMsg) => { @@ -316,7 +298,7 @@ public class ConfigInitializers : IService }); } - private Result> CreateConfigVector4(IConfigInfo configInfo) + private Result> CreateConfigVector4(IConfigInfo configInfo) { return CreateConfigEntry(configInfo, (inst, readMsg) => { diff --git a/Barotrauma/BarotraumaShared/SharedSource/LuaCs/Services/ConfigService.cs b/Barotrauma/BarotraumaShared/SharedSource/LuaCs/Services/ConfigService.cs index 8bcdb69fa..88c1f1e32 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/LuaCs/Services/ConfigService.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/LuaCs/Services/ConfigService.cs @@ -6,217 +6,318 @@ using System.Collections.Immutable; using System.IO; using System.Linq; using System.Text.RegularExpressions; +using System.Threading; using System.Threading.Tasks; using System.Xml.Linq; using Barotrauma.LuaCs.Configuration; using Barotrauma.LuaCs.Data; using Barotrauma.LuaCs.Events; using Barotrauma.LuaCs.Services.Processing; -using Barotrauma.Networking; -using Dynamitey.DynamicObjects; using FluentResults; -using Microsoft.Xna.Framework; -using OneOf; -using Path = Barotrauma.IO.Path; +using Microsoft.Toolkit.Diagnostics; namespace Barotrauma.LuaCs.Services; -public partial class ConfigService : IConfigService +public sealed partial class ConfigService : IConfigService { + #region Disposal_Locks_Reset + + private readonly AsyncReaderWriterLock _operationLock = new (); + private readonly AsyncReaderWriterLock _settingsByPackageLock = new (); + private int _isDisposed = 0; + public bool IsDisposed + { + get => ModUtils.Threading.GetBool(ref _isDisposed); + private set => ModUtils.Threading.SetBool(ref _isDisposed, value); + } + public void Dispose() { - throw new NotImplementedException(); - } + using var lck = _operationLock.AcquireWriterLock().ConfigureAwait(false).GetAwaiter().GetResult(); + using var settingsLck = _settingsByPackageLock.AcquireWriterLock().ConfigureAwait(false).GetAwaiter().GetResult(); + if (!ModUtils.Threading.CheckIfClearAndSetBool(ref _isDisposed)) + { + return; + } + + _logger.LogDebug($"{nameof(ConfigService)}: Disposing."); + + _configInfoParserService.Dispose(); + _configProfileInfoParserService.Dispose(); - public bool IsDisposed { get; } + if (!_settingsInstances.IsEmpty) + { + foreach (var instance in _settingsInstances) + { + try + { + if (instance.Value is null) + { + continue; + } + + _eventService.PublishEvent(sub => + // ReSharper disable once AccessToDisposedClosure + sub.OnSettingInstanceDisposed(instance.Value)); + instance.Value.Dispose(); + } + catch + { + // ignored + continue; + } + } + } + + _settingsInstances.Clear(); + _instanceFactory.Clear(); + _settingsInstancesByPackage.Clear(); + + _storageService = null; + _logger = null; + _eventService = null; + _configInfoParserService = null; + _configProfileInfoParserService = null; + } + public FluentResults.Result Reset() { - throw new NotImplementedException(); - } + using var lck = _operationLock.AcquireWriterLock().ConfigureAwait(false).GetAwaiter().GetResult(); + IService.CheckDisposed(this); + + var result = new FluentResults.Result(); + + if (!_settingsInstances.IsEmpty) + { + foreach (var instance in _settingsInstances) + { + try + { + if (instance.Value is null) + { + continue; + } - #region LuaInterface + _eventService.PublishEvent(sub => + // ReSharper disable once AccessToDisposedClosure + sub.OnSettingInstanceDisposed(instance.Value)); + instance.Value.Dispose(); + } + catch (Exception e) + { + result.WithError(new ExceptionalError(e)); + } + } + } + + _settingsInstances.Clear(); + _instanceFactory.Clear(); + _settingsInstancesByPackage.Clear(); - public bool TryGetConfigBool(string packageName, string configName, out bool value) - { - throw new NotImplementedException(); + return result; } - public bool TryGetConfigInt(string packageName, string configName, out int value) - { - throw new NotImplementedException(); - } - - public bool TryGetConfigFloat(string packageName, string configName, out float value) - { - throw new NotImplementedException(); - } - - public bool TryGetConfigNumber(string packageName, string configName, out double value) - { - throw new NotImplementedException(); - } - - public bool TryGetConfigString(string packageName, string configName, out string value) - { - throw new NotImplementedException(); - } - - public bool TryGetConfigVector2(string packageName, string configName, out Vector2 value) - { - throw new NotImplementedException(); - } - - public bool TryGetConfigVector3(string packageName, string configName, out Vector3 value) - { - throw new NotImplementedException(); - } - - public bool TryGetConfigColor(string packageName, string configName, out Color value) - { - throw new NotImplementedException(); - } - - public bool TryGetConfigList(string packageName, string configName, out IReadOnlyList value) - { - throw new NotImplementedException(); - } - - public void SetConfigBool(string packageName, string configName, bool value) - { - throw new NotImplementedException(); - } - - public void SetConfigInt(string packageName, string configName, int value) - { - throw new NotImplementedException(); - } - - public void SetConfigFloat(string packageName, string configName, float value) - { - throw new NotImplementedException(); - } - - public void SetConfigNumber(string packageName, string configName, double value) - { - throw new NotImplementedException(); - } - - public void SetConfigString(string packageName, string configName, string value) - { - throw new NotImplementedException(); - } - - public void SetConfigVector2(string packageName, string configName, Vector2 value) - { - throw new NotImplementedException(); - } - - public void SetConfigVector3(string packageName, string configName, Vector3 value) - { - throw new NotImplementedException(); - } - - public void SetConfigColor(string packageName, string configName, Color value) - { - throw new NotImplementedException(); - } - - public void SetConfigList(string packageName, string configName, string value) - { - throw new NotImplementedException(); - } - - public bool TryApplyProfileSettings(string packageName, string profileName) - { - throw new NotImplementedException(); - } - - #endregion + - public void RegisterTypeInitializer(Func> initializer, bool replaceIfExists = false) where TData : IEquatable where TConfig : IConfigBase + private readonly ConcurrentDictionary<(ContentPackage OwnerPackage, string InternalName), ISettingBase> + _settingsInstances = new(); + private readonly ConcurrentDictionary> + _instanceFactory = new(); + private readonly ConcurrentDictionary> + _settingsInstancesByPackage = new(); + + private IStorageService _storageService; + private ILoggerService _logger; + private IEventService _eventService; + private IParserServiceOneToManyAsync _configInfoParserService; + private IParserServiceOneToManyAsync _configProfileInfoParserService; + + public ConfigService(ILoggerService logger, + IStorageService storageService, + IParserServiceOneToManyAsync configInfoParserService, + IParserServiceOneToManyAsync configProfileInfoParserService, IEventService eventService) { - throw new NotImplementedException(); + _logger = logger; + _storageService = storageService; + _configInfoParserService = configInfoParserService; + _configProfileInfoParserService = configProfileInfoParserService; + _eventService = eventService; + } + + + public void RegisterSettingTypeInitializer(string typeIdentifier, Func settingFactory) where T : class, ISettingBase + { + Guard.IsNotNullOrWhiteSpace(typeIdentifier, nameof(typeIdentifier)); + Guard.IsNotNull(settingFactory, nameof(settingFactory)); + using var lck = _operationLock.AcquireReaderLock().ConfigureAwait(false).GetAwaiter().GetResult(); + IService.CheckDisposed(this); + + if (_instanceFactory.ContainsKey(typeIdentifier)) + { + ThrowHelper.ThrowArgumentException($"{nameof(RegisterSettingTypeInitializer)}: The type identifier {typeIdentifier} is already registered."); + } + + _instanceFactory[typeIdentifier] = settingFactory; } public async Task LoadConfigsAsync(ImmutableArray configResources) { -#if DEBUG - return FluentResults.Result.Ok(); // just for startup testing -#endif - throw new NotImplementedException(); + using var lck = _operationLock.AcquireReaderLock().ConfigureAwait(false).GetAwaiter().GetResult(); + IService.CheckDisposed(this); + if (configResources.IsDefaultOrEmpty) + { + return FluentResults.Result.Ok(); + } + + var taskBuilder = ImmutableArray.CreateBuilder>>(); + var toProcessErrors = new ConcurrentStack(); + + var taskCtx = TaskScheduler.FromCurrentSynchronizationContext(); + + foreach (var resource in configResources) + { + taskBuilder.Add(await Task.Factory.StartNew>>(async Task> () => + { + var r = await _configInfoParserService.TryParseResourcesAsync(resource); + if (r.IsFailed) + { + toProcessErrors.PushRange(r.Errors.ToArray()); + return ImmutableArray.Empty; + } + return r.Value; + })); + } + + var taskResults = await Task.WhenAll(taskBuilder.MoveToImmutable()); + + if (toProcessErrors.Count > 0) + { + return FluentResults.Result.Fail($"{nameof(LoadConfigsAsync)}: Errors while loading configuration info: ").WithErrors(toProcessErrors.ToArray()); + } + + var toProcessDocs = taskResults + .Where(tr => !tr.IsDefaultOrEmpty) + .SelectMany(tr => tr) + .ToImmutableArray(); + + var instanceQueue = new Queue<(IConfigInfo configInfo, Func factory)>(); + + foreach (var info in toProcessDocs) + { + if (!_instanceFactory.TryGetValue(info.DataType, out var factory)) + { + return FluentResults.Result.Fail($"{nameof(LoadConfigsAsync)}: Could not retrieve the instance factory for the data type of '{info.DataType}'!"); + } + if (_settingsInstances.ContainsKey((info.OwnerPackage, info.InternalName))) + { + // duplicate for some reason (ie. double loading). This should never happen. + ThrowHelper.ThrowInvalidOperationException($"{nameof(LoadConfigsAsync)}: A setting for the [ContentPackage].[InternalName] of '[{info.OwnerPackage.Name}].[{info.InternalName}]' already exists!"); + } + + instanceQueue.Enqueue((info, factory)); + } + + var toProcessInstanceQueue = new Queue<(IConfigInfo info, ISettingBase instance)>(); + + while (instanceQueue.TryDequeue(out var instanceFactoryInfo)) + { + try + { + toProcessInstanceQueue.Enqueue((instanceFactoryInfo.configInfo, instanceFactoryInfo.factory(instanceFactoryInfo.configInfo))); + } + catch (Exception e) + { + FluentResults.Result.Fail( + $"{nameof(LoadConfigsAsync)}: Error while instancing setting for '{instanceFactoryInfo.configInfo.OwnerPackage}.{instanceFactoryInfo.configInfo.InternalName}': {e.Message}!"); + } + } + + using var settingsLck = await _settingsByPackageLock.AcquireWriterLock(); // block to protect new bag instance creation + var result = new FluentResults.Result(); + + while (toProcessInstanceQueue.TryDequeue(out var newInstanceData)) + { + _settingsInstances[(newInstanceData.info.OwnerPackage, newInstanceData.info.InternalName)] = newInstanceData.instance; + if (!_settingsInstancesByPackage.TryGetValue(newInstanceData.info.OwnerPackage, out _)) + { + _settingsInstancesByPackage[newInstanceData.info.OwnerPackage] = new ConcurrentBag(); + } + _settingsInstancesByPackage[newInstanceData.info.OwnerPackage].Add(newInstanceData.instance); + result.WithReasons(_eventService.PublishEvent(sub => + sub.OnSettingInstanceCreated(newInstanceData.instance)).Reasons); + } + + return result; } public async Task LoadConfigsProfilesAsync(ImmutableArray configProfileResources) { #if DEBUG - return FluentResults.Result.Ok(); // just for startup testing + // TODO: Implement profiles. + return FluentResults.Result.Ok(); #endif throw new NotImplementedException(); } - public Result AddConfig(IConfigInfo configInfo) where TConfig : IConfigBase - { - throw new NotImplementedException(); - } - - public FluentResults.Result ApplyProfileSettings(ContentPackage package, string profileName) - { - throw new NotImplementedException(); - } - public FluentResults.Result DisposePackageData(ContentPackage package) { -#if DEBUG - return FluentResults.Result.Ok(); // just for startup testing -#endif - throw new NotImplementedException(); + Guard.IsNotNull(package, nameof(package)); + using var lck = _operationLock.AcquireReaderLock().ConfigureAwait(false).GetAwaiter().GetResult(); + ConcurrentBag toDispose; + using (var settingsLck = _settingsByPackageLock.AcquireWriterLock().ConfigureAwait(false).GetAwaiter().GetResult()) + { + if (!_settingsInstancesByPackage.TryRemove(package, out toDispose) || toDispose is null) + { + return FluentResults.Result.Ok(); + } + } + + var result = new FluentResults.Result(); + + foreach (var setting in toDispose) + { + result.WithReasons(_eventService.PublishEvent(sub => sub.OnSettingInstanceDisposed(setting)).Reasons); + try + { + setting.Dispose(); + } + catch (Exception e) + { + result.WithError(new ExceptionalError(e)); + } + } + + return result; } public FluentResults.Result DisposeAllPackageData() { -#if DEBUG - return FluentResults.Result.Ok(); // just for startup testing -#endif - throw new NotImplementedException(); + return this.Reset(); } - public Result> GetConfigsForPackage(ContentPackage package) + public bool TryGetConfig(ContentPackage package, string internalName, out T instance) where T : ISettingBase { - throw new NotImplementedException(); - } + Guard.IsNotNull(package, nameof(package)); + Guard.IsNotNullOrWhiteSpace(internalName, nameof(internalName)); + using var lck = _operationLock.AcquireReaderLock().ConfigureAwait(false).GetAwaiter().GetResult(); + using var settingsLck = + _settingsByPackageLock.AcquireReaderLock().ConfigureAwait(false).GetAwaiter().GetResult(); + IService.CheckDisposed(this); + + instance = default; + + if(!_settingsInstances.TryGetValue((package, internalName), out var inst)) + { + return false; + } - public Result Value)>>> GetProfilesForPackage(ContentPackage package) - { - throw new NotImplementedException(); - } - - public IReadOnlyDictionary<(ContentPackage Package, string Name), IConfigBase> GetAllConfigs() - { - throw new NotImplementedException(); - } - - public bool TryGetConfig(ContentPackage package, string name, out T config) where T : IConfigBase - { -#if DEBUG - config = default(T); - return true; // just for startup testing -#endif - throw new NotImplementedException(); - } - - public async Task SaveAllConfigs() - { - throw new NotImplementedException(); - } - - public async Task SaveConfigsForPackage(ContentPackage package) - { - throw new NotImplementedException(); - } - - public async Task SaveConfig((ContentPackage Package, string ConfigName) config) - { - throw new NotImplementedException(); + if (inst is not T instanceT) + { + return false; + } + + instance = instanceT; + return true; } } diff --git a/Barotrauma/BarotraumaShared/SharedSource/LuaCs/Services/EventService.cs b/Barotrauma/BarotraumaShared/SharedSource/LuaCs/Services/EventService.cs index c237015a7..80ce7628c 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/LuaCs/Services/EventService.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/LuaCs/Services/EventService.cs @@ -325,6 +325,9 @@ public class EventService : IEventService, IEventAssemblyContextUnloading } catch (Exception e) { +#if DEBUG + throw; //make errors apparent +#endif errors.Enqueue(new Error($"Error while executing runner for {eventType.Name} on type {eventSub.GetType().Name}.") .WithMetadata(MetadataType.ExceptionObject, this) .WithMetadata(MetadataType.RootObject, eventSub) diff --git a/Barotrauma/BarotraumaShared/SharedSource/LuaCs/Services/Processing/IHelperServiceDefinitions.cs b/Barotrauma/BarotraumaShared/SharedSource/LuaCs/Services/Processing/IHelperServiceDefinitions.cs index a1ddb3f94..b9d3146f9 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/LuaCs/Services/Processing/IHelperServiceDefinitions.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/LuaCs/Services/Processing/IHelperServiceDefinitions.cs @@ -18,3 +18,8 @@ public interface IParserServiceAsync : IService Task> TryParseResourceAsync(TSrc src); Task>> TryParseResourcesAsync(IEnumerable sources); } + +public interface IParserServiceOneToManyAsync : IService +{ + Task>> TryParseResourcesAsync(TSrc src); +} diff --git a/Barotrauma/BarotraumaShared/SharedSource/LuaCs/Services/Processing/ConfigFileParserService.cs b/Barotrauma/BarotraumaShared/SharedSource/LuaCs/Services/Processing/ModConfigFileParserService.cs similarity index 98% rename from Barotrauma/BarotraumaShared/SharedSource/LuaCs/Services/Processing/ConfigFileParserService.cs rename to Barotrauma/BarotraumaShared/SharedSource/LuaCs/Services/Processing/ModConfigFileParserService.cs index 292ac3eea..1e4399e94 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/LuaCs/Services/Processing/ConfigFileParserService.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/LuaCs/Services/Processing/ModConfigFileParserService.cs @@ -10,7 +10,7 @@ using Microsoft.Toolkit.Diagnostics; namespace Barotrauma.LuaCs.Services.Processing; -public sealed class ConfigFileParserService : +public sealed class ModConfigFileParserService : IParserServiceAsync, IParserServiceAsync, IParserServiceAsync @@ -18,7 +18,7 @@ public sealed class ConfigFileParserService : private IStorageService _storageService; private readonly AsyncReaderWriterLock _operationsLock = new(); - public ConfigFileParserService(IStorageService storageService) + public ModConfigFileParserService(IStorageService storageService) { _storageService = storageService; } diff --git a/Barotrauma/BarotraumaShared/SharedSource/LuaCs/Services/Processing/SettingsFileParserService.cs b/Barotrauma/BarotraumaShared/SharedSource/LuaCs/Services/Processing/SettingsFileParserService.cs new file mode 100644 index 000000000..3a3f631d0 --- /dev/null +++ b/Barotrauma/BarotraumaShared/SharedSource/LuaCs/Services/Processing/SettingsFileParserService.cs @@ -0,0 +1,212 @@ +using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Linq; +using System.Threading.Tasks; +using System.Xml.Linq; +using Barotrauma.LuaCs.Data; +using FluentResults; +using Microsoft.Toolkit.Diagnostics; +using OneOf; + +namespace Barotrauma.LuaCs.Services.Processing; + +public sealed class SettingsFileParserService : + IParserServiceOneToManyAsync, + IParserServiceOneToManyAsync +{ + #region DisposalControl + + private AsyncReaderWriterLock _operationLock = new(); + + public void Dispose() + { + using var lck = _operationLock.AcquireWriterLock().ConfigureAwait(false).GetAwaiter().GetResult(); + if (!ModUtils.Threading.CheckIfClearAndSetBool(ref _isDisposed)) + { + return; + } + _storageService.Dispose(); + _storageService = null; + } + + private int _isDisposed = 0; + public bool IsDisposed + { + get => ModUtils.Threading.GetBool(ref _isDisposed); + private set => ModUtils.Threading.SetBool(ref _isDisposed, value); + } + + #endregion + + private IStorageService _storageService; + + public SettingsFileParserService(IStorageService storageService) + { + _storageService = storageService; + } + + async Task>> IParserServiceOneToManyAsync + .TryParseResourcesAsync(IConfigResourceInfo src) + { + Guard.IsNotNull(src, nameof(src)); + Guard.IsNotNull(src.OwnerPackage, nameof(src.OwnerPackage)); + using var lck = await _operationLock.AcquireReaderLock(); + IService.CheckDisposed(this); + + if (src.FilePaths.IsDefaultOrEmpty) + { + return ReturnFail($"The config file list is empty."); + } + + var parsedInfo = ImmutableArray.CreateBuilder(); + + foreach ((ContentPath path, Result docLoadResult) res in await _storageService.LoadPackageXmlFilesAsync(src.FilePaths)) + { + if (res.docLoadResult.IsFailed) + { + return ReturnFail($"Failed to load document for {src.OwnerPackage.Name}").WithErrors(res.docLoadResult.Errors); + } + + var settingElements = res.docLoadResult.Value.GetChildElement("Configuration") + .GetChildElements("Settings").SelectMany(e => e.GetChildElements("Setting")).ToImmutableArray(); + if (settingElements.IsDefaultOrEmpty) + { + continue; + } + + var packageIdent = res.path.ContentPackage.ToIdentifier().ToString(); + + foreach (var element in settingElements) + { + var name = element.GetAttributeString("Name", string.Empty); + if (name.IsNullOrWhiteSpace()) + { + return ReturnFail( + $"The internal name for a setting in the config file '{res.path.FullPath}' is empty!"); + } + + var newSetting = new ConfigInfo() + { + InternalName = name, + OwnerPackage = res.path.ContentPackage, + DataType = element.GetAttributeString("Type", string.Empty), + Element = element, + EditableStates = element.GetAttributeBool("AllowChangesWhileExecuting", true) ? RunState.Running : + element.GetAttributeBool("ReadOnly", false) ? RunState.LoadedNoExec : + RunState.Unloaded, + NetSync = element.GetAttributeEnum("NetSync", NetSync.None), +#if CLIENT + DisplayName = $"{packageIdent}.{name}.DisplayName", + Description = $"{packageIdent}.{name}.Description", + DisplayCategory = $"{packageIdent}.{name}.DisplayCategory", + ShowInMenus = element.GetAttributeBool("ShowInMenus", true), + Tooltip = $"{packageIdent}.{name}.Tooltip", + ImageIconPath = element.GetAttributeString("ImageIcon", string.Empty) is {} val && !val.IsNullOrWhiteSpace() ? + ContentPath.FromRaw(res.path.ContentPackage, val) : ContentPath.Empty +#endif + }; + if (!IsInfoValid(newSetting)) + { + return ReturnFail($"A setting was invalid. ContentPackage: {res.path.ContentPackage}"); + } + parsedInfo.Add(newSetting); + } + } + + return FluentResults.Result.Ok(parsedInfo.MoveToImmutable()); + + // Helpers + + FluentResults.Result ReturnFail(string msg) + { + return FluentResults.Result.Fail($"{nameof(IParserServiceOneToManyAsync.TryParseResourcesAsync)}: {msg}"); + } + + bool IsInfoValid(ConfigInfo info) + { + return info.OwnerPackage != null + && !info.InternalName.IsNullOrWhiteSpace() + && !info.DataType.IsNullOrWhiteSpace() + && !info.DataType.IsNullOrWhiteSpace() + && info.Element != null +#if CLIENT + && !info.DisplayName.IsNullOrWhiteSpace() + && !info.Description.IsNullOrWhiteSpace() + && !info.DisplayCategory.IsNullOrWhiteSpace() + && !info.Tooltip.IsNullOrWhiteSpace() +#endif + ; + } + } + + async Task>> + IParserServiceOneToManyAsync + .TryParseResourcesAsync(IConfigResourceInfo src) + { + Guard.IsNotNull(src, nameof(src)); + Guard.IsNotNull(src.OwnerPackage, nameof(src.OwnerPackage)); + using var lck = await _operationLock.AcquireReaderLock(); + IService.CheckDisposed(this); + + if (src.FilePaths.IsDefaultOrEmpty) + { + return ReturnFail($"The config file list is empty."); + } + + var parsedInfo = ImmutableArray.CreateBuilder(); + + foreach ((ContentPath path, Result docLoadResult) res in await _storageService + .LoadPackageXmlFilesAsync(src.FilePaths)) + { + if (res.docLoadResult.IsFailed) + { + return ReturnFail($"Failed to load document for {src.OwnerPackage.Name}") + .WithErrors(res.docLoadResult.Errors); + } + + var profileCollection = res.docLoadResult.Value.GetChildElement("Configuration") + .GetChildElement("Profiles"); + if (profileCollection == null) + { + continue; + } + + foreach (var profile in profileCollection.GetChildElements("Profile")) + { + var profileName = profile.GetAttributeString("Name", string.Empty); + Guard.IsNotNullOrWhiteSpace(profileName, nameof(profileName)); + + var settingValues = profile.GetChildElements("SettingValue").ToImmutableArray(); + if (settingValues.IsDefaultOrEmpty) + { + ThrowHelper.ThrowArgumentNullException(nameof(settingValues)); + } + + var profileValuesBuilder = ImmutableArray.CreateBuilder<(string ConfigName, XElement Value)>(); + + foreach (var settingValue in settingValues) + { + var cfgName = settingValue.GetAttributeString("Name", string.Empty); + Guard.IsNotNullOrWhiteSpace(cfgName, nameof(cfgName)); + profileValuesBuilder.Add((cfgName, settingValue)); + } + + parsedInfo.Add(new ConfigProfileInfo() + { + InternalName = profileName, + OwnerPackage = res.path.ContentPackage, + ProfileValues = profileValuesBuilder.MoveToImmutable() + }); + } + } + + return parsedInfo.MoveToImmutable(); + + FluentResults.Result ReturnFail(string msg) + { + return FluentResults.Result.Fail($"{nameof(IParserServiceOneToManyAsync.TryParseResourcesAsync)}: {msg}"); + } + } + +} diff --git a/Barotrauma/BarotraumaShared/SharedSource/LuaCs/Services/Safe/ILuaConfigService.cs b/Barotrauma/BarotraumaShared/SharedSource/LuaCs/Services/Safe/ILuaConfigService.cs index 182f4fc4e..f349e0f6a 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/LuaCs/Services/Safe/ILuaConfigService.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/LuaCs/Services/Safe/ILuaConfigService.cs @@ -6,27 +6,5 @@ namespace Barotrauma.LuaCs.Services.Safe; public interface ILuaConfigService : ILuaService { - // get values - bool TryGetConfigBool(string packageName, string configName, out bool value); - bool TryGetConfigInt(string packageName, string configName, out int value); - bool TryGetConfigFloat(string packageName, string configName, out float value); - bool TryGetConfigNumber(string packageName, string configName, out double value); - bool TryGetConfigString(string packageName, string configName, out string value); - bool TryGetConfigVector2(string packageName, string configName, out Vector2 value); - bool TryGetConfigVector3(string packageName, string configName, out Vector3 value); - bool TryGetConfigColor(string packageName, string configName, out Color value); - bool TryGetConfigList(string packageName, string configName, out IReadOnlyList value); - // set values - void SetConfigBool(string packageName, string configName, bool value); - void SetConfigInt(string packageName, string configName, int value); - void SetConfigFloat(string packageName, string configName, float value); - void SetConfigNumber(string packageName, string configName, double value); - void SetConfigString(string packageName, string configName, string value); - void SetConfigVector2(string packageName, string configName, Vector2 value); - void SetConfigVector3(string packageName, string configName, Vector3 value); - void SetConfigColor(string packageName, string configName, Color value); - void SetConfigList(string packageName, string configName, string value); - // profiles - bool TryApplyProfileSettings(string packageName, string profileName); - + } diff --git a/Barotrauma/BarotraumaShared/SharedSource/LuaCs/Services/_Interfaces/IConfigService.cs b/Barotrauma/BarotraumaShared/SharedSource/LuaCs/Services/_Interfaces/IConfigService.cs index 38498830b..cddaa17bb 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/LuaCs/Services/_Interfaces/IConfigService.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/LuaCs/Services/_Interfaces/IConfigService.cs @@ -15,33 +15,18 @@ namespace Barotrauma.LuaCs.Services; public partial interface IConfigService : IReusableService, ILuaConfigService { + void RegisterSettingTypeInitializer(string typeIdentifier, Func settingFactory) + where T : class, ISettingBase; /// - /// Registers a type initializer from instancing config types by indicated type from config. + /// /// - /// - /// - /// The as parsed from the configuration info. - /// The resulting configuration instance. - void RegisterTypeInitializer(Func> initializer, bool replaceIfExists = false) - where TData : IEquatable where TConfig : IConfigBase; - - // Config Files/Resources + /// + /// + /// + /// Task LoadConfigsAsync(ImmutableArray configResources); Task LoadConfigsProfilesAsync(ImmutableArray configProfileResources); - - // Immediate Mode - FluentResults.Result AddConfig(IConfigInfo configInfo) where TConfig : IConfigBase; - - // Utility - FluentResults.Result ApplyProfileSettings(ContentPackage package, string profileName); FluentResults.Result DisposePackageData(ContentPackage package); FluentResults.Result DisposeAllPackageData(); - FluentResults.Result> GetConfigsForPackage(ContentPackage package); - FluentResults.Result Value)>>> - GetProfilesForPackage(ContentPackage package); - IReadOnlyDictionary<(ContentPackage Package, string Name), IConfigBase> GetAllConfigs(); - bool TryGetConfig(ContentPackage package, string name, out T config) where T : IConfigBase; - Task SaveAllConfigs(); - Task SaveConfigsForPackage(ContentPackage package); - Task SaveConfig((ContentPackage Package, string ConfigName) config); + bool TryGetConfig(ContentPackage package, string internalName, out T instance) where T : ISettingBase; }