- Finished most of LuaCsSetup top-level functionality.
- Removed some unneeded interface definitions. - Clean-slated some Services that need to be re-written.
This commit is contained in:
@@ -1,130 +1,77 @@
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Barotrauma.LuaCs.Configuration;
|
||||
using Barotrauma.LuaCs.Data;
|
||||
using Barotrauma.LuaCs.Events;
|
||||
using Barotrauma.LuaCs.Services;
|
||||
using Barotrauma.LuaCs.Services.Compatibility;
|
||||
using Barotrauma.LuaCs.Services.Processing;
|
||||
using Barotrauma.Networking;
|
||||
using FluentResults;
|
||||
using ImpromptuInterface;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
class LuaCsSetupConfig
|
||||
{
|
||||
public bool EnableCsScripting = false;
|
||||
public bool TreatForcedModsAsNormal = true;
|
||||
public bool PreferToUseWorkshopLuaSetup = false;
|
||||
public bool DisableErrorGUIOverlay = false;
|
||||
public bool HideUserNames
|
||||
{
|
||||
get { return LuaCsLogger.HideUserNames; }
|
||||
set { LuaCsLogger.HideUserNames = value; }
|
||||
}
|
||||
|
||||
public LuaCsSetupConfig() { }
|
||||
public LuaCsSetupConfig(LuaCsSetupConfig config)
|
||||
{
|
||||
EnableCsScripting = config.EnableCsScripting;
|
||||
TreatForcedModsAsNormal = config.TreatForcedModsAsNormal;
|
||||
PreferToUseWorkshopLuaSetup = config.PreferToUseWorkshopLuaSetup;
|
||||
DisableErrorGUIOverlay = config.DisableErrorGUIOverlay;
|
||||
}
|
||||
}
|
||||
|
||||
internal delegate void LuaCsMessageLogger(string message);
|
||||
internal delegate void LuaCsErrorHandler(Exception ex, LuaCsMessageOrigin origin);
|
||||
internal delegate void LuaCsExceptionHandler(Exception ex, LuaCsMessageOrigin origin);
|
||||
|
||||
partial class LuaCsSetup : IDisposable
|
||||
partial class LuaCsSetup : IDisposable, IEventScreenSelected, IEventAllPackageListChanged, IEventEnabledPackageListChanged
|
||||
{
|
||||
public LuaCsSetup()
|
||||
{
|
||||
// load services
|
||||
// == startup
|
||||
_servicesProvider = new ServicesProvider();
|
||||
RegisterServices();
|
||||
|
||||
// load manifest
|
||||
if (!_servicesProvider.TryGetService(out IModConfigCreatorService modConfigSvc))
|
||||
throw new NullReferenceException("LuaCsSetup: Failed to get mod config parser service!"); // we should crash here
|
||||
var luaConfig = modConfigSvc.BuildConfigFromManifest(Directory.GetCurrentDirectory() + LuaCsConfigFile);
|
||||
if (!luaConfig.IsSuccess)
|
||||
{
|
||||
Logger.LogResults(luaConfig.ToResult());
|
||||
throw new FileLoadException("LuaCsSetup: Failed to load config file!");
|
||||
}
|
||||
|
||||
// load resources
|
||||
RegisterLocalizations();
|
||||
RegisterConfigs();
|
||||
|
||||
LuaForBarotraumaId = new SteamWorkshopId(LuaForBarotraumaSteamId.Value);
|
||||
ValidateLuaCsContent();
|
||||
SubscribeToLuaCsEvents();
|
||||
|
||||
return;
|
||||
//---
|
||||
// == end
|
||||
|
||||
// == helpers
|
||||
void RegisterServices()
|
||||
{
|
||||
_servicesProvider.RegisterServiceType<ILoggerService, LoggerService>(ServiceLifetime.Singleton);
|
||||
_servicesProvider.RegisterServiceType<PerformanceCounterService, PerformanceCounterService>(ServiceLifetime.Singleton);
|
||||
_servicesProvider.RegisterServiceType<IPackageService, PackageService>(ServiceLifetime.Singleton);
|
||||
_servicesProvider.RegisterServiceType<IStorageService, StorageService>(ServiceLifetime.Transient);
|
||||
_servicesProvider.RegisterServiceType<IEventService, EventService>(ServiceLifetime.Singleton);
|
||||
#if CLIENT
|
||||
_servicesProvider.RegisterServiceType<IStylesService, StylesService>(ServiceLifetime.Transient);
|
||||
_servicesProvider.RegisterServiceType<IStylesManagementService, StylesManagementService>(ServiceLifetime.Singleton);
|
||||
#endif
|
||||
_servicesProvider.RegisterServiceType<IPackageManagementService, PackageManagementService>(ServiceLifetime.Singleton);
|
||||
_servicesProvider.RegisterServiceType<ILuaScriptService, LuaScriptService>(ServiceLifetime.Singleton);
|
||||
_servicesProvider.RegisterServiceType<ILuaScriptManagementService, LuaScriptService>(ServiceLifetime.Singleton);
|
||||
_servicesProvider.RegisterServiceType<IPluginManagementService, PluginManagementService>(ServiceLifetime.Singleton);
|
||||
_servicesProvider.RegisterServiceType<ILuaScriptManagementService, LuaScriptManagementService>(ServiceLifetime.Singleton);
|
||||
// TODO: ILocalizationService
|
||||
// TODO: IConfigService
|
||||
// TODO: INetworkingService
|
||||
// TODO: [Resource Converter/Parser Services]
|
||||
// TODO: ILocalizationService
|
||||
// TODO: IEventService
|
||||
|
||||
_servicesProvider.Compile();
|
||||
}
|
||||
|
||||
void RegisterLocalizations()
|
||||
// Validates LuaCs assets in /Content are valid and ready to use.
|
||||
void ValidateLuaCsContent()
|
||||
{
|
||||
LocalizationService.LoadLocalizations(luaConfig.Value.Localizations);
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
void RegisterConfigs()
|
||||
{
|
||||
if (ConfigService.AddConfigs(luaConfig.Value.Configs) is { IsSuccess: false } res1)
|
||||
{
|
||||
Logger.LogResults(res1);
|
||||
throw new Exception("LuaCsSetup: Failed to load config!");
|
||||
}
|
||||
|
||||
if (ConfigService.AddConfigsProfiles(luaConfig.Value.ConfigProfiles) is { IsSuccess: false } res2)
|
||||
{
|
||||
Logger.LogResults(res2);
|
||||
throw new Exception("LuaCsSetup: Failed to load config profiles!");
|
||||
}
|
||||
|
||||
IsCsEnabled = GetOrThrowForConfig<bool>(luaConfig.Value.PackageName, "IsCsEnabled");
|
||||
TreatForcedModsAsNormal = GetOrThrowForConfig<bool>(luaConfig.Value.PackageName, "TreatForcedModsAsNormal");
|
||||
PreferToUseWorkshopLuaSetup = GetOrThrowForConfig<bool>(luaConfig.Value.PackageName, "PreferToUseWorkshopLuaSetup");
|
||||
DisableErrorGUIOverlay = GetOrThrowForConfig<bool>(luaConfig.Value.PackageName, "DisableErrorGUIOverlay");
|
||||
EnableThreadedLoading = GetOrThrowForConfig<bool>(luaConfig.Value.PackageName, "EnableThreadedLoading");
|
||||
HideUserNamesInLogs = GetOrThrowForConfig<bool>(luaConfig.Value.PackageName, "HideUserNamesInLogs");
|
||||
LuaForBarotraumaSteamId = GetOrThrowForConfig<ulong>(luaConfig.Value.PackageName, "LuaForBarotraumaSteamId");
|
||||
|
||||
return;
|
||||
//---
|
||||
|
||||
IConfigEntry<T> GetOrThrowForConfig<T>(string packName, string internalName) where T : IConvertible, IEquatable<T>
|
||||
{
|
||||
var cfgRes = ConfigService.GetConfig<IConfigEntry<T>>(packName, internalName);
|
||||
if (cfgRes.IsSuccess)
|
||||
{
|
||||
return cfgRes.Value;
|
||||
}
|
||||
Logger.LogResults(cfgRes.ToResult());
|
||||
throw new Exception($"LuaCsSetup: Failed to load config for {internalName}!");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
void SubscribeToLuaCsEvents()
|
||||
{
|
||||
EventService.Subscribe<IEventScreenSelected>(this); // game state hook in
|
||||
EventService.Subscribe<IEventAllPackageListChanged>(this);
|
||||
EventService.Subscribe<IEventEnabledPackageListChanged>(this);
|
||||
}
|
||||
|
||||
#region CONST_DEF
|
||||
|
||||
public const string LuaCsConfigFile = "LuaCsConfig.xml";
|
||||
|
||||
#if SERVER
|
||||
public const bool IsServer = true;
|
||||
@@ -154,7 +101,7 @@ namespace Barotrauma
|
||||
? svc : throw new NullReferenceException("Package Manager service not found!");
|
||||
public IPluginManagementService PluginManagementService => _servicesProvider.TryGetService<IPluginManagementService>(out var svc)
|
||||
? svc : throw new NullReferenceException("Plugin Manager service not found!");
|
||||
public ILuaScriptManagementService LuaScriptService => _servicesProvider.TryGetService<ILuaScriptManagementService>(out var svc)
|
||||
public ILuaScriptManagementService LuaScriptManagementService => _servicesProvider.TryGetService<ILuaScriptManagementService>(out var svc)
|
||||
? svc : throw new NullReferenceException("Lua Script Manager service not found!");
|
||||
public ILocalizationService LocalizationService => _servicesProvider.TryGetService<ILocalizationService>(out var svc)
|
||||
? svc : throw new NullReferenceException("Localization Manager service not found!");
|
||||
@@ -187,17 +134,42 @@ namespace Barotrauma
|
||||
/// </summary>
|
||||
public IConfigEntry<bool> DisableErrorGUIOverlay { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// [Experimental] Whether multithreading should be used for loading.
|
||||
/// </summary>
|
||||
public IConfigEntry<bool> EnableThreadedLoading { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Whether usernames are anonymized or show in logs.
|
||||
/// </summary>
|
||||
public IConfigEntry<bool> HideUserNamesInLogs { get; private set; }
|
||||
|
||||
private IConfigEntry<ulong> LuaForBarotraumaSteamId { get; set; }
|
||||
/// <summary>
|
||||
/// The SteamId of the Workshop LuaCs CPackage in use, if available.
|
||||
/// </summary>
|
||||
public IConfigEntry<ulong> LuaForBarotraumaSteamId { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// The SteamId of the Workshop LuaCs CsForBarotrauma add-on, if available.
|
||||
/// </summary>
|
||||
public IConfigEntry<ulong> CsForBarotraumaSteamId { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Whether to (re)load all package assets when a lobby starts/code session begins.
|
||||
/// Intended for development use, or when packages are expected to change outside of External Updates (ie. Steam Workshop).
|
||||
/// </summary>
|
||||
public IConfigEntry<bool> ReloadPackagesOnLobbyStart { get; private set; }
|
||||
|
||||
/**
|
||||
* == Ops Vars
|
||||
*/
|
||||
private RunState _runState;
|
||||
/// <summary>
|
||||
/// The current run state of all services managed by LuaCs.
|
||||
/// </summary>
|
||||
public RunState CurrentRunState => _runState;
|
||||
|
||||
private bool CPacksParsed => CurrentRunState >= RunState.Parsed;
|
||||
private bool IsStaticAssetsLoaded => CurrentRunState >= RunState.Configuration;
|
||||
private bool IsCodeRunning => CurrentRunState >= RunState.Running;
|
||||
|
||||
private readonly ConcurrentQueue<ContentPackage> _toLoad = new();
|
||||
private readonly ConcurrentQueue<ContentPackage> _toUnload = new();
|
||||
|
||||
#endregion
|
||||
|
||||
@@ -208,13 +180,6 @@ namespace Barotrauma
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Whether mod content is loaded and being executed.
|
||||
/// </summary>
|
||||
public bool IsModContentRunning { get; private set; }
|
||||
|
||||
public readonly ContentPackageId LuaForBarotraumaId;
|
||||
|
||||
public static bool IsRunningInsideWorkshop
|
||||
{
|
||||
get
|
||||
@@ -227,84 +192,16 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
/*public Script Lua { get; private set; }
|
||||
public LuaScriptLoader LuaScriptLoader { get; private set; }
|
||||
|
||||
public LuaGame Game { get; private set; }
|
||||
public LuaCsHook Hook { get; private set; }
|
||||
public LuaCsTimer Timer { get; private set; }
|
||||
public LuaCsNetworking Networking { get; private set; }
|
||||
public LuaCsSteam Steam { get; private set; }
|
||||
|
||||
// must be available at anytime
|
||||
private static AssemblyManager _assemblyManager;
|
||||
public static AssemblyManager AssemblyManager => _assemblyManager ??= new AssemblyManager();
|
||||
|
||||
private CsPackageManager _pluginPackageManager;
|
||||
public CsPackageManager PluginPackageManager => _pluginPackageManager ??= new CsPackageManager(AssemblyManager, this);
|
||||
private LuaRequire Require { get; set; }
|
||||
public LuaCsSetupConfig Config { get; private set; }
|
||||
public MoonSharpVsCodeDebugServer DebugServer { get; private set; }
|
||||
public bool IsInitialized { get; private set; }*/
|
||||
|
||||
private bool ShouldRunCs
|
||||
{
|
||||
get
|
||||
{
|
||||
#if SERVER
|
||||
if (GetPackage(CsForBarotraumaId, false, false) != null && GameMain.Server.ServerPeer is LidgrenServerPeer) { return true; }
|
||||
#endif
|
||||
return IsCsEnabled.Value;
|
||||
}
|
||||
}
|
||||
|
||||
private partial bool ShouldRunCs();
|
||||
|
||||
|
||||
[Obsolete("Use AssemblyManager::GetTypesByName()")]
|
||||
// TODO: Rework
|
||||
[Obsolete("Use IPluginManagementService::GetTypesByName()")]
|
||||
public static Type GetType(string typeName, bool throwOnError = false, bool ignoreCase = false)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
//return AssemblyManager.GetTypesByName(typeName).FirstOrDefault((Type)null);
|
||||
}
|
||||
|
||||
// Old config ref
|
||||
/*public void ReadSettings()
|
||||
{
|
||||
Config = new LuaCsSetupConfig();
|
||||
|
||||
if (File.Exists(configFileName))
|
||||
{
|
||||
try
|
||||
{
|
||||
using (var file = File.Open(configFileName, FileMode.Open, FileAccess.Read))
|
||||
{
|
||||
XDocument document = XDocument.Load(file);
|
||||
Config.EnableCsScripting = document.Root.GetAttributeBool("EnableCsScripting", Config.EnableCsScripting);
|
||||
Config.TreatForcedModsAsNormal = document.Root.GetAttributeBool("TreatForcedModsAsNormal", Config.TreatForcedModsAsNormal);
|
||||
Config.PreferToUseWorkshopLuaSetup = document.Root.GetAttributeBool("PreferToUseWorkshopLuaSetup", Config.PreferToUseWorkshopLuaSetup);
|
||||
Config.DisableErrorGUIOverlay = document.Root.GetAttributeBool("DisableErrorGUIOverlay", Config.DisableErrorGUIOverlay);
|
||||
Config.HideUserNames = document.Root.GetAttributeBool("HideUserNames", Config.HideUserNames);
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
LuaCsLogger.HandleException(e, LuaCsMessageOrigin.LuaCs);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void WriteSettings()
|
||||
{
|
||||
XDocument document = new XDocument();
|
||||
document.Add(new XElement("LuaCsSetupConfig"));
|
||||
document.Root.SetAttributeValue("EnableCsScripting", Config.EnableCsScripting);
|
||||
document.Root.SetAttributeValue("EnableCsScripting", Config.EnableCsScripting);
|
||||
document.Root.SetAttributeValue("TreatForcedModsAsNormal", Config.TreatForcedModsAsNormal);
|
||||
document.Root.SetAttributeValue("PreferToUseWorkshopLuaSetup", Config.PreferToUseWorkshopLuaSetup);
|
||||
document.Root.SetAttributeValue("DisableErrorGUIOverlay", Config.DisableErrorGUIOverlay);
|
||||
document.Root.SetAttributeValue("HideUserNames", Config.HideUserNames);
|
||||
document.Save(configFileName);
|
||||
}*/
|
||||
|
||||
public static ContentPackage GetPackage(ContentPackageId id, bool fallbackToAll = true, bool useBackup = false)
|
||||
{
|
||||
@@ -349,111 +246,495 @@ namespace Barotrauma
|
||||
return null;
|
||||
}
|
||||
|
||||
// Old code ref
|
||||
/*private DynValue DoFile(string file, Table globalContext = null, string codeStringFriendly = null)
|
||||
{
|
||||
if (!LuaCsFile.CanReadFromPath(file))
|
||||
{
|
||||
throw new ScriptRuntimeException($"dofile: File access to {file} not allowed.");
|
||||
}
|
||||
|
||||
if (!LuaCsFile.Exists(file))
|
||||
{
|
||||
throw new ScriptRuntimeException($"dofile: File {file} not found.");
|
||||
}
|
||||
|
||||
return Lua.DoFile(file, globalContext, codeStringFriendly);
|
||||
}
|
||||
|
||||
private DynValue LoadFile(string file, Table globalContext = null, string codeStringFriendly = null)
|
||||
{
|
||||
if (!LuaCsFile.CanReadFromPath(file))
|
||||
{
|
||||
throw new ScriptRuntimeException($"loadfile: File access to {file} not allowed.");
|
||||
}
|
||||
|
||||
if (!LuaCsFile.Exists(file))
|
||||
{
|
||||
throw new ScriptRuntimeException($"loadfile: File {file} not found.");
|
||||
}
|
||||
|
||||
return Lua.LoadFile(file, globalContext, codeStringFriendly);
|
||||
}
|
||||
|
||||
public DynValue CallLuaFunction(object function, params object[] args)
|
||||
{
|
||||
// XXX: `lua` might be null if `LuaCsSetup.Stop()` is called while
|
||||
// a patched function is still running.
|
||||
if (Lua == null) { return null; }
|
||||
|
||||
lock (Lua)
|
||||
{
|
||||
try
|
||||
{
|
||||
return Lua.Call(function, args);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
LuaCsLogger.HandleException(e, LuaCsMessageOrigin.LuaMod);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private void SetModulePaths(string[] str)
|
||||
{
|
||||
LuaScriptLoader.ModulePaths = str;
|
||||
}
|
||||
|
||||
public void Update()
|
||||
{
|
||||
Timer?.Update();
|
||||
Steam?.Update();
|
||||
|
||||
#if CLIENT
|
||||
Stopwatch luaSw = new Stopwatch();
|
||||
luaSw.Start();
|
||||
#endif
|
||||
Hook?.Call("think");
|
||||
#if CLIENT
|
||||
luaSw.Stop();
|
||||
GameMain.PerformanceCounter.AddElapsedTicks("Think Hook", luaSw.ElapsedTicks);
|
||||
#endif
|
||||
}
|
||||
|
||||
*/
|
||||
public void Stop()
|
||||
{
|
||||
|
||||
|
||||
IsInitialized = false;
|
||||
}
|
||||
|
||||
public void Initialize(bool forceEnableCs = false)
|
||||
{
|
||||
if (IsInitialized)
|
||||
{
|
||||
Stop();
|
||||
}
|
||||
|
||||
IsInitialized = true;
|
||||
|
||||
Logger.Log($"Initializing LuaCs, git revision = {AssemblyInfo.GitRevision}");
|
||||
}
|
||||
|
||||
public void Update()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
// TODO release managed resources here
|
||||
try
|
||||
{
|
||||
SetRunState(RunState.Unloaded);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logger.LogError(e.Message);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
DisposeLuaCsConfig();
|
||||
|
||||
PluginManagementService.Dispose();
|
||||
LuaScriptManagementService.Dispose();
|
||||
#if CLIENT
|
||||
StylesManagementService.Dispose();
|
||||
#endif
|
||||
ConfigService.Dispose();
|
||||
LocalizationService.Dispose();
|
||||
PackageManagementService.Dispose();
|
||||
// TODO: Add all missing services.
|
||||
//NetworkingService.Dispose();
|
||||
EventService.Dispose();
|
||||
|
||||
_servicesProvider.DisposeAndReset();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Console.WriteLine(e);
|
||||
throw;
|
||||
}
|
||||
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handles changes in game states tracked by screen changes.
|
||||
/// </summary>
|
||||
/// <param name="screen">The new game screen.</param>
|
||||
public partial void OnScreenSelected(Screen screen);
|
||||
|
||||
public void OnAllPackageListChanged(IEnumerable<CorePackage> corePackages, IEnumerable<RegularPackage> regularPackages)
|
||||
{
|
||||
UpdateLoadedPackagesList();
|
||||
}
|
||||
|
||||
public void OnEnabledPackageListChanged(CorePackage corePackage, IEnumerable<RegularPackage> regularPackages)
|
||||
{
|
||||
UpdateLoadedPackagesList();
|
||||
}
|
||||
|
||||
private void UpdateLoadedPackagesList()
|
||||
{
|
||||
var newPackSet = ContentPackageManager.AllPackages
|
||||
.Union(ContentPackageManager.EnabledPackages.All)
|
||||
.ToHashSet();
|
||||
var currPackSet = PackageManagementService.GetAllLoadedPackages().ToHashSet();
|
||||
var toAdd = newPackSet.Except(currPackSet);
|
||||
var toRemove = currPackSet.Except(newPackSet);
|
||||
foreach (var package in toAdd)
|
||||
_toLoad.Enqueue(package);
|
||||
foreach (var package in toRemove)
|
||||
_toUnload.Enqueue(package);
|
||||
|
||||
|
||||
ProcessPackagesListDifferences();
|
||||
}
|
||||
|
||||
void ProcessPackagesListDifferences()
|
||||
{
|
||||
if (IsCodeRunning)
|
||||
return;
|
||||
|
||||
// no reason to do anything if we're fully unloaded.
|
||||
if (!CPacksParsed)
|
||||
{
|
||||
_toLoad.Clear();
|
||||
_toUnload.Clear();
|
||||
}
|
||||
|
||||
while (_toUnload.TryDequeue(out var cp))
|
||||
{
|
||||
LuaScriptManagementService.DisposePackageResources(cp);
|
||||
ConfigService.DisposeConfigsProfiles(cp);
|
||||
ConfigService.DisposeConfigs(cp);
|
||||
#if CLIENT
|
||||
StylesManagementService.DisposeStylesForPackage(cp);
|
||||
#endif
|
||||
LocalizationService.DisposePackage(cp);
|
||||
PackageManagementService.DisposePackageInfos(cp);
|
||||
}
|
||||
|
||||
var ls = new List<ContentPackage>();
|
||||
|
||||
while (_toLoad.TryDequeue(out var cp))
|
||||
{
|
||||
if (PackageManagementService.LoadPackageInfosAsync(cp).GetAwaiter().GetResult() is
|
||||
{ IsFailed: true } failure)
|
||||
{
|
||||
Logger.LogError($"Failed to load package infos for {cp.Name}");
|
||||
Logger.LogResults(failure);
|
||||
continue;
|
||||
}
|
||||
|
||||
ls.Add(cp);
|
||||
}
|
||||
|
||||
if (ls.Any())
|
||||
{
|
||||
LoadStaticAssetsAsync(ls).GetAwaiter().GetResult();
|
||||
}
|
||||
}
|
||||
|
||||
void SetRunState(RunState runState)
|
||||
{
|
||||
if (CurrentRunState == runState)
|
||||
return;
|
||||
if (runState > CurrentRunState)
|
||||
{
|
||||
if (CurrentRunState < RunState.Parsed)
|
||||
LoadCurrentContentPackageInfos();
|
||||
|
||||
if (runState <= CurrentRunState)
|
||||
return;
|
||||
|
||||
if (CurrentRunState < RunState.Configuration)
|
||||
LoadStaticAssets();
|
||||
|
||||
if (runState <= CurrentRunState)
|
||||
return;
|
||||
|
||||
if (CurrentRunState < RunState.Running)
|
||||
RunScripts();
|
||||
}
|
||||
else if (runState < CurrentRunState)
|
||||
{
|
||||
if (CurrentRunState >= RunState.Running)
|
||||
{
|
||||
StopScripts();
|
||||
ProcessPackagesListDifferences();
|
||||
_runState = RunState.Configuration;
|
||||
}
|
||||
|
||||
if (runState >= CurrentRunState)
|
||||
return;
|
||||
|
||||
if (CurrentRunState == RunState.Configuration)
|
||||
{
|
||||
UnloadStaticAssets();
|
||||
_runState = RunState.Parsed;
|
||||
}
|
||||
|
||||
if (runState >= CurrentRunState)
|
||||
return;
|
||||
|
||||
if (CurrentRunState == RunState.Parsed)
|
||||
{
|
||||
UnloadContentPackageInfos();
|
||||
_runState = RunState.Unloaded;
|
||||
}
|
||||
|
||||
// we should be unloaded completely now | RunState.Unloaded
|
||||
}
|
||||
}
|
||||
|
||||
void LoadCurrentContentPackageInfos()
|
||||
{
|
||||
if (CurrentRunState >= RunState.Parsed)
|
||||
return;
|
||||
|
||||
// load core
|
||||
var result1 = PackageManagementService.LoadPackageInfosAsync(ContentPackageManager.VanillaCorePackage)
|
||||
.GetAwaiter().GetResult();
|
||||
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.LoadPackagesInfosAsync(packages)
|
||||
.GetAwaiter().GetResult();
|
||||
|
||||
foreach (var entry in result2)
|
||||
{
|
||||
if (entry.Item2.IsSuccess)
|
||||
Logger.LogMessage($"Successfully parsed package: {entry.Item1.Name}");
|
||||
else if (entry.Item2.IsFailed)
|
||||
Logger.LogResults(entry.Item2);
|
||||
}
|
||||
}
|
||||
|
||||
void LoadStaticAssets()
|
||||
{
|
||||
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.DisposePackageInfos(cp);
|
||||
|
||||
LoadStaticAssetsAsync(PackageManagementService.GetAllLoadedPackages()).GetAwaiter().GetResult();
|
||||
LoadLuaCsConfig();
|
||||
|
||||
if (CurrentRunState < RunState.Configuration)
|
||||
_runState = RunState.Configuration;
|
||||
}
|
||||
|
||||
void LoadLuaCsConfig()
|
||||
{
|
||||
IsCsEnabled = ConfigService.GetConfig<IConfigEntry<bool>>(ContentPackageManager.VanillaCorePackage, "IsCsEnabled")
|
||||
?? throw new NullReferenceException($"{nameof(IsCsEnabled)} cannot be loaded.");
|
||||
TreatForcedModsAsNormal = ConfigService.GetConfig<IConfigEntry<bool>>(ContentPackageManager.VanillaCorePackage, "TreatForcedModsAsNormal")
|
||||
?? throw new NullReferenceException($"{nameof(TreatForcedModsAsNormal)} cannot be loaded.");
|
||||
DisableErrorGUIOverlay = ConfigService.GetConfig<IConfigEntry<bool>>(ContentPackageManager.VanillaCorePackage, "DisableErrorGUIOverlay")
|
||||
?? throw new NullReferenceException($"{nameof(DisableErrorGUIOverlay)} cannot be loaded.");
|
||||
HideUserNamesInLogs = ConfigService.GetConfig<IConfigEntry<bool>>(ContentPackageManager.VanillaCorePackage, "HideUserNamesInLogs")
|
||||
?? throw new NullReferenceException($"{nameof(HideUserNamesInLogs)} cannot be loaded.");
|
||||
LuaForBarotraumaSteamId = ConfigService.GetConfig<IConfigEntry<ulong>>(ContentPackageManager.VanillaCorePackage, "LuaForBarotraumaSteamId")
|
||||
?? throw new NullReferenceException($"{nameof(LuaForBarotraumaSteamId)} cannot be loaded.");
|
||||
CsForBarotraumaSteamId = ConfigService.GetConfig<IConfigEntry<ulong>>(ContentPackageManager.VanillaCorePackage, "CsForBarotraumaSteamId")
|
||||
?? throw new NullReferenceException($"{nameof(CsForBarotraumaSteamId)} cannot be loaded.");
|
||||
}
|
||||
|
||||
void DisposeLuaCsConfig()
|
||||
{
|
||||
IsCsEnabled = null;
|
||||
TreatForcedModsAsNormal = null;
|
||||
DisableErrorGUIOverlay = null;
|
||||
HideUserNamesInLogs = null;
|
||||
LuaForBarotraumaSteamId = null;
|
||||
CsForBarotraumaSteamId = null;
|
||||
}
|
||||
|
||||
async Task LoadStaticAssetsAsync(IReadOnlyList<ContentPackage> packages)
|
||||
{
|
||||
var locRes = ImmutableArray<ILocalizationResourceInfo>.Empty;
|
||||
var cfgRes = ImmutableArray<IConfigResourceInfo>.Empty;
|
||||
var cfpRes = ImmutableArray<IConfigProfileResourceInfo>.Empty;
|
||||
var luaRes = ImmutableArray<ILuaScriptResourceInfo>.Empty;
|
||||
|
||||
#if CLIENT
|
||||
var styleRes = ImmutableArray<IStylesResourceInfo>.Empty;
|
||||
#endif
|
||||
|
||||
var tasksBuilder = ImmutableArray.CreateBuilder<Task>();
|
||||
|
||||
//---- get resource infos
|
||||
tasksBuilder.AddRange(new Func<Task>(async () =>
|
||||
{
|
||||
var res = await PackageManagementService.GetLocalizationsInfosAsync(packages);
|
||||
if (res.IsSuccess)
|
||||
locRes = res.Value.Localizations;
|
||||
if (res.Errors.Any())
|
||||
ThreadPool.QueueUserWorkItem(state => Logger.LogResults((FluentResults.Result)state),
|
||||
res.ToResult());
|
||||
})(),
|
||||
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.GetConfigProfilesInfosAsync(packages);
|
||||
if (res.IsSuccess)
|
||||
cfpRes = res.Value.ConfigProfiles;
|
||||
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());
|
||||
})());
|
||||
|
||||
#if CLIENT
|
||||
tasksBuilder.Add(new Func<Task>(async () =>
|
||||
{
|
||||
var res = await PackageManagementService.GetStylesInfosAsync(packages);
|
||||
if (res.IsSuccess)
|
||||
styleRes = res.Value.StylesResourceInfos;
|
||||
if (res.Errors.Any())
|
||||
ThreadPool.QueueUserWorkItem(state => Logger.LogResults((FluentResults.Result)state),
|
||||
res.ToResult());
|
||||
})());
|
||||
#endif
|
||||
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);
|
||||
res = await ConfigService.LoadConfigsProfilesAsync(cfpRes);
|
||||
if (res.Errors.Any())
|
||||
Logger.LogResults(res);
|
||||
})(),
|
||||
new Func<Task>(async () =>
|
||||
{
|
||||
var res = await LuaScriptManagementService.LoadScriptResourcesAsync(luaRes);
|
||||
if (res.Errors.Any())
|
||||
Logger.LogResults(res);
|
||||
})());
|
||||
|
||||
#if CLIENT
|
||||
tasksBuilder.Add(new Func<Task>(async () =>
|
||||
{
|
||||
var res = await StylesManagementService.LoadStylesAsync(styleRes);
|
||||
if (res.Errors.Any())
|
||||
Logger.LogResults(res);
|
||||
})());
|
||||
#endif
|
||||
|
||||
// load localizations first
|
||||
if (!locRes.IsDefaultOrEmpty)
|
||||
{
|
||||
var res = await LocalizationService.LoadLocalizations(locRes);
|
||||
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.GetLuaScriptsInfos(PackageManagementService
|
||||
.GetAllLoadedPackages()
|
||||
.Where(ContentPackageManager.EnabledPackages.All.Contains)
|
||||
.ToList());
|
||||
if (luaRes.IsFailed)
|
||||
{
|
||||
Logger.LogError($"{nameof(RunScripts)}: Failed to get enabled lua script resources!");
|
||||
Logger.LogResults(luaRes.ToResult());
|
||||
return;
|
||||
}
|
||||
|
||||
if (luaRes.Errors.Any())
|
||||
Logger.LogResults(luaRes.ToResult());
|
||||
|
||||
|
||||
LuaScriptManagementService.ExecuteLoadedScripts(luaRes.Value.LuaScripts);
|
||||
|
||||
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 CLIENT
|
||||
StylesManagementService.Reset();
|
||||
#endif
|
||||
LocalizationService.Reset();
|
||||
|
||||
if (CurrentRunState >= RunState.Configuration)
|
||||
{
|
||||
_runState = RunState.Parsed;
|
||||
}
|
||||
}
|
||||
|
||||
void StopScripts()
|
||||
{
|
||||
EventService.ClearAllSubscribers();
|
||||
LuaScriptManagementService.UnloadActiveScripts();
|
||||
PluginManagementService.UnloadAllAssemblyResources();
|
||||
SubscribeToLuaCsEvents();
|
||||
|
||||
if (IsCodeRunning)
|
||||
{
|
||||
_runState = RunState.Configuration;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Specifies the current run state of the LuaCs Modding System.
|
||||
/// <b>[Important]Enum State values ordering must be in the form of (lower state) === (higher state)</b>
|
||||
/// </summary>
|
||||
public enum RunState : byte
|
||||
{
|
||||
Unloaded = 0, // No asset data loaded.
|
||||
Parsed, // CPacks' ResourceInfos are parsed.
|
||||
Configuration, // localization and configuration assets loaded.
|
||||
Running // all assets loaded, code running.
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user