- ConfigService.cs alpha testing.

This commit is contained in:
MapleWheels
2026-01-22 14:58:03 -05:00
committed by Maplewheels
parent cc07db941f
commit 7e0e671539
27 changed files with 795 additions and 546 deletions
@@ -2,9 +2,9 @@
namespace Barotrauma.LuaCs.Configuration; namespace Barotrauma.LuaCs.Configuration;
public interface IConfigControl : IConfigBase public interface ISettingControl : ISettingBase
{ {
event Action<IConfigControl> OnDown; event Action<ISettingControl> OnDown;
KeyOrMouse Value { get; } KeyOrMouse Value { get; }
bool IsAssignable(KeyOrMouse value); bool IsAssignable(KeyOrMouse value);
bool TrySetValue(KeyOrMouse value); bool TrySetValue(KeyOrMouse value);
@@ -7,11 +7,11 @@ public partial interface IConfigInfo : IConfigDisplayInfo { }
public interface IConfigDisplayInfo public interface IConfigDisplayInfo
{ {
/// <summary> /// <summary>
/// User-friendly name or Localization Token. /// Localization Token for display name.
/// </summary> /// </summary>
string DisplayName { get; } string DisplayName { get; }
/// <summary> /// <summary>
/// User-friendly description or Localization Token. /// Localization Token for description.
/// </summary> /// </summary>
string Description { get; } string Description { get; }
/// <summary> /// <summary>
@@ -29,5 +29,5 @@ public interface IConfigDisplayInfo
/// <summary> /// <summary>
/// Icon for display in menus, if available. /// Icon for display in menus, if available.
/// </summary> /// </summary>
string ImageIconPath { get; } ContentPath ImageIconPath { get; }
} }
@@ -21,8 +21,20 @@ namespace Barotrauma
} }
} }
public void CheckCsEnabled() /// <summary>
///
/// </summary>
/// <returns>Returns whether the IsCsEnabled has been changed to true/enabled. Returns false if already enabled.</returns>
public bool CheckCsEnabled()
{ {
// fast exit if enabled or unavailable.
if (this.IsCsEnabled?.Value ?? true )
{
return false;
}
bool isCsValueChanged = false;
var csharpMods = PackageManagementService.GetLoadedAssemblyPackages(); var csharpMods = PackageManagementService.GetLoadedAssemblyPackages();
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
@@ -38,7 +50,7 @@ namespace Barotrauma
if (GameMain.Client == null || GameMain.Client.IsServerOwner) 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}"); 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( GUIMessageBox msg = new GUIMessageBox(
@@ -49,6 +61,7 @@ namespace Barotrauma
msg.Buttons[0].OnClicked = (GUIButton button, object obj) => msg.Buttons[0].OnClicked = (GUIButton button, object obj) =>
{ {
this.IsCsEnabled.TrySetValue(true); this.IsCsEnabled.TrySetValue(true);
isCsValueChanged = true;
return true; return true;
}; };
@@ -57,6 +70,8 @@ namespace Barotrauma
this.IsCsEnabled.TrySetValue(false); this.IsCsEnabled.TrySetValue(false);
return true; return true;
}; };
return isCsValueChanged;
} }
/// <summary> /// <summary>
@@ -85,7 +100,10 @@ namespace Barotrauma
case SpriteEditorScreen: case SpriteEditorScreen:
case SubEditorScreen: case SubEditorScreen:
case TestScreen: // notes: TestScreen is a Linux edge case editor screen and is deprecated. 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); SetRunState(RunState.Running);
break; break;
default: default:
@@ -19,7 +19,7 @@ public partial class ConfigService
throw new NotImplementedException(); throw new NotImplementedException();
} }
public Result<IConfigControl> AddConfigControl(IConfigInfo configInfo) public Result<ISettingControl> AddConfigControl(IConfigInfo configInfo)
{ {
throw new NotImplementedException(); throw new NotImplementedException();
} }
@@ -13,5 +13,5 @@ public partial interface IConfigService
ImmutableArray<IDisplayableConfigBase> GetDisplayableConfigs(); ImmutableArray<IDisplayableConfigBase> GetDisplayableConfigs();
ImmutableArray<IDisplayableConfigBase> GetDisplayableConfigsForPackage(ContentPackage package); ImmutableArray<IDisplayableConfigBase> GetDisplayableConfigsForPackage(ContentPackage package);
FluentResults.Result<IConfigControl> AddConfigControl(IConfigInfo configInfo); FluentResults.Result<ISettingControl> AddConfigControl(IConfigInfo configInfo);
} }
@@ -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<T> : IConfigEntry<T> where T : IEquatable<T>
{
private readonly Action<ConfigEntry<T>, INetReadMessage> _readMessageHandler;
private readonly Action<ConfigEntry<T>, INetWriteMessage> _writeMessageHandler;
public ConfigEntry(IConfigInfo configInfo, Action<ConfigEntry<T>, INetReadMessage> readMessageHandler,
Action<ConfigEntry<T>, 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<string, XElement> value)
{
throw new NotImplementedException();
}
public bool IsAssignable(OneOf<string, XElement> value)
{
throw new NotImplementedException();
}
private event Action<IConfigEntry<T>> _onValueChanged;
public event Action<IConfigEntry<T>> OnValueChanged
{
add => _onValueChanged += value;
remove => _onValueChanged -= value;
}
event Action<IConfigBase> IConfigBase.OnValueChanged
{
add => _onValueChanged += value;
remove => _onValueChanged -= value;
}
public OneOf<string, XElement> 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();
}
}
@@ -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<T> : IConfigList<T> where T : IEquatable<T>
{
private readonly Action<ConfigList<T>, INetReadMessage> _readMessageHandler;
private readonly Action<ConfigList<T>, INetWriteMessage> _writeMessageHandler;
public ConfigList(IConfigInfo configInfo, Action<ConfigList<T>, INetReadMessage> readMessageHandler,
Action<ConfigList<T>, 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<string, XElement> value)
{
throw new NotImplementedException();
}
public bool IsAssignable(OneOf<string, XElement> value)
{
throw new NotImplementedException();
}
private event Action<IConfigList<T>> _onValueChanged;
public event Action<IConfigList<T>> OnValueChanged
{
add => _onValueChanged += value;
remove => _onValueChanged -= value;
}
event Action<IConfigEntry<T>> IConfigEntry<T>.OnValueChanged
{
add => _onValueChanged += value;
remove => _onValueChanged -= value;
}
event Action<IConfigBase> 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<string, XElement> 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<T> Options => throw new NotImplementedException();
}
@@ -6,12 +6,13 @@ using Barotrauma.Networking;
namespace Barotrauma.LuaCs.Configuration; namespace Barotrauma.LuaCs.Configuration;
public partial interface IConfigBase : IDataInfo, IEquatable<IConfigBase>, IDisposable public partial interface ISettingBase : IDataInfo, IEquatable<ISettingBase>, IDisposable
{ {
Type GetValueType(); Type GetValueType();
string GetValue(); string GetStringValue();
bool TrySetValue(OneOf.OneOf<string, XElement> value); bool TrySetValue(OneOf.OneOf<string, XElement> value);
bool IsAssignable(OneOf.OneOf<string, XElement> value); bool IsAssignable(OneOf.OneOf<string, XElement> value);
event Action<IConfigBase> OnValueChanged; event Func<OneOf.OneOf<string, XElement>, bool> IsNewValueValid;
event Action<ISettingBase> OnValueChanged;
OneOf.OneOf<string, XElement> GetSerializableValue(); OneOf.OneOf<string, XElement> GetSerializableValue();
} }
@@ -3,10 +3,10 @@ using Barotrauma.LuaCs.Services;
namespace Barotrauma.LuaCs.Configuration; namespace Barotrauma.LuaCs.Configuration;
public interface IConfigEntry<T> : IConfigBase, INetworkSyncEntity where T : IEquatable<T> public interface ISettingEntry<T> : ISettingBase, INetworkSyncEntity where T : IEquatable<T>
{ {
T Value { get; } T Value { get; }
bool TrySetValue(T value); bool TrySetValue(T value);
bool IsAssignable(T value); bool IsAssignable(T value);
new event Action<IConfigEntry<T>> OnValueChanged; new event Action<ISettingEntry<T>> OnValueChanged;
} }
@@ -3,7 +3,7 @@ using Barotrauma.LuaCs.Services;
namespace Barotrauma.LuaCs.Configuration; namespace Barotrauma.LuaCs.Configuration;
public interface IConfigEnum : IConfigBase, INetworkSyncEntity public interface ISettingEnum : ISettingBase, INetworkSyncEntity
{ {
} }
@@ -4,8 +4,8 @@ using Barotrauma.LuaCs.Services;
namespace Barotrauma.LuaCs.Configuration; namespace Barotrauma.LuaCs.Configuration;
public interface IConfigList<T> : IConfigEntry<T>, INetworkSyncEntity where T : IEquatable<T> public interface ISettingList<T> : ISettingEntry<T>, INetworkSyncEntity where T : IEquatable<T>
{ {
IReadOnlyList<T> Options { get; } IReadOnlyList<T> Options { get; }
new event Action<IConfigList<T>> OnValueChanged; new event Action<ISettingList<T>> OnValueChanged;
} }
@@ -2,7 +2,7 @@ using System;
namespace Barotrauma.LuaCs.Configuration; namespace Barotrauma.LuaCs.Configuration;
public interface IConfigRangeEntry<T> : IConfigEntry<T> where T : IConvertible, IEquatable<T> public interface ISettingRangeEntry<T> : ISettingEntry<T> where T : IConvertible, IEquatable<T>
{ {
T MinValue { get; } T MinValue { get; }
T MaxValue { get; } T MaxValue { get; }
@@ -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<T> : ISettingEntry<T> where T : IEquatable<T>
{
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<string, XElement> value)
{
throw new NotImplementedException();
}
public bool IsAssignable(OneOf<string, XElement> value)
{
throw new NotImplementedException();
}
public event Func<OneOf<string, XElement>, 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<T>> ISettingEntry<T>.OnValueChanged
{
add => throw new NotImplementedException();
remove => throw new NotImplementedException();
}
event Action<ISettingBase> ISettingBase.OnValueChanged
{
add => throw new NotImplementedException();
remove => throw new NotImplementedException();
}
public OneOf<string, XElement> 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();
}
}
@@ -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<T> : ISettingList<T> where T : IEquatable<T>
{
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<string, XElement> value)
{
throw new NotImplementedException();
}
public bool IsAssignable(OneOf<string, XElement> value)
{
throw new NotImplementedException();
}
public event Func<OneOf<string, XElement>, 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<T>> ISettingList<T>.OnValueChanged
{
add => throw new NotImplementedException();
remove => throw new NotImplementedException();
}
public IReadOnlyList<T> Options { get; }
event Action<ISettingEntry<T>> ISettingEntry<T>.OnValueChanged
{
add => throw new NotImplementedException();
remove => throw new NotImplementedException();
}
event Action<ISettingBase> ISettingBase.OnValueChanged
{
add => throw new NotImplementedException();
remove => throw new NotImplementedException();
}
public OneOf<string, XElement> 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();
}
}
@@ -67,9 +67,8 @@ public record ConfigInfo : IConfigInfo
{ {
public string InternalName { get; init; } public string InternalName { get; init; }
public ContentPackage OwnerPackage { get; init; } public ContentPackage OwnerPackage { get; init; }
public Type DataType { get; init; } public string DataType { get; init; }
public OneOf<string, XElement> DefaultValue { get; init; } public XElement Element { get; init; }
public OneOf<string, XElement> Value { get; init; }
public RunState EditableStates { get; init; } public RunState EditableStates { get; init; }
public NetSync NetSync { get; init; } public NetSync NetSync { get; init; }
@@ -79,7 +78,7 @@ public record ConfigInfo : IConfigInfo
public string DisplayCategory { get; init; } public string DisplayCategory { get; init; }
public bool ShowInMenus { get; init; } public bool ShowInMenus { get; init; }
public string Tooltip { get; init; } public string Tooltip { get; init; }
public string ImageIconPath { get; init; } public ContentPath ImageIconPath { get; init; }
#endif #endif
} }
@@ -87,7 +86,7 @@ public record ConfigProfileInfo : IConfigProfileInfo
{ {
public string InternalName { get; init; } public string InternalName { get; init; }
public ContentPackage OwnerPackage { get; init; } public ContentPackage OwnerPackage { get; init; }
public IReadOnlyList<(string ConfigName, OneOf<string, XElement> Value)> ProfileValues { get; init; } public IReadOnlyList<(string ConfigName, XElement Element)> ProfileValues { get; init; }
} }
#endregion #endregion
@@ -13,26 +13,18 @@ public partial interface IConfigInfo : IDataInfo
/// <summary> /// <summary>
/// Specifies the type initializer that will be used to instantiate the config var. /// Specifies the type initializer that will be used to instantiate the config var.
/// </summary> /// </summary>
Type DataType { get; } string DataType { get; }
/// <summary> /// <summary>
/// The default value. /// The 'Setting' XML element.
/// </summary> /// </summary>
OneOf.OneOf<string, XElement> DefaultValue { get; } XElement Element { get; }
/// <summary>
/// The value the last time this config was saved. If not found, returns the default value.
/// <br/><b>[If(Type='<see cref="string"/>')]</b><br/>
/// The value is from the 'Value' Attribute. Typically used for types with single/simple values, such as primitives.
/// <br/><b>[If(Type='<see cref="XElement"/>')]</b><br/>
/// The value is from the first 'Value' child element. Typically used with complex config types, such as range and list.
/// </summary>
OneOf.OneOf<string, XElement> Value { get; }
/// <summary> /// <summary>
/// In what <see cref="RunState"/>(s) is this config editable. Will be editable in the selected state, and lower value states. /// In what <see cref="RunState"/>(s) is this config editable. Will be editable in the selected state, and lower value states.
/// <br/><br/> /// <br/><br/>
/// <b>[Important]</b><br/> Setting this to value lower than 'Configuration` will render this config read-only. /// <b>[Important]</b><br/> Setting this to value lower than 'Configuration` will render this config read-only.
/// <br/><br/><b>Expected Behaviour</b>: /// <br/><br/><b>Expected Behaviour</b>:
/// <br/><b>[<see cref="RunState.Unloaded"/>|<see cref="RunState.Parsed"/>]</b>: Read-Only. /// <br/><b>[<see cref="RunState.Unloaded"/>|<see cref="RunState.Unloaded"/>]</b>: Read-Only.
/// <br/><b>[<see cref="RunState.Configuration"/>]</b>: Can only be changed at the Main Menu (not in a lobby). /// <br/><b>[<see cref="RunState.LoadedNoExec"/>]</b>: Can only be changed at the Main Menu (not in a lobby).
/// <br/><b>[<see cref="RunState.Running"/>]</b>: Can be changed at the Main Menu and while a lobby is active. /// <br/><b>[<see cref="RunState.Running"/>]</b>: Can be changed at the Main Menu and while a lobby is active.
/// </summary> /// </summary>
RunState EditableStates { get; } RunState EditableStates { get; }
@@ -5,5 +5,5 @@ namespace Barotrauma.LuaCs.Data;
public interface IConfigProfileInfo : IDataInfo public interface IConfigProfileInfo : IDataInfo
{ {
IReadOnlyList<(string ConfigName, OneOf.OneOf<string, XElement> Value)> ProfileValues { get; } IReadOnlyList<(string ConfigName, XElement Element)> ProfileValues { get; }
} }
@@ -30,7 +30,7 @@ public interface IEvent<out T> : IEvent where T : IEvent<T>
} }
} }
#region RuntimeEvents #region RuntimeServiceEvents
/// <summary> /// <summary>
/// Called when the current <see cref="Screen"/> (game state) changes. Upstream Type 'Screen' is internal. /// Called when the current <see cref="Screen"/> (game state) changes. Upstream Type 'Screen' is internal.
@@ -61,6 +61,12 @@ internal interface IEventReloadAllPackages : IEvent<IEventReloadAllPackages>
void OnReloadAllPackages(); void OnReloadAllPackages();
} }
internal interface IEventSettingInstanceLifetime : IEvent<IEventSettingInstanceLifetime>
{
void OnSettingInstanceCreated<T>(T configInstance) where T : ISettingBase;
void OnSettingInstanceDisposed<T>(T configInstance) where T : ISettingBase;
}
#endregion #endregion
#region GameEvents #region GameEvents
@@ -99,56 +99,56 @@ namespace Barotrauma
/// <summary> /// <summary>
/// Whether C# plugin code is enabled. /// Whether C# plugin code is enabled.
/// </summary> /// </summary>
internal IConfigEntry<bool> IsCsEnabled { get; private set; } internal ISettingEntry<bool> IsCsEnabled { get; private set; }
/// <summary> /// <summary>
/// Whether mods marked as 'forced' or 'always load' should only be loaded if they're in the enabled mods list. /// Whether mods marked as 'forced' or 'always load' should only be loaded if they're in the enabled mods list.
/// </summary> /// </summary>
internal IConfigEntry<bool> TreatForcedModsAsNormal { get; private set; } internal ISettingEntry<bool> TreatForcedModsAsNormal { get; private set; }
/// <summary> /// <summary>
/// Whether the lua script runner from Workshop package should be used over the in-built version. /// Whether the lua script runner from Workshop package should be used over the in-built version.
/// </summary> /// </summary>
internal IConfigEntry<bool> PreferToUseWorkshopLuaSetup { get; private set; } internal ISettingEntry<bool> PreferToUseWorkshopLuaSetup { get; private set; }
/// <summary> /// <summary>
/// Whether the popup error GUI should be hidden/suppressed. /// Whether the popup error GUI should be hidden/suppressed.
/// </summary> /// </summary>
internal IConfigEntry<bool> DisableErrorGUIOverlay { get; private set; } internal ISettingEntry<bool> DisableErrorGUIOverlay { get; private set; }
/// <summary> /// <summary>
/// Whether usernames are anonymized or show in logs. /// Whether usernames are anonymized or show in logs.
/// </summary> /// </summary>
internal IConfigEntry<bool> HideUserNamesInLogs { get; private set; } internal ISettingEntry<bool> HideUserNamesInLogs { get; private set; }
/// <summary> /// <summary>
/// The SteamId of the Workshop LuaCs CPackage in use, if available. /// The SteamId of the Workshop LuaCs CPackage in use, if available.
/// </summary> /// </summary>
internal IConfigEntry<ulong> LuaForBarotraumaSteamId { get; private set; } internal ISettingEntry<ulong> LuaForBarotraumaSteamId { get; private set; }
/// <summary> /// <summary>
/// TODO: @evilfactory@users.noreply.github.com /// TODO: @evilfactory@users.noreply.github.com
/// </summary> /// </summary>
internal IConfigEntry<bool> RestrictMessageSize { get; private set; } internal ISettingEntry<bool> RestrictMessageSize { get; private set; }
/// <summary> /// <summary>
/// The local save path for all local data storage for mods. /// The local save path for all local data storage for mods.
/// </summary> /// </summary>
internal IConfigEntry<string> LocalDataSavePath { get; private set; } internal ISettingEntry<string> LocalDataSavePath { get; private set; }
void LoadLuaCsConfig() void LoadLuaCsConfig()
{ {
IsCsEnabled = ConfigService.TryGetConfig<IConfigEntry<bool>>(ContentPackageManager.VanillaCorePackage, "IsCsEnabled", out var val1) ? val1 IsCsEnabled = ConfigService.TryGetConfig<ISettingEntry<bool>>(ContentPackageManager.VanillaCorePackage, "IsCsEnabled", out var val1) ? val1
: throw new NullReferenceException($"{nameof(IsCsEnabled)} cannot be loaded."); : throw new NullReferenceException($"{nameof(IsCsEnabled)} cannot be loaded.");
TreatForcedModsAsNormal = ConfigService.TryGetConfig<IConfigEntry<bool>>(ContentPackageManager.VanillaCorePackage, "TreatForcedModsAsNormal", out var val2) ? val2 TreatForcedModsAsNormal = ConfigService.TryGetConfig<ISettingEntry<bool>>(ContentPackageManager.VanillaCorePackage, "TreatForcedModsAsNormal", out var val2) ? val2
: throw new NullReferenceException($"{nameof(TreatForcedModsAsNormal)} cannot be loaded."); : throw new NullReferenceException($"{nameof(TreatForcedModsAsNormal)} cannot be loaded.");
DisableErrorGUIOverlay = ConfigService.TryGetConfig<IConfigEntry<bool>>(ContentPackageManager.VanillaCorePackage, "DisableErrorGUIOverlay", out var val3) ? val3 DisableErrorGUIOverlay = ConfigService.TryGetConfig<ISettingEntry<bool>>(ContentPackageManager.VanillaCorePackage, "DisableErrorGUIOverlay", out var val3) ? val3
: throw new NullReferenceException($"{nameof(DisableErrorGUIOverlay)} cannot be loaded."); : throw new NullReferenceException($"{nameof(DisableErrorGUIOverlay)} cannot be loaded.");
HideUserNamesInLogs = ConfigService.TryGetConfig<IConfigEntry<bool>>(ContentPackageManager.VanillaCorePackage, "HideUserNamesInLogs", out var val4) ? val4 HideUserNamesInLogs = ConfigService.TryGetConfig<ISettingEntry<bool>>(ContentPackageManager.VanillaCorePackage, "HideUserNamesInLogs", out var val4) ? val4
: throw new NullReferenceException($"{nameof(HideUserNamesInLogs)} cannot be loaded."); : throw new NullReferenceException($"{nameof(HideUserNamesInLogs)} cannot be loaded.");
LuaForBarotraumaSteamId = ConfigService.TryGetConfig<IConfigEntry<ulong>>(ContentPackageManager.VanillaCorePackage, "LuaForBarotraumaSteamId", out var val5) ? val5 LuaForBarotraumaSteamId = ConfigService.TryGetConfig<ISettingEntry<ulong>>(ContentPackageManager.VanillaCorePackage, "LuaForBarotraumaSteamId", out var val5) ? val5
: throw new NullReferenceException($"{nameof(LuaForBarotraumaSteamId)} cannot be loaded."); : throw new NullReferenceException($"{nameof(LuaForBarotraumaSteamId)} cannot be loaded.");
RestrictMessageSize = ConfigService.TryGetConfig<IConfigEntry<bool>>(ContentPackageManager.VanillaCorePackage, "RestrictMessageSize", out var val7) ? val7 RestrictMessageSize = ConfigService.TryGetConfig<ISettingEntry<bool>>(ContentPackageManager.VanillaCorePackage, "RestrictMessageSize", out var val7) ? val7
: throw new NullReferenceException($"{nameof(RestrictMessageSize)} cannot be loaded."); : throw new NullReferenceException($"{nameof(RestrictMessageSize)} cannot be loaded.");
} }
@@ -170,9 +170,11 @@ namespace Barotrauma
// TODO: INetworkingService // TODO: INetworkingService
servicesProvider.RegisterServiceType<IConfigService, ConfigService>(ServiceLifetime.Singleton); servicesProvider.RegisterServiceType<IConfigService, ConfigService>(ServiceLifetime.Singleton);
servicesProvider.RegisterServiceType<IModConfigService, ModConfigService>(ServiceLifetime.Transient); servicesProvider.RegisterServiceType<IModConfigService, ModConfigService>(ServiceLifetime.Transient);
servicesProvider.RegisterServiceType<IParserServiceAsync<ResourceParserInfo, IAssemblyResourceInfo>, ConfigFileParserService>(ServiceLifetime.Transient); servicesProvider.RegisterServiceType<IParserServiceAsync<ResourceParserInfo, IAssemblyResourceInfo>, ModConfigFileParserService>(ServiceLifetime.Transient);
servicesProvider.RegisterServiceType<IParserServiceAsync<ResourceParserInfo, ILuaScriptResourceInfo>, ConfigFileParserService>(ServiceLifetime.Transient); servicesProvider.RegisterServiceType<IParserServiceAsync<ResourceParserInfo, ILuaScriptResourceInfo>, ModConfigFileParserService>(ServiceLifetime.Transient);
servicesProvider.RegisterServiceType<IParserServiceAsync<ResourceParserInfo, IConfigResourceInfo>, ConfigFileParserService>(ServiceLifetime.Transient); servicesProvider.RegisterServiceType<IParserServiceAsync<ResourceParserInfo, IConfigResourceInfo>, ModConfigFileParserService>(ServiceLifetime.Transient);
servicesProvider.RegisterServiceType<IParserServiceOneToManyAsync<IConfigResourceInfo, IConfigInfo>, SettingsFileParserService>(ServiceLifetime.Transient);
servicesProvider.RegisterServiceType<IParserServiceOneToManyAsync<IConfigResourceInfo, IConfigProfileInfo>, SettingsFileParserService>(ServiceLifetime.Transient);
// service config data // service config data
servicesProvider.RegisterServiceType<IStorageServiceConfig, StorageServiceConfig>(ServiceLifetime.Singleton); servicesProvider.RegisterServiceType<IStorageServiceConfig, StorageServiceConfig>(ServiceLifetime.Singleton);
servicesProvider.RegisterServiceType<ILuaScriptServicesConfig, LuaScriptServicesConfig>(ServiceLifetime.Singleton); servicesProvider.RegisterServiceType<ILuaScriptServicesConfig, LuaScriptServicesConfig>(ServiceLifetime.Singleton);
@@ -26,37 +26,19 @@ public class ConfigInitializers : IService
// stateless service // stateless service
public bool IsDisposed => false; public bool IsDisposed => false;
private Result<IConfigEntry<T>> CreateConfigEntry<T>(IConfigInfo configInfo, private Result<ISettingEntry<T>> CreateConfigEntry<T>(IConfigInfo configInfo,
Action<ConfigEntry<T>, INetReadMessage> readHandler, Action<SettingEntry<T>, INetReadMessage> readHandler,
Action<ConfigEntry<T>, INetWriteMessage> writeHandler) Action<SettingEntry<T>, INetWriteMessage> writeHandler)
where T : IEquatable<T> where T : IEquatable<T>
{ {
try throw new NotImplementedException();
{
var ice = new ConfigEntry<T>(configInfo, readHandler, writeHandler);
return FluentResults.Result.Ok<IConfigEntry<T>>(ice);
}
catch (Exception e)
{
return FluentResults.Result.Fail($"Error while initializing config var: {configInfo?.OwnerPackage} - {configInfo?.InternalName}")
.WithError(new ExceptionalError(e));
}
} }
private Result<IConfigList<T>> CreateConfigList<T>(IConfigInfo configInfo, private Result<ISettingList<T>> CreateConfigList<T>(IConfigInfo configInfo,
Action<IConfigList<T>, INetReadMessage> readHandler, Action<IConfigList<T>, INetWriteMessage> writeHandler) Action<ISettingList<T>, INetReadMessage> readHandler, Action<ISettingList<T>, INetWriteMessage> writeHandler)
where T : IEquatable<T> where T : IEquatable<T>
{ {
try throw new NotImplementedException();
{
var icl = new ConfigList<T>(configInfo, readHandler, writeHandler);
return FluentResults.Result.Ok<IConfigList<T>>(icl);
}
catch (Exception e)
{
return FluentResults.Result.Fail($"Error while initializing config var: {configInfo?.OwnerPackage} - {configInfo?.InternalName}")
.WithError(new ExceptionalError(e));
}
} }
public void RegisterTypeInitializers(IConfigService configService) public void RegisterTypeInitializers(IConfigService configService)
@@ -64,30 +46,30 @@ public class ConfigInitializers : IService
if (configService == null) if (configService == null)
throw new ArgumentNullException($"{nameof(RegisterTypeInitializers)}: {nameof(IConfigService)} is null."); throw new ArgumentNullException($"{nameof(RegisterTypeInitializers)}: {nameof(IConfigService)} is null.");
configService.RegisterTypeInitializer<bool, IConfigEntry<bool>>(this.CreateConfigBool); /*configService.RegisterTypeInitializer<bool, ISettingEntry<bool>>(this.CreateConfigBool);
configService.RegisterTypeInitializer<sbyte, IConfigEntry<sbyte>>(this.CreateConfigSbyte); configService.RegisterTypeInitializer<sbyte, ISettingEntry<sbyte>>(this.CreateConfigSbyte);
configService.RegisterTypeInitializer<byte, IConfigEntry<byte>>(this.CreateConfigByte); configService.RegisterTypeInitializer<byte, ISettingEntry<byte>>(this.CreateConfigByte);
configService.RegisterTypeInitializer<short, IConfigEntry<short>>(this.CreateConfigShort); configService.RegisterTypeInitializer<short, ISettingEntry<short>>(this.CreateConfigShort);
configService.RegisterTypeInitializer<ushort, IConfigEntry<ushort>>(this.CreateConfigUShort); configService.RegisterTypeInitializer<ushort, ISettingEntry<ushort>>(this.CreateConfigUShort);
configService.RegisterTypeInitializer<int, IConfigEntry<int>>(this.CreateConfigInt32); configService.RegisterTypeInitializer<int, ISettingEntry<int>>(this.CreateConfigInt32);
configService.RegisterTypeInitializer<uint, IConfigEntry<uint>>(this.CreateConfigUInt32); configService.RegisterTypeInitializer<uint, ISettingEntry<uint>>(this.CreateConfigUInt32);
configService.RegisterTypeInitializer<long, IConfigEntry<long>>(this.CreateConfigInt64); configService.RegisterTypeInitializer<long, ISettingEntry<long>>(this.CreateConfigInt64);
configService.RegisterTypeInitializer<ulong, IConfigEntry<ulong>>(this.CreateConfigUInt64); configService.RegisterTypeInitializer<ulong, ISettingEntry<ulong>>(this.CreateConfigUInt64);
configService.RegisterTypeInitializer<float, IConfigEntry<float>>(this.CreateConfigFloat32); configService.RegisterTypeInitializer<float, ISettingEntry<float>>(this.CreateConfigFloat32);
configService.RegisterTypeInitializer<double, IConfigEntry<double>>(this.CreateConfigFloat64); configService.RegisterTypeInitializer<double, ISettingEntry<double>>(this.CreateConfigFloat64);
configService.RegisterTypeInitializer<decimal, IConfigEntry<decimal>>(this.CreateConfigFloat128); configService.RegisterTypeInitializer<decimal, ISettingEntry<decimal>>(this.CreateConfigFloat128);
configService.RegisterTypeInitializer<char, IConfigEntry<char>>(this.CreateConfigChar); configService.RegisterTypeInitializer<char, ISettingEntry<char>>(this.CreateConfigChar);
configService.RegisterTypeInitializer<string, IConfigEntry<string>>(this.CreateConfigString); configService.RegisterTypeInitializer<string, ISettingEntry<string>>(this.CreateConfigString);
configService.RegisterTypeInitializer<Color, IConfigEntry<Color>>(this.CreateConfigColor); configService.RegisterTypeInitializer<Color, ISettingEntry<Color>>(this.CreateConfigColor);
configService.RegisterTypeInitializer<Vector2, IConfigEntry<Vector2>>(this.CreateConfigVector2); configService.RegisterTypeInitializer<Vector2, ISettingEntry<Vector2>>(this.CreateConfigVector2);
configService.RegisterTypeInitializer<Vector3, IConfigEntry<Vector3>>(this.CreateConfigVector3); configService.RegisterTypeInitializer<Vector3, ISettingEntry<Vector3>>(this.CreateConfigVector3);
configService.RegisterTypeInitializer<Vector4, IConfigEntry<Vector4>>(this.CreateConfigVector4); configService.RegisterTypeInitializer<Vector4, ISettingEntry<Vector4>>(this.CreateConfigVector4);*/
} }
#region InitializerWrappers_NetworkInjected #region InitializerWrappers_NetworkInjected
private void AssignValueConditional<T>(T val, IConfigEntry<T> inst) where T : IEquatable<T> private void AssignValueConditional<T>(T val, ISettingEntry<T> inst) where T : IEquatable<T>
{ {
#if SERVER #if SERVER
if (inst.SyncType is NetSync.None or NetSync.ServerAuthority) if (inst.SyncType is NetSync.None or NetSync.ServerAuthority)
@@ -100,7 +82,7 @@ public class ConfigInitializers : IService
#endif #endif
} }
private Result<IConfigEntry<bool>> CreateConfigBool(IConfigInfo configInfo) private Result<ISettingEntry<bool>> CreateConfigBool(IConfigInfo configInfo)
{ {
return CreateConfigEntry<bool>(configInfo, (inst, readMsg) => return CreateConfigEntry<bool>(configInfo, (inst, readMsg) =>
{ {
@@ -112,7 +94,7 @@ public class ConfigInitializers : IService
}); });
} }
private Result<IConfigEntry<sbyte>> CreateConfigSbyte(IConfigInfo configInfo) private Result<ISettingEntry<sbyte>> CreateConfigSbyte(IConfigInfo configInfo)
{ {
return CreateConfigEntry<sbyte>(configInfo, (inst, readMsg) => return CreateConfigEntry<sbyte>(configInfo, (inst, readMsg) =>
{ {
@@ -124,7 +106,7 @@ public class ConfigInitializers : IService
}); });
} }
private Result<IConfigEntry<byte>> CreateConfigByte(IConfigInfo configInfo) private Result<ISettingEntry<byte>> CreateConfigByte(IConfigInfo configInfo)
{ {
return CreateConfigEntry<byte>(configInfo, (inst, readMsg) => return CreateConfigEntry<byte>(configInfo, (inst, readMsg) =>
{ {
@@ -136,7 +118,7 @@ public class ConfigInitializers : IService
}); });
} }
private Result<IConfigEntry<short>> CreateConfigShort(IConfigInfo configInfo) private Result<ISettingEntry<short>> CreateConfigShort(IConfigInfo configInfo)
{ {
return CreateConfigEntry<short>(configInfo, (inst, readMsg) => return CreateConfigEntry<short>(configInfo, (inst, readMsg) =>
{ {
@@ -148,7 +130,7 @@ public class ConfigInitializers : IService
}); });
} }
private Result<IConfigEntry<ushort>> CreateConfigUShort(IConfigInfo configInfo) private Result<ISettingEntry<ushort>> CreateConfigUShort(IConfigInfo configInfo)
{ {
return CreateConfigEntry<ushort>(configInfo, (inst, readMsg) => return CreateConfigEntry<ushort>(configInfo, (inst, readMsg) =>
{ {
@@ -160,7 +142,7 @@ public class ConfigInitializers : IService
}); });
} }
private Result<IConfigEntry<int>> CreateConfigInt32(IConfigInfo configInfo) private Result<ISettingEntry<int>> CreateConfigInt32(IConfigInfo configInfo)
{ {
return CreateConfigEntry<int>(configInfo, (inst, readMsg) => return CreateConfigEntry<int>(configInfo, (inst, readMsg) =>
{ {
@@ -172,7 +154,7 @@ public class ConfigInitializers : IService
}); });
} }
private Result<IConfigEntry<uint>> CreateConfigUInt32(IConfigInfo configInfo) private Result<ISettingEntry<uint>> CreateConfigUInt32(IConfigInfo configInfo)
{ {
return CreateConfigEntry<uint>(configInfo, (inst, readMsg) => return CreateConfigEntry<uint>(configInfo, (inst, readMsg) =>
{ {
@@ -184,7 +166,7 @@ public class ConfigInitializers : IService
}); });
} }
private Result<IConfigEntry<long>> CreateConfigInt64(IConfigInfo configInfo) private Result<ISettingEntry<long>> CreateConfigInt64(IConfigInfo configInfo)
{ {
return CreateConfigEntry<long>(configInfo, (inst, readMsg) => return CreateConfigEntry<long>(configInfo, (inst, readMsg) =>
{ {
@@ -196,7 +178,7 @@ public class ConfigInitializers : IService
}); });
} }
private Result<IConfigEntry<ulong>> CreateConfigUInt64(IConfigInfo configInfo) private Result<ISettingEntry<ulong>> CreateConfigUInt64(IConfigInfo configInfo)
{ {
return CreateConfigEntry<ulong>(configInfo, (inst, readMsg) => return CreateConfigEntry<ulong>(configInfo, (inst, readMsg) =>
{ {
@@ -208,7 +190,7 @@ public class ConfigInitializers : IService
}); });
} }
private Result<IConfigEntry<float>> CreateConfigFloat32(IConfigInfo configInfo) private Result<ISettingEntry<float>> CreateConfigFloat32(IConfigInfo configInfo)
{ {
return CreateConfigEntry<float>(configInfo, (inst, readMsg) => return CreateConfigEntry<float>(configInfo, (inst, readMsg) =>
{ {
@@ -220,7 +202,7 @@ public class ConfigInitializers : IService
}); });
} }
private Result<IConfigEntry<double>> CreateConfigFloat64(IConfigInfo configInfo) private Result<ISettingEntry<double>> CreateConfigFloat64(IConfigInfo configInfo)
{ {
return CreateConfigEntry<double>(configInfo, (inst, readMsg) => return CreateConfigEntry<double>(configInfo, (inst, readMsg) =>
{ {
@@ -232,7 +214,7 @@ public class ConfigInitializers : IService
}); });
} }
private Result<IConfigEntry<decimal>> CreateConfigFloat128(IConfigInfo configInfo) private Result<ISettingEntry<decimal>> CreateConfigFloat128(IConfigInfo configInfo)
{ {
return CreateConfigEntry<decimal>(configInfo, (inst, readMsg) => return CreateConfigEntry<decimal>(configInfo, (inst, readMsg) =>
{ {
@@ -253,7 +235,7 @@ public class ConfigInitializers : IService
}); });
} }
private Result<IConfigEntry<char>> CreateConfigChar(IConfigInfo configInfo) private Result<ISettingEntry<char>> CreateConfigChar(IConfigInfo configInfo)
{ {
return CreateConfigEntry<char>(configInfo, (inst, readMsg) => return CreateConfigEntry<char>(configInfo, (inst, readMsg) =>
{ {
@@ -265,7 +247,7 @@ public class ConfigInitializers : IService
}); });
} }
private Result<IConfigEntry<string>> CreateConfigString(IConfigInfo configInfo) private Result<ISettingEntry<string>> CreateConfigString(IConfigInfo configInfo)
{ {
return CreateConfigEntry<string>(configInfo, (inst, readMsg) => return CreateConfigEntry<string>(configInfo, (inst, readMsg) =>
{ {
@@ -277,7 +259,7 @@ public class ConfigInitializers : IService
}); });
} }
private Result<IConfigEntry<Color>> CreateConfigColor(IConfigInfo configInfo) private Result<ISettingEntry<Color>> CreateConfigColor(IConfigInfo configInfo)
{ {
return CreateConfigEntry<Color>(configInfo, (inst, readMsg) => return CreateConfigEntry<Color>(configInfo, (inst, readMsg) =>
{ {
@@ -289,7 +271,7 @@ public class ConfigInitializers : IService
}); });
} }
private Result<IConfigEntry<Vector2>> CreateConfigVector2(IConfigInfo configInfo) private Result<ISettingEntry<Vector2>> CreateConfigVector2(IConfigInfo configInfo)
{ {
return CreateConfigEntry<Vector2>(configInfo, (inst, readMsg) => return CreateConfigEntry<Vector2>(configInfo, (inst, readMsg) =>
{ {
@@ -302,7 +284,7 @@ public class ConfigInitializers : IService
}); });
} }
private Result<IConfigEntry<Vector3>> CreateConfigVector3(IConfigInfo configInfo) private Result<ISettingEntry<Vector3>> CreateConfigVector3(IConfigInfo configInfo)
{ {
return CreateConfigEntry<Vector3>(configInfo, (inst, readMsg) => return CreateConfigEntry<Vector3>(configInfo, (inst, readMsg) =>
{ {
@@ -316,7 +298,7 @@ public class ConfigInitializers : IService
}); });
} }
private Result<IConfigEntry<Vector4>> CreateConfigVector4(IConfigInfo configInfo) private Result<ISettingEntry<Vector4>> CreateConfigVector4(IConfigInfo configInfo)
{ {
return CreateConfigEntry<Vector4>(configInfo, (inst, readMsg) => return CreateConfigEntry<Vector4>(configInfo, (inst, readMsg) =>
{ {
@@ -6,217 +6,318 @@ using System.Collections.Immutable;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Xml.Linq; using System.Xml.Linq;
using Barotrauma.LuaCs.Configuration; using Barotrauma.LuaCs.Configuration;
using Barotrauma.LuaCs.Data; using Barotrauma.LuaCs.Data;
using Barotrauma.LuaCs.Events; using Barotrauma.LuaCs.Events;
using Barotrauma.LuaCs.Services.Processing; using Barotrauma.LuaCs.Services.Processing;
using Barotrauma.Networking;
using Dynamitey.DynamicObjects;
using FluentResults; using FluentResults;
using Microsoft.Xna.Framework; using Microsoft.Toolkit.Diagnostics;
using OneOf;
using Path = Barotrauma.IO.Path;
namespace Barotrauma.LuaCs.Services; 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() 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<IEventSettingInstanceLifetime>(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() 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<IEventSettingInstanceLifetime>(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) return result;
{
throw new NotImplementedException();
} }
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<string> 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 #endregion
public void RegisterTypeInitializer<TData, TConfig>(Func<IConfigInfo, Result<TConfig>> initializer, bool replaceIfExists = false) where TData : IEquatable<TData> where TConfig : IConfigBase private readonly ConcurrentDictionary<(ContentPackage OwnerPackage, string InternalName), ISettingBase>
_settingsInstances = new();
private readonly ConcurrentDictionary<string, Func<IConfigInfo, ISettingBase>>
_instanceFactory = new();
private readonly ConcurrentDictionary<ContentPackage, ConcurrentBag<ISettingBase>>
_settingsInstancesByPackage = new();
private IStorageService _storageService;
private ILoggerService _logger;
private IEventService _eventService;
private IParserServiceOneToManyAsync<IConfigResourceInfo, IConfigInfo> _configInfoParserService;
private IParserServiceOneToManyAsync<IConfigResourceInfo, IConfigProfileInfo> _configProfileInfoParserService;
public ConfigService(ILoggerService logger,
IStorageService storageService,
IParserServiceOneToManyAsync<IConfigResourceInfo, IConfigInfo> configInfoParserService,
IParserServiceOneToManyAsync<IConfigResourceInfo, IConfigProfileInfo> configProfileInfoParserService, IEventService eventService)
{ {
throw new NotImplementedException(); _logger = logger;
_storageService = storageService;
_configInfoParserService = configInfoParserService;
_configProfileInfoParserService = configProfileInfoParserService;
_eventService = eventService;
}
public void RegisterSettingTypeInitializer<T>(string typeIdentifier, Func<IConfigInfo, T> 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<FluentResults.Result> LoadConfigsAsync(ImmutableArray<IConfigResourceInfo> configResources) public async Task<FluentResults.Result> LoadConfigsAsync(ImmutableArray<IConfigResourceInfo> configResources)
{ {
#if DEBUG using var lck = _operationLock.AcquireReaderLock().ConfigureAwait(false).GetAwaiter().GetResult();
return FluentResults.Result.Ok(); // just for startup testing IService.CheckDisposed(this);
#endif if (configResources.IsDefaultOrEmpty)
throw new NotImplementedException(); {
return FluentResults.Result.Ok();
}
var taskBuilder = ImmutableArray.CreateBuilder<Task<ImmutableArray<IConfigInfo>>>();
var toProcessErrors = new ConcurrentStack<IError>();
var taskCtx = TaskScheduler.FromCurrentSynchronizationContext();
foreach (var resource in configResources)
{
taskBuilder.Add(await Task.Factory.StartNew<Task<ImmutableArray<IConfigInfo>>>(async Task<ImmutableArray<IConfigInfo>> () =>
{
var r = await _configInfoParserService.TryParseResourcesAsync(resource);
if (r.IsFailed)
{
toProcessErrors.PushRange(r.Errors.ToArray());
return ImmutableArray<IConfigInfo>.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<IConfigInfo, ISettingBase> 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<ISettingBase>();
}
_settingsInstancesByPackage[newInstanceData.info.OwnerPackage].Add(newInstanceData.instance);
result.WithReasons(_eventService.PublishEvent<IEventSettingInstanceLifetime>(sub =>
sub.OnSettingInstanceCreated(newInstanceData.instance)).Reasons);
}
return result;
} }
public async Task<FluentResults.Result> LoadConfigsProfilesAsync(ImmutableArray<IConfigResourceInfo> configProfileResources) public async Task<FluentResults.Result> LoadConfigsProfilesAsync(ImmutableArray<IConfigResourceInfo> configProfileResources)
{ {
#if DEBUG #if DEBUG
return FluentResults.Result.Ok(); // just for startup testing // TODO: Implement profiles.
return FluentResults.Result.Ok();
#endif #endif
throw new NotImplementedException(); throw new NotImplementedException();
} }
public Result<TConfig> AddConfig<TConfig>(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) public FluentResults.Result DisposePackageData(ContentPackage package)
{ {
#if DEBUG Guard.IsNotNull(package, nameof(package));
return FluentResults.Result.Ok(); // just for startup testing using var lck = _operationLock.AcquireReaderLock().ConfigureAwait(false).GetAwaiter().GetResult();
#endif ConcurrentBag<ISettingBase> toDispose;
throw new NotImplementedException(); 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<IEventSettingInstanceLifetime>(sub => sub.OnSettingInstanceDisposed(setting)).Reasons);
try
{
setting.Dispose();
}
catch (Exception e)
{
result.WithError(new ExceptionalError(e));
}
}
return result;
} }
public FluentResults.Result DisposeAllPackageData() public FluentResults.Result DisposeAllPackageData()
{ {
#if DEBUG return this.Reset();
return FluentResults.Result.Ok(); // just for startup testing
#endif
throw new NotImplementedException();
} }
public Result<IReadOnlyDictionary<(ContentPackage Package, string ConfigName), IConfigBase>> GetConfigsForPackage(ContentPackage package) public bool TryGetConfig<T>(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<IReadOnlyDictionary<(ContentPackage Package, string ConfigName), ImmutableArray<(string ConfigName, OneOf<string, XElement> Value)>>> GetProfilesForPackage(ContentPackage package) if (inst is not T instanceT)
{ {
throw new NotImplementedException(); return false;
} }
public IReadOnlyDictionary<(ContentPackage Package, string Name), IConfigBase> GetAllConfigs() instance = instanceT;
{ return true;
throw new NotImplementedException();
}
public bool TryGetConfig<T>(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<FluentResults.Result> SaveAllConfigs()
{
throw new NotImplementedException();
}
public async Task<FluentResults.Result> SaveConfigsForPackage(ContentPackage package)
{
throw new NotImplementedException();
}
public async Task<FluentResults.Result> SaveConfig((ContentPackage Package, string ConfigName) config)
{
throw new NotImplementedException();
} }
} }
@@ -325,6 +325,9 @@ public class EventService : IEventService, IEventAssemblyContextUnloading
} }
catch (Exception e) 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}.") errors.Enqueue(new Error($"Error while executing runner for {eventType.Name} on type {eventSub.GetType().Name}.")
.WithMetadata(MetadataType.ExceptionObject, this) .WithMetadata(MetadataType.ExceptionObject, this)
.WithMetadata(MetadataType.RootObject, eventSub) .WithMetadata(MetadataType.RootObject, eventSub)
@@ -18,3 +18,8 @@ public interface IParserServiceAsync<in TSrc, TOut> : IService
Task<Result<TOut>> TryParseResourceAsync(TSrc src); Task<Result<TOut>> TryParseResourceAsync(TSrc src);
Task<ImmutableArray<Result<TOut>>> TryParseResourcesAsync(IEnumerable<TSrc> sources); Task<ImmutableArray<Result<TOut>>> TryParseResourcesAsync(IEnumerable<TSrc> sources);
} }
public interface IParserServiceOneToManyAsync<in TSrc, TOut> : IService
{
Task<Result<ImmutableArray<TOut>>> TryParseResourcesAsync(TSrc src);
}
@@ -10,7 +10,7 @@ using Microsoft.Toolkit.Diagnostics;
namespace Barotrauma.LuaCs.Services.Processing; namespace Barotrauma.LuaCs.Services.Processing;
public sealed class ConfigFileParserService : public sealed class ModConfigFileParserService :
IParserServiceAsync<ResourceParserInfo, IAssemblyResourceInfo>, IParserServiceAsync<ResourceParserInfo, IAssemblyResourceInfo>,
IParserServiceAsync<ResourceParserInfo, ILuaScriptResourceInfo>, IParserServiceAsync<ResourceParserInfo, ILuaScriptResourceInfo>,
IParserServiceAsync<ResourceParserInfo, IConfigResourceInfo> IParserServiceAsync<ResourceParserInfo, IConfigResourceInfo>
@@ -18,7 +18,7 @@ public sealed class ConfigFileParserService :
private IStorageService _storageService; private IStorageService _storageService;
private readonly AsyncReaderWriterLock _operationsLock = new(); private readonly AsyncReaderWriterLock _operationsLock = new();
public ConfigFileParserService(IStorageService storageService) public ModConfigFileParserService(IStorageService storageService)
{ {
_storageService = storageService; _storageService = storageService;
} }
@@ -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<IConfigResourceInfo, IConfigInfo>,
IParserServiceOneToManyAsync<IConfigResourceInfo, IConfigProfileInfo>
{
#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<Result<ImmutableArray<IConfigInfo>>> IParserServiceOneToManyAsync<IConfigResourceInfo, IConfigInfo>
.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<IConfigInfo>();
foreach ((ContentPath path, Result<XDocument> 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<IConfigResourceInfo, IConfigInfo>.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<Result<ImmutableArray<IConfigProfileInfo>>>
IParserServiceOneToManyAsync<IConfigResourceInfo, IConfigProfileInfo>
.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<IConfigProfileInfo>();
foreach ((ContentPath path, Result<XDocument> 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<IConfigResourceInfo, IConfigProfileInfo>.TryParseResourcesAsync)}: {msg}");
}
}
}
@@ -6,27 +6,5 @@ namespace Barotrauma.LuaCs.Services.Safe;
public interface ILuaConfigService : ILuaService 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<string> 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);
} }
@@ -15,33 +15,18 @@ namespace Barotrauma.LuaCs.Services;
public partial interface IConfigService : IReusableService, ILuaConfigService public partial interface IConfigService : IReusableService, ILuaConfigService
{ {
void RegisterSettingTypeInitializer<T>(string typeIdentifier, Func<IConfigInfo, T> settingFactory)
where T : class, ISettingBase;
/// <summary> /// <summary>
/// Registers a type initializer from instancing config types by indicated type from config. ///
/// </summary> /// </summary>
/// <param name="initializer"></param> /// <param name="configResources"></param>
/// <param name="replaceIfExists"></param> /// <exception cref="ArgumentException"></exception>
/// <typeparam name="TData">The <see cref="Type"/> as parsed from the configuration info.</typeparam> /// <exception cref="NullReferenceException"></exception>
/// <typeparam name="TConfig">The resulting configuration instance.</typeparam> /// <returns></returns>
void RegisterTypeInitializer<TData, TConfig>(Func<IConfigInfo, FluentResults.Result<TConfig>> initializer, bool replaceIfExists = false)
where TData : IEquatable<TData> where TConfig : IConfigBase;
// Config Files/Resources
Task<FluentResults.Result> LoadConfigsAsync(ImmutableArray<IConfigResourceInfo> configResources); Task<FluentResults.Result> LoadConfigsAsync(ImmutableArray<IConfigResourceInfo> configResources);
Task<FluentResults.Result> LoadConfigsProfilesAsync(ImmutableArray<IConfigResourceInfo> configProfileResources); Task<FluentResults.Result> LoadConfigsProfilesAsync(ImmutableArray<IConfigResourceInfo> configProfileResources);
// Immediate Mode
FluentResults.Result<TConfig> AddConfig<TConfig>(IConfigInfo configInfo) where TConfig : IConfigBase;
// Utility
FluentResults.Result ApplyProfileSettings(ContentPackage package, string profileName);
FluentResults.Result DisposePackageData(ContentPackage package); FluentResults.Result DisposePackageData(ContentPackage package);
FluentResults.Result DisposeAllPackageData(); FluentResults.Result DisposeAllPackageData();
FluentResults.Result<IReadOnlyDictionary<(ContentPackage Package, string ConfigName), IConfigBase>> GetConfigsForPackage(ContentPackage package); bool TryGetConfig<T>(ContentPackage package, string internalName, out T instance) where T : ISettingBase;
FluentResults.Result<IReadOnlyDictionary<(ContentPackage Package, string ConfigName), ImmutableArray<(string ConfigName, OneOf.OneOf<string, XElement> Value)>>>
GetProfilesForPackage(ContentPackage package);
IReadOnlyDictionary<(ContentPackage Package, string Name), IConfigBase> GetAllConfigs();
bool TryGetConfig<T>(ContentPackage package, string name, out T config) where T : IConfigBase;
Task<FluentResults.Result> SaveAllConfigs();
Task<FluentResults.Result> SaveConfigsForPackage(ContentPackage package);
Task<FluentResults.Result> SaveConfig((ContentPackage Package, string ConfigName) config);
} }