[Save/Sync] Big If tru Rewrite in progress.

- Removed IProcessors
- Removed old ModConfigService format.
- Converting to ContentPath from absolute paths where possible.
- Added: Microsoft.Toolkit.Diagnostics package.
This commit is contained in:
MapleWheels
2026-01-02 18:02:01 -05:00
committed by Maplewheels
parent 6a6be3caa4
commit 7d39c092c6
12 changed files with 132 additions and 680 deletions
@@ -1,30 +0,0 @@
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;
namespace Barotrauma.LuaCs.Services.Processing;
public partial class ModConfigService
{
private partial async Task<Result<IModConfigInfo>> GetModConfigInfoAsync(ContentPackage package, XElement root)
{
var asm = root.GetChildElements("Assembly").ToImmutableArray();
var cfg = root.GetChildElements("Config").ToImmutableArray();
var lua = root.GetChildElements("Lua").ToImmutableArray();
return FluentResults.Result.Ok<IModConfigInfo>(new ModConfigInfo()
{
Package = package,
PackageName = package.Name,
Assemblies = asm.Any() ? GetAssemblies(package, asm) : ImmutableArray<IAssemblyResourceInfo>.Empty,
Configs = cfg.Any() ? GetConfigs(package, cfg) : ImmutableArray<IConfigResourceInfo>.Empty,
ConfigProfiles = cfg.Any() ? GetConfigProfiles(package, cfg) : ImmutableArray<IConfigProfileResourceInfo>.Empty,
LuaScripts = lua.Any() ? GetLuaScripts(package, lua) : ImmutableArray<ILuaScriptResourceInfo>.Empty
});
}
}
+19 -20
View File
@@ -1,25 +1,24 @@
<Project> <Project>
<ItemGroup> <ItemGroup>
<PackageReference Include="Luatrauma.Internal.AssemblyPublicizer.MSBuild" Version="0.1.4" /> <PackageReference Include="Luatrauma.Internal.AssemblyPublicizer.MSBuild" Version="0.1.4" />
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.11.0" /> <PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.11.0" />
<PackageReference Include="HarmonyX" Version="2.13.0" /> <PackageReference Include="HarmonyX" Version="2.13.0" />
<PackageReference Include="Sigil" Version="5.0.0" /> <PackageReference Include="Sigil" Version="5.0.0" />
<PackageReference Include="LightInject" Version="6.6.4" /> <PackageReference Include="LightInject" Version="6.6.4" />
<PackageReference Include="QuikGraph" Version="2.5.0" /> <PackageReference Include="OneOf" Version="3.0.271" />
<PackageReference Include="OneOf" Version="3.0.271" /> <PackageReference Include="FluentResults" Version="3.16.0" />
<PackageReference Include="FluentResults" Version="3.16.0" /> <PackageReference Include="Basic.Reference.Assemblies.Net60" Version="1.7.9" />
<PackageReference Include="Basic.Reference.Assemblies.Net60" Version="1.7.9" /> <PackageReference Include="ImpromptuInterface " Version="8.0.4" />
<PackageReference Include="ImpromptuInterface " Version="8.0.4" /> <PackageReference Include="Microsoft.Toolkit.Diagnostics" Version="7.1.2"/>
<ProjectReference Include="$(MSBuildThisFileDirectory)..\..\Libraries\moonsharp\MoonSharp.Interpreter\MoonSharp.Interpreter.csproj" /> <ProjectReference Include="$(MSBuildThisFileDirectory)..\..\Libraries\moonsharp\MoonSharp.Interpreter\MoonSharp.Interpreter.csproj" />
<ProjectReference Include="$(MSBuildThisFileDirectory)..\..\Libraries\moonsharp\MoonSharp.VsCodeDebugger\MoonSharp.VsCodeDebugger.csproj" /> <ProjectReference Include="$(MSBuildThisFileDirectory)..\..\Libraries\moonsharp\MoonSharp.VsCodeDebugger\MoonSharp.VsCodeDebugger.csproj" />
</ItemGroup> </ItemGroup>
<!--
<!--
The `Microsoft.CodeAnalysis.CSharp.Scripting` package includes satellites The `Microsoft.CodeAnalysis.CSharp.Scripting` package includes satellites
assemblies, which end up polluting the build folder. assemblies, which end up polluting the build folder.
This suppresses the extra satellite assemblies. This suppresses the extra satellite assemblies.
--> -->
<PropertyGroup> <PropertyGroup>
<SatelliteResourceLanguages>en</SatelliteResourceLanguages> <SatelliteResourceLanguages>en</SatelliteResourceLanguages>
</PropertyGroup> </PropertyGroup>
</Project> </Project>
@@ -40,7 +40,6 @@ namespace Barotrauma
void RegisterServices() void RegisterServices()
{ {
_servicesProvider.RegisterServiceType<IPackageListRetrievalService, PackageListRetrievalService>(ServiceLifetime.Transient); _servicesProvider.RegisterServiceType<IPackageListRetrievalService, PackageListRetrievalService>(ServiceLifetime.Transient);
_servicesProvider.RegisterServiceType<IPackageInfoLookupService, ContentPackageInfoLookup>(ServiceLifetime.Singleton);
_servicesProvider.RegisterServiceType<ILoggerService, LoggerService>(ServiceLifetime.Singleton); _servicesProvider.RegisterServiceType<ILoggerService, LoggerService>(ServiceLifetime.Singleton);
_servicesProvider.RegisterServiceType<PerformanceCounterService, PerformanceCounterService>(ServiceLifetime.Singleton); _servicesProvider.RegisterServiceType<PerformanceCounterService, PerformanceCounterService>(ServiceLifetime.Singleton);
_servicesProvider.RegisterServiceType<IStorageService, StorageService>(ServiceLifetime.Transient); _servicesProvider.RegisterServiceType<IStorageService, StorageService>(ServiceLifetime.Transient);
@@ -55,15 +54,9 @@ namespace Barotrauma
// TODO: INetworkingService // TODO: INetworkingService
// TODO: [Resource Converter/Parser Services] // TODO: [Resource Converter/Parser Services]
// IResourceInfo wrappers and mutators.
_servicesProvider.RegisterServiceType<IProcessorService<IReadOnlyList<IAssemblyResourceInfo>, IAssembliesResourcesInfo>, ResourceInfoArrayPacker>(ServiceLifetime.Transient);
_servicesProvider.RegisterServiceType<IProcessorService<IReadOnlyList<IConfigResourceInfo>, IConfigsResourcesInfo>, ResourceInfoArrayPacker>(ServiceLifetime.Transient);
_servicesProvider.RegisterServiceType<IProcessorService<IReadOnlyList<IConfigProfileResourceInfo>, IConfigProfilesResourcesInfo>, ResourceInfoArrayPacker>(ServiceLifetime.Transient);
_servicesProvider.RegisterServiceType<IProcessorService<IReadOnlyList<ILuaScriptResourceInfo>, ILuaScriptsResourcesInfo>, ResourceInfoArrayPacker>(ServiceLifetime.Transient);
// Loaders and Processors (yes the naming is reversed, oops). // Loaders and Processors (yes the naming is reversed, oops).
_servicesProvider.RegisterServiceType<IConverterService<ContentPackage, IModConfigInfo>, ModConfigService>(ServiceLifetime.Transient); _servicesProvider.RegisterServiceType<IParserService<ContentPackage, IModConfigInfo>, ModConfigService>(ServiceLifetime.Transient);
_servicesProvider.RegisterServiceType<IConverterServiceAsync<ContentPackage, IModConfigInfo>, ModConfigService>(ServiceLifetime.Transient); _servicesProvider.RegisterServiceType<IParserServiceAsync<ContentPackage, IModConfigInfo>, ModConfigService>(ServiceLifetime.Transient);
_servicesProvider.RegisterServiceType<IConfigIOService, ConfigIOService>(ServiceLifetime.Transient); _servicesProvider.RegisterServiceType<IConfigIOService, ConfigIOService>(ServiceLifetime.Transient);
// service config data // service config data
@@ -24,11 +24,11 @@ namespace Barotrauma.LuaCs.Services;
public partial class ConfigService : IConfigService public partial class ConfigService : IConfigService
{ {
//--- Internals //--- Internals
public ConfigService(IConverterServiceAsync<IConfigProfileResourceInfo, IReadOnlyList<IConfigProfileInfo>> configProfileResourceConverter, public ConfigService(IParserServiceAsync<IConfigProfileResourceInfo, IReadOnlyList<IConfigProfileInfo>> configProfileResourceParser,
IConverterServiceAsync<IConfigResourceInfo, IReadOnlyList<IConfigInfo>> configResourceConverter, IEventService eventService, System.Lazy<IStorageService> storageService) IParserServiceAsync<IConfigResourceInfo, IReadOnlyList<IConfigInfo>> configResourceParser, IEventService eventService, System.Lazy<IStorageService> storageService)
{ {
_configProfileResourceConverter = configProfileResourceConverter; _configProfileResourceParser = configProfileResourceParser;
_configResourceConverter = configResourceConverter; _configResourceParser = configResourceParser;
_eventService = eventService; _eventService = eventService;
_storageService = storageService; _storageService = storageService;
this._base = this; this._base = this;
@@ -47,8 +47,8 @@ public partial class ConfigService : IConfigService
private readonly AsyncReaderWriterLock _disposeOpsLock = new(); private readonly AsyncReaderWriterLock _disposeOpsLock = new();
// extern services // extern services
private readonly IConverterServiceAsync<IConfigResourceInfo, IReadOnlyList<IConfigInfo>> _configResourceConverter; private readonly IParserServiceAsync<IConfigResourceInfo, IReadOnlyList<IConfigInfo>> _configResourceParser;
private readonly IConverterServiceAsync<IConfigProfileResourceInfo, IReadOnlyList<IConfigProfileInfo>> _configProfileResourceConverter; private readonly IParserServiceAsync<IConfigProfileResourceInfo, IReadOnlyList<IConfigProfileInfo>> _configProfileResourceParser;
private readonly IEventService _eventService; private readonly IEventService _eventService;
private readonly System.Lazy<IStorageService> _storageService; private readonly System.Lazy<IStorageService> _storageService;
@@ -318,7 +318,7 @@ public partial class ConfigService : IConfigService
if (configResources.IsDefaultOrEmpty) if (configResources.IsDefaultOrEmpty)
return FluentResults.Result.Fail($"{nameof(LoadConfigsAsync)}: Array is empty."); return FluentResults.Result.Fail($"{nameof(LoadConfigsAsync)}: Array is empty.");
var results = await _configResourceConverter.TryParseResourcesAsync(configResources); var results = await _configResourceParser.TryParseResourcesAsync(configResources);
var ret = new FluentResults.Result(); var ret = new FluentResults.Result();
foreach (var result in results) foreach (var result in results)
@@ -365,7 +365,7 @@ public partial class ConfigService : IConfigService
if (configProfileResources.IsDefaultOrEmpty) if (configProfileResources.IsDefaultOrEmpty)
return FluentResults.Result.Fail($"{nameof(LoadConfigsProfilesAsync)}: Array is empty."); return FluentResults.Result.Fail($"{nameof(LoadConfigsProfilesAsync)}: Array is empty.");
var results = await _configProfileResourceConverter.TryParseResourcesAsync(configProfileResources); var results = await _configProfileResourceParser.TryParseResourcesAsync(configProfileResources);
var ret = new FluentResults.Result(); var ret = new FluentResults.Result();
foreach (var result in results) foreach (var result in results)
@@ -46,7 +46,7 @@ public class ConfigIOService : IConfigIOService
try try
{ {
var infos = await _storageService.LoadPackageXmlFilesAsync(src.OwnerPackage, src.FilePaths); var infos = await _storageService.LoadPackageXmlFilesAsync(src.OwnerPackage, [..src.FilePaths.Select(fp => fp.FullPath)]);
if (infos.IsDefaultOrEmpty) if (infos.IsDefaultOrEmpty)
return FluentResults.Result.Fail($"{nameof(TryParseResourceAsync)}: No resources found."); return FluentResults.Result.Fail($"{nameof(TryParseResourceAsync)}: No resources found.");
@@ -7,8 +7,8 @@ using Barotrauma.LuaCs.Services.Processing;
namespace Barotrauma.LuaCs.Services.Processing; namespace Barotrauma.LuaCs.Services.Processing;
public interface IConfigIOService : IReusableService, public interface IConfigIOService : IReusableService,
IConverterServiceAsync<IConfigResourceInfo, IReadOnlyList<IConfigInfo>>, IParserServiceAsync<IConfigResourceInfo, IReadOnlyList<IConfigInfo>>,
IConverterServiceAsync<IConfigProfileResourceInfo, IReadOnlyList<IConfigProfileInfo>> IParserServiceAsync<IConfigProfileResourceInfo, IReadOnlyList<IConfigProfileInfo>>
{ {
Task<FluentResults.Result> SaveConfigDataLocal(ContentPackage package, string configName, XElement serializedValue); Task<FluentResults.Result> SaveConfigDataLocal(ContentPackage package, string configName, XElement serializedValue);
Task<FluentResults.Result<OneOf.OneOf<string, XElement>>> LoadConfigDataFromLocal(ContentPackage package, string configName); Task<FluentResults.Result<OneOf.OneOf<string, XElement>>> LoadConfigDataFromLocal(ContentPackage package, string configName);
@@ -7,24 +7,14 @@ using FluentResults;
namespace Barotrauma.LuaCs.Services.Processing; namespace Barotrauma.LuaCs.Services.Processing;
public interface IConverterService<in TSrc, TOut> : IService public interface IParserService<in TSrc, TOut> : IService
{ {
Result<TOut> TryParseResource(TSrc src); Result<TOut> TryParseResource(TSrc src);
ImmutableArray<Result<TOut>> TryParseResources(IEnumerable<TSrc> sources); ImmutableArray<Result<TOut>> TryParseResources(IEnumerable<TSrc> sources);
} }
public interface IConverterServiceAsync<in TSrc, TOut> : IService 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 IProcessorService<in TSrc, TOut> : IService
{
TOut Process(TSrc src);
}
public interface IProcessorServiceAsync<in TSrc, TOut> : IService
{
Task<TOut> ProcessAsync(TSrc src);
}
@@ -12,545 +12,81 @@ using FluentResults;
namespace Barotrauma.LuaCs.Services.Processing; namespace Barotrauma.LuaCs.Services.Processing;
public partial class ModConfigService : IConverterServiceAsync<ContentPackage, IModConfigInfo>, IConverterService<ContentPackage, IModConfigInfo> public sealed class ModConfigService : IModConfigService
{ {
private readonly IStorageService _storageService; private IStorageService _storageService;
private readonly Lazy<IPackageManagementService> _packageManagementService; private IParserServiceAsync<XElement, IAssemblyResourceInfo> _assemblyParserService;
private int _isDisposed; private IParserServiceAsync<XElement, ILuaScriptResourceInfo> _luaScriptParserService;
private IParserServiceAsync<XElement, IConfigResourceInfo> _configParserService;
private IParserServiceAsync<XElement, IConfigProfileResourceInfo> _configProfileParserService;
private const string ModConfigFileName = "ModConfig.xml"; public ModConfigService(IStorageService storageService,
private const string ModConfigRootName = "ModConfig"; IParserServiceAsync<XElement, IAssemblyResourceInfo> assemblyParserService,
IParserServiceAsync<XElement, ILuaScriptResourceInfo> luaScriptParserService,
public ModConfigService(IStorageService storageService, Lazy<IPackageManagementService> pms) IParserServiceAsync<XElement, IConfigResourceInfo> configParserService,
IParserServiceAsync<XElement, IConfigProfileResourceInfo> configProfileParserService)
{ {
_storageService = storageService; _storageService = storageService;
_packageManagementService = pms; _assemblyParserService = assemblyParserService;
_luaScriptParserService = luaScriptParserService;
_configParserService = configParserService;
_configProfileParserService = configProfileParserService;
} }
#region Disposal
public void Dispose() public void Dispose()
{ {
throw new System.NotImplementedException(); throw new NotImplementedException();
} }
private int _isDisposed = 0;
public bool IsDisposed public bool IsDisposed
{ {
get => ModUtils.Threading.GetBool(ref _isDisposed); get => ModUtils.Threading.GetBool(ref _isDisposed);
private set => ModUtils.Threading.SetBool(ref _isDisposed, value); protected set => ModUtils.Threading.SetBool(ref _isDisposed, value);
} }
public async Task<Result<IModConfigInfo>> TryParseResourceAsync(ContentPackage src) #endregion
{
((IService)this).CheckDisposed();
// validate package public async Task<Result<IModConfigInfo>> CreateConfigAsync(ContentPackage src)
{
if (src is null) if (src is null)
return FluentResults.Result.Fail<IModConfigInfo>("ContentPackage is null"); ArgumentNullException.ThrowIfNull($"{nameof(CreateConfigAsync)}: Source is null.");
if (_storageService.DirectoryExists(src.Path) is { } res && (res.IsFailed || !res.Value))
return FluentResults.Result.Fail<IModConfigInfo>($"ContentPackage does not exist or cannot be accessed: {src.Path}");
// find ModConfig.xml or deep scan on fail (legacy) if (await TryGetModConfigXmlAsync(src) is { IsSuccess: true, Value: { } config })
if (await _storageService.LoadPackageXmlAsync(src, ModConfigFileName) is
{ IsSuccess: true, Value: var modConfigXml }
&& modConfigXml.Root is { Name.LocalName: ModConfigRootName } root)
{ {
return await GetModConfigInfoAsync(src, root); return await CreateFromConfigXmlAsync(config);
} }
// legacy mode return await CreateFromLegacyAsync(src);
try
{
// we only supported assemblies and lua scripts
var asm = GetAssembliesLegacy(src);
var lua = GetLuaScriptsLegacy(src);
return new ModConfigInfo()
{
Assemblies = asm,
LuaScripts = lua,
Configs = ImmutableArray<IConfigResourceInfo>.Empty,
ConfigProfiles = ImmutableArray<IConfigProfileResourceInfo>.Empty,
Package = src,
PackageName = src.Name
};
}
catch (Exception e)
{
return FluentResults.Result.Fail<IModConfigInfo>($"Unable to parse legacy content package: {src.Name}: {src.Path}");
}
} }
private partial Task<Result<IModConfigInfo>> GetModConfigInfoAsync(ContentPackage package, XElement root); public async Task<ImmutableArray<(ContentPackage Source, Result<IModConfigInfo> Config)>> CreateConfigsAsync(ImmutableArray<ContentPackage> src)
private ImmutableArray<IAssemblyResourceInfo> GetAssemblies(ContentPackage src, IEnumerable<XElement> elements)
{ {
var builder = ImmutableArray.CreateBuilder<IAssemblyResourceInfo>(); var builder = ImmutableArray.CreateBuilder<(ContentPackage Source, Result<IModConfigInfo> Config)>();
var elementsList = elements.ToImmutableArray();
if (GetFilesList(src, elementsList, "Assembly", "*.dll") foreach (var package in src)
is not { IsSuccess: true, Value: { } xmlFiles })
return ImmutableArray<IAssemblyResourceInfo>.Empty;
foreach (var file in xmlFiles)
{ {
// get platform, culture and target architecture builder.Add((package, await CreateConfigAsync(package)));
var info = GetElementsAttributesData(file.Item1, file.Item2.First());
builder.Add(new AssemblyResourceInfo()
{
Optional = info.IsOptional,
FilePaths = file.Item2,
InternalName = info.Name,
LoadPriority = info.LoadPriority,
OwnerPackage = src,
SupportedPlatforms = info.SupportedPlatforms,
SupportedTargets = info.SupportedTargets,
FriendlyName = file.Item1.GetAttributeString("Name", info.Name),
IsScript = false
});
} }
if (GetFilesList(src, elementsList, "Assembly", "*.cs") return builder.ToImmutable();
is not { IsSuccess: true, Value: { } xmlFiles2 })
return ImmutableArray<IAssemblyResourceInfo>.Empty;
foreach (var file in xmlFiles2)
{
// get platform, culture and target architecture
var info = GetElementsAttributesData(file.Item1, file.Item2.First());
builder.Add(new AssemblyResourceInfo()
{
Optional = info.IsOptional,
FilePaths = file.Item2,
InternalName = info.Name,
LoadPriority = info.LoadPriority,
OwnerPackage = src,
SupportedPlatforms = info.SupportedPlatforms,
SupportedTargets = info.SupportedTargets,
FriendlyName = file.Item1.GetAttributeString("Name", info.Name),
IsScript = true
});
}
return builder.Count > 0
? builder.ToImmutable()
: ImmutableArray<IAssemblyResourceInfo>.Empty;
} }
private ImmutableArray<IConfigResourceInfo> GetConfigs(ContentPackage src, IEnumerable<XElement> elements) //--- Helpers
private async Task<Result<XElement>> TryGetModConfigXmlAsync(ContentPackage src)
{ {
var builder = ImmutableArray.CreateBuilder<IConfigResourceInfo>();
if (GetXmlFilesList(src, elements, "Config")
is not { IsSuccess: true, Value: { } xmlFiles })
return ImmutableArray<IConfigResourceInfo>.Empty;
foreach (var file in xmlFiles)
{
// get platform, culture and target architecture
var info = GetElementsAttributesData(file.Item1, file.Item2.First());
builder.Add(new ConfigResourceInfo()
{
Optional = info.IsOptional,
FilePaths = file.Item2,
InternalName = info.Name,
LoadPriority = info.LoadPriority,
OwnerPackage = src,
SupportedPlatforms = info.SupportedPlatforms,
SupportedTargets = info.SupportedTargets
});
}
return builder.Count > 0
? builder.ToImmutable()
: ImmutableArray<IConfigResourceInfo>.Empty;
} }
private ImmutableArray<IConfigProfileResourceInfo> GetConfigProfiles(ContentPackage src, IEnumerable<XElement> elements) private async Task<Result<IModConfigInfo>> CreateFromConfigXmlAsync(XElement src)
{ {
var builder = ImmutableArray.CreateBuilder<IConfigProfileResourceInfo>(); throw new NotImplementedException();
if (GetXmlFilesList(src, elements, "Config")
is not { IsSuccess: true, Value: { } xmlFiles })
return ImmutableArray<IConfigProfileResourceInfo>.Empty;
foreach (var file in xmlFiles)
{
// get platform, culture and target architecture
var info = GetElementsAttributesData(file.Item1, file.Item2.First());
builder.Add(new ConfigProfileResourceInfo()
{
Optional = info.IsOptional,
FilePaths = file.Item2,
InternalName = info.Name,
LoadPriority = info.LoadPriority,
OwnerPackage = src,
SupportedPlatforms = info.SupportedPlatforms,
SupportedTargets = info.SupportedTargets
});
}
return builder.Count > 0
? builder.ToImmutable()
: ImmutableArray<IConfigProfileResourceInfo>.Empty;
} }
private ImmutableArray<ILuaScriptResourceInfo> GetLuaScripts(ContentPackage src, IEnumerable<XElement> elements) private async Task<Result<IModConfigInfo>> CreateFromLegacyAsync(ContentPackage src)
{ {
var builder = ImmutableArray.CreateBuilder<ILuaScriptResourceInfo>(); throw new NotImplementedException();
if (GetXmlFilesList(src, elements, "Config")
is not { IsSuccess: true, Value: { } xmlFiles })
return ImmutableArray<ILuaScriptResourceInfo>.Empty;
foreach (var file in xmlFiles)
{
// get platform, culture and target architecture
var info = GetElementsAttributesData(file.Item1, file.Item2.First());
builder.Add(new LuaScriptsResourceInfo()
{
Optional = info.IsOptional,
FilePaths = file.Item2,
InternalName = info.Name,
LoadPriority = info.LoadPriority,
OwnerPackage = src,
SupportedPlatforms = info.SupportedPlatforms,
SupportedTargets = info.SupportedTargets,
IsAutorun = file.Item1.GetAttributeBool("RunFile", true)
});
}
return builder.Count > 0
? builder.ToImmutable()
: ImmutableArray<ILuaScriptResourceInfo>.Empty;
} }
private Result<ImmutableArray<(XElement, ImmutableArray<string>)>> GetXmlFilesList(ContentPackage src,
IEnumerable<XElement> elements, string elementNameCheck) =>
GetFilesList(src, elements, elementNameCheck, "*.xml");
private Result<ImmutableArray<(XElement, ImmutableArray<string>)>> GetFilesList(ContentPackage src,
IEnumerable<XElement> elements, string elementNameCheck, string filter)
{
var builder = ImmutableArray.CreateBuilder<(XElement, ImmutableArray<string>)>();
if (elementNameCheck.IsNullOrWhiteSpace())
throw new ArgumentNullException($"{nameof(GetXmlFilesList)}: The element check is null.");
foreach (var element in elements)
{
if (element.Name.LocalName != elementNameCheck)
throw new ArgumentException("Element is not a Localization element");
if (element.GetAttributeString("Folder", string.Empty) is { } str
&& !string.IsNullOrWhiteSpace(str))
{
if (_storageService.FindFilesInPackage(src, str, filter, true)
is not { IsSuccess: true, Value: var fpList } || !fpList.Any())
{
continue;
}
foreach (var fileP in fpList)
builder.Add((element, fpList.ToImmutableArray()));
}
else if (element.GetAttributeString("File", string.Empty) is { } fileStr
&& !string.IsNullOrWhiteSpace(fileStr)
&& _storageService.GetAbsFromPackage(src, fileStr) is { IsSuccess: true, Value: var fp }
&& _storageService.FileExists(fp) is { IsSuccess: true, Value: true })
{
builder.Add((element, new [] { fileStr }.ToImmutableArray()));
}
}
return builder.Count > 0
? FluentResults.Result.Ok(builder.ToImmutable())
: FluentResults.Result.Fail($"No files found");
}
private ResourceAdditionalInfo GetElementsAttributesData(XElement element, string localPath)
{
return new ResourceAdditionalInfo(
element.GetAttributeString("Name", localPath),
GetSupportedPlatforms(element.GetAttributeString("Platform", "any")),
GetSupportedTargets(element.GetAttributeString("Target", "any")),
GetSupportedCultures(element),
element.GetAttributeBool("Optional", false),
element.GetAttributeInt("Priority", 0));
Platform GetSupportedPlatforms(string platformName) => platformName.ToLowerInvariant().Trim() switch
{
"windows" => Platform.Windows,
"linux" => Platform.Linux,
"osx" => Platform.OSX,
_ => Platform.Windows | Platform.Linux | Platform.OSX
};
Target GetSupportedTargets(string targetName) => targetName.ToLowerInvariant().Trim() switch
{
"client" => Target.Client,
"server" => Target.Server,
_ => Target.Client | Target.Server,
};
ImmutableArray<CultureInfo> GetSupportedCultures(XElement element)
{
var culture = element.GetAttributeString("Culture", string.Empty);
if (string.IsNullOrWhiteSpace(culture))
return new[] { CultureInfo.InvariantCulture }.ToImmutableArray();
var builder = ImmutableArray.CreateBuilder<CultureInfo>();
var arr = culture.Split(',');
if (arr.Length == 0)
return new[] { CultureInfo.InvariantCulture }.ToImmutableArray();
foreach (var culstr in arr)
{
if (string.IsNullOrWhiteSpace(culstr))
continue;
try
{
builder.Add(
culstr.ToLowerInvariant().Trim() == "default"
? CultureInfo.InvariantCulture
: CultureInfo.GetCultureInfo(culstr));
}
catch (CultureNotFoundException e)
{
// This is the case if a culture is specified by the package that is not supported by the OS/.NET ENV.
// We ignore it since we can never use it.
continue;
}
}
return builder.Count > 0
? builder.ToImmutable()
: new[] { CultureInfo.InvariantCulture }.ToImmutableArray();
}
}
private ImmutableArray<IAssemblyResourceInfo> GetAssembliesLegacy(ContentPackage src)
{
var builder = ImmutableArray.CreateBuilder<IAssemblyResourceInfo>();
// server, linux
if (_storageService.FindFilesInPackage(src, "bin/Server/Linux", "*.dll", true)
is { IsSuccess: true, Value: { IsDefaultOrEmpty: false} filesSrvLin})
{
builder.Add(new AssemblyResourceInfo()
{
FilePaths = filesSrvLin,
FriendlyName = "AssembliesServerLinux",
InternalName = "AssembliesServerLinux",
IsScript = false,
LoadPriority = 1,
Optional = false,
OwnerPackage = src,
SupportedPlatforms = Platform.Linux,
SupportedTargets = Target.Server
});
}
// server, osx
if (_storageService.FindFilesInPackage(src, "bin/Server/OSX", "*.dll", true)
is { IsSuccess: true, Value: { IsDefaultOrEmpty: false} filesSrvOsx})
{
builder.Add(new AssemblyResourceInfo()
{
FilePaths = filesSrvOsx,
FriendlyName = "AssembliesServerOSX",
InternalName = "AssembliesServerOSX",
IsScript = false,
LoadPriority = 1,
Optional = false,
OwnerPackage = src,
SupportedPlatforms = Platform.OSX,
SupportedTargets = Target.Server
});
}
// server, osx
if (_storageService.FindFilesInPackage(src, "bin/Server/Windows", "*.dll", true)
is { IsSuccess: true, Value: { IsDefaultOrEmpty: false} filesSrvWin})
{
builder.Add(new AssemblyResourceInfo()
{
FilePaths = filesSrvWin,
FriendlyName = "AssembliesServerWin",
InternalName = "AssembliesServerWin",
IsScript = false,
LoadPriority = 1,
Optional = false,
OwnerPackage = src,
SupportedPlatforms = Platform.Windows,
SupportedTargets = Target.Server
});
}
// client, linux
if (_storageService.FindFilesInPackage(src, "bin/Client/Linux", "*.dll", true)
is { IsSuccess: true, Value: { IsDefaultOrEmpty: false} filesCliLin})
{
builder.Add(new AssemblyResourceInfo()
{
FilePaths = filesCliLin,
FriendlyName = "AssembliesClientLinux",
InternalName = "AssembliesClientLinux",
IsScript = false,
LoadPriority = 1,
Optional = false,
OwnerPackage = src,
SupportedPlatforms = Platform.Linux,
SupportedTargets = Target.Client
});
}
// server, osx
if (_storageService.FindFilesInPackage(src, "bin/Client/OSX", "*.dll", true)
is { IsSuccess: true, Value: { IsDefaultOrEmpty: false} filesCliOsx})
{
builder.Add(new AssemblyResourceInfo()
{
FilePaths = filesCliOsx,
FriendlyName = "AssembliesClientOSX",
InternalName = "AssembliesClientOSX",
IsScript = false,
LoadPriority = 1,
Optional = false,
OwnerPackage = src,
SupportedPlatforms = Platform.OSX,
SupportedTargets = Target.Client
});
}
// server, osx
if (_storageService.FindFilesInPackage(src, "bin/Client/Windows", "*.dll", true)
is { IsSuccess: true, Value: { IsDefaultOrEmpty: false} filesCliWin})
{
builder.Add(new AssemblyResourceInfo()
{
FilePaths = filesCliWin,
FriendlyName = "AssembliesClientWin",
InternalName = "AssembliesClientWin",
IsScript = false,
LoadPriority = 1,
Optional = false,
OwnerPackage = src,
SupportedPlatforms = Platform.Windows,
SupportedTargets = Target.Client
});
}
var sharedCsBuilder = ImmutableArray.CreateBuilder<string>();
if (_storageService.FindFilesInPackage(src, "CSharp/Shared", "*.cs", true)
is { IsSuccess: true, Value: { IsDefaultOrEmpty: false } files })
{
sharedCsBuilder.AddRange<string>(files);
}
var filesCssShared = sharedCsBuilder.MoveToImmutable();
var sharedFound = !filesCssShared.IsDefaultOrEmpty;
// source files legacy: server
if (_storageService.FindFilesInPackage(src, "CSharp/Server", "*.cs", true)
is { IsSuccess: true, Value: { IsDefaultOrEmpty: false} filesCssServer})
{
builder.Add(new AssemblyResourceInfo()
{
FilePaths = sharedFound ? filesCssServer.Concat(filesCssShared).ToImmutableArray() : filesCssServer,
FriendlyName = "CssServer",
InternalName = "CssServer",
IsScript = true,
LoadPriority = 1,
Optional = false,
OwnerPackage = src,
SupportedPlatforms = Platform.Linux | Platform.OSX | Platform.Windows,
SupportedTargets = Target.Server
});
}
// source files legacy: client
if (_storageService.FindFilesInPackage(src, "CSharp/Client", "*.cs", true)
is { IsSuccess: true, Value: { IsDefaultOrEmpty: false} filesCssClient})
{
builder.Add(new AssemblyResourceInfo()
{
FilePaths = sharedFound ? filesCssClient.Concat(filesCssShared).ToImmutableArray() : filesCssClient,
FriendlyName = "CssClient",
InternalName = "CssClient",
IsScript = true,
LoadPriority = 1,
Optional = false,
OwnerPackage = src,
SupportedPlatforms = Platform.Linux | Platform.OSX | Platform.Windows,
SupportedTargets = Target.Client
});
}
return builder.MoveToImmutable();
}
private ImmutableArray<ILuaScriptResourceInfo> GetLuaScriptsLegacy(ContentPackage src)
{
var builder = ImmutableArray.CreateBuilder<ILuaScriptResourceInfo>();
if (_storageService.FindFilesInPackage(src, "Lua", "*.lua", true)
is { IsSuccess: true, Value: { IsDefaultOrEmpty: false } fileAll })
{
builder.Add(new LuaScriptsResourceInfo()
{
FilePaths = fileAll.Where(path => !path.Contains("Autorun")).ToImmutableArray(),
InternalName = "LuaScriptsNormal",
Optional = false,
IsAutorun = false,
OwnerPackage = src,
SupportedPlatforms = Platform.Linux | Platform.OSX | Platform.Windows,
SupportedTargets = Target.Client | Target.Server
});
builder.Add(new LuaScriptsResourceInfo()
{
FilePaths = fileAll.Where(path => path.Contains("Autorun")).ToImmutableArray(),
InternalName = "LuaScriptsAutorun",
Optional = false,
IsAutorun = true,
OwnerPackage = src,
SupportedPlatforms = Platform.Linux | Platform.OSX | Platform.Windows,
SupportedTargets = Target.Client | Target.Server
});
}
return builder.MoveToImmutable();
}
public async Task<ImmutableArray<Result<IModConfigInfo>>> TryParseResourcesAsync(IEnumerable<ContentPackage> sources)
{
((IService)this).CheckDisposed();
var srcs = sources.ToImmutableArray();
var results = new AsyncLocal<ConcurrentQueue<Result<IModConfigInfo>>>();
await srcs.ParallelForEachAsync(async pkg =>
{
try
{
results.Value.Enqueue(await TryParseResourceAsync(pkg));
}
catch (Exception e)
{
// this should never happen but this is to stop partial execution exit.
results.Value.Enqueue(
FluentResults.Result.Fail<IModConfigInfo>($"Failed to parse package {pkg?.Name}: {e.Message}"));
}
});
return results.Value.ToImmutableArray();
}
public Result<IModConfigInfo> TryParseResource(ContentPackage src) =>
TryParseResourceAsync(src).GetAwaiter().GetResult();
public ImmutableArray<Result<IModConfigInfo>> TryParseResources(IEnumerable<ContentPackage> sources) =>
TryParseResourcesAsync(sources.ToImmutableArray()).GetAwaiter().GetResult();
private record ResourceAdditionalInfo(
string Name,
Platform SupportedPlatforms,
Target SupportedTargets,
ImmutableArray<CultureInfo> SupportedCultures,
bool IsOptional,
int LoadPriority);
} }
@@ -1,47 +0,0 @@
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using Barotrauma.LuaCs.Data;
namespace Barotrauma.LuaCs.Services.Processing;
public partial class ResourceInfoArrayPacker :
IProcessorService<IReadOnlyList<IAssemblyResourceInfo>, IAssembliesResourcesInfo>,
IProcessorService<IReadOnlyList<IConfigResourceInfo>, IConfigsResourcesInfo>,
IProcessorService<IReadOnlyList<IConfigProfileResourceInfo>, IConfigProfilesResourcesInfo>,
IProcessorService<IReadOnlyList<ILuaScriptResourceInfo>, ILuaScriptsResourcesInfo>
{
private bool _isDisposed;
public IAssembliesResourcesInfo Process(IReadOnlyList<IAssemblyResourceInfo> src)
{
return new AssemblyResourcesInfo(src.ToImmutableArray());
}
public IConfigsResourcesInfo Process(IReadOnlyList<IConfigResourceInfo> src)
{
return new ConfigResourcesInfo(src.ToImmutableArray());
}
public IConfigProfilesResourcesInfo Process(IReadOnlyList<IConfigProfileResourceInfo> src)
{
return new ConfigProfilesResourcesInfo(src.ToImmutableArray());
}
public ILuaScriptsResourcesInfo Process(IReadOnlyList<ILuaScriptResourceInfo> src)
{
return new LuaScriptsResourcesInfo(src.ToImmutableArray());
}
public void Dispose()
{
// Stateless class
GC.SuppressFinalize(this);
IsDisposed = true;
}
public bool IsDisposed
{
get => _isDisposed;
set => _isDisposed = value;
}
}
@@ -15,6 +15,7 @@ using Barotrauma.LuaCs.Data;
using Barotrauma.Steam; using Barotrauma.Steam;
using FluentResults; using FluentResults;
using FluentResults.LuaCs; using FluentResults.LuaCs;
using Microsoft.Toolkit.Diagnostics;
using Error = FluentResults.Error; using Error = FluentResults.Error;
using Path = Barotrauma.IO.Path; using Path = Barotrauma.IO.Path;
@@ -98,49 +99,49 @@ public class StorageService : IStorageService
} }
public virtual FluentResults.Result<XDocument> LoadLocalXml(ContentPackage package, string localFilePath) => public virtual FluentResults.Result<XDocument> LoadLocalXml(ContentPackage package, string localFilePath) =>
GetAbsFromLocal(package, localFilePath) is var r && r is { IsSuccess: true, Value: not null } GetAbsoluePathFromLocal(package, localFilePath) is var r && r is { IsSuccess: true, Value: not null }
? TryLoadXml(r.Value) : r.ToResult(); ? TryLoadXml(r.Value) : r.ToResult();
public virtual FluentResults.Result<byte[]> LoadLocalBinary(ContentPackage package, string localFilePath) => public virtual FluentResults.Result<byte[]> LoadLocalBinary(ContentPackage package, string localFilePath) =>
GetAbsFromLocal(package, localFilePath) is var r && r is { IsSuccess: true, Value: not null } GetAbsoluePathFromLocal(package, localFilePath) is var r && r is { IsSuccess: true, Value: not null }
? TryLoadBinary(r.Value) : r.ToResult(); ? TryLoadBinary(r.Value) : r.ToResult();
public virtual FluentResults.Result<string> LoadLocalText(ContentPackage package, string localFilePath) => public virtual FluentResults.Result<string> LoadLocalText(ContentPackage package, string localFilePath) =>
GetAbsFromLocal(package, localFilePath) is var r && r is { IsSuccess: true, Value: not null } GetAbsoluePathFromLocal(package, localFilePath) is var r && r is { IsSuccess: true, Value: not null }
? TryLoadText(r.Value) : r.ToResult(); ? TryLoadText(r.Value) : r.ToResult();
public virtual FluentResults.Result SaveLocalXml(ContentPackage package, string localFilePath, XDocument document) => public virtual FluentResults.Result SaveLocalXml(ContentPackage package, string localFilePath, XDocument document) =>
GetAbsFromLocal(package, localFilePath) is var r && r is { IsSuccess: true, Value: not null } GetAbsoluePathFromLocal(package, localFilePath) is var r && r is { IsSuccess: true, Value: not null }
? TrySaveXml(r.Value, document) : r.ToResult(); ? TrySaveXml(r.Value, document) : r.ToResult();
public virtual FluentResults.Result SaveLocalBinary(ContentPackage package, string localFilePath, in byte[] bytes) => public virtual FluentResults.Result SaveLocalBinary(ContentPackage package, string localFilePath, in byte[] bytes) =>
GetAbsFromLocal(package, localFilePath) is var r && r is { IsSuccess: true, Value: not null } GetAbsoluePathFromLocal(package, localFilePath) is var r && r is { IsSuccess: true, Value: not null }
? TrySaveBinary(r.Value, bytes) : r.ToResult(); ? TrySaveBinary(r.Value, bytes) : r.ToResult();
public virtual FluentResults.Result SaveLocalText(ContentPackage package, string localFilePath, in string text) => public virtual FluentResults.Result SaveLocalText(ContentPackage package, string localFilePath, in string text) =>
GetAbsFromLocal(package, localFilePath) is var r && r is { IsSuccess: true, Value: not null } GetAbsoluePathFromLocal(package, localFilePath) is var r && r is { IsSuccess: true, Value: not null }
? TrySaveText(r.Value, text) : r.ToResult(); ? TrySaveText(r.Value, text) : r.ToResult();
public virtual async Task<FluentResults.Result<XDocument>> LoadLocalXmlAsync(ContentPackage package, string localFilePath) => public virtual async Task<FluentResults.Result<XDocument>> LoadLocalXmlAsync(ContentPackage package, string localFilePath) =>
GetAbsFromLocal(package, localFilePath) is var r && r is { IsSuccess: true, Value: not null } GetAbsoluePathFromLocal(package, localFilePath) is var r && r is { IsSuccess: true, Value: not null }
? await TryLoadXmlAsync(r.Value) : r.ToResult(); ? await TryLoadXmlAsync(r.Value) : r.ToResult();
public virtual async Task<FluentResults.Result<byte[]>> LoadLocalBinaryAsync(ContentPackage package, string localFilePath) => public virtual async Task<FluentResults.Result<byte[]>> LoadLocalBinaryAsync(ContentPackage package, string localFilePath) =>
GetAbsFromLocal(package, localFilePath) is var r && r is { IsSuccess: true, Value: not null } GetAbsoluePathFromLocal(package, localFilePath) is var r && r is { IsSuccess: true, Value: not null }
? await TryLoadBinaryAsync(r.Value) : r.ToResult(); ? await TryLoadBinaryAsync(r.Value) : r.ToResult();
public virtual async Task<FluentResults.Result<string>> LoadLocalTextAsync(ContentPackage package, string localFilePath) => public virtual async Task<FluentResults.Result<string>> LoadLocalTextAsync(ContentPackage package, string localFilePath) =>
GetAbsFromLocal(package, localFilePath) is var r && r is { IsSuccess: true, Value: not null } GetAbsoluePathFromLocal(package, localFilePath) is var r && r is { IsSuccess: true, Value: not null }
? await TryLoadTextAsync(r.Value) : r.ToResult(); ? await TryLoadTextAsync(r.Value) : r.ToResult();
public virtual async Task<FluentResults.Result> SaveLocalXmlAsync(ContentPackage package, string localFilePath, XDocument document) => public virtual async Task<FluentResults.Result> SaveLocalXmlAsync(ContentPackage package, string localFilePath, XDocument document) =>
GetAbsFromLocal(package, localFilePath) is var r && r is { IsSuccess: true, Value: not null } GetAbsoluePathFromLocal(package, localFilePath) is var r && r is { IsSuccess: true, Value: not null }
? await TrySaveXmlAsync(r.Value, document) : r.ToResult(); ? await TrySaveXmlAsync(r.Value, document) : r.ToResult();
public virtual async Task<FluentResults.Result> SaveLocalBinaryAsync(ContentPackage package, string localFilePath, byte[] bytes) => public virtual async Task<FluentResults.Result> SaveLocalBinaryAsync(ContentPackage package, string localFilePath, byte[] bytes) =>
GetAbsFromLocal(package, localFilePath) is var r && r is { IsSuccess: true, Value: not null } GetAbsoluePathFromLocal(package, localFilePath) is var r && r is { IsSuccess: true, Value: not null }
? await TrySaveBinaryAsync(r.Value, bytes) : r.ToResult(); ? await TrySaveBinaryAsync(r.Value, bytes) : r.ToResult();
public virtual async Task<FluentResults.Result> SaveLocalTextAsync(ContentPackage package, string localFilePath, string text) => public virtual async Task<FluentResults.Result> SaveLocalTextAsync(ContentPackage package, string localFilePath, string text) =>
GetAbsFromLocal(package, localFilePath) is var r && r is { IsSuccess: true, Value: not null } GetAbsoluePathFromLocal(package, localFilePath) is var r && r is { IsSuccess: true, Value: not null }
? await TrySaveTextAsync(r.Value, text) : r.ToResult(); ? await TrySaveTextAsync(r.Value, text) : r.ToResult();
public virtual FluentResults.Result<XDocument> LoadPackageXml(ContentPackage package, string localFilePath) => public virtual FluentResults.Result<XDocument> LoadPackageXml(ContentPackage package, string localFilePath) =>
GetAbsFromPackage(package, localFilePath) is var r && r is { IsSuccess: true, Value: not null } GetAbsoluePathFromPackage(package, localFilePath) is var r && r is { IsSuccess: true, Value: not null }
? TryLoadXml(r.Value) : r.ToResult(); ? TryLoadXml(r.Value) : r.ToResult();
public virtual FluentResults.Result<byte[]> LoadPackageBinary(ContentPackage package, string localFilePath) => public virtual FluentResults.Result<byte[]> LoadPackageBinary(ContentPackage package, string localFilePath) =>
GetAbsFromPackage(package, localFilePath) is var r && r is { IsSuccess: true, Value: not null } GetAbsoluePathFromPackage(package, localFilePath) is var r && r is { IsSuccess: true, Value: not null }
? TryLoadBinary(r.Value) : r.ToResult(); ? TryLoadBinary(r.Value) : r.ToResult();
public virtual FluentResults.Result<string> LoadPackageText(ContentPackage package, string localFilePath) => public virtual FluentResults.Result<string> LoadPackageText(ContentPackage package, string localFilePath) =>
GetAbsFromPackage(package, localFilePath) is var r && r is { IsSuccess: true, Value: not null } GetAbsoluePathFromPackage(package, localFilePath) is var r && r is { IsSuccess: true, Value: not null }
? TryLoadText(r.Value) : r.ToResult(); ? TryLoadText(r.Value) : r.ToResult();
@@ -181,7 +182,7 @@ public class StorageService : IStorageService
public virtual FluentResults.Result<ImmutableArray<string>> FindFilesInPackage(ContentPackage package, string localSubfolder, string regexFilter, bool searchRecursively) public virtual FluentResults.Result<ImmutableArray<string>> FindFilesInPackage(ContentPackage package, string localSubfolder, string regexFilter, bool searchRecursively)
{ {
((IService)this).CheckDisposed(); ((IService)this).CheckDisposed();
var r = GetAbsFromPackage(package, localSubfolder); var r = GetAbsoluePathFromPackage(package, localSubfolder);
if (r is { IsFailed: true }) if (r is { IsFailed: true })
return r.ToResult(); return r.ToResult();
var builder = ImmutableArray.CreateBuilder<(string, FluentResults.Result<ImmutableArray<string>>)>(); var builder = ImmutableArray.CreateBuilder<(string, FluentResults.Result<ImmutableArray<string>>)>();
@@ -192,15 +193,15 @@ public class StorageService : IStorageService
} }
public virtual async Task<FluentResults.Result<XDocument>> LoadPackageXmlAsync(ContentPackage package, string localFilePath) => public virtual async Task<FluentResults.Result<XDocument>> LoadPackageXmlAsync(ContentPackage package, string localFilePath) =>
GetAbsFromPackage(package, localFilePath) is var r && r is { IsSuccess: true, Value: not null } GetAbsoluePathFromPackage(package, localFilePath) is var r && r is { IsSuccess: true, Value: not null }
? await TryLoadXmlAsync(r.Value) : r.ToResult(); ? await TryLoadXmlAsync(r.Value) : r.ToResult();
public virtual async Task<FluentResults.Result<byte[]>> LoadPackageBinaryAsync(ContentPackage package, string localFilePath) => public virtual async Task<FluentResults.Result<byte[]>> LoadPackageBinaryAsync(ContentPackage package, string localFilePath) =>
GetAbsFromPackage(package, localFilePath) is var r && r is { IsSuccess: true, Value: not null } GetAbsoluePathFromPackage(package, localFilePath) is var r && r is { IsSuccess: true, Value: not null }
? await TryLoadBinaryAsync(r.Value) : r.ToResult(); ? await TryLoadBinaryAsync(r.Value) : r.ToResult();
public virtual async Task<FluentResults.Result<string>> LoadPackageTextAsync(ContentPackage package, string localFilePath) => public virtual async Task<FluentResults.Result<string>> LoadPackageTextAsync(ContentPackage package, string localFilePath) =>
GetAbsFromPackage(package, localFilePath) is var r && r is { IsSuccess: true, Value: not null } GetAbsoluePathFromPackage(package, localFilePath) is var r && r is { IsSuccess: true, Value: not null }
? await TryLoadTextAsync(r.Value) : r.ToResult(); ? await TryLoadTextAsync(r.Value) : r.ToResult();
public virtual async Task<ImmutableArray<(string, FluentResults.Result<XDocument>)>> LoadPackageXmlFilesAsync(ContentPackage package, ImmutableArray<string> localFilePaths) public virtual async Task<ImmutableArray<(string, FluentResults.Result<XDocument>)>> LoadPackageXmlFilesAsync(ContentPackage package, ImmutableArray<string> localFilePaths)
@@ -529,7 +530,7 @@ public class StorageService : IStorageService
.WithMetadata(MetadataType.ExceptionObject, this) .WithMetadata(MetadataType.ExceptionObject, this)
.WithMetadata(MetadataType.Sources, localfp); .WithMetadata(MetadataType.Sources, localfp);
private FluentResults.Result<string> GetAbsFromLocal(ContentPackage package, string localFilePath) private FluentResults.Result<string> GetAbsoluePathFromLocal(ContentPackage package, string localFilePath)
{ {
if (Path.IsPathRooted(localFilePath)) if (Path.IsPathRooted(localFilePath))
{ {
@@ -539,13 +540,7 @@ public class StorageService : IStorageService
.WithMetadata(MetadataType.RootObject, localFilePath)); .WithMetadata(MetadataType.RootObject, localFilePath));
} }
if (package is null) Guard.IsNotNull(package, nameof(package));
{
return new FluentResults.Result<string>().WithError(
new Error($"{nameof(GetAbsFromPackage)} The package reference for {localFilePath} is null!")
.WithMetadata(MetadataType.ExceptionObject, this)
.WithMetadata(MetadataType.RootObject, localFilePath));
}
return new FluentResults.Result<string>().WithSuccess($"Path constructed") return new FluentResults.Result<string>().WithSuccess($"Path constructed")
.WithValue(System.IO.Path.GetFullPath(System.IO.Path.Combine( .WithValue(System.IO.Path.GetFullPath(System.IO.Path.Combine(
@@ -556,15 +551,9 @@ public class StorageService : IStorageService
localFilePath))); localFilePath)));
} }
public FluentResults.Result<string> GetAbsFromPackage(ContentPackage package, string localFilePath) public FluentResults.Result<string> GetAbsoluePathFromPackage(ContentPackage package, string localFilePath)
{ {
if (package is null) Guard.IsNotNull(package, nameof(package));
{
return new FluentResults.Result<string>().WithError(
new Error($"{nameof(GetAbsFromPackage)} The package reference for {localFilePath} is null!")
.WithMetadata(MetadataType.ExceptionObject, this)
.WithMetadata(MetadataType.RootObject, localFilePath));
}
if (localFilePath.IsNullOrWhiteSpace()) if (localFilePath.IsNullOrWhiteSpace())
{ {
@@ -0,0 +1,22 @@
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Diagnostics.CodeAnalysis;
using System.Threading.Tasks;
using Barotrauma.LuaCs.Data;
using Barotrauma.LuaCs.Services.Processing;
using FluentResults;
namespace Barotrauma.LuaCs.Services;
public interface IModConfigService : IService
{
/// <summary>
/// Loads or dynamically generates a <see cref="IModConfigInfo"/> for the given <see cref="ContentPackage"/>.
/// <br/> Throws a <see cref="NullReferenceException"/> if the package is null.
/// </summary>
/// <param name="src"></param>
/// <returns></returns>
Task<Result<IModConfigInfo>> CreateConfigAsync([NotNull]ContentPackage src);
Task<ImmutableArray<(ContentPackage Source, Result<IModConfigInfo> Config)>> CreateConfigsAsync(ImmutableArray<ContentPackage> src);
}
@@ -53,7 +53,7 @@ public interface IStorageService : IService
ImmutableArray<(string, FluentResults.Result<byte[]>)> LoadPackageBinaryFiles(ContentPackage package, ImmutableArray<string> localFilePaths); ImmutableArray<(string, FluentResults.Result<byte[]>)> LoadPackageBinaryFiles(ContentPackage package, ImmutableArray<string> localFilePaths);
ImmutableArray<(string, FluentResults.Result<string>)> LoadPackageTextFiles(ContentPackage package, ImmutableArray<string> localFilePaths); ImmutableArray<(string, FluentResults.Result<string>)> LoadPackageTextFiles(ContentPackage package, ImmutableArray<string> localFilePaths);
FluentResults.Result<ImmutableArray<string>> FindFilesInPackage(ContentPackage package, string localSubfolder, string regexFilter, bool searchRecursively); FluentResults.Result<ImmutableArray<string>> FindFilesInPackage(ContentPackage package, string localSubfolder, string regexFilter, bool searchRecursively);
FluentResults.Result<string> GetAbsFromPackage(ContentPackage package, string localFilePath); FluentResults.Result<string> GetAbsoluePathFromPackage(ContentPackage package, string localFilePath);
// async // async
// singles // singles
Task<FluentResults.Result<XDocument>> LoadPackageXmlAsync(ContentPackage package, string localFilePath); Task<FluentResults.Result<XDocument>> LoadPackageXmlAsync(ContentPackage package, string localFilePath);