- Deleted unused service IPackageListRetrievalService.cs

- Added caching function to LuaScriptLoader.cs
- Added sample async code to LuaScriptManagementService.cs
- Removed most of the State functions in LuaCsSetup.cs (requires rewrite).
- Fixed CsEnabled check.
- Moved IsRunningWorkshop check to client-only project.
This commit is contained in:
MapleWheels
2026-01-14 08:50:09 -05:00
committed by Maplewheels
parent 0bfceacaf3
commit 055a508901
10 changed files with 94 additions and 295 deletions
@@ -25,16 +25,7 @@ namespace Barotrauma
public void CheckCsEnabled() public void CheckCsEnabled()
{ {
throw new NotImplementedException($"Replace PMS.Assemblies with checks on ContentPackageManager.EnabledPackages"); var csharpMods = PackageManagementService.GetLoadedAssemblyPackages();
/*var csharpMods = PackageManagementService.Assemblies
.GroupBy(ass => ass.OwnerPackage)
.Select(grp => grp.Key)
.Where(ContentPackageManager.EnabledPackages.All.Contains)
.ToImmutableArray();
if (!csharpMods.Any())
return;
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
@@ -67,7 +58,7 @@ namespace Barotrauma
{ {
this.IsCsEnabled.TrySetValue(false); this.IsCsEnabled.TrySetValue(false);
return true; return true;
};*/ };
} }
/// <summary> /// <summary>
@@ -1,4 +1,6 @@
using Barotrauma.Networking; using System;
using System.IO;
using Barotrauma.Networking;
namespace Barotrauma; namespace Barotrauma;
@@ -19,4 +21,10 @@ partial class LuaCsSetup
private partial bool ShouldRunCs() => IsCsEnabled.Value || private partial bool ShouldRunCs() => IsCsEnabled.Value ||
(GetPackage(new SteamWorkshopId(CsForBarotraumaSteamId.Value), false, false) is { } (GetPackage(new SteamWorkshopId(CsForBarotraumaSteamId.Value), false, false) is { }
&& GameMain.Server.ServerPeer is LidgrenServerPeer); && GameMain.Server.ServerPeer is LidgrenServerPeer);
// ReSharper disable once InconsistentNaming
private static readonly Lazy<bool> isRunningInsideWorkshop = new Lazy<bool>(() =>
Path.GetDirectoryName(System.Reflection.Assembly.GetEntryAssembly()!.Location) !=
Directory.GetCurrentDirectory());
public static bool IsRunningInsideWorkshop => isRunningInsideWorkshop.Value;
} }
@@ -16,6 +16,7 @@ using Barotrauma.LuaCs.Services.Safe;
using Barotrauma.Networking; using Barotrauma.Networking;
using FluentResults; using FluentResults;
using ImpromptuInterface; using ImpromptuInterface;
using Microsoft.Toolkit.Diagnostics;
namespace Barotrauma namespace Barotrauma
{ {
@@ -39,7 +40,6 @@ namespace Barotrauma
// == sub processes // == sub processes
void RegisterServices() void RegisterServices()
{ {
_servicesProvider.RegisterServiceType<IPackageListRetrievalService, PackageListRetrievalService>(ServiceLifetime.Transient);
_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);
@@ -195,17 +195,6 @@ namespace Barotrauma
#endregion #endregion
public static bool IsRunningInsideWorkshop
{
get
{
#if SERVER
return Path.GetDirectoryName(System.Reflection.Assembly.GetEntryAssembly().Location) != Directory.GetCurrentDirectory();
#else
return false; // unnecessary but just keeps things clear that this is NOT for client stuff
#endif
}
}
private partial bool ShouldRunCs(); private partial bool ShouldRunCs();
@@ -329,6 +318,8 @@ namespace Barotrauma
private void UpdateLoadedPackagesList() private void UpdateLoadedPackagesList()
{ {
throw new NotImplementedException($"Rewrite the loading state system.");
var newPackSet = ContentPackageManager.AllPackages var newPackSet = ContentPackageManager.AllPackages
.Union(ContentPackageManager.EnabledPackages.All) .Union(ContentPackageManager.EnabledPackages.All)
.ToHashSet(); .ToHashSet();
@@ -340,10 +331,10 @@ namespace Barotrauma
foreach (var package in toRemove) foreach (var package in toRemove)
_toUnload.Enqueue(package); _toUnload.Enqueue(package);
ProcessPackagesListDifferences(); //ProcessPackagesListDifferences();
} }
void ProcessPackagesListDifferences() /*void ProcessPackagesListDifferences()
{ {
if (IsCodeRunning) if (IsCodeRunning)
return; return;
@@ -379,13 +370,13 @@ namespace Barotrauma
{ {
LoadStaticAssetsAsync(ls).GetAwaiter().GetResult(); LoadStaticAssetsAsync(ls).GetAwaiter().GetResult();
} }
} }*/
void SetRunState(RunState runState) void SetRunState(RunState runState)
{ {
if (CurrentRunState == runState) if (CurrentRunState == runState)
return; return;
if (runState > CurrentRunState) /*if (runState > CurrentRunState)
{ {
if (CurrentRunState <= RunState.Parsed) if (CurrentRunState <= RunState.Parsed)
{ {
@@ -444,58 +435,7 @@ namespace Barotrauma
} }
// we should be unloaded completely now | RunState.Unloaded // we should be unloaded completely now | RunState.Unloaded
} }*/
}
void LoadCurrentContentPackageInfos()
{
if (CurrentRunState >= RunState.Parsed)
return;
// load core
var result1 = PackageManagementService.LoadPackageInfo(ContentPackageManager.VanillaCorePackage);
if (result1.IsFailed)
{
Logger.LogError($"Unable to load LuaCs CorePackage resources! Running in degraded mode.");
Logger.LogResults(result1);
}
// load regular
var list = ContentPackageManager.RegularPackages
.Union(ContentPackageManager.EnabledPackages.All)
.ToImmutableList();
LoadContentPackagesInfos(list);
if (CurrentRunState < RunState.Parsed)
_runState = RunState.Parsed;
}
void LoadContentPackagesInfos(IReadOnlyList<ContentPackage> packages)
{
var result2 = PackageManagementService.LoadPackagesInfo([..packages]);
if (result2.IsFailed)
Logger.LogResults(result2);
}
void LoadStaticAssets()
{
if (CurrentRunState < RunState.Parsed)
{
throw new InvalidOperationException($"{nameof(LoadStaticAssets)} cannot load assets in the '{CurrentRunState}' state.");
}
if (CurrentRunState >= RunState.Configuration)
return;
while (_toUnload.TryDequeue(out var cp))
PackageManagementService.UnloadPackage(cp);
LoadStaticAssetsAsync(PackageManagementService.GetAllLoadedPackages()).GetAwaiter().GetResult();
LoadLuaCsConfig();
if (CurrentRunState < RunState.Configuration)
_runState = RunState.Configuration;
} }
void LoadLuaCsConfig() void LoadLuaCsConfig()
@@ -530,172 +470,6 @@ namespace Barotrauma
ReloadPackagesOnLobbyStart = null; ReloadPackagesOnLobbyStart = null;
} }
async Task LoadStaticAssetsAsync(IReadOnlyList<ContentPackage> packages)
{
throw new NotImplementedException();
/*var cfgRes = ImmutableArray<IConfigResourceInfo>.Empty;
var luaRes = ImmutableArray<ILuaScriptResourceInfo>.Empty;
var tasksBuilder = ImmutableArray.CreateBuilder<Task>();
//---- get resource infos
tasksBuilder.AddRange(
new Func<Task>(async () =>
{
var res = await PackageManagementService.GetConfigsInfosAsync(packages);
if (res.IsSuccess)
cfgRes = res.Value.Configs;
if (res.Errors.Any())
ThreadPool.QueueUserWorkItem(state => Logger.LogResults((FluentResults.Result)state),
res.ToResult());
})(),
new Func<Task>(async () =>
{
var res = await PackageManagementService.GetLuaScriptsInfosAsync(packages);
if (res.IsSuccess)
luaRes = res.Value.LuaScripts;
if (res.Errors.Any())
ThreadPool.QueueUserWorkItem(state => Logger.LogResults((FluentResults.Result)state),
res.ToResult());
})());
await Task.WhenAll(tasksBuilder.MoveToImmutable());
tasksBuilder.Clear();
//---- load resources
tasksBuilder.AddRange(new Func<Task>(async () =>
{
var res = await ConfigService.LoadConfigsAsync(cfgRes);
if (res.Errors.Any())
Logger.LogResults(res);
})(),
new Func<Task>(async () =>
{
var res = await LuaScriptManagementService.LoadScriptResourcesAsync(luaRes);
if (res.Errors.Any())
Logger.LogResults(res);
})());
await Task.WhenAll(tasksBuilder.MoveToImmutable());*/
}
void RunScripts()
{
/*if (!IsStaticAssetsLoaded)
{
throw new InvalidOperationException($"{nameof(RunScripts)} cannot load assets in the '{CurrentRunState}' state.");
}
if (CurrentRunState >= RunState.Running)
return;
if (ShouldRunCs())
{
var asmRes =
PackageManagementService.GetAssembliesInfos(PackageManagementService
.GetAllLoadedPackages()
.Where(ContentPackageManager.EnabledPackages.All.Contains)
.ToList());
if (asmRes.IsFailed)
{
Logger.LogError($"{nameof(RunScripts)}: Errors will retrieving assembly resources, cannot load scripts!");
Logger.LogResults(asmRes.ToResult());
return;
}
var res = PluginManagementService.LoadAssemblyResources(asmRes.Value.Assemblies);
if (res.IsFailed)
{
Logger.LogError($"{nameof(RunScripts)}: Failed to initialize scripts!");
Logger.LogResults(res.ToResult());
}
else
{
if (res.Errors.Any())
Logger.LogResults(res.ToResult());
if (PluginManagementService.GetImplementingTypes<IAssemblyPlugin>() is {IsSuccess: true} types)
{
var typeInst = PluginManagementService.ActivateTypeInstances<IAssemblyPlugin>(types.Value, true, true);
foreach (var loadRes in typeInst)
{
if (loadRes is { IsSuccess: true, Value: { Item2: { } pluginInstance } })
{
EventService.Subscribe<IEventPluginPreInitialize>(pluginInstance);
EventService.Subscribe<IEventPluginInitialize>(pluginInstance);
EventService.Subscribe<IEventPluginLoadCompleted>(pluginInstance);
}
else
{
Logger.LogResults(loadRes.ToResult());
}
}
EventService.PublishEvent<IEventPluginPreInitialize>(sub => sub.PreInitPatching());
EventService.PublishEvent<IEventPluginInitialize>(sub => sub.Initialize());
EventService.PublishEvent<IEventPluginLoadCompleted>(sub => sub.OnLoadCompleted());
}
}
}
//lua
var luaRes = PackageManagementService.LuaScripts
.Select(ls => ls.OwnerPackage)
.Where(p => p is not null)
.Where(ContentPackageManager.EnabledPackages.All.Contains)
.ToImmutableArray();
if (luaRes.IsDefaultOrEmpty)
{
Logger.LogError($"{nameof(RunScripts)}: Failed to get enabled lua script resources!");
return;
}
LuaScriptManagementService.ExecuteLoadedScripts();
if (CurrentRunState < RunState.Running)
_runState = RunState.Running;*/
}
void UnloadContentPackageInfos()
{
/*if (IsStaticAssetsLoaded)
{
throw new InvalidOperationException($"{nameof(UnloadStaticAssets)}: Cannot unload static assets when the current run state is {CurrentRunState}.");
}
PackageManagementService.Reset();
_toUnload.Clear();*/
}
void UnloadStaticAssets()
{
/*if (IsCodeRunning)
{
throw new InvalidOperationException($"{nameof(UnloadStaticAssets)}: Cannot unload static assets when the current run state is {CurrentRunState}.");
}
PluginManagementService.Reset();
LuaScriptManagementService.Reset();
ConfigService.Reset();
if (CurrentRunState >= RunState.Configuration)
{
_runState = RunState.Parsed;
}*/
}
void StopScripts()
{
/*EventService.ClearAllSubscribers();
LuaScriptManagementService.UnloadActiveScripts();
PluginManagementService.UnloadManagedAssemblies();
SubscribeToLuaCsEvents();
if (IsCodeRunning)
{
_runState = RunState.Configuration;
}*/
}
} }
@@ -23,6 +23,7 @@ using System.Reflection;
using System.Text; using System.Text;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.Toolkit.Diagnostics;
using static Barotrauma.GameSettings; using static Barotrauma.GameSettings;
namespace Barotrauma.LuaCs.Services; namespace Barotrauma.LuaCs.Services;
@@ -35,6 +36,8 @@ class LuaScriptManagementService : ILuaScriptManagementService, ILuaDataService
public bool IsRunning => _isRunning; public bool IsRunning => _isRunning;
private List<ILuaScriptResourceInfo> _resourcesInfo = new List<ILuaScriptResourceInfo>(); private List<ILuaScriptResourceInfo> _resourcesInfo = new List<ILuaScriptResourceInfo>();
private readonly AsyncReaderWriterLock _operationsLock = new ();
private readonly ILuaScriptLoader _luaScriptLoader; private readonly ILuaScriptLoader _luaScriptLoader;
private readonly ILuaScriptServicesConfig _luaScriptServicesConfig; private readonly ILuaScriptServicesConfig _luaScriptServicesConfig;
private readonly ILoggerService _loggerService; private readonly ILoggerService _loggerService;
@@ -67,13 +70,30 @@ class LuaScriptManagementService : ILuaScriptManagementService, ILuaDataService
public bool IsDisposed { get; private set; } public bool IsDisposed { get; private set; }
public Task<FluentResults.Result> LoadScriptResourcesAsync(ImmutableArray<ILuaScriptResourceInfo> resourcesInfo) public async Task<FluentResults.Result> LoadScriptResourcesAsync(ImmutableArray<ILuaScriptResourceInfo> resourcesInfo)
{ {
// Do any exception checks you can before acquiring a lock to avoid needlessly holding up resources.
if (resourcesInfo.IsDefaultOrEmpty)
ThrowHelper.ThrowArgumentNullException($"{nameof(LoadScriptResourcesAsync)}: The parameter is empty!");
// Acquire a lock:
// Reader = Allow parallel operations (try to avoid nesting acquiring the lock when possible)
// Writer = Exclusive use (ie. executing scripts or Dispose())
using var lck = await _operationsLock.AcquireWriterLock(); // IDisposable using with generate a try-finally and release for you.
IService.CheckDisposed(this); // Check disposed after you have the lock
// If you use a ConcurrentDictionary instead of a List, it will handle threading issues for you.
_resourcesInfo.AddRange(resourcesInfo.OrderBy(static r => r.LoadPriority)); _resourcesInfo.AddRange(resourcesInfo.OrderBy(static r => r.LoadPriority));
// TODO disk caching // Use the StorageService's caching function by just loading the file with caching turned on.
// Right now the LuaScriptLoader has this on by default.
var cacheRes = await _luaScriptLoader.CacheResourcesAsync(resourcesInfo);
return Task.FromResult(FluentResults.Result.Ok()); // Aggregate and return results to the caller to deal with. Optionally, log here if you want.
// Automatically converted to a Task<T> when 'async' is in the method declaration.
if (cacheRes.IsFailed)
return cacheRes.ToResult();
return new FluentResults.Result().WithReasons(cacheRes.Value.SelectMany(cr => cr.Item2.Reasons));
} }
private void SetupEnvironment() private void SetupEnvironment()
@@ -1,30 +0,0 @@
using System.Collections.Generic;
namespace Barotrauma.LuaCs.Services;
public sealed class PackageListRetrievalService : IPackageListRetrievalService
{
public void Dispose()
{
// stateless service
return;
}
public void CheckDisposed()
{
// stateless service
return;
}
public bool IsDisposed => false;
public IEnumerable<ContentPackage> GetEnabledContentPackages()
{
return ContentPackageManager.EnabledPackages.All;
}
public IEnumerable<ContentPackage> GetAllContentPackages()
{
return ContentPackageManager.AllPackages;
}
}
@@ -141,16 +141,31 @@ public sealed class PackageManagementService : IPackageManagementService
private FluentResults.Result UnsafeAddPackageInternal(ContentPackage package, IModConfigInfo config) private FluentResults.Result UnsafeAddPackageInternal(ContentPackage package, IModConfigInfo config)
{ {
if (_loadedPackages.TryGetValue(package, out var result)) if (_loadedPackages.TryGetValue(package, out _))
{ {
_logger.LogWarning($"Tried to load already-loaded package {package.Name}."); _logger.LogWarning($"Tried to load already-loaded package {package.Name}.");
return FluentResults.Result.Ok(); return FluentResults.Result.Ok();
} }
_loadedPackages[package] = config; _loadedPackages[package] = config;
var res = new FluentResults.Result(); try
res.WithReasons(_luaScriptManagementService.LoadScriptResourcesAsync(config.LuaScripts).ConfigureAwait(false).GetAwaiter().GetResult().Reasons); {
return res; var res = new FluentResults.Result();
var r = Task.WhenAll(
new Task<Task<FluentResults.Result>>(async Task<FluentResults.Result> () => new FluentResults.Result()
.WithReasons((await _configService.LoadConfigsAsync(config.Configs)).Reasons)
.WithReasons((await _configService.LoadConfigsProfilesAsync(config.Configs)).Reasons)),
new Task<Task<FluentResults.Result>>(async () => await _luaScriptManagementService.LoadScriptResourcesAsync(config.LuaScripts))
).ConfigureAwait(false).GetAwaiter().GetResult();
foreach (var task in r)
res.WithReasons(task.ConfigureAwait(false).GetAwaiter().GetResult().Reasons);
return res;
}
catch (Exception e)
{
return FluentResults.Result.Fail(new ExceptionalError(e));
}
} }
public FluentResults.Result ExecuteLoadedPackages(ImmutableArray<ContentPackage> executionOrder) public FluentResults.Result ExecuteLoadedPackages(ImmutableArray<ContentPackage> executionOrder)
@@ -292,4 +307,15 @@ public sealed class PackageManagementService : IPackageManagementService
IService.CheckDisposed(this); IService.CheckDisposed(this);
return _runningPackages.ContainsKey(package); return _runningPackages.ContainsKey(package);
} }
public ImmutableArray<ContentPackage> GetLoadedAssemblyPackages()
{
using var lck = _operationsLock.AcquireReaderLock().ConfigureAwait(false).GetAwaiter().GetResult();
IService.CheckDisposed(this);
if (_loadedPackages.IsEmpty)
return ImmutableArray<ContentPackage>.Empty;
return [.._loadedPackages.Values
.Where(cfg => !cfg.Assemblies.IsDefaultOrEmpty)
.Select(cfg => cfg.Package)];
}
} }
@@ -1,8 +1,13 @@
using MoonSharp.Interpreter.Loaders; using System.Collections.Immutable;
using System.Threading.Tasks;
using Barotrauma.LuaCs.Data;
using FluentResults;
using MoonSharp.Interpreter.Loaders;
namespace Barotrauma.LuaCs.Services.Safe; namespace Barotrauma.LuaCs.Services.Safe;
public interface ILuaScriptLoader : IService, IScriptLoader public interface ILuaScriptLoader : IService, IScriptLoader
{ {
void ClearCaches(); void ClearCaches();
Task<Result<ImmutableArray<(ContentPath Path, Result<string>)>>> CacheResourcesAsync(ImmutableArray<ILuaScriptResourceInfo> resourceInfos);
} }
@@ -1,12 +1,15 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Collections.Immutable;
using System.Text; using System.Text;
using System.IO; using System.IO;
using MoonSharp.Interpreter; using MoonSharp.Interpreter;
using MoonSharp.Interpreter.Loaders; using MoonSharp.Interpreter.Loaders;
using System.Linq; using System.Linq;
using System.Threading.Tasks;
using Barotrauma.LuaCs.Data; using Barotrauma.LuaCs.Data;
using Barotrauma.LuaCs.Services.Safe; using Barotrauma.LuaCs.Services.Safe;
using FluentResults;
namespace Barotrauma.LuaCs.Services.Safe namespace Barotrauma.LuaCs.Services.Safe
{ {
@@ -59,6 +62,15 @@ namespace Barotrauma.LuaCs.Services.Safe
_storageService?.PurgeCache(); _storageService?.PurgeCache();
} }
public async Task<Result<ImmutableArray<(ContentPath Path, Result<string>)>>> CacheResourcesAsync(ImmutableArray<ILuaScriptResourceInfo> resourceInfos)
{
// TODO: Needs an async lock?
IService.CheckDisposed(this);
if (!_storageService.UseCaching)
return FluentResults.Result.Fail($"Caching is not enabled.");
return await this._storageService.LoadPackageTextFilesAsync([..resourceInfos.SelectMany(ri => ri.FilePaths)]);
}
public override bool ScriptFileExists(string file) public override bool ScriptFileExists(string file)
{ {
((IService)this).CheckDisposed(); ((IService)this).CheckDisposed();
@@ -1,9 +0,0 @@
using System.Collections.Generic;
namespace Barotrauma.LuaCs.Services;
public interface IPackageListRetrievalService : IService
{
IEnumerable<ContentPackage> GetEnabledContentPackages();
IEnumerable<ContentPackage> GetAllContentPackages();
}
@@ -6,6 +6,7 @@ using System.Globalization;
using System.Threading.Tasks; using System.Threading.Tasks;
using Barotrauma.Extensions; using Barotrauma.Extensions;
using Barotrauma.LuaCs.Data; using Barotrauma.LuaCs.Data;
using FluentResults;
namespace Barotrauma.LuaCs.Services; namespace Barotrauma.LuaCs.Services;
@@ -20,4 +21,5 @@ public interface IPackageManagementService : IReusableService
public FluentResults.Result UnloadAllPackages(); public FluentResults.Result UnloadAllPackages();
public ImmutableArray<ContentPackage> GetAllLoadedPackages(); public ImmutableArray<ContentPackage> GetAllLoadedPackages();
public bool IsPackageRunning(ContentPackage package); public bool IsPackageRunning(ContentPackage package);
public ImmutableArray<ContentPackage> GetLoadedAssemblyPackages();
} }