- Removed all package dependency lookup code.
- Changed from absolute file paths to the upstream `ContentPath` system.
This commit is contained in:
@@ -33,146 +33,29 @@ public record LuaScriptsResourcesInfo(ImmutableArray<ILuaScriptResourceInfo> Lua
|
||||
public record ConfigResourcesInfo(ImmutableArray<IConfigResourceInfo> Configs) : IConfigsResourcesInfo;
|
||||
public record ConfigProfilesResourcesInfo(ImmutableArray<IConfigProfileResourceInfo> ConfigProfiles) : IConfigProfilesResourcesInfo;
|
||||
|
||||
public record AssemblyResourceInfo : IAssemblyResourceInfo
|
||||
public record BaseResourceInfo : IBaseResourceInfo
|
||||
{
|
||||
public Platform SupportedPlatforms { get; init; }
|
||||
public Target SupportedTargets { get; init; }
|
||||
public int LoadPriority { get; init; }
|
||||
public ImmutableArray<ContentPath> FilePaths { get; init; }
|
||||
public bool Optional { get; init; }
|
||||
public string InternalName { get; init; }
|
||||
public ContentPackage OwnerPackage { get; init; }
|
||||
}
|
||||
|
||||
public record AssemblyResourceInfo : BaseResourceInfo, IAssemblyResourceInfo
|
||||
{
|
||||
public string FriendlyName { get; init; }
|
||||
public bool IsScript { get; init; }
|
||||
public string InternalName { get; init; }
|
||||
public bool LazyLoad { get; init; }
|
||||
public Platform SupportedPlatforms { get; init; }
|
||||
public Target SupportedTargets { get; init; }
|
||||
public int LoadPriority { get; init; }
|
||||
public ImmutableArray<string> FilePaths { get; init; }
|
||||
public ImmutableArray<CultureInfo> SupportedCultures { get; init; }
|
||||
public ImmutableArray<IPackageDependency> Dependencies { get; init; }
|
||||
public bool Optional { get; init; }
|
||||
}
|
||||
|
||||
public record PackageDependency : IPackageDependency
|
||||
public record ConfigResourceInfo : BaseResourceInfo, IConfigResourceInfo {}
|
||||
|
||||
public record ConfigProfileResourceInfo : BaseResourceInfo, IConfigProfileResourceInfo {}
|
||||
|
||||
public record LuaScriptsResourceInfo : BaseResourceInfo, ILuaScriptResourceInfo
|
||||
{
|
||||
public PackageDependency(ContentPackage package, IPackageInfo dependencyInfo, string internalName)
|
||||
{
|
||||
Dependency = dependencyInfo ?? throw new ArgumentNullException(nameof(dependencyInfo));
|
||||
OwnerPackage = package ?? throw new ArgumentNullException(nameof(package));
|
||||
InternalName = internalName ?? throw new ArgumentNullException(nameof(internalName));
|
||||
}
|
||||
public string InternalName { get; init; }
|
||||
public ContentPackage OwnerPackage { get; init; }
|
||||
public IPackageInfo Dependency { get; init; }
|
||||
public override int GetHashCode() => Dependency.GetHashCode();
|
||||
|
||||
}
|
||||
|
||||
public record PackageInfo : IPackageInfo
|
||||
{
|
||||
public string Name { get; private set; }
|
||||
public ulong SteamWorkshopId { get; private set; }
|
||||
public uint Id { get; private set; }
|
||||
|
||||
private readonly Func<IPackageInfo, ContentPackage> _getPackage;
|
||||
|
||||
public ContentPackage GetPackage() => _getPackage?.Invoke(this) ?? null;
|
||||
|
||||
public void UpdateInfo(string name, ulong steamId, uint packageId)
|
||||
{
|
||||
if (name.IsNullOrWhiteSpace() || steamId == 0 || packageId == 0)
|
||||
{
|
||||
throw new ArgumentException(
|
||||
$"{nameof(PackageInfo)}: You cannot update a package with an invalid name or steam id with a valid id, or vice-versa.");
|
||||
}
|
||||
|
||||
Name = name;
|
||||
SteamWorkshopId = steamId;
|
||||
Id = packageId;
|
||||
}
|
||||
|
||||
public PackageInfo(ContentPackage package, uint id, Func<IPackageInfo, ContentPackage> getPackage)
|
||||
{
|
||||
if (package is null)
|
||||
throw new ArgumentNullException($"{nameof(PackageInfo)}: package is null");
|
||||
if (id == 0)
|
||||
throw new ArgumentNullException($"{nameof(PackageInfo)}: id is zero.");
|
||||
|
||||
this.Name = package.Name;
|
||||
this.SteamWorkshopId = package.TryExtractSteamWorkshopId(out var sId) ? sId.Value : 0;
|
||||
this.Id = id;
|
||||
this._getPackage = getPackage;
|
||||
}
|
||||
|
||||
public PackageInfo(string name, ulong steamWorkshopId, uint id, Func<IPackageInfo, ContentPackage> getPackage)
|
||||
{
|
||||
Name = !name.IsNullOrWhiteSpace() ? name : throw new ArgumentNullException($"{nameof(PackageInfo)}: name cannot be null or empty.");
|
||||
SteamWorkshopId = steamWorkshopId != 0 ? steamWorkshopId : throw new ArgumentNullException($"{nameof(PackageInfo)}: steam id cannot be 0.");
|
||||
this.Id = id;
|
||||
this._getPackage = getPackage;
|
||||
}
|
||||
|
||||
public PackageInfo(string name, uint id, Func<IPackageInfo, ContentPackage> getPackage)
|
||||
{
|
||||
Name = name ?? throw new ArgumentNullException($"{nameof(PackageInfo)}: name cannot be null or empty.");
|
||||
this.SteamWorkshopId = 0;
|
||||
this.Id = id;
|
||||
this._getPackage = getPackage;
|
||||
}
|
||||
|
||||
public PackageInfo(ulong steamWorkshopId, uint id, Func<IPackageInfo, ContentPackage> getPackage)
|
||||
{
|
||||
SteamWorkshopId = steamWorkshopId != 0 ? steamWorkshopId : throw new ArgumentNullException($"{nameof(PackageInfo)}: steamid cannot be 0.");
|
||||
this.Id = id;
|
||||
this._getPackage = getPackage;
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return (int)Id;
|
||||
}
|
||||
|
||||
public virtual bool Equals(PackageInfo other)
|
||||
{
|
||||
return ((IEquatable<IPackageInfo>)this).Equals(other);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
public record ConfigResourceInfo : IConfigResourceInfo
|
||||
{
|
||||
public Platform SupportedPlatforms { get; init; }
|
||||
public Target SupportedTargets { get; init; }
|
||||
public int LoadPriority { get; init; }
|
||||
public ImmutableArray<string> FilePaths { get; init; }
|
||||
public bool Optional { get; init; }
|
||||
public ImmutableArray<CultureInfo> SupportedCultures { get; init; }
|
||||
public ImmutableArray<IPackageDependency> Dependencies { get; init; }
|
||||
public string InternalName { get; init; }
|
||||
public ContentPackage OwnerPackage { get; init; }
|
||||
}
|
||||
|
||||
public record ConfigProfileResourceInfo : IConfigProfileResourceInfo
|
||||
{
|
||||
public Platform SupportedPlatforms { get; init; }
|
||||
public Target SupportedTargets { get; init; }
|
||||
public int LoadPriority { get; init; }
|
||||
public ImmutableArray<string> FilePaths { get; init; }
|
||||
public bool Optional { get; init; }
|
||||
public ImmutableArray<CultureInfo> SupportedCultures { get; init; }
|
||||
public ImmutableArray<IPackageDependency> Dependencies { get; init; }
|
||||
public string InternalName { get; init; }
|
||||
public ContentPackage OwnerPackage { get; init; }
|
||||
}
|
||||
|
||||
public readonly struct LuaScriptsResourceInfo : ILuaScriptResourceInfo
|
||||
{
|
||||
public ContentPackage OwnerPackage { get; init; }
|
||||
public Platform SupportedPlatforms { get; init; }
|
||||
public Target SupportedTargets { get; init; }
|
||||
public int LoadPriority { get; init; }
|
||||
public ImmutableArray<string> FilePaths { get; init; }
|
||||
public ImmutableArray<CultureInfo> SupportedCultures { get; init; }
|
||||
public ImmutableArray<IPackageDependency> Dependencies { get; init; }
|
||||
public bool Optional { get; init; }
|
||||
public string InternalName { get; init; }
|
||||
public bool IsAutorun { get; init; }
|
||||
}
|
||||
|
||||
|
||||
@@ -37,7 +37,7 @@ public interface IResourceInfo : IPlatformInfo
|
||||
/// Resource absolute file paths.
|
||||
/// </summary>
|
||||
[Required]
|
||||
ImmutableArray<string> FilePaths { get; }
|
||||
ImmutableArray<ContentPath> FilePaths { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Marks this resource as optional (ie. Cross-CP content). Setting this to true will allow the dependency system to
|
||||
@@ -45,14 +45,3 @@ public interface IResourceInfo : IPlatformInfo
|
||||
/// </summary>
|
||||
bool Optional { get; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Information about supported cultures. It is intended to be ignored if the array is ImmutableArray.Empty .
|
||||
/// </summary>
|
||||
public interface IResourceCultureInfo
|
||||
{
|
||||
/// <summary>
|
||||
/// List of supported cultures by this resource.
|
||||
/// </summary>
|
||||
ImmutableArray<CultureInfo> SupportedCultures { get; }
|
||||
}
|
||||
|
||||
@@ -1,66 +0,0 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
using Barotrauma;
|
||||
using Barotrauma.LuaCs.Data;
|
||||
|
||||
namespace Barotrauma.LuaCs.Data;
|
||||
|
||||
public interface IPackageDependency : IDataInfo, IEquatable<IPackageDependency>
|
||||
{
|
||||
public IPackageInfo Dependency { get; }
|
||||
|
||||
bool IEquatable<IPackageDependency>.Equals(IPackageDependency other)
|
||||
{
|
||||
return other is not null && Dependency.Equals(other.Dependency);
|
||||
}
|
||||
}
|
||||
|
||||
public interface IPackageInfo : IEquatable<IPackageInfo>
|
||||
{
|
||||
/// <summary>
|
||||
/// Name of the content package.
|
||||
/// </summary>
|
||||
public string Name { get; }
|
||||
/// <summary>
|
||||
/// Steam ID of the package.
|
||||
/// </summary>
|
||||
public ulong SteamWorkshopId { get; }
|
||||
/// <summary>
|
||||
/// The Guid for the runtime instance of the package.
|
||||
/// </summary>
|
||||
public uint Id { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the reference to the best-match target ContentPackage that meets the requirement.
|
||||
/// </summary>
|
||||
/// <returns>The <see cref="ContentPackage"/> reference, or null if none was found.</returns>
|
||||
public ContentPackage GetPackage();
|
||||
|
||||
/// <summary>
|
||||
/// Tries to retrieve the current best <see cref="ContentPackage"/> and returns true if none was found.
|
||||
/// </summary>
|
||||
public bool IsMissing => GetPackage() is null;
|
||||
|
||||
bool IEquatable<IPackageInfo>.Equals(IPackageInfo other)
|
||||
{
|
||||
if (other is null)
|
||||
return false;
|
||||
if (ReferenceEquals(other, this))
|
||||
return true;
|
||||
if (!this.IsMissing && !other.IsMissing && ReferenceEquals(other.GetPackage, this.GetPackage))
|
||||
return true;
|
||||
if (this.SteamWorkshopId != 0 && other.SteamWorkshopId == this.SteamWorkshopId)
|
||||
return true;
|
||||
return this.Name == other.Name;
|
||||
}
|
||||
}
|
||||
|
||||
public interface IPackageDependenciesInfo
|
||||
{
|
||||
/// <summary>
|
||||
/// List of required packages.
|
||||
/// </summary>
|
||||
ImmutableArray<IPackageDependency> Dependencies { get; }
|
||||
}
|
||||
@@ -4,13 +4,17 @@ using System.Globalization;
|
||||
|
||||
namespace Barotrauma.LuaCs.Data;
|
||||
|
||||
public interface IConfigResourceInfo : IResourceInfo, IResourceCultureInfo, IPackageDependenciesInfo, IDataInfo { }
|
||||
public interface IConfigProfileResourceInfo : IResourceInfo, IResourceCultureInfo, IPackageDependenciesInfo, IDataInfo { }
|
||||
|
||||
public interface IBaseResourceInfo : IResourceInfo, IDataInfo {}
|
||||
|
||||
public interface IConfigResourceInfo : IBaseResourceInfo {}
|
||||
|
||||
public interface IConfigProfileResourceInfo :IBaseResourceInfo {}
|
||||
|
||||
/// <summary>
|
||||
/// Represents loadable Lua files.
|
||||
/// </summary>
|
||||
public interface ILuaScriptResourceInfo : IResourceInfo, IResourceCultureInfo, IPackageDependenciesInfo, IDataInfo
|
||||
public interface ILuaScriptResourceInfo : IBaseResourceInfo
|
||||
{
|
||||
/// <summary>
|
||||
/// Should this script be run automatically.
|
||||
@@ -18,7 +22,7 @@ public interface ILuaScriptResourceInfo : IResourceInfo, IResourceCultureInfo, I
|
||||
public bool IsAutorun { get; }
|
||||
}
|
||||
|
||||
public interface IAssemblyResourceInfo : IResourceInfo, IResourceCultureInfo, IPackageDependenciesInfo, IDataInfo
|
||||
public interface IAssemblyResourceInfo : IBaseResourceInfo
|
||||
{
|
||||
/// <summary>
|
||||
/// The friendly name of the assembly. Script files belonging to the same assembly should all have the same name.
|
||||
|
||||
@@ -1,393 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Barotrauma.LuaCs.Data;
|
||||
using Barotrauma.LuaCs.Events;
|
||||
using Barotrauma.Steam;
|
||||
using FluentResults;
|
||||
using OneOf;
|
||||
|
||||
namespace Barotrauma.LuaCs.Services;
|
||||
|
||||
/// <summary>
|
||||
/// Provides <see cref="IPackageInfo"/> resolution for dynamically locating the best matching package at the time of consumption.
|
||||
/// </summary>
|
||||
public sealed class ContentPackageInfoLookup : IPackageInfoLookupService, IEventEnabledPackageListChanged, IEventAllPackageListChanged
|
||||
{
|
||||
#region INTERNAL
|
||||
|
||||
// packageinfo query data
|
||||
private readonly ConcurrentDictionary<OneOf.OneOf<string, ulong, (string, ulong)>, IPackageInfo> _packageInfoMap = new();
|
||||
// package query data
|
||||
private readonly ConcurrentDictionary<uint, ImmutableArray<ContentPackage>> _packageIdGroups = new();
|
||||
private readonly ConcurrentDictionary<ContentPackage, ImmutableArray<uint>> _reversePackageIdGroups = new();
|
||||
private readonly HashSet<ContentPackage> _enabledPackages;
|
||||
private readonly HashSet<ContentPackage> _allPackages;
|
||||
// threading
|
||||
private readonly AsyncReaderWriterLock _packageIdGroupsLock = new();
|
||||
private readonly AsyncReaderWriterLock _packageSetsLock = new();
|
||||
// services
|
||||
private readonly IEventService _eventService;
|
||||
private readonly IPackageListRetrievalService _packageListRetrievalService;
|
||||
|
||||
private int _isDisposed = 0;
|
||||
private uint _idCounter = 0;
|
||||
|
||||
// returns ++_idCounter;
|
||||
private uint GetNextId() => Interlocked.Increment(ref _idCounter);
|
||||
|
||||
private ContentPackage GetBestMatchPackage(IPackageInfo packageInfo)
|
||||
{
|
||||
if (packageInfo is null)
|
||||
return null;
|
||||
if (!_packageIdGroups.TryGetValue(packageInfo.Id, out var packageGroup)
|
||||
|| packageGroup.IsDefaultOrEmpty)
|
||||
return null;
|
||||
if (packageGroup.Length == 1)
|
||||
return packageGroup[0];
|
||||
|
||||
bool nameGood = !packageInfo.Name.IsNullOrWhiteSpace();
|
||||
|
||||
// try by enabled
|
||||
var prev = packageGroup;
|
||||
|
||||
var packList = packageGroup;
|
||||
using (_packageSetsLock.AcquireReaderLock().GetAwaiter().GetResult())
|
||||
{
|
||||
packList = packList
|
||||
.Where(p => p is not null && _enabledPackages.Contains(p))
|
||||
.ToImmutableArray();
|
||||
}
|
||||
|
||||
if (ReturnValue())
|
||||
return packList[0];
|
||||
|
||||
// try by steam id
|
||||
if (packageInfo.SteamWorkshopId != 0)
|
||||
{
|
||||
packList = packList
|
||||
.Where(p => p.TryExtractSteamWorkshopId(out var sId) && sId.Value == packageInfo.SteamWorkshopId)
|
||||
.ToImmutableArray();
|
||||
|
||||
if (ReturnValue())
|
||||
return packList[0];
|
||||
}
|
||||
|
||||
// try by name
|
||||
if (nameGood)
|
||||
{
|
||||
packList = packList
|
||||
.Where(p => p.Name == packageInfo.Name)
|
||||
.ToImmutableArray();
|
||||
|
||||
if (ReturnValue())
|
||||
return packList[0];
|
||||
}
|
||||
|
||||
// try by localmods
|
||||
packList = packList.Where(p => p.Path.ToLowerInvariant().Contains("localmods"))
|
||||
.ToImmutableArray();
|
||||
|
||||
if (ReturnValue())
|
||||
return packList[0];
|
||||
|
||||
// get the first in the list
|
||||
return packList.First();
|
||||
|
||||
bool ReturnValue()
|
||||
{
|
||||
if (packList.IsDefaultOrEmpty)
|
||||
packList = prev;
|
||||
else if (packList.Length == 1)
|
||||
return true;
|
||||
else
|
||||
prev = packList;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private async Task SyncPackagesLists(IReadOnlyList<ContentPackage> enabledPackages,
|
||||
IReadOnlyList<ContentPackage> allPackages)
|
||||
{
|
||||
if (enabledPackages is null || allPackages is null)
|
||||
return;
|
||||
|
||||
// take all locks
|
||||
using var l1 = await _packageIdGroupsLock.AcquireWriterLock();
|
||||
using var l2 = await _packageSetsLock.AcquireWriterLock();
|
||||
|
||||
// calc diffs
|
||||
var toAddAll = allPackages.Except(_allPackages).ToHashSet();
|
||||
var toAddEnabled = enabledPackages.Except(_enabledPackages).ToHashSet();
|
||||
var toRemoveAll = _allPackages.Except(allPackages).ToHashSet();
|
||||
var toRemoveEnabled = _enabledPackages.Except(enabledPackages).ToHashSet();
|
||||
|
||||
// remove old
|
||||
if (toRemoveAll.Any())
|
||||
{
|
||||
foreach (var package in toRemoveAll)
|
||||
{
|
||||
if (package is null)
|
||||
continue;
|
||||
|
||||
_allPackages.Remove(package);
|
||||
|
||||
// try to find id lookup
|
||||
if (!_reversePackageIdGroups.TryGetValue(package, out var idGroup))
|
||||
continue;
|
||||
|
||||
// found packs
|
||||
if (!idGroup.IsDefaultOrEmpty)
|
||||
{
|
||||
foreach (var id in idGroup)
|
||||
{
|
||||
if (!_packageIdGroups.TryGetValue(id, out var packageGroup)
|
||||
|| packageGroup.IsDefaultOrEmpty)
|
||||
continue;
|
||||
_packageIdGroups[id] = packageGroup.RemoveAll(p => toRemoveAll.Contains(p));
|
||||
}
|
||||
}
|
||||
|
||||
// remove ref
|
||||
_reversePackageIdGroups.Remove(package, out _);
|
||||
}
|
||||
}
|
||||
|
||||
if (toRemoveEnabled.Any())
|
||||
{
|
||||
foreach (var package in toRemoveEnabled)
|
||||
{
|
||||
if (package is null)
|
||||
continue;
|
||||
_enabledPackages.Remove(package);
|
||||
}
|
||||
}
|
||||
|
||||
// add new
|
||||
if (toAddAll.Any())
|
||||
{
|
||||
foreach (var package in toAddAll)
|
||||
{
|
||||
if (package is null)
|
||||
continue;
|
||||
|
||||
_allPackages.Add(package);
|
||||
|
||||
var steamId = package.TryExtractSteamWorkshopId(out var id) ? id.Value : 0;
|
||||
IPackageInfo packageInfo;
|
||||
Queue<uint> idListsToAdd = new();
|
||||
if (!package.Name.IsNullOrWhiteSpace() && steamId > 0)
|
||||
{
|
||||
// combined key
|
||||
packageInfo = GetOrCreateInfoForMap(package, (package.Name, steamId));
|
||||
AddToPackageIdGroups(packageInfo.Id, package);
|
||||
// string key
|
||||
packageInfo = GetOrCreateInfoForMap(package, package.Name);
|
||||
AddToPackageIdGroups(packageInfo.Id, package);
|
||||
// steamId key
|
||||
packageInfo = GetOrCreateInfoForMap(package, steamId);
|
||||
AddToPackageIdGroups(packageInfo.Id, package);
|
||||
}
|
||||
|
||||
// try find in the existing list, or make a new one
|
||||
IPackageInfo GetOrCreateInfoForMap(ContentPackage package, OneOf.OneOf<string, ulong, (string, ulong)> infoKey)
|
||||
{
|
||||
return _packageInfoMap.TryGetValue(infoKey, out var pInfo)
|
||||
? pInfo
|
||||
: new PackageInfo(package, GetNextId(), GetBestMatchPackage);
|
||||
}
|
||||
|
||||
// add to package lookups
|
||||
void AddToPackageIdGroups(uint id, ContentPackage package)
|
||||
{
|
||||
if (_packageIdGroups.TryGetValue(id, out var packageGroup))
|
||||
{
|
||||
if (!packageGroup.Contains(package))
|
||||
_packageIdGroups[id] = packageGroup.Add(package);
|
||||
}
|
||||
else
|
||||
_packageIdGroups[id] = new[] { package }.ToImmutableArray();
|
||||
|
||||
if (_reversePackageIdGroups.TryGetValue(package, out var idGroup))
|
||||
{
|
||||
if (!idGroup.Contains(id))
|
||||
_reversePackageIdGroups[package] = idGroup.Add(id);
|
||||
}
|
||||
else
|
||||
_reversePackageIdGroups[package] = new[] { id }.ToImmutableArray();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (toAddEnabled.Any())
|
||||
{
|
||||
foreach (var package in toAddEnabled)
|
||||
{
|
||||
if (package is null)
|
||||
continue;
|
||||
_enabledPackages.Add(package);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<Result<IPackageInfo>> LookupInternal(OneOf.OneOf<string, ulong, (string, ulong)> infoKey)
|
||||
{
|
||||
using (await _packageIdGroupsLock.AcquireReaderLock())
|
||||
{
|
||||
if (_packageInfoMap.TryGetValue(infoKey, out var packageInfo))
|
||||
return FluentResults.Result.Ok(packageInfo);
|
||||
}
|
||||
|
||||
// change to write lock
|
||||
using (await _packageIdGroupsLock.AcquireWriterLock())
|
||||
{
|
||||
// create one
|
||||
var packageInfo = infoKey.Match<IPackageInfo>(
|
||||
sPackName => new PackageInfo(sPackName, GetNextId(), GetBestMatchPackage),
|
||||
uSteamId => new PackageInfo(uSteamId, GetNextId(), GetBestMatchPackage),
|
||||
cKey => new PackageInfo(cKey.Item1, cKey.Item2, GetNextId(), GetBestMatchPackage)
|
||||
);
|
||||
_packageInfoMap[infoKey] = packageInfo;
|
||||
// empty array
|
||||
_packageIdGroups[packageInfo.Id] = ImmutableArray<ContentPackage>.Empty;
|
||||
return FluentResults.Result.Ok(packageInfo);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
public ContentPackageInfoLookup(IEventService eventService, IPackageListRetrievalService packageListRetrievalService)
|
||||
{
|
||||
_eventService = eventService ?? throw new ArgumentNullException(
|
||||
$"{nameof(ContentPackageInfoLookup)}: {nameof(eventService)} cannot be null.");
|
||||
_packageListRetrievalService = packageListRetrievalService ?? throw new ArgumentNullException(nameof(packageListRetrievalService));
|
||||
this._enabledPackages = new HashSet<ContentPackage>();
|
||||
this._allPackages = new HashSet<ContentPackage>();
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
IsDisposed = true;
|
||||
// locks
|
||||
using var l1 = _packageIdGroupsLock.AcquireWriterLock().GetAwaiter().GetResult();
|
||||
using var l2 = _packageSetsLock.AcquireWriterLock().GetAwaiter().GetResult();
|
||||
|
||||
_eventService.Unsubscribe<IEventEnabledPackageListChanged>(this);
|
||||
_eventService.Unsubscribe<IEventAllPackageListChanged>(this);
|
||||
|
||||
_packageIdGroups.Clear();
|
||||
_packageInfoMap.Clear();
|
||||
_reversePackageIdGroups.Clear();
|
||||
}
|
||||
|
||||
public bool IsDisposed
|
||||
{
|
||||
get => ModUtils.Threading.GetBool(ref _isDisposed);
|
||||
private set => ModUtils.Threading.SetBool(ref _isDisposed, value);
|
||||
}
|
||||
|
||||
public FluentResults.Result Reset()
|
||||
{
|
||||
if (IsDisposed)
|
||||
return FluentResults.Result.Fail($"Service is disposed.");
|
||||
|
||||
using var l1 = _packageIdGroupsLock.AcquireWriterLock().GetAwaiter().GetResult();
|
||||
using var l2 = _packageSetsLock.AcquireWriterLock().GetAwaiter().GetResult();
|
||||
|
||||
_packageIdGroups.Clear();
|
||||
_packageInfoMap.Clear();
|
||||
_reversePackageIdGroups.Clear();
|
||||
|
||||
RefreshPackageLists();
|
||||
|
||||
return FluentResults.Result.Ok();
|
||||
}
|
||||
|
||||
public void OnEnabledPackageListChanged(CorePackage package, IEnumerable<RegularPackage> regularPackages)
|
||||
{
|
||||
((IService)this).CheckDisposed();
|
||||
SyncPackagesLists(
|
||||
regularPackages.Select(p => (ContentPackage)p).ToImmutableArray().Add(package),
|
||||
_allPackages.ToImmutableArray())
|
||||
.GetAwaiter().GetResult();
|
||||
}
|
||||
|
||||
public void OnAllPackageListChanged(IEnumerable<CorePackage> corePackages, IEnumerable<RegularPackage> regularPackages)
|
||||
{
|
||||
((IService)this).CheckDisposed();
|
||||
SyncPackagesLists(
|
||||
_enabledPackages.ToImmutableArray(),
|
||||
regularPackages.Select(p => p as ContentPackage)
|
||||
.Union(corePackages.Select(p => p as ContentPackage))
|
||||
.ToImmutableArray()
|
||||
).GetAwaiter().GetResult();
|
||||
}
|
||||
|
||||
public bool IsPackageEnabled(ContentPackage package)
|
||||
{
|
||||
if (package is null)
|
||||
return false;
|
||||
using (_packageSetsLock.AcquireReaderLock().GetAwaiter().GetResult())
|
||||
{
|
||||
return _enabledPackages.Contains(package);
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<Result<IPackageInfo>> Lookup(string packageName)
|
||||
{
|
||||
((IService)this).CheckDisposed();
|
||||
if(packageName.IsNullOrWhiteSpace())
|
||||
return FluentResults.Result.Fail($"Name is null or empty.");
|
||||
return await LookupInternal(packageName);
|
||||
}
|
||||
|
||||
public async Task<Result<IPackageInfo>> Lookup(string packageName, ulong steamWorkshopId)
|
||||
{
|
||||
((IService)this).CheckDisposed();
|
||||
if (packageName.IsNullOrWhiteSpace() || steamWorkshopId == 0)
|
||||
return FluentResults.Result.Fail($"Name or steam id is null or empty.");
|
||||
return await LookupInternal((packageName, steamWorkshopId));
|
||||
}
|
||||
|
||||
public async Task<Result<IPackageInfo>> Lookup(ulong steamWorkshopId)
|
||||
{
|
||||
((IService)this).CheckDisposed();
|
||||
if (steamWorkshopId is 0)
|
||||
return FluentResults.Result.Fail($"SteamId is 0.");
|
||||
return await LookupInternal(steamWorkshopId);
|
||||
}
|
||||
|
||||
public async Task<Result<IPackageInfo>> Lookup(ContentPackage package)
|
||||
{
|
||||
((IService)this).CheckDisposed();
|
||||
if (package is null)
|
||||
return FluentResults.Result.Fail($"Package is null.");
|
||||
|
||||
if (package.TryExtractSteamWorkshopId(out var steamWorkshopId) && steamWorkshopId.Value != 0)
|
||||
{
|
||||
if (!package.Name.IsNullOrWhiteSpace())
|
||||
return await LookupInternal((package.Name, steamWorkshopId.Value));
|
||||
else
|
||||
return await LookupInternal(steamWorkshopId.Value);
|
||||
}
|
||||
|
||||
if (!package.Name.IsNullOrWhiteSpace())
|
||||
return await LookupInternal(package.Name);
|
||||
|
||||
return FluentResults.Result.Fail($"Package name is null and steamid is 0.");
|
||||
}
|
||||
|
||||
public void RefreshPackageLists()
|
||||
{
|
||||
((IService)this).CheckDisposed();
|
||||
if (Thread.CurrentThread != GameMain.MainThread)
|
||||
throw new InvalidOperationException($"{nameof(ContentPackageInfoLookup)}: {nameof(RefreshPackageLists)} must be run on the main thread.");
|
||||
var enabledPackages = _packageListRetrievalService.GetEnabledContentPackages().ToImmutableArray();
|
||||
var allPackages = _packageListRetrievalService.GetAllContentPackages().ToImmutableArray();
|
||||
SyncPackagesLists(enabledPackages, allPackages).GetAwaiter().GetResult();
|
||||
}
|
||||
}
|
||||
@@ -1,376 +1,127 @@
|
||||
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Barotrauma.LuaCs.Data;
|
||||
using Barotrauma.LuaCs.Services.Processing;
|
||||
using Barotrauma.Steam;
|
||||
using FluentResults;
|
||||
using OneOf;
|
||||
|
||||
// ReSharper disable UseCollectionExpression
|
||||
|
||||
namespace Barotrauma.LuaCs.Services;
|
||||
|
||||
public partial class PackageManagementService : IPackageManagementService
|
||||
{
|
||||
private int _isDisposed;
|
||||
private readonly ConcurrentDictionary<ContentPackage, IModConfigInfo> _modInfos = new();
|
||||
// lookup caches
|
||||
private readonly IPackageInfoLookupService _packageInfoLookupService;
|
||||
// processors
|
||||
private readonly IConverterServiceAsync<ContentPackage, IModConfigInfo> _modConfigParserService;
|
||||
private readonly IProcessorService<IReadOnlyList<IAssemblyResourceInfo>, IAssembliesResourcesInfo> _assemblyInfoConverter;
|
||||
private readonly IProcessorService<IReadOnlyList<IConfigResourceInfo>, IConfigsResourcesInfo> _configsInfoConverter;
|
||||
private readonly IProcessorService<IReadOnlyList<IConfigProfileResourceInfo>, IConfigProfilesResourcesInfo> _configProfilesConverter;
|
||||
private readonly IProcessorService<IReadOnlyList<ILuaScriptResourceInfo>, ILuaScriptsResourcesInfo> _luaScriptsConverter;
|
||||
|
||||
public PackageManagementService(
|
||||
IConverterServiceAsync<ContentPackage, IModConfigInfo> modConfigParserService,
|
||||
IProcessorService<IReadOnlyList<IAssemblyResourceInfo>, IAssembliesResourcesInfo> assemblyInfoConverter,
|
||||
IProcessorService<IReadOnlyList<IConfigResourceInfo>, IConfigsResourcesInfo> configsInfoConverter,
|
||||
IProcessorService<IReadOnlyList<IConfigProfileResourceInfo>, IConfigProfilesResourcesInfo> configProfilesConverter,
|
||||
IProcessorService<IReadOnlyList<ILuaScriptResourceInfo>, ILuaScriptsResourcesInfo> luaScriptsConverter,
|
||||
IPackageInfoLookupService packageInfoLookupService)
|
||||
{
|
||||
_modConfigParserService = modConfigParserService;
|
||||
_assemblyInfoConverter = assemblyInfoConverter;
|
||||
_configsInfoConverter = configsInfoConverter;
|
||||
_configProfilesConverter = configProfilesConverter;
|
||||
_luaScriptsConverter = luaScriptsConverter;
|
||||
_packageInfoLookupService = packageInfoLookupService;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
IsDisposed = true;
|
||||
_modInfos.Clear();
|
||||
throw new System.NotImplementedException();
|
||||
}
|
||||
|
||||
private int _isDisposed = 0;
|
||||
public bool IsDisposed
|
||||
{
|
||||
get => ModUtils.Threading.GetBool(ref _isDisposed);
|
||||
private set => ModUtils.Threading.SetBool(ref _isDisposed, value);
|
||||
get => ModUtils.Threading.GetBool(ref _isDisposed);
|
||||
private set => ModUtils.Threading.SetBool(ref _isDisposed, value);
|
||||
}
|
||||
|
||||
|
||||
|
||||
public FluentResults.Result Reset()
|
||||
{
|
||||
try
|
||||
{
|
||||
((IService)this).CheckDisposed();
|
||||
_modInfos.Clear();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
return FluentResults.Result.Fail(new ExceptionalError(e));
|
||||
}
|
||||
return FluentResults.Result.Ok();
|
||||
throw new System.NotImplementedException();
|
||||
}
|
||||
|
||||
public ImmutableArray<IConfigResourceInfo> Configs => _modInfos.IsEmpty ? ImmutableArray<IConfigResourceInfo>.Empty
|
||||
: _modInfos.SelectMany(kvp => kvp.Value.Configs).ToImmutableArray();
|
||||
public ImmutableArray<IConfigProfileResourceInfo> ConfigProfiles => _modInfos.IsEmpty ? ImmutableArray<IConfigProfileResourceInfo>.Empty
|
||||
: _modInfos.SelectMany(kvp => kvp.Value.ConfigProfiles).ToImmutableArray();
|
||||
public ImmutableArray<ILuaScriptResourceInfo> LuaScripts => _modInfos.IsEmpty ? ImmutableArray<ILuaScriptResourceInfo>.Empty
|
||||
: _modInfos.SelectMany(kvp => kvp.Value.LuaScripts).ToImmutableArray();
|
||||
public ImmutableArray<IAssemblyResourceInfo> Assemblies => _modInfos.IsEmpty ? ImmutableArray<IAssemblyResourceInfo>.Empty
|
||||
: _modInfos.SelectMany(kvp => kvp.Value.Assemblies).ToImmutableArray();
|
||||
|
||||
|
||||
public ImmutableArray<IConfigResourceInfo> Configs { get; }
|
||||
public ImmutableArray<IConfigProfileResourceInfo> ConfigProfiles { get; }
|
||||
public ImmutableArray<ILuaScriptResourceInfo> LuaScripts { get; }
|
||||
public ImmutableArray<IAssemblyResourceInfo> Assemblies { get; }
|
||||
public async Task<FluentResults.Result> LoadPackageInfosAsync(ContentPackage package)
|
||||
{
|
||||
((IService)this).CheckDisposed();
|
||||
if (package is null)
|
||||
return FluentResults.Result.Fail(new ExceptionalError(new NullReferenceException($"{nameof(LoadPackageInfosAsync)}: ContentPackage is null.")));
|
||||
var result = await _modConfigParserService.TryParseResourceAsync(package);
|
||||
if (result.IsFailed)
|
||||
return FluentResults.Result.Fail($"$Could not parse package mod config.").WithErrors(result.Errors);
|
||||
if (!_modInfos.TryAdd(package, result.Value))
|
||||
return FluentResults.Result.Fail($"Failed to add ModInfo for {package.Name}.");
|
||||
return FluentResults.Result.Ok();
|
||||
throw new System.NotImplementedException();
|
||||
}
|
||||
|
||||
public async Task<IReadOnlyList<(ContentPackage, FluentResults.Result)>> LoadPackagesInfosAsync(IReadOnlyList<ContentPackage> packages)
|
||||
{
|
||||
((IService)this).CheckDisposed();
|
||||
if (packages is null || packages.Count == 0)
|
||||
throw new ArgumentNullException(nameof(LoadPackagesInfosAsync));
|
||||
ConcurrentQueue<(ContentPackage, FluentResults.Result)> results = new();
|
||||
await packages.ParallelForEachAsync(async package =>
|
||||
{
|
||||
var res = await LoadPackageInfosAsync(package);
|
||||
results.Enqueue((package, res));
|
||||
}, Environment.ProcessorCount);
|
||||
return results.ToImmutableArray();
|
||||
throw new System.NotImplementedException();
|
||||
}
|
||||
|
||||
public IReadOnlyList<ContentPackage> GetAllLoadedPackages()
|
||||
{
|
||||
((IService)this).CheckDisposed();
|
||||
return _modInfos.IsEmpty ? ImmutableArray<ContentPackage>.Empty
|
||||
: _modInfos.Select(kvp => kvp.Key).ToImmutableArray();
|
||||
throw new System.NotImplementedException();
|
||||
}
|
||||
|
||||
public bool IsPackageLoaded(ContentPackage package)
|
||||
{
|
||||
return package is not null && _modInfos.ContainsKey(package);
|
||||
throw new System.NotImplementedException();
|
||||
}
|
||||
|
||||
public ImmutableArray<T> FilterUnloadableResources<T>(IReadOnlyList<T> resources, bool enabledPackagesOnly = false)
|
||||
where T : IResourceInfo, IResourceCultureInfo, IPackageDependenciesInfo
|
||||
public ImmutableArray<T> FilterUnloadableResources<T>(IReadOnlyList<T> resources, bool enabledPackagesOnly = false) where T : IResourceInfo
|
||||
{
|
||||
return resources
|
||||
.Where(r => r is not null)
|
||||
.Where(r => (r.SupportedTargets & ModUtils.Environment.CurrentTarget) > 0)
|
||||
.Where(r => (r.SupportedPlatforms & ModUtils.Environment.CurrentPlatform) > 0)
|
||||
.Where(r => !r.Dependencies.Any() || r.Dependencies.All(d =>
|
||||
d.Dependency.GetPackage() is {} p // cp is valid
|
||||
&& _modInfos.ContainsKey(p) // cp is parsed
|
||||
&& (!enabledPackagesOnly || _packageInfoLookupService.IsPackageEnabled(p)))) // cp is enabled
|
||||
.ToImmutableArray();
|
||||
throw new System.NotImplementedException();
|
||||
}
|
||||
|
||||
public void DisposePackageInfos(ContentPackage package)
|
||||
{
|
||||
_modInfos.TryRemove(package, out _);
|
||||
throw new System.NotImplementedException();
|
||||
}
|
||||
|
||||
public void DisposePackagesInfos(IReadOnlyList<ContentPackage> packages)
|
||||
{
|
||||
if (packages is null || packages.Count == 0)
|
||||
return;
|
||||
|
||||
foreach (var package in packages)
|
||||
{
|
||||
DisposePackageInfos(package);
|
||||
}
|
||||
}
|
||||
|
||||
public Result<IPackageDependency> GetPackageDependencyInfo(ContentPackage ownerPackage, string packageName,
|
||||
ulong steamWorkshopId)
|
||||
{
|
||||
((IService)this).CheckDisposed();
|
||||
|
||||
if (ownerPackage is null)
|
||||
return FluentResults.Result.Fail($"OwnerPackage is null.");
|
||||
var nameGood = !packageName.IsNullOrWhiteSpace();
|
||||
|
||||
if (!nameGood && steamWorkshopId == 0)
|
||||
FluentResults.Result.Fail($"PackageName and SteamId cannot both be invalid.");
|
||||
|
||||
IPackageInfo depInfo = null;
|
||||
|
||||
// complex key
|
||||
if (nameGood && steamWorkshopId != 0
|
||||
&& _packageInfoLookupService.Lookup(packageName, steamWorkshopId).GetAwaiter().GetResult() is
|
||||
{ IsSuccess: true, Value: {} dep1 })
|
||||
{
|
||||
depInfo = dep1;
|
||||
}
|
||||
// name key
|
||||
else if (nameGood && _packageInfoLookupService.Lookup(packageName).GetAwaiter().GetResult() is
|
||||
{ IsSuccess: true, Value: { } dep2 })
|
||||
{
|
||||
depInfo = dep2;
|
||||
}
|
||||
// steamid key
|
||||
else if (_packageInfoLookupService.Lookup(steamWorkshopId).GetAwaiter().GetResult() is
|
||||
{ IsSuccess: true, Value: { } dep3 })
|
||||
{
|
||||
depInfo = dep3;
|
||||
}
|
||||
// this should never be null so we return an exception
|
||||
else
|
||||
{
|
||||
return FluentResults.Result.Fail($"Package Dependency for {ownerPackage.Name} was not found.");
|
||||
}
|
||||
|
||||
return FluentResults.Result.Ok<IPackageDependency>(new PackageDependency(ownerPackage, depInfo, ownerPackage.Name));
|
||||
throw new System.NotImplementedException();
|
||||
}
|
||||
|
||||
public Result<IAssembliesResourcesInfo> GetAssembliesInfos(ContentPackage package, bool onlySupportedResources = true)
|
||||
{
|
||||
((IService)this).CheckDisposed();
|
||||
if (package is null)
|
||||
return FluentResults.Result.Fail($"{nameof(GetAssembliesInfos)}: ContentPackage is null.");
|
||||
if (_modInfos.TryGetValue(package, out var result))
|
||||
return FluentResults.Result.Ok<IAssembliesResourcesInfo>(_assemblyInfoConverter.Process(onlySupportedResources?
|
||||
result.Assemblies.Where(r =>
|
||||
(r.SupportedPlatforms & ModUtils.Environment.CurrentPlatform) > 0
|
||||
&& (r.SupportedTargets & ModUtils.Environment.CurrentTarget) > 0).ToImmutableArray()
|
||||
: result.Assemblies
|
||||
));
|
||||
return FluentResults.Result.Fail(
|
||||
$"{nameof(GetAssembliesInfos)}: ContentPackage {package.Name} is not registered.");
|
||||
throw new System.NotImplementedException();
|
||||
}
|
||||
|
||||
public Result<IConfigsResourcesInfo> GetConfigsInfos(ContentPackage package, bool onlySupportedResources = true)
|
||||
{
|
||||
((IService)this).CheckDisposed();
|
||||
if (package is null)
|
||||
return FluentResults.Result.Fail($"{nameof(GetConfigsInfos)}: ContentPackage is null.");
|
||||
|
||||
if (_modInfos.TryGetValue(package, out var result))
|
||||
{
|
||||
return FluentResults.Result.Ok<IConfigsResourcesInfo>(_configsInfoConverter.Process(onlySupportedResources?
|
||||
result.Configs.Where(r =>
|
||||
(r.SupportedPlatforms & ModUtils.Environment.CurrentPlatform) > 0
|
||||
&& (r.SupportedTargets & ModUtils.Environment.CurrentTarget) > 0).ToImmutableArray()
|
||||
: result.Configs
|
||||
));
|
||||
}
|
||||
|
||||
return FluentResults.Result.Fail(
|
||||
$"{nameof(GetConfigsInfos)}: ContentPackage {package.Name} is not registered.");
|
||||
throw new System.NotImplementedException();
|
||||
}
|
||||
|
||||
public Result<IConfigProfilesResourcesInfo> GetConfigProfilesInfos(ContentPackage package, bool onlySupportedResources = true)
|
||||
{
|
||||
((IService)this).CheckDisposed();
|
||||
if (package is null)
|
||||
return FluentResults.Result.Fail($"{nameof(GetConfigProfilesInfos)}: ContentPackage is null.");
|
||||
|
||||
if (_modInfos.TryGetValue(package, out var result))
|
||||
{
|
||||
return FluentResults.Result.Ok<IConfigProfilesResourcesInfo>(_configProfilesConverter.Process(onlySupportedResources?
|
||||
result.ConfigProfiles.Where(r =>
|
||||
(r.SupportedPlatforms & ModUtils.Environment.CurrentPlatform) > 0
|
||||
&& (r.SupportedTargets & ModUtils.Environment.CurrentTarget) > 0).ToImmutableArray()
|
||||
: result.ConfigProfiles
|
||||
));
|
||||
}
|
||||
|
||||
return FluentResults.Result.Fail(
|
||||
$"{nameof(GetConfigProfilesInfos)}: ContentPackage {package.Name} is not registered.");
|
||||
throw new System.NotImplementedException();
|
||||
}
|
||||
|
||||
public Result<ILuaScriptsResourcesInfo> GetLuaScriptsInfos(ContentPackage package, bool onlySupportedResources = true)
|
||||
{
|
||||
((IService)this).CheckDisposed();
|
||||
if (package is null)
|
||||
return FluentResults.Result.Fail($"{nameof(GetLuaScriptsInfos)}: ContentPackage is null.");
|
||||
|
||||
if (_modInfos.TryGetValue(package, out var result))
|
||||
{
|
||||
return FluentResults.Result.Ok<ILuaScriptsResourcesInfo>(_luaScriptsConverter.Process(onlySupportedResources?
|
||||
result.LuaScripts.Where(r =>
|
||||
(r.SupportedPlatforms & ModUtils.Environment.CurrentPlatform) > 0
|
||||
&& (r.SupportedTargets & ModUtils.Environment.CurrentTarget) > 0).ToImmutableArray()
|
||||
: result.LuaScripts
|
||||
));
|
||||
}
|
||||
|
||||
return FluentResults.Result.Fail(
|
||||
$"{nameof(GetLuaScriptsInfos)}: ContentPackage {package.Name} is not registered.");
|
||||
throw new System.NotImplementedException();
|
||||
}
|
||||
|
||||
public Result<IAssembliesResourcesInfo> GetAssembliesInfos(IReadOnlyList<ContentPackage> packages, bool onlySupportedResources = true)
|
||||
{
|
||||
((IService)this).CheckDisposed();
|
||||
if (packages is null || packages.Count == 0)
|
||||
return FluentResults.Result.Fail($"{nameof(GetAssembliesInfos)}: ContentPackage list is null or empty.");
|
||||
var builder = ImmutableArray.CreateBuilder<IAssemblyResourceInfo>();
|
||||
foreach (var package in packages)
|
||||
{
|
||||
if (_modInfos.TryGetValue(package, out var result) && result.Assemblies is { IsEmpty: false })
|
||||
{
|
||||
builder.AddRange(onlySupportedResources?
|
||||
result.Assemblies.Where(r =>
|
||||
(r.SupportedPlatforms & ModUtils.Environment.CurrentPlatform) > 0
|
||||
&& (r.SupportedTargets & ModUtils.Environment.CurrentTarget) > 0).ToImmutableArray()
|
||||
: result.Assemblies);
|
||||
}
|
||||
}
|
||||
|
||||
return FluentResults.Result.Ok(_assemblyInfoConverter.Process(builder.MoveToImmutable()));
|
||||
throw new System.NotImplementedException();
|
||||
}
|
||||
|
||||
public Result<IConfigsResourcesInfo> GetConfigsInfos(IReadOnlyList<ContentPackage> packages, bool onlySupportedResources = true)
|
||||
{
|
||||
((IService)this).CheckDisposed();
|
||||
if (packages is null || packages.Count == 0)
|
||||
return FluentResults.Result.Fail($"{nameof(GetConfigsInfos)}: ContentPackage list is null or empty.");
|
||||
var builder = ImmutableArray.CreateBuilder<IConfigResourceInfo>();
|
||||
foreach (var package in packages)
|
||||
{
|
||||
if (_modInfos.TryGetValue(package, out var result) && result.Configs is { IsEmpty: false })
|
||||
{
|
||||
builder.AddRange(onlySupportedResources?
|
||||
result.Configs.Where(r =>
|
||||
(r.SupportedPlatforms & ModUtils.Environment.CurrentPlatform) > 0
|
||||
&& (r.SupportedTargets & ModUtils.Environment.CurrentTarget) > 0).ToImmutableArray()
|
||||
: result.Configs);
|
||||
}
|
||||
}
|
||||
|
||||
return FluentResults.Result.Ok(_configsInfoConverter.Process(builder.MoveToImmutable()));
|
||||
throw new System.NotImplementedException();
|
||||
}
|
||||
|
||||
public Result<IConfigProfilesResourcesInfo> GetConfigProfilesInfos(IReadOnlyList<ContentPackage> packages, bool onlySupportedResources = true)
|
||||
{
|
||||
((IService)this).CheckDisposed();
|
||||
if (packages is null || packages.Count == 0)
|
||||
return FluentResults.Result.Fail($"{nameof(GetConfigProfilesInfos)}: ContentPackage list is null or empty.");
|
||||
var builder = ImmutableArray.CreateBuilder<IConfigProfileResourceInfo>();
|
||||
foreach (var package in packages)
|
||||
{
|
||||
if (_modInfos.TryGetValue(package, out var result) && result.ConfigProfiles is { IsEmpty: false })
|
||||
{
|
||||
builder.AddRange(onlySupportedResources?
|
||||
result.ConfigProfiles.Where(r =>
|
||||
(r.SupportedPlatforms & ModUtils.Environment.CurrentPlatform) > 0
|
||||
&& (r.SupportedTargets & ModUtils.Environment.CurrentTarget) > 0).ToImmutableArray()
|
||||
: result.ConfigProfiles);
|
||||
}
|
||||
}
|
||||
|
||||
return FluentResults.Result.Ok(_configProfilesConverter.Process(builder.MoveToImmutable()));
|
||||
throw new System.NotImplementedException();
|
||||
}
|
||||
|
||||
public Result<ILuaScriptsResourcesInfo> GetLuaScriptsInfos(IReadOnlyList<ContentPackage> packages, bool onlySupportedResources = true)
|
||||
{
|
||||
((IService)this).CheckDisposed();
|
||||
if (packages is null || packages.Count == 0)
|
||||
return FluentResults.Result.Fail($"{nameof(GetLuaScriptsInfos)}: ContentPackage list is null or empty.");
|
||||
var builder = ImmutableArray.CreateBuilder<ILuaScriptResourceInfo>();
|
||||
foreach (var package in packages)
|
||||
{
|
||||
if (_modInfos.TryGetValue(package, out var result) && result.LuaScripts is { IsEmpty: false })
|
||||
{
|
||||
builder.AddRange(onlySupportedResources?
|
||||
result.LuaScripts.Where(r =>
|
||||
(r.SupportedPlatforms & ModUtils.Environment.CurrentPlatform) > 0
|
||||
&& (r.SupportedTargets & ModUtils.Environment.CurrentTarget) > 0).ToImmutableArray()
|
||||
: result.LuaScripts);
|
||||
}
|
||||
}
|
||||
|
||||
return FluentResults.Result.Ok(_luaScriptsConverter.Process(builder.MoveToImmutable()));
|
||||
throw new System.NotImplementedException();
|
||||
}
|
||||
|
||||
public async Task<Result<IAssembliesResourcesInfo>> GetAssembliesInfosAsync(IReadOnlyList<ContentPackage> packages, bool onlySupportedResources = true)
|
||||
{
|
||||
return await Task.Run(() => GetAssembliesInfos(packages, onlySupportedResources));
|
||||
throw new System.NotImplementedException();
|
||||
}
|
||||
|
||||
public async Task<Result<IConfigsResourcesInfo>> GetConfigsInfosAsync(IReadOnlyList<ContentPackage> packages, bool onlySupportedResources = true)
|
||||
{
|
||||
return await Task.Run(() => GetConfigsInfos(packages, onlySupportedResources));
|
||||
throw new System.NotImplementedException();
|
||||
}
|
||||
|
||||
public async Task<Result<IConfigProfilesResourcesInfo>> GetConfigProfilesInfosAsync(IReadOnlyList<ContentPackage> packages, bool onlySupportedResources = true)
|
||||
{
|
||||
return await Task.Run(() => GetConfigProfilesInfos(packages, onlySupportedResources));
|
||||
throw new System.NotImplementedException();
|
||||
}
|
||||
|
||||
public async Task<Result<ILuaScriptsResourcesInfo>> GetLuaScriptsInfosAsync(IReadOnlyList<ContentPackage> packages, bool onlySupportedResources = true)
|
||||
{
|
||||
return await Task.Run(() => GetLuaScriptsInfos(packages, onlySupportedResources));
|
||||
throw new System.NotImplementedException();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -92,25 +92,20 @@ public partial class ModConfigService : IConverterServiceAsync<ContentPackage, I
|
||||
|
||||
foreach (var file in xmlFiles)
|
||||
{
|
||||
// get dependencies
|
||||
var deps = GetElementsDependenciesData(file.Item1, src);
|
||||
// get platform, culture and target architecture
|
||||
var info = GetElementsAttributesData(file.Item1, file.Item2.First());
|
||||
|
||||
builder.Add(new AssemblyResourceInfo()
|
||||
{
|
||||
Dependencies = deps,
|
||||
Optional = info.IsOptional,
|
||||
FilePaths = file.Item2,
|
||||
InternalName = info.Name,
|
||||
LoadPriority = info.LoadPriority,
|
||||
OwnerPackage = src,
|
||||
SupportedCultures = info.SupportedCultures,
|
||||
SupportedPlatforms = info.SupportedPlatforms,
|
||||
SupportedTargets = info.SupportedTargets,
|
||||
FriendlyName = file.Item1.GetAttributeString("Name", info.Name),
|
||||
IsScript = false,
|
||||
LazyLoad = !file.Item1.GetAttributeBool("RunFile", true)
|
||||
IsScript = false
|
||||
});
|
||||
}
|
||||
|
||||
@@ -120,25 +115,20 @@ public partial class ModConfigService : IConverterServiceAsync<ContentPackage, I
|
||||
|
||||
foreach (var file in xmlFiles2)
|
||||
{
|
||||
// get dependencies
|
||||
var deps = GetElementsDependenciesData(file.Item1, src);
|
||||
// get platform, culture and target architecture
|
||||
var info = GetElementsAttributesData(file.Item1, file.Item2.First());
|
||||
|
||||
builder.Add(new AssemblyResourceInfo()
|
||||
{
|
||||
Dependencies = deps,
|
||||
Optional = info.IsOptional,
|
||||
FilePaths = file.Item2,
|
||||
InternalName = info.Name,
|
||||
LoadPriority = info.LoadPriority,
|
||||
OwnerPackage = src,
|
||||
SupportedCultures = info.SupportedCultures,
|
||||
SupportedPlatforms = info.SupportedPlatforms,
|
||||
SupportedTargets = info.SupportedTargets,
|
||||
FriendlyName = file.Item1.GetAttributeString("Name", info.Name),
|
||||
IsScript = true,
|
||||
LazyLoad = !file.Item1.GetAttributeBool("RunFile", true)
|
||||
IsScript = true
|
||||
});
|
||||
}
|
||||
|
||||
@@ -156,20 +146,16 @@ public partial class ModConfigService : IConverterServiceAsync<ContentPackage, I
|
||||
|
||||
foreach (var file in xmlFiles)
|
||||
{
|
||||
// get dependencies
|
||||
var deps = GetElementsDependenciesData(file.Item1, src);
|
||||
// get platform, culture and target architecture
|
||||
var info = GetElementsAttributesData(file.Item1, file.Item2.First());
|
||||
|
||||
builder.Add(new ConfigResourceInfo()
|
||||
{
|
||||
Dependencies = deps,
|
||||
Optional = info.IsOptional,
|
||||
FilePaths = file.Item2,
|
||||
InternalName = info.Name,
|
||||
LoadPriority = info.LoadPriority,
|
||||
OwnerPackage = src,
|
||||
SupportedCultures = info.SupportedCultures,
|
||||
SupportedPlatforms = info.SupportedPlatforms,
|
||||
SupportedTargets = info.SupportedTargets
|
||||
});
|
||||
@@ -189,20 +175,16 @@ public partial class ModConfigService : IConverterServiceAsync<ContentPackage, I
|
||||
|
||||
foreach (var file in xmlFiles)
|
||||
{
|
||||
// get dependencies
|
||||
var deps = GetElementsDependenciesData(file.Item1, src);
|
||||
// get platform, culture and target architecture
|
||||
var info = GetElementsAttributesData(file.Item1, file.Item2.First());
|
||||
|
||||
builder.Add(new ConfigProfileResourceInfo()
|
||||
{
|
||||
Dependencies = deps,
|
||||
Optional = info.IsOptional,
|
||||
FilePaths = file.Item2,
|
||||
InternalName = info.Name,
|
||||
LoadPriority = info.LoadPriority,
|
||||
OwnerPackage = src,
|
||||
SupportedCultures = info.SupportedCultures,
|
||||
SupportedPlatforms = info.SupportedPlatforms,
|
||||
SupportedTargets = info.SupportedTargets
|
||||
});
|
||||
@@ -222,20 +204,16 @@ public partial class ModConfigService : IConverterServiceAsync<ContentPackage, I
|
||||
|
||||
foreach (var file in xmlFiles)
|
||||
{
|
||||
// get dependencies
|
||||
var deps = GetElementsDependenciesData(file.Item1, src);
|
||||
// get platform, culture and target architecture
|
||||
var info = GetElementsAttributesData(file.Item1, file.Item2.First());
|
||||
|
||||
builder.Add(new LuaScriptsResourceInfo()
|
||||
{
|
||||
Dependencies = deps,
|
||||
Optional = info.IsOptional,
|
||||
FilePaths = file.Item2,
|
||||
InternalName = info.Name,
|
||||
LoadPriority = info.LoadPriority,
|
||||
OwnerPackage = src,
|
||||
SupportedCultures = info.SupportedCultures,
|
||||
SupportedPlatforms = info.SupportedPlatforms,
|
||||
SupportedTargets = info.SupportedTargets,
|
||||
IsAutorun = file.Item1.GetAttributeBool("RunFile", true)
|
||||
@@ -348,30 +326,6 @@ public partial class ModConfigService : IConverterServiceAsync<ContentPackage, I
|
||||
: new[] { CultureInfo.InvariantCulture }.ToImmutableArray();
|
||||
}
|
||||
}
|
||||
|
||||
private ImmutableArray<IPackageDependency> GetElementsDependenciesData(XElement element, ContentPackage src)
|
||||
{
|
||||
if (element.GetChildElement("Dependencies") is not {} dependencies
|
||||
|| dependencies.GetChildElements("Dependency").ToImmutableArray() is not { Length: >0 } depsList)
|
||||
return ImmutableArray<IPackageDependency>.Empty;
|
||||
var builder = ImmutableArray.CreateBuilder<IPackageDependency>();
|
||||
foreach (var dep in depsList)
|
||||
{
|
||||
var packName = dep.GetAttributeString("PackageName", string.Empty);
|
||||
var packId = dep.GetAttributeUInt64("PackageId", 0);
|
||||
|
||||
// invalid entry
|
||||
if (packName.IsNullOrWhiteSpace() && packId == 0)
|
||||
continue;
|
||||
|
||||
if (_packageManagementService.Value.GetPackageDependencyInfo(src, packName, packId) is
|
||||
{ IsSuccess: true, Value: { } depsInfo })
|
||||
{
|
||||
builder.Add(depsInfo);
|
||||
}
|
||||
}
|
||||
return builder.ToImmutable();
|
||||
}
|
||||
|
||||
private ImmutableArray<IAssemblyResourceInfo> GetAssembliesLegacy(ContentPackage src)
|
||||
{
|
||||
@@ -382,16 +336,13 @@ public partial class ModConfigService : IConverterServiceAsync<ContentPackage, I
|
||||
{
|
||||
builder.Add(new AssemblyResourceInfo()
|
||||
{
|
||||
Dependencies = ImmutableArray<IPackageDependency>.Empty,
|
||||
FilePaths = filesSrvLin,
|
||||
FriendlyName = "AssembliesServerLinux",
|
||||
InternalName = "AssembliesServerLinux",
|
||||
IsScript = false,
|
||||
LazyLoad = false,
|
||||
LoadPriority = 1,
|
||||
Optional = false,
|
||||
OwnerPackage = src,
|
||||
SupportedCultures = new CultureInfo[]{ CultureInfo.InvariantCulture }.ToImmutableArray(),
|
||||
SupportedPlatforms = Platform.Linux,
|
||||
SupportedTargets = Target.Server
|
||||
});
|
||||
@@ -403,16 +354,13 @@ public partial class ModConfigService : IConverterServiceAsync<ContentPackage, I
|
||||
{
|
||||
builder.Add(new AssemblyResourceInfo()
|
||||
{
|
||||
Dependencies = ImmutableArray<IPackageDependency>.Empty,
|
||||
FilePaths = filesSrvOsx,
|
||||
FriendlyName = "AssembliesServerOSX",
|
||||
InternalName = "AssembliesServerOSX",
|
||||
IsScript = false,
|
||||
LazyLoad = false,
|
||||
LoadPriority = 1,
|
||||
Optional = false,
|
||||
OwnerPackage = src,
|
||||
SupportedCultures = new CultureInfo[]{ CultureInfo.InvariantCulture }.ToImmutableArray(),
|
||||
SupportedPlatforms = Platform.OSX,
|
||||
SupportedTargets = Target.Server
|
||||
});
|
||||
@@ -424,16 +372,13 @@ public partial class ModConfigService : IConverterServiceAsync<ContentPackage, I
|
||||
{
|
||||
builder.Add(new AssemblyResourceInfo()
|
||||
{
|
||||
Dependencies = ImmutableArray<IPackageDependency>.Empty,
|
||||
FilePaths = filesSrvWin,
|
||||
FriendlyName = "AssembliesServerWin",
|
||||
InternalName = "AssembliesServerWin",
|
||||
IsScript = false,
|
||||
LazyLoad = false,
|
||||
LoadPriority = 1,
|
||||
Optional = false,
|
||||
OwnerPackage = src,
|
||||
SupportedCultures = new CultureInfo[]{ CultureInfo.InvariantCulture }.ToImmutableArray(),
|
||||
SupportedPlatforms = Platform.Windows,
|
||||
SupportedTargets = Target.Server
|
||||
});
|
||||
@@ -445,16 +390,13 @@ public partial class ModConfigService : IConverterServiceAsync<ContentPackage, I
|
||||
{
|
||||
builder.Add(new AssemblyResourceInfo()
|
||||
{
|
||||
Dependencies = ImmutableArray<IPackageDependency>.Empty,
|
||||
FilePaths = filesCliLin,
|
||||
FriendlyName = "AssembliesClientLinux",
|
||||
InternalName = "AssembliesClientLinux",
|
||||
IsScript = false,
|
||||
LazyLoad = false,
|
||||
LoadPriority = 1,
|
||||
Optional = false,
|
||||
OwnerPackage = src,
|
||||
SupportedCultures = new CultureInfo[]{ CultureInfo.InvariantCulture }.ToImmutableArray(),
|
||||
SupportedPlatforms = Platform.Linux,
|
||||
SupportedTargets = Target.Client
|
||||
});
|
||||
@@ -466,16 +408,13 @@ public partial class ModConfigService : IConverterServiceAsync<ContentPackage, I
|
||||
{
|
||||
builder.Add(new AssemblyResourceInfo()
|
||||
{
|
||||
Dependencies = ImmutableArray<IPackageDependency>.Empty,
|
||||
FilePaths = filesCliOsx,
|
||||
FriendlyName = "AssembliesClientOSX",
|
||||
InternalName = "AssembliesClientOSX",
|
||||
IsScript = false,
|
||||
LazyLoad = false,
|
||||
LoadPriority = 1,
|
||||
Optional = false,
|
||||
OwnerPackage = src,
|
||||
SupportedCultures = new CultureInfo[]{ CultureInfo.InvariantCulture }.ToImmutableArray(),
|
||||
SupportedPlatforms = Platform.OSX,
|
||||
SupportedTargets = Target.Client
|
||||
});
|
||||
@@ -487,16 +426,13 @@ public partial class ModConfigService : IConverterServiceAsync<ContentPackage, I
|
||||
{
|
||||
builder.Add(new AssemblyResourceInfo()
|
||||
{
|
||||
Dependencies = ImmutableArray<IPackageDependency>.Empty,
|
||||
FilePaths = filesCliWin,
|
||||
FriendlyName = "AssembliesClientWin",
|
||||
InternalName = "AssembliesClientWin",
|
||||
IsScript = false,
|
||||
LazyLoad = false,
|
||||
LoadPriority = 1,
|
||||
Optional = false,
|
||||
OwnerPackage = src,
|
||||
SupportedCultures = new CultureInfo[]{ CultureInfo.InvariantCulture }.ToImmutableArray(),
|
||||
SupportedPlatforms = Platform.Windows,
|
||||
SupportedTargets = Target.Client
|
||||
});
|
||||
@@ -518,16 +454,13 @@ public partial class ModConfigService : IConverterServiceAsync<ContentPackage, I
|
||||
{
|
||||
builder.Add(new AssemblyResourceInfo()
|
||||
{
|
||||
Dependencies = ImmutableArray<IPackageDependency>.Empty,
|
||||
FilePaths = sharedFound ? filesCssServer.Concat(filesCssShared).ToImmutableArray() : filesCssServer,
|
||||
FriendlyName = "CssServer",
|
||||
InternalName = "CssServer",
|
||||
IsScript = true,
|
||||
LazyLoad = false,
|
||||
LoadPriority = 1,
|
||||
Optional = false,
|
||||
OwnerPackage = src,
|
||||
SupportedCultures = new CultureInfo[]{ CultureInfo.InvariantCulture }.ToImmutableArray(),
|
||||
SupportedPlatforms = Platform.Linux | Platform.OSX | Platform.Windows,
|
||||
SupportedTargets = Target.Server
|
||||
});
|
||||
@@ -539,16 +472,13 @@ public partial class ModConfigService : IConverterServiceAsync<ContentPackage, I
|
||||
{
|
||||
builder.Add(new AssemblyResourceInfo()
|
||||
{
|
||||
Dependencies = ImmutableArray<IPackageDependency>.Empty,
|
||||
FilePaths = sharedFound ? filesCssClient.Concat(filesCssShared).ToImmutableArray() : filesCssClient,
|
||||
FriendlyName = "CssClient",
|
||||
InternalName = "CssClient",
|
||||
IsScript = true,
|
||||
LazyLoad = false,
|
||||
LoadPriority = 1,
|
||||
Optional = false,
|
||||
OwnerPackage = src,
|
||||
SupportedCultures = new CultureInfo[]{ CultureInfo.InvariantCulture }.ToImmutableArray(),
|
||||
SupportedPlatforms = Platform.Linux | Platform.OSX | Platform.Windows,
|
||||
SupportedTargets = Target.Client
|
||||
});
|
||||
@@ -565,26 +495,22 @@ public partial class ModConfigService : IConverterServiceAsync<ContentPackage, I
|
||||
{
|
||||
builder.Add(new LuaScriptsResourceInfo()
|
||||
{
|
||||
Dependencies = ImmutableArray<IPackageDependency>.Empty,
|
||||
FilePaths = fileAll.Where(path => !path.Contains("Autorun")).ToImmutableArray(),
|
||||
InternalName = "LuaScriptsNormal",
|
||||
Optional = false,
|
||||
IsAutorun = false,
|
||||
OwnerPackage = src,
|
||||
SupportedCultures = new CultureInfo[]{ CultureInfo.InvariantCulture }.ToImmutableArray(),
|
||||
SupportedPlatforms = Platform.Linux | Platform.OSX | Platform.Windows,
|
||||
SupportedTargets = Target.Client | Target.Server
|
||||
});
|
||||
|
||||
builder.Add(new LuaScriptsResourceInfo()
|
||||
{
|
||||
Dependencies = ImmutableArray<IPackageDependency>.Empty,
|
||||
FilePaths = fileAll.Where(path => path.Contains("Autorun")).ToImmutableArray(),
|
||||
InternalName = "LuaScriptsAutorun",
|
||||
Optional = false,
|
||||
IsAutorun = true,
|
||||
OwnerPackage = src,
|
||||
SupportedCultures = new CultureInfo[]{ CultureInfo.InvariantCulture }.ToImmutableArray(),
|
||||
SupportedPlatforms = Platform.Linux | Platform.OSX | Platform.Windows,
|
||||
SupportedTargets = Target.Client | Target.Server
|
||||
});
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Threading.Tasks;
|
||||
using Barotrauma.LuaCs.Data;
|
||||
using Barotrauma.LuaCs.Events;
|
||||
|
||||
namespace Barotrauma.LuaCs.Services;
|
||||
|
||||
public interface IPackageInfoLookupService : IReusableService
|
||||
{
|
||||
bool IsPackageEnabled(ContentPackage package);
|
||||
Task<FluentResults.Result<IPackageInfo>> Lookup(string packageName);
|
||||
Task<FluentResults.Result<IPackageInfo>> Lookup(string packageName, ulong steamWorkshopId);
|
||||
Task<FluentResults.Result<IPackageInfo>> Lookup(ulong steamWorkshopId);
|
||||
Task<FluentResults.Result<IPackageInfo>> Lookup(ContentPackage package);
|
||||
void RefreshPackageLists();
|
||||
}
|
||||
@@ -39,10 +39,9 @@ public interface IPackageManagementService : IReusableService, IConfigsResources
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <returns></returns>
|
||||
ImmutableArray<T> FilterUnloadableResources<T>(IReadOnlyList<T> resources, bool enabledPackagesOnly = false)
|
||||
where T : IResourceInfo, IResourceCultureInfo, IPackageDependenciesInfo;
|
||||
where T : IResourceInfo;
|
||||
void DisposePackageInfos(ContentPackage package);
|
||||
void DisposePackagesInfos(IReadOnlyList<ContentPackage> packages);
|
||||
FluentResults.Result<IPackageDependency> GetPackageDependencyInfo(ContentPackage ownerPackage, string packageName, ulong steamWorkshopId);
|
||||
|
||||
// single
|
||||
FluentResults.Result<IAssembliesResourcesInfo> GetAssembliesInfos(ContentPackage package, bool onlySupportedResources = true);
|
||||
|
||||
Reference in New Issue
Block a user