- Completed most of PackageManagementService.cs
- Some areas of code need to be rewritten for the simplified loading and execution process.
This commit is contained in:
@@ -25,8 +25,9 @@ namespace Barotrauma
|
|||||||
|
|
||||||
public void CheckCsEnabled()
|
public void CheckCsEnabled()
|
||||||
{
|
{
|
||||||
|
throw new NotImplementedException($"Replace PMS.Assemblies with checks on ContentPackageManager.EnabledPackages");
|
||||||
|
|
||||||
var csharpMods = PackageManagementService.Assemblies
|
/*var csharpMods = PackageManagementService.Assemblies
|
||||||
.GroupBy(ass => ass.OwnerPackage)
|
.GroupBy(ass => ass.OwnerPackage)
|
||||||
.Select(grp => grp.Key)
|
.Select(grp => grp.Key)
|
||||||
.Where(ContentPackageManager.EnabledPackages.All.Contains)
|
.Where(ContentPackageManager.EnabledPackages.All.Contains)
|
||||||
@@ -66,7 +67,7 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
this.IsCsEnabled.TrySetValue(false);
|
this.IsCsEnabled.TrySetValue(false);
|
||||||
return true;
|
return true;
|
||||||
};
|
};*/
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ using System.Security.AccessControl;
|
|||||||
using Barotrauma.LuaCs.Services;
|
using Barotrauma.LuaCs.Services;
|
||||||
using Barotrauma.Networking;
|
using Barotrauma.Networking;
|
||||||
using FluentResults;
|
using FluentResults;
|
||||||
|
using OneOf.Types;
|
||||||
|
|
||||||
namespace Barotrauma.LuaCs.Data;
|
namespace Barotrauma.LuaCs.Data;
|
||||||
|
|
||||||
@@ -224,3 +225,20 @@ public record LuaScriptServicesConfig : ILuaScriptServicesConfig
|
|||||||
|
|
||||||
public bool IsDisposed => false;
|
public bool IsDisposed => false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// --- Package Management Service
|
||||||
|
public interface IPackageManagementServiceConfig : IService
|
||||||
|
{
|
||||||
|
bool IsCsEnabled { get; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class PackageManagementServiceConfig : IPackageManagementServiceConfig
|
||||||
|
{
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
// ignored
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsDisposed => false;
|
||||||
|
public bool IsCsEnabled => true;
|
||||||
|
}
|
||||||
|
|||||||
@@ -340,7 +340,6 @@ namespace Barotrauma
|
|||||||
foreach (var package in toRemove)
|
foreach (var package in toRemove)
|
||||||
_toUnload.Enqueue(package);
|
_toUnload.Enqueue(package);
|
||||||
|
|
||||||
|
|
||||||
ProcessPackagesListDifferences();
|
ProcessPackagesListDifferences();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -358,16 +357,14 @@ namespace Barotrauma
|
|||||||
|
|
||||||
while (_toUnload.TryDequeue(out var cp))
|
while (_toUnload.TryDequeue(out var cp))
|
||||||
{
|
{
|
||||||
LuaScriptManagementService.DisposePackageResources(cp);
|
|
||||||
ConfigService.DisposePackageData(cp);
|
|
||||||
PackageManagementService.DisposePackageInfos(cp);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var ls = new List<ContentPackage>();
|
var ls = new List<ContentPackage>();
|
||||||
|
|
||||||
while (_toLoad.TryDequeue(out var cp))
|
while (_toLoad.TryDequeue(out var cp))
|
||||||
{
|
{
|
||||||
if (PackageManagementService.LoadPackageInfosAsync(cp).GetAwaiter().GetResult() is
|
if (PackageManagementService.LoadPackageInfo(cp) is
|
||||||
{ IsFailed: true } failure)
|
{ IsFailed: true } failure)
|
||||||
{
|
{
|
||||||
Logger.LogError($"Failed to load package infos for {cp.Name}");
|
Logger.LogError($"Failed to load package infos for {cp.Name}");
|
||||||
@@ -456,8 +453,7 @@ namespace Barotrauma
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
// load core
|
// load core
|
||||||
var result1 = PackageManagementService.LoadPackageInfosAsync(ContentPackageManager.VanillaCorePackage)
|
var result1 = PackageManagementService.LoadPackageInfo(ContentPackageManager.VanillaCorePackage);
|
||||||
.GetAwaiter().GetResult();
|
|
||||||
if (result1.IsFailed)
|
if (result1.IsFailed)
|
||||||
{
|
{
|
||||||
Logger.LogError($"Unable to load LuaCs CorePackage resources! Running in degraded mode.");
|
Logger.LogError($"Unable to load LuaCs CorePackage resources! Running in degraded mode.");
|
||||||
@@ -477,16 +473,9 @@ namespace Barotrauma
|
|||||||
|
|
||||||
void LoadContentPackagesInfos(IReadOnlyList<ContentPackage> packages)
|
void LoadContentPackagesInfos(IReadOnlyList<ContentPackage> packages)
|
||||||
{
|
{
|
||||||
var result2 = PackageManagementService.LoadPackagesInfosAsync(packages)
|
var result2 = PackageManagementService.LoadPackagesInfo([..packages]);
|
||||||
.GetAwaiter().GetResult();
|
if (result2.IsFailed)
|
||||||
|
Logger.LogResults(result2);
|
||||||
foreach (var entry in result2)
|
|
||||||
{
|
|
||||||
if (entry.Item2.IsSuccess)
|
|
||||||
Logger.LogMessage($"Successfully parsed package: {entry.Item1.Name}");
|
|
||||||
else if (entry.Item2.IsFailed)
|
|
||||||
Logger.LogResults(entry.Item2);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void LoadStaticAssets()
|
void LoadStaticAssets()
|
||||||
@@ -500,7 +489,7 @@ namespace Barotrauma
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
while (_toUnload.TryDequeue(out var cp))
|
while (_toUnload.TryDequeue(out var cp))
|
||||||
PackageManagementService.DisposePackageInfos(cp);
|
PackageManagementService.UnloadPackage(cp);
|
||||||
|
|
||||||
LoadStaticAssetsAsync(PackageManagementService.GetAllLoadedPackages()).GetAwaiter().GetResult();
|
LoadStaticAssetsAsync(PackageManagementService.GetAllLoadedPackages()).GetAwaiter().GetResult();
|
||||||
LoadLuaCsConfig();
|
LoadLuaCsConfig();
|
||||||
@@ -543,7 +532,9 @@ namespace Barotrauma
|
|||||||
|
|
||||||
async Task LoadStaticAssetsAsync(IReadOnlyList<ContentPackage> packages)
|
async Task LoadStaticAssetsAsync(IReadOnlyList<ContentPackage> packages)
|
||||||
{
|
{
|
||||||
var cfgRes = ImmutableArray<IConfigResourceInfo>.Empty;
|
throw new NotImplementedException();
|
||||||
|
|
||||||
|
/*var cfgRes = ImmutableArray<IConfigResourceInfo>.Empty;
|
||||||
var luaRes = ImmutableArray<ILuaScriptResourceInfo>.Empty;
|
var luaRes = ImmutableArray<ILuaScriptResourceInfo>.Empty;
|
||||||
|
|
||||||
var tasksBuilder = ImmutableArray.CreateBuilder<Task>();
|
var tasksBuilder = ImmutableArray.CreateBuilder<Task>();
|
||||||
@@ -586,12 +577,12 @@ namespace Barotrauma
|
|||||||
Logger.LogResults(res);
|
Logger.LogResults(res);
|
||||||
})());
|
})());
|
||||||
|
|
||||||
await Task.WhenAll(tasksBuilder.MoveToImmutable());
|
await Task.WhenAll(tasksBuilder.MoveToImmutable());*/
|
||||||
}
|
}
|
||||||
|
|
||||||
void RunScripts()
|
void RunScripts()
|
||||||
{
|
{
|
||||||
if (!IsStaticAssetsLoaded)
|
/*if (!IsStaticAssetsLoaded)
|
||||||
{
|
{
|
||||||
throw new InvalidOperationException($"{nameof(RunScripts)} cannot load assets in the '{CurrentRunState}' state.");
|
throw new InvalidOperationException($"{nameof(RunScripts)} cannot load assets in the '{CurrentRunState}' state.");
|
||||||
}
|
}
|
||||||
@@ -661,23 +652,23 @@ namespace Barotrauma
|
|||||||
LuaScriptManagementService.ExecuteLoadedScripts();
|
LuaScriptManagementService.ExecuteLoadedScripts();
|
||||||
|
|
||||||
if (CurrentRunState < RunState.Running)
|
if (CurrentRunState < RunState.Running)
|
||||||
_runState = RunState.Running;
|
_runState = RunState.Running;*/
|
||||||
}
|
}
|
||||||
|
|
||||||
void UnloadContentPackageInfos()
|
void UnloadContentPackageInfos()
|
||||||
{
|
{
|
||||||
if (IsStaticAssetsLoaded)
|
/*if (IsStaticAssetsLoaded)
|
||||||
{
|
{
|
||||||
throw new InvalidOperationException($"{nameof(UnloadStaticAssets)}: Cannot unload static assets when the current run state is {CurrentRunState}.");
|
throw new InvalidOperationException($"{nameof(UnloadStaticAssets)}: Cannot unload static assets when the current run state is {CurrentRunState}.");
|
||||||
}
|
}
|
||||||
|
|
||||||
PackageManagementService.Reset();
|
PackageManagementService.Reset();
|
||||||
_toUnload.Clear();
|
_toUnload.Clear();*/
|
||||||
}
|
}
|
||||||
|
|
||||||
void UnloadStaticAssets()
|
void UnloadStaticAssets()
|
||||||
{
|
{
|
||||||
if (IsCodeRunning)
|
/*if (IsCodeRunning)
|
||||||
{
|
{
|
||||||
throw new InvalidOperationException($"{nameof(UnloadStaticAssets)}: Cannot unload static assets when the current run state is {CurrentRunState}.");
|
throw new InvalidOperationException($"{nameof(UnloadStaticAssets)}: Cannot unload static assets when the current run state is {CurrentRunState}.");
|
||||||
}
|
}
|
||||||
@@ -689,12 +680,12 @@ namespace Barotrauma
|
|||||||
if (CurrentRunState >= RunState.Configuration)
|
if (CurrentRunState >= RunState.Configuration)
|
||||||
{
|
{
|
||||||
_runState = RunState.Parsed;
|
_runState = RunState.Parsed;
|
||||||
}
|
}*/
|
||||||
}
|
}
|
||||||
|
|
||||||
void StopScripts()
|
void StopScripts()
|
||||||
{
|
{
|
||||||
EventService.ClearAllSubscribers();
|
/*EventService.ClearAllSubscribers();
|
||||||
LuaScriptManagementService.UnloadActiveScripts();
|
LuaScriptManagementService.UnloadActiveScripts();
|
||||||
PluginManagementService.UnloadManagedAssemblies();
|
PluginManagementService.UnloadManagedAssemblies();
|
||||||
SubscribeToLuaCsEvents();
|
SubscribeToLuaCsEvents();
|
||||||
@@ -702,7 +693,7 @@ namespace Barotrauma
|
|||||||
if (IsCodeRunning)
|
if (IsCodeRunning)
|
||||||
{
|
{
|
||||||
_runState = RunState.Configuration;
|
_runState = RunState.Configuration;
|
||||||
}
|
}*/
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -23,668 +23,179 @@ namespace Barotrauma.LuaCs.Services;
|
|||||||
|
|
||||||
public partial class ConfigService : IConfigService
|
public partial class ConfigService : IConfigService
|
||||||
{
|
{
|
||||||
//--- Internals
|
|
||||||
public ConfigService(IParserServiceAsync<IConfigResourceInfo, IReadOnlyList<IConfigProfileInfo>> configProfileResourceParser,
|
|
||||||
IParserServiceAsync<IConfigResourceInfo, IReadOnlyList<IConfigInfo>> configResourceParser, IEventService eventService, System.Lazy<IStorageService> storageService)
|
|
||||||
{
|
|
||||||
_configProfileResourceParser = configProfileResourceParser;
|
|
||||||
_configResourceParser = configResourceParser;
|
|
||||||
_eventService = eventService;
|
|
||||||
_storageService = storageService;
|
|
||||||
this._base = this;
|
|
||||||
}
|
|
||||||
|
|
||||||
// data, states
|
|
||||||
private readonly IService _base;
|
|
||||||
private int _isDisposed = 0;
|
|
||||||
private readonly ConcurrentDictionary<Type, Func<IConfigInfo, FluentResults.Result<IConfigBase>>> _configTypeInitializers = new();
|
|
||||||
private readonly ConcurrentDictionary<(ContentPackage Package, string ConfigName), IConfigBase> _configs = new();
|
|
||||||
private readonly ConcurrentDictionary<ContentPackage, ConcurrentBag<(ContentPackage Package, string ConfigName)>> _packageConfigReverseLookup = new();
|
|
||||||
private readonly ConcurrentDictionary<(ContentPackage Package, string ProfileName), ImmutableArray<(string ConfigName, OneOf.OneOf<string, XElement> Value)>> _configProfiles = new();
|
|
||||||
private readonly ConcurrentDictionary<ContentPackage, ConcurrentBag<(ContentPackage Package, string ProfileName)>> _packageProfilesReverseLookup = new();
|
|
||||||
private readonly ConcurrentDictionary<string, ContentPackage> _packageNameMap= new();
|
|
||||||
|
|
||||||
private readonly AsyncReaderWriterLock _disposeOpsLock = new();
|
|
||||||
|
|
||||||
// extern services
|
|
||||||
private readonly IParserServiceAsync<IConfigResourceInfo, IReadOnlyList<IConfigInfo>> _configResourceParser;
|
|
||||||
private readonly IParserServiceAsync<IConfigResourceInfo, IReadOnlyList<IConfigProfileInfo>> _configProfileResourceParser;
|
|
||||||
private readonly IEventService _eventService;
|
|
||||||
private readonly System.Lazy<IStorageService> _storageService;
|
|
||||||
|
|
||||||
//--- GC
|
|
||||||
public bool IsDisposed => ModUtils.Threading.GetBool(ref _isDisposed);
|
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
// stop all ops
|
throw new NotImplementedException();
|
||||||
using var lck = _disposeOpsLock.AcquireWriterLock().GetAwaiter().GetResult();
|
|
||||||
// set flag
|
|
||||||
ModUtils.Threading.SetBool(ref _isDisposed, true);
|
|
||||||
|
|
||||||
_configTypeInitializers.Clear();
|
|
||||||
if (!_configs.IsEmpty)
|
|
||||||
{
|
|
||||||
foreach (var config in _configs)
|
|
||||||
{
|
|
||||||
if (config.Value is IDisposable disposable)
|
|
||||||
disposable.Dispose();
|
|
||||||
config.Value.OnValueChanged -= this.SaveConfigEvent;
|
|
||||||
}
|
|
||||||
_configs.Clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
_configProfiles.Clear();
|
|
||||||
_packageConfigReverseLookup.Clear();
|
|
||||||
_packageNameMap.Clear();
|
|
||||||
_packageProfilesReverseLookup.Clear();
|
|
||||||
|
|
||||||
GC.SuppressFinalize(this);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public bool IsDisposed { get; }
|
||||||
public FluentResults.Result Reset()
|
public FluentResults.Result Reset()
|
||||||
{
|
{
|
||||||
using var lck = _disposeOpsLock.AcquireWriterLock().GetAwaiter().GetResult();
|
throw new NotImplementedException();
|
||||||
_base.CheckDisposed();
|
|
||||||
|
|
||||||
_configTypeInitializers.Clear();
|
|
||||||
_configs.Clear();
|
|
||||||
_configProfiles.Clear();
|
|
||||||
_packageConfigReverseLookup.Clear();
|
|
||||||
_packageNameMap.Clear();
|
|
||||||
_packageProfilesReverseLookup.Clear();
|
|
||||||
|
|
||||||
return FluentResults.Result.Ok();
|
|
||||||
}
|
|
||||||
|
|
||||||
//--- API contracts
|
|
||||||
// Notes:
|
|
||||||
// -- Lua Interface uses strong types due to lua limitations. May be required to move API to an adapter class
|
|
||||||
// to allow testing abstraction.
|
|
||||||
// -- Lua interface should not propagate errors.
|
|
||||||
#region LuaInterface
|
|
||||||
|
|
||||||
private bool TryGetConfigValue<T>(string packageName, string configName, out T value) where T : IEquatable<T>
|
|
||||||
{
|
|
||||||
value = default;
|
|
||||||
using var lck = _disposeOpsLock.AcquireReaderLock().GetAwaiter().GetResult();
|
|
||||||
if (ModUtils.Threading.GetBool(ref _isDisposed))
|
|
||||||
return false;
|
|
||||||
if (!_packageNameMap.TryGetValue(packageName, out var package))
|
|
||||||
return false;
|
|
||||||
if (!_configs.TryGetValue((package, configName), out var config))
|
|
||||||
return false;
|
|
||||||
if (config is not IConfigEntry<T> entry)
|
|
||||||
return false;
|
|
||||||
value = entry.Value;
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool TryGetConfigBool(string packageName, string configName, out bool value)
|
public bool TryGetConfigBool(string packageName, string configName, out bool value)
|
||||||
{
|
{
|
||||||
return TryGetConfigValue(packageName, configName, out value);
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool TryGetConfigInt(string packageName, string configName, out int value)
|
public bool TryGetConfigInt(string packageName, string configName, out int value)
|
||||||
{
|
{
|
||||||
return TryGetConfigValue(packageName, configName, out value);
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool TryGetConfigFloat(string packageName, string configName, out float value)
|
public bool TryGetConfigFloat(string packageName, string configName, out float value)
|
||||||
{
|
{
|
||||||
return TryGetConfigValue(packageName, configName, out value);
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool TryGetConfigNumber(string packageName, string configName, out double value)
|
public bool TryGetConfigNumber(string packageName, string configName, out double value)
|
||||||
{
|
{
|
||||||
return TryGetConfigValue(packageName, configName, out value);
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool TryGetConfigString(string packageName, string configName, out string value)
|
public bool TryGetConfigString(string packageName, string configName, out string value)
|
||||||
{
|
{
|
||||||
return TryGetConfigValue(packageName, configName, out value);
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool TryGetConfigVector2(string packageName, string configName, out Vector2 value)
|
public bool TryGetConfigVector2(string packageName, string configName, out Vector2 value)
|
||||||
{
|
{
|
||||||
return TryGetConfigValue(packageName, configName, out value);
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool TryGetConfigVector3(string packageName, string configName, out Vector3 value)
|
public bool TryGetConfigVector3(string packageName, string configName, out Vector3 value)
|
||||||
{
|
{
|
||||||
return TryGetConfigValue(packageName, configName, out value);
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool TryGetConfigColor(string packageName, string configName, out Color value)
|
public bool TryGetConfigColor(string packageName, string configName, out Color value)
|
||||||
{
|
{
|
||||||
return TryGetConfigValue(packageName, configName, out value);
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool TryGetConfigList(string packageName, string configName, out IReadOnlyList<string> value)
|
public bool TryGetConfigList(string packageName, string configName, out IReadOnlyList<string> value)
|
||||||
{
|
{
|
||||||
value = null;
|
throw new NotImplementedException();
|
||||||
using var lck = _disposeOpsLock.AcquireReaderLock().GetAwaiter().GetResult();
|
|
||||||
if (ModUtils.Threading.GetBool(ref _isDisposed))
|
|
||||||
return false;
|
|
||||||
if (!_packageNameMap.TryGetValue(packageName, out var package))
|
|
||||||
return false;
|
|
||||||
if (!_configs.TryGetValue((package, configName), out var config))
|
|
||||||
return false;
|
|
||||||
if (config is not IConfigList<string> entry)
|
|
||||||
return false;
|
|
||||||
value = entry.Options;
|
|
||||||
return value is not null && value.Count > 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void SetConfigValue<T>(string packageName, string configName, T value) where T : IEquatable<T>
|
|
||||||
{
|
|
||||||
using var lck = _disposeOpsLock.AcquireReaderLock().GetAwaiter().GetResult();
|
|
||||||
if (ModUtils.Threading.GetBool(ref _isDisposed))
|
|
||||||
return;
|
|
||||||
if (!_packageNameMap.TryGetValue(packageName, out var package))
|
|
||||||
return;
|
|
||||||
if (!_configs.TryGetValue((package, configName), out var config))
|
|
||||||
return;
|
|
||||||
if (config is not IConfigEntry<T> entry)
|
|
||||||
return;
|
|
||||||
entry.TrySetValue(value);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetConfigBool(string packageName, string configName, bool value)
|
public void SetConfigBool(string packageName, string configName, bool value)
|
||||||
{
|
{
|
||||||
SetConfigValue(packageName, configName, value);
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetConfigInt(string packageName, string configName, int value)
|
public void SetConfigInt(string packageName, string configName, int value)
|
||||||
{
|
{
|
||||||
SetConfigValue(packageName, configName, value);
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetConfigFloat(string packageName, string configName, float value)
|
public void SetConfigFloat(string packageName, string configName, float value)
|
||||||
{
|
{
|
||||||
SetConfigValue(packageName, configName, value);
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetConfigNumber(string packageName, string configName, double value)
|
public void SetConfigNumber(string packageName, string configName, double value)
|
||||||
{
|
{
|
||||||
SetConfigValue(packageName, configName, value);
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetConfigString(string packageName, string configName, string value)
|
public void SetConfigString(string packageName, string configName, string value)
|
||||||
{
|
{
|
||||||
SetConfigValue(packageName, configName, value);
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetConfigVector2(string packageName, string configName, Vector2 value)
|
public void SetConfigVector2(string packageName, string configName, Vector2 value)
|
||||||
{
|
{
|
||||||
SetConfigValue(packageName, configName, value);
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetConfigVector3(string packageName, string configName, Vector3 value)
|
public void SetConfigVector3(string packageName, string configName, Vector3 value)
|
||||||
{
|
{
|
||||||
SetConfigValue(packageName, configName, value);
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetConfigColor(string packageName, string configName, Color value)
|
public void SetConfigColor(string packageName, string configName, Color value)
|
||||||
{
|
{
|
||||||
SetConfigValue(packageName, configName, value);
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetConfigList(string packageName, string configName, string value)
|
public void SetConfigList(string packageName, string configName, string value)
|
||||||
{
|
{
|
||||||
using var lck = _disposeOpsLock.AcquireReaderLock().GetAwaiter().GetResult();
|
throw new NotImplementedException();
|
||||||
if (ModUtils.Threading.GetBool(ref _isDisposed))
|
|
||||||
return;
|
|
||||||
if (!_packageNameMap.TryGetValue(packageName, out var package))
|
|
||||||
return;
|
|
||||||
if (!_configs.TryGetValue((package, configName), out var config))
|
|
||||||
return;
|
|
||||||
if (config is not IConfigList<string> entry)
|
|
||||||
return;
|
|
||||||
entry.TrySetValue(value);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool TryApplyProfileSettings(string packageName, string profileName)
|
public bool TryApplyProfileSettings(string packageName, string profileName)
|
||||||
{
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
if (ModUtils.Threading.GetBool(ref _isDisposed))
|
|
||||||
return false;
|
|
||||||
if (packageName.IsNullOrWhiteSpace() || profileName.IsNullOrWhiteSpace())
|
|
||||||
return false;
|
|
||||||
ContentPackage package = null;
|
|
||||||
using (var lck = _disposeOpsLock.AcquireReaderLock().GetAwaiter().GetResult())
|
|
||||||
{
|
|
||||||
if (!_packageNameMap.TryGetValue(packageName, out package) || package == null)
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
// exit semaphore before invocation. Note: Race condition, may require copy implementation.
|
|
||||||
return this.ApplyProfileSettings(package, profileName).IsSuccess;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
public void RegisterTypeInitializer<TData, TConfig>(Func<IConfigInfo, Result<TConfig>> initializer, bool replaceIfExists = false) where TData : IEquatable<TData> where TConfig : IConfigBase
|
||||||
|
|
||||||
public void RegisterTypeInitializer<TData, TConfig>(Func<IConfigInfo, FluentResults.Result<TConfig>> initializer, bool replaceIfExists = false)
|
|
||||||
where TData : IEquatable<TData> where TConfig : IConfigBase
|
|
||||||
{
|
{
|
||||||
using var lck = _disposeOpsLock.AcquireReaderLock().GetAwaiter().GetResult();
|
throw new NotImplementedException();
|
||||||
_base.CheckDisposed();
|
|
||||||
|
|
||||||
Type dataType = typeof(TData);
|
|
||||||
if (_configTypeInitializers.ContainsKey(dataType) && !replaceIfExists)
|
|
||||||
return;
|
|
||||||
_configTypeInitializers[dataType] = (info =>
|
|
||||||
{
|
|
||||||
var res = initializer(info);
|
|
||||||
if (res.IsFailed)
|
|
||||||
return FluentResults.Result.Fail($"Failed to initialize config type {dataType.Name}").WithErrors(res.Errors);
|
|
||||||
return res.Value;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private void AddConfigInstance((ContentPackage Package, string ConfigName) key, IConfigBase instance)
|
|
||||||
{
|
|
||||||
_configs[key] = instance;
|
|
||||||
if (!_packageNameMap.ContainsKey(key.Package.Name))
|
|
||||||
_packageNameMap[key.Package.Name] = key.Package;
|
|
||||||
if (!_packageConfigReverseLookup.TryGetValue(key.Package, out var list))
|
|
||||||
{
|
|
||||||
list = new ConcurrentBag<(ContentPackage Package, string ConfigName)>();
|
|
||||||
_packageConfigReverseLookup[key.Package] = list;
|
|
||||||
}
|
|
||||||
list.Add(key);
|
|
||||||
// save hook
|
|
||||||
instance.OnValueChanged += this.SaveConfigEvent;
|
|
||||||
_eventService.PublishEvent<IEventConfigVarInstanced>(sub => sub.OnConfigCreated(instance));
|
|
||||||
}
|
|
||||||
|
|
||||||
private void AddProfileInstance((ContentPackage Package, string ProfileName) key, IConfigProfileInfo profile)
|
|
||||||
{
|
|
||||||
_configProfiles[key] = profile.ProfileValues.ToImmutableArray();
|
|
||||||
if (!_packageNameMap.ContainsKey(key.Package.Name))
|
|
||||||
_packageNameMap[key.Package.Name] = key.Package;
|
|
||||||
if (!_packageProfilesReverseLookup.TryGetValue(key.Package, out var list))
|
|
||||||
{
|
|
||||||
list = new ConcurrentBag<(ContentPackage Package, string ProfileName)>();
|
|
||||||
_packageProfilesReverseLookup[key.Package] = list;
|
|
||||||
}
|
|
||||||
list.Add(key);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<FluentResults.Result> LoadConfigsAsync(ImmutableArray<IConfigResourceInfo> configResources)
|
public async Task<FluentResults.Result> LoadConfigsAsync(ImmutableArray<IConfigResourceInfo> configResources)
|
||||||
{
|
{
|
||||||
using var lck = await _disposeOpsLock.AcquireReaderLock();
|
throw new NotImplementedException();
|
||||||
_base.CheckDisposed();
|
|
||||||
|
|
||||||
if (configResources.IsDefaultOrEmpty)
|
|
||||||
return FluentResults.Result.Fail($"{nameof(LoadConfigsAsync)}: Array is empty.");
|
|
||||||
|
|
||||||
var results = await _configResourceParser.TryParseResourcesAsync(configResources);
|
|
||||||
var ret = new FluentResults.Result();
|
|
||||||
|
|
||||||
foreach (var result in results)
|
|
||||||
{
|
|
||||||
if (result.Errors.Any())
|
|
||||||
ret.Errors.AddRange(result.Errors);
|
|
||||||
if (result.IsFailed || result.Value is not { Count: > 0 } res)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
foreach (var configInfo in res)
|
|
||||||
{
|
|
||||||
if (_configs.ContainsKey((configInfo.OwnerPackage, configInfo.InternalName)))
|
|
||||||
{
|
|
||||||
ret.Errors.Add(new Error($"{nameof(LoadConfigsAsync)}: Config already exists for the compound key {configInfo.OwnerPackage.Name} | {configInfo.InternalName}"));
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!_configTypeInitializers.TryGetValue(configInfo.DataType, out var initializer))
|
|
||||||
{
|
|
||||||
ret.Errors.Add(new Error($"{nameof(LoadConfigsAsync)} No type initializer for {configInfo.DataType}"));
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
var cfg = initializer(configInfo);
|
|
||||||
if (cfg.Errors.Any())
|
|
||||||
ret.Errors.AddRange(cfg.Errors);
|
|
||||||
if (cfg.IsFailed || cfg.Value is not {} val)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
AddConfigInstance((configInfo.OwnerPackage, configInfo.InternalName), val);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<FluentResults.Result> LoadConfigsProfilesAsync(ImmutableArray<IConfigResourceInfo> configProfileResources)
|
public async Task<FluentResults.Result> LoadConfigsProfilesAsync(ImmutableArray<IConfigResourceInfo> configProfileResources)
|
||||||
{
|
{
|
||||||
using var lck = await _disposeOpsLock.AcquireReaderLock();
|
throw new NotImplementedException();
|
||||||
_base.CheckDisposed();
|
|
||||||
|
|
||||||
if (configProfileResources.IsDefaultOrEmpty)
|
|
||||||
return FluentResults.Result.Fail($"{nameof(LoadConfigsProfilesAsync)}: Array is empty.");
|
|
||||||
|
|
||||||
var results = await _configProfileResourceParser.TryParseResourcesAsync(configProfileResources);
|
|
||||||
var ret = new FluentResults.Result();
|
|
||||||
|
|
||||||
foreach (var result in results)
|
|
||||||
{
|
|
||||||
if (result.Errors.Any())
|
|
||||||
ret.Errors.AddRange(result.Errors);
|
|
||||||
if (result.IsFailed || result.Value is not { Count: > 0 } res)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
foreach (var profileInfo in res)
|
|
||||||
{
|
|
||||||
if (_configProfiles.ContainsKey((profileInfo.OwnerPackage, profileInfo.InternalName)))
|
|
||||||
{
|
|
||||||
ret.Errors.Add(new Error($"{nameof(LoadConfigsProfilesAsync)}: Config already exists for the compound key {profileInfo.OwnerPackage.Name} | {profileInfo.InternalName}"));
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
AddProfileInstance((profileInfo.OwnerPackage, profileInfo.InternalName), profileInfo);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public FluentResults.Result<TConfig> AddConfig<TConfig>(IConfigInfo configInfo) where TConfig : IConfigBase
|
public Result<TConfig> AddConfig<TConfig>(IConfigInfo configInfo) where TConfig : IConfigBase
|
||||||
{
|
{
|
||||||
using var lck = _disposeOpsLock.AcquireReaderLock().GetAwaiter().GetResult();
|
throw new NotImplementedException();
|
||||||
_base.CheckDisposed();
|
|
||||||
|
|
||||||
if (configInfo is null)
|
|
||||||
return FluentResults.Result.Fail($"{nameof(AddConfig)}: Config is null.");
|
|
||||||
|
|
||||||
if (!_configTypeInitializers.TryGetValue(configInfo.DataType, out var initializer))
|
|
||||||
return FluentResults.Result.Fail($"{nameof(AddConfig)}: No type initializer for {configInfo.DataType}");
|
|
||||||
|
|
||||||
var errList = new List<IError>();
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var cfg = initializer(configInfo);
|
|
||||||
if (cfg.Errors.Any())
|
|
||||||
errList.AddRange(cfg.Errors);
|
|
||||||
if (cfg.IsFailed || cfg.Value is null)
|
|
||||||
return FluentResults.Result.Fail($"Failed to initialize {configInfo.DataType}").WithErrors(errList);
|
|
||||||
AddConfigInstance((configInfo.OwnerPackage, configInfo.InternalName), cfg.Value);
|
|
||||||
return (TConfig)cfg.Value;
|
|
||||||
}
|
|
||||||
catch(Exception ex)
|
|
||||||
{
|
|
||||||
return FluentResults.Result.Fail($"Failed to initialize {configInfo.DataType}").WithError(new ExceptionalError(ex));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public FluentResults.Result ApplyProfileSettings(ContentPackage package, string profileName)
|
public FluentResults.Result ApplyProfileSettings(ContentPackage package, string profileName)
|
||||||
{
|
{
|
||||||
using var lck = _disposeOpsLock.AcquireReaderLock().GetAwaiter().GetResult();
|
throw new NotImplementedException();
|
||||||
_base.CheckDisposed();
|
|
||||||
|
|
||||||
if (package == null || string.IsNullOrEmpty(profileName))
|
|
||||||
return FluentResults.Result.Fail($"{nameof(ApplyProfileSettings)}: ContentPackage and/or name were null or empty.");
|
|
||||||
|
|
||||||
if (!_configProfiles.TryGetValue((package, profileName), out var list))
|
|
||||||
return FluentResults.Result.Fail($"No profiles found for package {package.Name} with name {profileName}");
|
|
||||||
|
|
||||||
if (list.IsDefaultOrEmpty)
|
|
||||||
return FluentResults.Result.Fail($"{nameof(ApplyProfileSettings)}: No stored values for profile {profileName}.");
|
|
||||||
|
|
||||||
var errList = new List<IError>();
|
|
||||||
|
|
||||||
foreach (var profileVal in list)
|
|
||||||
{
|
|
||||||
if (!_configs.TryGetValue((package, profileVal.ConfigName), out var val))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (!val.TrySetValue(profileVal.Value))
|
|
||||||
errList.Add(new Error($"Failed to apply value from profile named {profileName} to {val.InternalName}"));
|
|
||||||
// continue
|
|
||||||
}
|
|
||||||
|
|
||||||
return FluentResults.Result.Ok().WithErrors(errList);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public FluentResults.Result DisposePackageData(ContentPackage package)
|
public FluentResults.Result DisposePackageData(ContentPackage package)
|
||||||
{
|
{
|
||||||
// stop regular ops during deletion ops
|
throw new NotImplementedException();
|
||||||
using var lck = _disposeOpsLock.AcquireWriterLock().GetAwaiter().GetResult();
|
}
|
||||||
_base.CheckDisposed();
|
|
||||||
|
|
||||||
if (package is null)
|
public FluentResults.Result DisposeAllPackageData()
|
||||||
return FluentResults.Result.Fail($"{nameof(DisposePackageData)}: Package was null.");
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
var errList = new List<IError>();
|
|
||||||
|
|
||||||
if (_packageConfigReverseLookup.Remove(package, out var cfgKeys))
|
|
||||||
{
|
|
||||||
if (cfgKeys.Any())
|
|
||||||
{
|
|
||||||
foreach (var key in cfgKeys)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
_configs.Remove(key, out var cfg);
|
|
||||||
cfg?.Dispose();
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
errList.Add(new ExceptionalError(e));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_packageProfilesReverseLookup.Remove(package, out var profileKeys))
|
|
||||||
{
|
|
||||||
if (profileKeys.Any())
|
|
||||||
{
|
|
||||||
foreach (var key in profileKeys)
|
|
||||||
{
|
|
||||||
_configProfiles.Remove(key, out _);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
_packageNameMap.Remove(package.Name, out _);
|
|
||||||
|
|
||||||
return FluentResults.Result.Ok().WithErrors(errList);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Result<IReadOnlyDictionary<(ContentPackage Package, string ConfigName), IConfigBase>> GetConfigsForPackage(ContentPackage package)
|
public Result<IReadOnlyDictionary<(ContentPackage Package, string ConfigName), IConfigBase>> GetConfigsForPackage(ContentPackage package)
|
||||||
{
|
{
|
||||||
using var lck = _disposeOpsLock.AcquireReaderLock().GetAwaiter().GetResult();
|
throw new NotImplementedException();
|
||||||
_base.CheckDisposed();
|
|
||||||
|
|
||||||
if (!_packageConfigReverseLookup.TryGetValue(package, out var keys) || keys.IsEmpty)
|
|
||||||
return FluentResults.Result.Fail($"No configs found for package {package.Name}");
|
|
||||||
|
|
||||||
return _configs.Where(kvp => keys.Contains(kvp.Key)).ToFrozenDictionary(kvp => kvp.Key, kvp => kvp.Value);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Result<IReadOnlyDictionary<(ContentPackage Package, string ConfigName), ImmutableArray<(string ConfigName, OneOf<string, XElement> Value)>>> GetProfilesForPackage(ContentPackage package)
|
public Result<IReadOnlyDictionary<(ContentPackage Package, string ConfigName), ImmutableArray<(string ConfigName, OneOf<string, XElement> Value)>>> GetProfilesForPackage(ContentPackage package)
|
||||||
{
|
{
|
||||||
using var lck = _disposeOpsLock.AcquireReaderLock().GetAwaiter().GetResult();
|
throw new NotImplementedException();
|
||||||
_base.CheckDisposed();
|
|
||||||
|
|
||||||
if (!_packageProfilesReverseLookup.TryGetValue(package, out var keys) || keys.IsEmpty)
|
|
||||||
return FluentResults.Result.Fail($"No profiles found for package {package.Name}");
|
|
||||||
|
|
||||||
return _configProfiles.Where(kvp => keys.Contains(kvp.Key)).ToFrozenDictionary(kvp => kvp.Key, kvp => kvp.Value);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public IReadOnlyDictionary<(ContentPackage Package, string Name), IConfigBase> GetAllConfigs()
|
public IReadOnlyDictionary<(ContentPackage Package, string Name), IConfigBase> GetAllConfigs()
|
||||||
{
|
{
|
||||||
using var lck = _disposeOpsLock.AcquireReaderLock().GetAwaiter().GetResult();
|
throw new NotImplementedException();
|
||||||
_base.CheckDisposed();
|
|
||||||
|
|
||||||
return _configs.ToFrozenDictionary(kvp => kvp.Key, kvp => kvp.Value);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool TryGetConfig<T>(ContentPackage package, string name, out T config) where T : IConfigBase
|
public bool TryGetConfig<T>(ContentPackage package, string name, out T config) where T : IConfigBase
|
||||||
{
|
{
|
||||||
using var lck = _disposeOpsLock.AcquireReaderLock().GetAwaiter().GetResult();
|
throw new NotImplementedException();
|
||||||
_base.CheckDisposed();
|
|
||||||
|
|
||||||
config = default;
|
|
||||||
if (!_configs.TryGetValue((package, name), out var value))
|
|
||||||
return false;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
config = (T)value;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<FluentResults.Result> SaveAllConfigs()
|
public async Task<FluentResults.Result> SaveAllConfigs()
|
||||||
{
|
{
|
||||||
using var lck = await _disposeOpsLock.AcquireReaderLock();
|
throw new NotImplementedException();
|
||||||
_base.CheckDisposed();
|
|
||||||
if (_configs.IsEmpty)
|
|
||||||
return FluentResults.Result.Ok();
|
|
||||||
var toSave = _configs.Where(kvp => kvp.Value is not null).Select(kvp => kvp.Value)
|
|
||||||
.ToImmutableArray();
|
|
||||||
var errList = ImmutableArray.CreateBuilder<IError>();
|
|
||||||
foreach (var config in toSave)
|
|
||||||
{
|
|
||||||
var res = await SaveConfigInternal(config);
|
|
||||||
if (res.Errors.Any())
|
|
||||||
errList.AddRange(res.Errors);
|
|
||||||
}
|
|
||||||
return FluentResults.Result.Ok().WithErrors(errList.MoveToImmutable());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<FluentResults.Result> SaveConfigsForPackage(ContentPackage package)
|
public async Task<FluentResults.Result> SaveConfigsForPackage(ContentPackage package)
|
||||||
{
|
{
|
||||||
if (package is null)
|
throw new NotImplementedException();
|
||||||
return FluentResults.Result.Fail($"{nameof(SaveConfigsForPackage)}: Package was null.");
|
|
||||||
using var lck = await _disposeOpsLock.AcquireReaderLock();
|
|
||||||
_base.CheckDisposed();
|
|
||||||
if (!_packageConfigReverseLookup.TryGetValue(package, out var keys) || keys.IsEmpty)
|
|
||||||
return FluentResults.Result.Fail($"No configs found for package {package.Name}");
|
|
||||||
ConcurrentQueue<IConfigBase> toSave = new();
|
|
||||||
foreach (var key in keys)
|
|
||||||
{
|
|
||||||
if (_configs.TryGetValue(key, out var config))
|
|
||||||
toSave.Enqueue(config);
|
|
||||||
}
|
|
||||||
if (toSave.IsEmpty)
|
|
||||||
return FluentResults.Result.Fail($"No configs found for package {package.Name}");
|
|
||||||
var errList = ImmutableArray.CreateBuilder<IError>();
|
|
||||||
while (toSave.TryDequeue(out var config))
|
|
||||||
{
|
|
||||||
var res = await SaveConfigInternal(config);
|
|
||||||
if (res.Errors.Any())
|
|
||||||
errList.AddRange(res.Errors);
|
|
||||||
}
|
|
||||||
return FluentResults.Result.Ok().WithErrors(errList.MoveToImmutable());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<FluentResults.Result> SaveConfig((ContentPackage Package, string ConfigName) config)
|
public async Task<FluentResults.Result> SaveConfig((ContentPackage Package, string ConfigName) config)
|
||||||
{
|
{
|
||||||
if (config.Package is null || config.ConfigName.IsNullOrWhiteSpace())
|
throw new NotImplementedException();
|
||||||
return FluentResults.Result.Fail($"{nameof(SaveConfig)}: Config properties were null or empty.");
|
|
||||||
using var lck = await _disposeOpsLock.AcquireReaderLock();
|
|
||||||
_base.CheckDisposed();
|
|
||||||
if (!_configs.TryGetValue(config, out var instance))
|
|
||||||
return FluentResults.Result.Fail($"{nameof(SaveConfig)}: No config found for package {config.Package.Name} and name {config.ConfigName}");
|
|
||||||
return await SaveConfigInternal(instance);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void SaveConfigEvent(IConfigBase instance)
|
|
||||||
{
|
|
||||||
using var lck = _disposeOpsLock.AcquireWriterLock().GetAwaiter().GetResult();
|
|
||||||
_base.CheckDisposed();
|
|
||||||
SaveConfigInternal(instance).GetAwaiter().GetResult();
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task<FluentResults.Result> SaveConfigInternal(IConfigBase instance)
|
|
||||||
{
|
|
||||||
var localStorePath = Path.Combine("Config", SanitizedFileName($"{instance.OwnerPackage.Name}.xml)"));
|
|
||||||
// Locking and checks must be handled by the caller.
|
|
||||||
var val = instance.GetSerializableValue();
|
|
||||||
var docRes = await _storageService.Value.LoadLocalXmlAsync(instance.OwnerPackage, localStorePath);
|
|
||||||
XDocument doc;
|
|
||||||
XElement cfgElement;
|
|
||||||
XElement valueElement;
|
|
||||||
|
|
||||||
// structure is
|
|
||||||
/*
|
|
||||||
* <Config ContentPackage="[PackageName]">
|
|
||||||
* <[instance.InternalName]>
|
|
||||||
* <Value>
|
|
||||||
* <--Contents Here->
|
|
||||||
* </Value>
|
|
||||||
* </[instance.InternalName]>
|
|
||||||
* </Config>
|
|
||||||
*/
|
|
||||||
|
|
||||||
if (docRes.IsFailed || docRes.Value is null)
|
|
||||||
{
|
|
||||||
doc = new XDocument(
|
|
||||||
new XElement("Config", new XAttribute("ContentPackage", instance.OwnerPackage.Name),
|
|
||||||
cfgElement = new XElement(instance.InternalName, valueElement = new XElement("Value"))));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
doc = docRes.Value;
|
|
||||||
var e1 = doc.GetChildElement("Config");
|
|
||||||
if (e1 is null)
|
|
||||||
{
|
|
||||||
e1 = new XElement("Config");
|
|
||||||
doc.Add(e1);
|
|
||||||
}
|
|
||||||
|
|
||||||
cfgElement = e1.GetChildElement(instance.InternalName);
|
|
||||||
if (cfgElement is null)
|
|
||||||
{
|
|
||||||
cfgElement = new XElement(instance.InternalName);
|
|
||||||
e1.Add(cfgElement);
|
|
||||||
}
|
|
||||||
|
|
||||||
valueElement = cfgElement.GetChildElement("Value");
|
|
||||||
if (valueElement is null)
|
|
||||||
{
|
|
||||||
valueElement = new XElement("Value");
|
|
||||||
cfgElement.Add(valueElement);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
valueElement.Remove(); // remove from cfg
|
|
||||||
|
|
||||||
// get potential updated element
|
|
||||||
var updatedElement = val.Match<XElement>(str =>
|
|
||||||
{
|
|
||||||
valueElement.RemoveAll();
|
|
||||||
valueElement.Value = str;
|
|
||||||
return valueElement;
|
|
||||||
}, element =>
|
|
||||||
{
|
|
||||||
valueElement.RemoveAll();
|
|
||||||
valueElement.Add(element);
|
|
||||||
return valueElement;
|
|
||||||
});
|
|
||||||
|
|
||||||
// (re) add updated element.
|
|
||||||
cfgElement.Add(updatedElement);
|
|
||||||
|
|
||||||
return await _storageService.Value.SaveLocalXmlAsync(instance.OwnerPackage, localStorePath, doc);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static readonly Regex RemoveInvalidChars = new Regex($"[{Regex.Escape(new string(System.IO.Path.GetInvalidFileNameChars()))}]",
|
|
||||||
RegexOptions.Singleline | RegexOptions.Compiled | RegexOptions.CultureInvariant);
|
|
||||||
|
|
||||||
private string SanitizedFileName(string fileName, string replacement = "_")
|
|
||||||
{
|
|
||||||
return RemoveInvalidChars.Replace(fileName, replacement);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+3
-1
@@ -116,8 +116,10 @@ class LuaScriptManagementService : ILuaScriptManagementService, ILuaDataService
|
|||||||
_script.Globals["CLIENT"] = LuaCsSetup.IsClient;
|
_script.Globals["CLIENT"] = LuaCsSetup.IsClient;
|
||||||
}
|
}
|
||||||
|
|
||||||
public FluentResults.Result ExecuteLoadedScripts()
|
public FluentResults.Result ExecuteLoadedScripts(ImmutableArray<ILuaScriptResourceInfo> executionOrder)
|
||||||
{
|
{
|
||||||
|
throw new NotImplementedException($"Need to implement {nameof(executionOrder)} logic.");
|
||||||
|
|
||||||
if (_isRunning)
|
if (_isRunning)
|
||||||
{
|
{
|
||||||
return FluentResults.Result.Fail("Tried to execute Lua scripts without unloading first.");
|
return FluentResults.Result.Fail("Tried to execute Lua scripts without unloading first.");
|
||||||
|
|||||||
+203
-47
@@ -1,9 +1,12 @@
|
|||||||
using System.Collections.Concurrent;
|
using System;
|
||||||
|
using System.Collections.Concurrent;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Collections.Immutable;
|
using System.Collections.Immutable;
|
||||||
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Barotrauma.LuaCs.Data;
|
using Barotrauma.LuaCs.Data;
|
||||||
using FluentResults;
|
using FluentResults;
|
||||||
|
using Microsoft.Toolkit.Diagnostics;
|
||||||
|
|
||||||
namespace Barotrauma.LuaCs.Services;
|
namespace Barotrauma.LuaCs.Services;
|
||||||
|
|
||||||
@@ -12,20 +15,37 @@ public sealed class PackageManagementService : IPackageManagementService
|
|||||||
// svc
|
// svc
|
||||||
private ILoggerService _logger;
|
private ILoggerService _logger;
|
||||||
private IModConfigService _modConfigService;
|
private IModConfigService _modConfigService;
|
||||||
|
private IConfigService _configService;
|
||||||
private ILuaScriptManagementService _luaScriptManagementService;
|
private ILuaScriptManagementService _luaScriptManagementService;
|
||||||
private IPluginManagementService _pluginManagementService;
|
private IPluginManagementService _pluginManagementService;
|
||||||
|
private IPackageManagementServiceConfig _runConfig;
|
||||||
// state
|
// state
|
||||||
private readonly ConcurrentDictionary<ContentPackage, IModConfigInfo> _loadedPackages = new();
|
private readonly ConcurrentDictionary<ContentPackage, IModConfigInfo> _loadedPackages = new();
|
||||||
private readonly ConcurrentDictionary<ContentPackage, IModConfigInfo> _runningPackages = new();
|
private readonly ConcurrentDictionary<ContentPackage, IModConfigInfo> _runningPackages = new();
|
||||||
// control
|
// control
|
||||||
|
/// <summary>
|
||||||
|
/// Service Disposal Lock.
|
||||||
|
/// </summary>
|
||||||
private readonly AsyncReaderWriterLock _operationsLock = new();
|
private readonly AsyncReaderWriterLock _operationsLock = new();
|
||||||
|
/// <summary>
|
||||||
|
/// Execution of packages lock.
|
||||||
|
/// <br/> Read: Package loading/unloading (Multi-operation mode).
|
||||||
|
/// <br/> Write: Package execution (exclusive mode).
|
||||||
|
/// </summary>
|
||||||
|
private readonly AsyncReaderWriterLock _executionLock = new();
|
||||||
|
|
||||||
public PackageManagementService(ILoggerService logger, IModConfigService modConfigService, ILuaScriptManagementService luaScriptManagementService, IPluginManagementService pluginManagementService)
|
public PackageManagementService(ILoggerService logger,
|
||||||
|
IModConfigService modConfigService,
|
||||||
|
ILuaScriptManagementService luaScriptManagementService,
|
||||||
|
IPluginManagementService pluginManagementService,
|
||||||
|
IConfigService configService, IPackageManagementServiceConfig runConfig)
|
||||||
{
|
{
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
_modConfigService = modConfigService;
|
_modConfigService = modConfigService;
|
||||||
_luaScriptManagementService = luaScriptManagementService;
|
_luaScriptManagementService = luaScriptManagementService;
|
||||||
_pluginManagementService = pluginManagementService;
|
_pluginManagementService = pluginManagementService;
|
||||||
|
_configService = configService;
|
||||||
|
_runConfig = runConfig;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
@@ -34,7 +54,7 @@ public sealed class PackageManagementService : IPackageManagementService
|
|||||||
if (!ModUtils.Threading.CheckIfClearAndSetBool(ref _isDisposed))
|
if (!ModUtils.Threading.CheckIfClearAndSetBool(ref _isDisposed))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
_logger.LogMessage($"{nameof(PackageManagementService)} is disposing");
|
_logger.LogMessage($"{nameof(PackageManagementService)} is disposing.");
|
||||||
_luaScriptManagementService.Dispose();
|
_luaScriptManagementService.Dispose();
|
||||||
_pluginManagementService.Dispose();
|
_pluginManagementService.Dispose();
|
||||||
_modConfigService.Dispose();
|
_modConfigService.Dispose();
|
||||||
@@ -61,79 +81,215 @@ public sealed class PackageManagementService : IPackageManagementService
|
|||||||
if (IsDisposed)
|
if (IsDisposed)
|
||||||
return FluentResults.Result.Fail($"{nameof(PackageManagementService)}failed to reset. Has already been disposed.");
|
return FluentResults.Result.Fail($"{nameof(PackageManagementService)}failed to reset. Has already been disposed.");
|
||||||
|
|
||||||
var operationResult = new FluentResults.Result();
|
try
|
||||||
CombineResultErrors(operationResult, UnsafeStopRunningPackagesInternal());
|
|
||||||
CombineResultErrors(operationResult, UnsafeUnloadAllPackagesInternal());
|
|
||||||
return operationResult;
|
|
||||||
|
|
||||||
void CombineResultErrors(FluentResults.Result result,
|
|
||||||
ImmutableArray<(ContentPackage Package, FluentResults.Result OperationResult)> packRes)
|
|
||||||
{
|
{
|
||||||
if (packRes.IsDefaultOrEmpty)
|
var operationResult = new FluentResults.Result();
|
||||||
return;
|
operationResult.WithReasons(_configService.Reset().Reasons);
|
||||||
|
operationResult.WithReasons(_luaScriptManagementService.Reset().Reasons);
|
||||||
foreach (var r in packRes)
|
operationResult.WithReasons(_pluginManagementService.Reset().Reasons);
|
||||||
{
|
_runningPackages.Clear();
|
||||||
if (r.OperationResult.IsSuccess)
|
_loadedPackages.Clear();
|
||||||
continue;
|
return operationResult;
|
||||||
_logger.LogResults(r.OperationResult);
|
}
|
||||||
result.WithErrors(r.OperationResult.Errors);
|
catch (Exception e)
|
||||||
}
|
{
|
||||||
|
return FluentResults.Result.Fail(new ExceptionalError(e));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public FluentResults.Result LoadPackageInfo(ContentPackage package)
|
public FluentResults.Result LoadPackageInfo(ContentPackage package)
|
||||||
{
|
{
|
||||||
throw new System.NotImplementedException();
|
Guard.IsNotNull(package, nameof(package));
|
||||||
|
using var lck = _operationsLock.AcquireReaderLock().ConfigureAwait(false).GetAwaiter().GetResult();
|
||||||
|
using var executeLock = _executionLock.AcquireReaderLock().ConfigureAwait(false).GetAwaiter().GetResult();
|
||||||
|
|
||||||
|
IService.CheckDisposed(this);
|
||||||
|
if (_loadedPackages.TryGetValue(package, out var result))
|
||||||
|
{
|
||||||
|
_logger.LogWarning($"{nameof(LoadPackageInfo)}: Tried to load already-loaded package {package.Name}.");
|
||||||
|
return FluentResults.Result.Ok();
|
||||||
|
}
|
||||||
|
|
||||||
|
var pkgCfgInfo = _modConfigService.CreateConfigAsync(package).ConfigureAwait(false).GetAwaiter().GetResult();
|
||||||
|
if (pkgCfgInfo.IsFailed)
|
||||||
|
{
|
||||||
|
_logger.LogResults(pkgCfgInfo.ToResult());
|
||||||
|
return pkgCfgInfo.ToResult();
|
||||||
|
}
|
||||||
|
return UnsafeAddPackageInternal(package, pkgCfgInfo.Value);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ImmutableArray<(ContentPackage Package, FluentResults.Result LoadSuccessResult)> LoadPackagesInfo(IReadOnlyCollection<ContentPackage> packages)
|
public FluentResults.Result LoadPackagesInfo(ImmutableArray<ContentPackage> packages)
|
||||||
{
|
{
|
||||||
throw new System.NotImplementedException();
|
if (packages.IsDefaultOrEmpty)
|
||||||
|
ThrowHelper.ThrowArgumentException($"{nameof(LoadPackagesInfo)}: packages list is empty.");
|
||||||
|
using var lck = _operationsLock.AcquireReaderLock().ConfigureAwait(false).GetAwaiter().GetResult();
|
||||||
|
using var executeLock = _executionLock.AcquireReaderLock().ConfigureAwait(false).GetAwaiter().GetResult();
|
||||||
|
|
||||||
|
IService.CheckDisposed(this);
|
||||||
|
var result = new FluentResults.Result();
|
||||||
|
var pkgConfigs = _modConfigService.CreateConfigsAsync([..packages]).ConfigureAwait(false).GetAwaiter().GetResult();
|
||||||
|
foreach (var pkgConfig in pkgConfigs)
|
||||||
|
{
|
||||||
|
result.WithReasons(pkgConfig.Config.Reasons);
|
||||||
|
if (pkgConfig.Config.IsSuccess)
|
||||||
|
result.WithReasons(UnsafeAddPackageInternal(pkgConfig.Source, pkgConfig.Config.Value).Reasons);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
private FluentResults.Result UnsafeLoadPackageInfoInternal(ContentPackage package)
|
private FluentResults.Result UnsafeAddPackageInternal(ContentPackage package, IModConfigInfo config)
|
||||||
{
|
{
|
||||||
throw new System.NotImplementedException();
|
if (_loadedPackages.TryGetValue(package, out var result))
|
||||||
|
{
|
||||||
|
_logger.LogWarning($"Tried to load already-loaded package {package.Name}.");
|
||||||
|
return FluentResults.Result.Ok();
|
||||||
|
}
|
||||||
|
|
||||||
|
_loadedPackages[package] = config;
|
||||||
|
var res = new FluentResults.Result();
|
||||||
|
res.WithReasons(_luaScriptManagementService.LoadScriptResourcesAsync(config.LuaScripts).ConfigureAwait(false).GetAwaiter().GetResult().Reasons);
|
||||||
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ImmutableArray<(ContentPackage Package, FluentResults.Result ExecutionResult)> ExecuteLoadedPackages()
|
public FluentResults.Result ExecuteLoadedPackages(ImmutableArray<ContentPackage> executionOrder)
|
||||||
{
|
{
|
||||||
throw new System.NotImplementedException();
|
using var lck = _operationsLock.AcquireReaderLock().ConfigureAwait(false).GetAwaiter().GetResult();
|
||||||
|
using var executeLock = _executionLock.AcquireWriterLock().ConfigureAwait(false).GetAwaiter().GetResult();
|
||||||
|
IService.CheckDisposed(this);
|
||||||
|
|
||||||
|
if (executionOrder.IsDefaultOrEmpty)
|
||||||
|
return FluentResults.Result.Fail($"{nameof(ExecuteLoadedPackages)}: No packages in the execution order list.");
|
||||||
|
|
||||||
|
if (!_runningPackages.IsEmpty)
|
||||||
|
{
|
||||||
|
return FluentResults.Result.Fail(
|
||||||
|
$"{nameof(ExecuteLoadedPackages)}: There are already packages running! List: {
|
||||||
|
_runningPackages.Aggregate(string.Empty, (acc, kvp) => "-" + kvp + "\n" + kvp.Key.Name)}");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_loadedPackages.IsEmpty)
|
||||||
|
return FluentResults.Result.Fail($"{nameof(ExecuteLoadedPackages)}: No packages loaded. Nothing to run!)");
|
||||||
|
|
||||||
|
var result = new FluentResults.Result();
|
||||||
|
|
||||||
|
// get loading order. Note: packages not in the execution order list will load first.
|
||||||
|
var loadingOrderedPackages = _loadedPackages.OrderBy(pkg => executionOrder.IndexOf(pkg.Key))
|
||||||
|
.ToImmutableArray();
|
||||||
|
|
||||||
|
//mod settings
|
||||||
|
var settings = loadingOrderedPackages
|
||||||
|
.SelectMany(pkg => pkg.Value.Configs.OrderBy(scr => scr.LoadPriority))
|
||||||
|
.ToImmutableArray();
|
||||||
|
if (!settings.IsDefaultOrEmpty)
|
||||||
|
{
|
||||||
|
result.WithReasons(_configService.LoadConfigsAsync(settings).ConfigureAwait(false).GetAwaiter()
|
||||||
|
.GetResult().Reasons);
|
||||||
|
result.WithReasons(_configService.LoadConfigsProfilesAsync(settings).ConfigureAwait(false)
|
||||||
|
.GetAwaiter().GetResult().Reasons);
|
||||||
|
}
|
||||||
|
|
||||||
|
//lua scripts
|
||||||
|
var luaScripts = loadingOrderedPackages
|
||||||
|
.SelectMany(pkg => pkg.Value.LuaScripts.OrderBy(scr => scr.LoadPriority))
|
||||||
|
.ToImmutableArray();
|
||||||
|
if (!luaScripts.IsDefaultOrEmpty)
|
||||||
|
result.WithReasons(_luaScriptManagementService.ExecuteLoadedScripts(luaScripts).Reasons);
|
||||||
|
|
||||||
|
if (_runConfig.IsCsEnabled)
|
||||||
|
{
|
||||||
|
var plugins =
|
||||||
|
loadingOrderedPackages.SelectMany(pkg => pkg.Value.Assemblies.OrderBy(scr => scr.LoadPriority))
|
||||||
|
.ToImmutableArray();
|
||||||
|
if (!plugins.IsDefaultOrEmpty)
|
||||||
|
result.WithReasons(_pluginManagementService.LoadAssemblyResources(plugins).Reasons);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
private ImmutableArray<(ContentPackage Package, FluentResults.Result StopExectionResult)> UnsafeStopRunningPackagesInternal()
|
public FluentResults.Result StopRunningPackages()
|
||||||
{
|
{
|
||||||
throw new System.NotImplementedException();
|
using var lck = _operationsLock.AcquireReaderLock().ConfigureAwait(false).GetAwaiter().GetResult();
|
||||||
}
|
using var executeLock = _executionLock.AcquireWriterLock().ConfigureAwait(false).GetAwaiter().GetResult();
|
||||||
|
IService.CheckDisposed(this);
|
||||||
|
|
||||||
public ImmutableArray<(ContentPackage Package, FluentResults.Result StopExecutionResult)> StopRunningPackages()
|
if (_loadedPackages.IsEmpty || _runningPackages.IsEmpty)
|
||||||
{
|
{
|
||||||
throw new System.NotImplementedException();
|
_logger.LogWarning($"{nameof(StopRunningPackages)}: No packages are currently executing.");
|
||||||
}
|
return FluentResults.Result.Ok();
|
||||||
|
}
|
||||||
|
|
||||||
private FluentResults.Result UnsafeUnloadPackageInternal(ContentPackage package)
|
var res = new FluentResults.Result();
|
||||||
{
|
res.WithReasons(_luaScriptManagementService.UnloadActiveScripts().Reasons);
|
||||||
throw new System.NotImplementedException();
|
res.WithReasons(_pluginManagementService.UnloadManagedAssemblies().Reasons);
|
||||||
}
|
_runningPackages.Clear();
|
||||||
|
return res;
|
||||||
private ImmutableArray<(ContentPackage Package, FluentResults.Result UnloadSuccessResult)> UnsafeUnloadAllPackagesInternal()
|
|
||||||
{
|
|
||||||
throw new System.NotImplementedException();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public FluentResults.Result UnloadPackage(ContentPackage package)
|
public FluentResults.Result UnloadPackage(ContentPackage package)
|
||||||
{
|
{
|
||||||
throw new System.NotImplementedException();
|
Guard.IsNotNull(package, nameof(package));
|
||||||
|
using var lck = _operationsLock.AcquireReaderLock().ConfigureAwait(false).GetAwaiter().GetResult();
|
||||||
|
using var executeLock = _executionLock.AcquireReaderLock().ConfigureAwait(false).GetAwaiter().GetResult();
|
||||||
|
IService.CheckDisposed(this);
|
||||||
|
|
||||||
|
if (!_loadedPackages.ContainsKey(package))
|
||||||
|
return FluentResults.Result.Fail($"{nameof(UnloadPackage)}: The package is not loaded.");
|
||||||
|
if (!_runningPackages.IsEmpty)
|
||||||
|
return FluentResults.Result.Fail($"{nameof(UnloadPackage)}: Packages are currently executing.");
|
||||||
|
var result = new FluentResults.Result();
|
||||||
|
result.WithReasons(_luaScriptManagementService.DisposePackageResources(package).Reasons);
|
||||||
|
result.WithReasons(_configService.DisposePackageData(package).Reasons);
|
||||||
|
_loadedPackages.TryRemove(package, out _);
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ImmutableArray<(ContentPackage Package, FluentResults.Result UnloadSuccessResult)> UnloadPackages(IReadOnlyCollection<ContentPackage> packages)
|
public FluentResults.Result UnloadPackages(ImmutableArray<ContentPackage> packages)
|
||||||
{
|
{
|
||||||
throw new System.NotImplementedException();
|
if (packages.IsDefaultOrEmpty)
|
||||||
|
return FluentResults.Result.Fail($"{nameof(UnloadPackages)}: Package list is empty.");
|
||||||
|
|
||||||
|
using var lck = _operationsLock.AcquireReaderLock().ConfigureAwait(false).GetAwaiter().GetResult();
|
||||||
|
using var executeLock = _executionLock.AcquireReaderLock().ConfigureAwait(false).GetAwaiter().GetResult();
|
||||||
|
IService.CheckDisposed(this);
|
||||||
|
|
||||||
|
var result = new FluentResults.Result();
|
||||||
|
foreach (var package in packages)
|
||||||
|
result.WithReasons(UnloadPackage(package).Reasons);
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ImmutableArray<(ContentPackage Package, FluentResults.Result UnloadSuccessResult)> UnloadAllPackages()
|
public FluentResults.Result UnloadAllPackages()
|
||||||
{
|
{
|
||||||
throw new System.NotImplementedException();
|
using var lck = _operationsLock.AcquireWriterLock().ConfigureAwait(false).GetAwaiter().GetResult();
|
||||||
|
using var executeLock = _executionLock.AcquireReaderLock().ConfigureAwait(false).GetAwaiter().GetResult();
|
||||||
|
IService.CheckDisposed(this);
|
||||||
|
|
||||||
|
if (_loadedPackages.IsEmpty)
|
||||||
|
return FluentResults.Result.Ok();
|
||||||
|
if (!_runningPackages.IsEmpty)
|
||||||
|
return FluentResults.Result.Fail($"{nameof(UnloadAllPackages)}: Packages are currently executing.");
|
||||||
|
var result = new FluentResults.Result();
|
||||||
|
result.WithReasons(_luaScriptManagementService.DisposeAllPackageResources().Reasons);
|
||||||
|
result.WithReasons(_configService.DisposeAllPackageData().Reasons);
|
||||||
|
_loadedPackages.Clear();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ImmutableArray<ContentPackage> GetAllLoadedPackages()
|
||||||
|
{
|
||||||
|
using var lck = _operationsLock.AcquireReaderLock().ConfigureAwait(false).GetAwaiter().GetResult();
|
||||||
|
IService.CheckDisposed(this);
|
||||||
|
return [.._loadedPackages.Keys];
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsPackageRunning(ContentPackage package)
|
||||||
|
{
|
||||||
|
Guard.IsNotNull(package, nameof(package));
|
||||||
|
using var lck = _operationsLock.AcquireReaderLock().ConfigureAwait(false).GetAwaiter().GetResult();
|
||||||
|
IService.CheckDisposed(this);
|
||||||
|
return _runningPackages.ContainsKey(package);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -128,7 +128,7 @@ public class PluginManagementService : IPluginManagementService, IAssemblyManage
|
|||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
public IReadOnlyList<Result<(Type, T)>> ActivateTypeInstances<T>(ImmutableArray<Type> types, bool serviceInjection = true,
|
public ImmutableArray<Result<(Type, T)>> ActivateTypeInstances<T>(ImmutableArray<Type> types, bool serviceInjection = true,
|
||||||
bool hostInstanceReference = false) where T : IDisposable
|
bool hostInstanceReference = false) where T : IDisposable
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
|
|||||||
@@ -35,6 +35,7 @@ public partial interface IConfigService : IReusableService, ILuaConfigService
|
|||||||
// Utility
|
// Utility
|
||||||
FluentResults.Result ApplyProfileSettings(ContentPackage package, string profileName);
|
FluentResults.Result ApplyProfileSettings(ContentPackage package, string profileName);
|
||||||
FluentResults.Result DisposePackageData(ContentPackage package);
|
FluentResults.Result DisposePackageData(ContentPackage package);
|
||||||
|
FluentResults.Result DisposeAllPackageData();
|
||||||
FluentResults.Result<IReadOnlyDictionary<(ContentPackage Package, string ConfigName), IConfigBase>> GetConfigsForPackage(ContentPackage package);
|
FluentResults.Result<IReadOnlyDictionary<(ContentPackage Package, string ConfigName), IConfigBase>> GetConfigsForPackage(ContentPackage package);
|
||||||
FluentResults.Result<IReadOnlyDictionary<(ContentPackage Package, string ConfigName), ImmutableArray<(string ConfigName, OneOf.OneOf<string, XElement> Value)>>>
|
FluentResults.Result<IReadOnlyDictionary<(ContentPackage Package, string ConfigName), ImmutableArray<(string ConfigName, OneOf.OneOf<string, XElement> Value)>>>
|
||||||
GetProfilesForPackage(ContentPackage package);
|
GetProfilesForPackage(ContentPackage package);
|
||||||
|
|||||||
+3
-2
@@ -27,11 +27,12 @@ public interface ILuaScriptManagementService : IReusableService
|
|||||||
Task<FluentResults.Result> LoadScriptResourcesAsync(ImmutableArray<ILuaScriptResourceInfo> resourcesInfo);
|
Task<FluentResults.Result> LoadScriptResourcesAsync(ImmutableArray<ILuaScriptResourceInfo> resourcesInfo);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
///
|
/// Executes already loaded into memory scripts data, in the supplied order.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
/// <param name="executionOrder"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
// [Required]
|
// [Required]
|
||||||
FluentResults.Result ExecuteLoadedScripts();
|
FluentResults.Result ExecuteLoadedScripts(ImmutableArray<ILuaScriptResourceInfo> executionOrder);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
///
|
///
|
||||||
|
|||||||
+7
-5
@@ -12,10 +12,12 @@ namespace Barotrauma.LuaCs.Services;
|
|||||||
public interface IPackageManagementService : IReusableService
|
public interface IPackageManagementService : IReusableService
|
||||||
{
|
{
|
||||||
public FluentResults.Result LoadPackageInfo(ContentPackage package);
|
public FluentResults.Result LoadPackageInfo(ContentPackage package);
|
||||||
public ImmutableArray<(ContentPackage Package, FluentResults.Result LoadSuccessResult)> LoadPackagesInfo(IReadOnlyCollection<ContentPackage> packages);
|
public FluentResults.Result LoadPackagesInfo(ImmutableArray<ContentPackage> packages);
|
||||||
public ImmutableArray<(ContentPackage Package, FluentResults.Result ExecutionResult)> ExecuteLoadedPackages();
|
public FluentResults.Result ExecuteLoadedPackages(ImmutableArray<ContentPackage> executionOrder);
|
||||||
public ImmutableArray<(ContentPackage Package, FluentResults.Result StopExecutionResult)> StopRunningPackages();
|
public FluentResults.Result StopRunningPackages();
|
||||||
public FluentResults.Result UnloadPackage(ContentPackage package);
|
public FluentResults.Result UnloadPackage(ContentPackage package);
|
||||||
public ImmutableArray<(ContentPackage Package, FluentResults.Result UnloadSuccessResult)> UnloadPackages(IReadOnlyCollection<ContentPackage> packages);
|
public FluentResults.Result UnloadPackages(ImmutableArray<ContentPackage> packages);
|
||||||
public ImmutableArray<(ContentPackage Package, FluentResults.Result UnloadSuccessResult)> UnloadAllPackages();
|
public FluentResults.Result UnloadAllPackages();
|
||||||
|
public ImmutableArray<ContentPackage> GetAllLoadedPackages();
|
||||||
|
public bool IsPackageRunning(ContentPackage package);
|
||||||
}
|
}
|
||||||
|
|||||||
+3
-2
@@ -47,12 +47,13 @@ public interface IPluginManagementService : IReusableService
|
|||||||
/// <param name="serviceInjection"></param>
|
/// <param name="serviceInjection"></param>
|
||||||
/// <param name="hostInstanceReference"></param>
|
/// <param name="hostInstanceReference"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
IReadOnlyList<FluentResults.Result<(Type, T)>> ActivateTypeInstances<T>(ImmutableArray<Type> types, bool serviceInjection = true,
|
ImmutableArray<FluentResults.Result<(Type, T)>> ActivateTypeInstances<T>(ImmutableArray<Type> types, bool serviceInjection = true,
|
||||||
bool hostInstanceReference = false) where T : IDisposable;
|
bool hostInstanceReference = false) where T : IDisposable;
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Unloads all managed <see cref="IAssemblyPlugin"/>, <see cref="Assembly"/>, and <see cref="IAssemblyLoaderService"/>s.
|
/// Unloads all managed <see cref="IAssemblyPlugin"/>, <see cref="Assembly"/>, and <see cref="IAssemblyLoaderService"/>s.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>Success of the operation. <br/><b>Note: does not guarantee .NET runtime assembly unloading success.<b/></returns>
|
/// <returns>Success of the operation. <br/><b>Note: does not guarantee .NET runtime assembly unloading success.</b></returns>
|
||||||
FluentResults.Result UnloadManagedAssemblies();
|
FluentResults.Result UnloadManagedAssemblies();
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user