From 4d97a427f9e8abb62fccf5374f1c0728183d5231 Mon Sep 17 00:00:00 2001 From: Evil Factory <36804725+evilfactory@users.noreply.github.com> Date: Sat, 27 Dec 2025 00:08:53 -0300 Subject: [PATCH] WIP Lua script management service --- .../SharedSource/LuaCs/LuaCsSetup.cs | 2 +- .../Services/LuaScriptManagementService.cs | 278 ++++++++---------- .../LuaCs/Services/Safe/ILuaDataService.cs | 30 -- .../ILuaScriptManagementService.cs | 61 +--- 4 files changed, 121 insertions(+), 250 deletions(-) diff --git a/Barotrauma/BarotraumaShared/SharedSource/LuaCs/LuaCsSetup.cs b/Barotrauma/BarotraumaShared/SharedSource/LuaCs/LuaCsSetup.cs index ae24a2efc..4996dcc00 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/LuaCs/LuaCsSetup.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/LuaCs/LuaCsSetup.cs @@ -664,7 +664,7 @@ namespace Barotrauma return; } - LuaScriptManagementService.ExecuteLoadedScriptsForPackages(luaRes); + LuaScriptManagementService.ExecuteLoadedScripts(); if (CurrentRunState < RunState.Running) _runState = RunState.Running; diff --git a/Barotrauma/BarotraumaShared/SharedSource/LuaCs/Services/LuaScriptManagementService.cs b/Barotrauma/BarotraumaShared/SharedSource/LuaCs/Services/LuaScriptManagementService.cs index f8531acef..8dda54b32 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/LuaCs/Services/LuaScriptManagementService.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/LuaCs/Services/LuaScriptManagementService.cs @@ -1,217 +1,171 @@ -using Barotrauma.LuaCs.Data; +#nullable enable + +using Barotrauma.LuaCs.Data; +using Barotrauma.LuaCs.Services.Safe; +using FluentResults; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp.Syntax; using MoonSharp.Interpreter; using MoonSharp.Interpreter.Interop; +using MoonSharp.Interpreter.Loaders; using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Collections.Immutable; +using System.ComponentModel.DataAnnotations; +using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.Linq; using System.Reflection; using System.Text; using System.Threading; using System.Threading.Tasks; -using Barotrauma.LuaCs.Services.Safe; -using FluentResults; -using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.CSharp.Syntax; -using MoonSharp.Interpreter.Loaders; namespace Barotrauma.LuaCs.Services; public class LuaScriptManagementService : ILuaScriptManagementService, ILuaDataService { - public LuaScriptManagementService(ILuaScriptLoader loader, ILuaScriptServicesConfig luaScriptServicesConfig) + private Script? _script; + private bool _isRunning; + [MemberNotNullWhen(true, nameof(_script))] + public bool IsRunning => _isRunning; + private List _resourcesInfo = new List(); + private readonly ILuaScriptLoader _luaScriptLoader; + private readonly ILuaScriptServicesConfig _luaScriptServicesConfig; + private readonly ILoggerService _loggerService; + + public LuaScriptManagementService(ILoggerService loggerService, ILuaScriptLoader loader, ILuaScriptServicesConfig luaScriptServicesConfig) { _luaScriptLoader = loader; _luaScriptServicesConfig = luaScriptServicesConfig; - } - - private readonly ILuaScriptLoader _luaScriptLoader; - private readonly ILuaScriptServicesConfig _luaScriptServicesConfig; - - public void Dispose() - { - _luaScriptLoader.Dispose(); + _loggerService = loggerService; } - public bool IsDisposed + public bool IsDisposed { get; private set; } + + public Task LoadScriptResourcesAsync(ImmutableArray resourcesInfo) { - get => throw new NotImplementedException(); + _resourcesInfo.AddRange(resourcesInfo.OrderBy(static r => r.LoadPriority)); + + // TODO disk caching + + return Task.FromResult(FluentResults.Result.Ok()); } - public FluentResults.Result Reset() + private void SetupEnvironment() { - throw new NotImplementedException(); - } + _script = new Script(CoreModules.Preset_SoftSandbox | CoreModules.Debug | CoreModules.IO | CoreModules.OS_System); + _script.Options.DebugPrint = (string msg) => + { + _loggerService.Log(msg); + }; + _script.Options.ScriptLoader = _luaScriptLoader; + _script.Options.CheckThreadAccess = false; - public Result GetGlobalTableValue(string tableName) - { - throw new NotImplementedException(); - } - - public async Task LoadScriptResourcesAsync(ImmutableArray resourcesInfo) - { - throw new NotImplementedException(); - } - - public FluentResults.Result ExecuteLoadedScriptsForPackage(ContentPackage package) - { - throw new NotImplementedException(); - } - - public FluentResults.Result ExecuteLoadedScriptsForPackages(IEnumerable packages) - { - throw new NotImplementedException(); + Script.GlobalOptions.ShouldPCallCatchException = (Exception ex) => { return true; }; } public FluentResults.Result ExecuteLoadedScripts() { - throw new NotImplementedException(); + if (_isRunning) + { + return FluentResults.Result.Fail("Tried to execute Lua scripts without unloading first."); + } + + SetupEnvironment(); + + _isRunning = true; + + var result = FluentResults.Result.Ok(); + + foreach (var resource in _resourcesInfo) + { + foreach (var filePath in resource.FilePaths) + { + try + { + _script?.Call(_script.LoadFile(filePath)); + } + catch(Exception e) + { + result = result.WithError(new ExceptionalError(e)); + } + } + } + + return result; } - public FluentResults.Result DisposePackageResources(ContentPackage package) + public DynValue? CallFunction(DynValue luaFunction, params object[] args) { - throw new NotImplementedException(); + if (!IsRunning) { return null; } + + lock (_script) + { + try + { + return _script.Call(luaFunction, args); + } + catch (Exception e) + { + _loggerService.HandleException(e); + } + return null; + } } public FluentResults.Result UnloadActiveScripts() { - throw new NotImplementedException(); + _isRunning = false; + + _script = null; + + // todo unregister everything + + return FluentResults.Result.Ok(); + } + + public FluentResults.Result DisposePackageResources(ContentPackage package) + { + return FluentResults.Result.Fail("Not supported for Lua"); } public FluentResults.Result DisposeAllPackageResources() { - throw new NotImplementedException(); + if (IsRunning) + { + UnloadActiveScripts(); + } + + _resourcesInfo.Clear(); + + return FluentResults.Result.Ok(); + } + + public FluentResults.Result Reset() + { + return DisposeAllPackageResources(); + } + + public void Dispose() + { + _luaScriptLoader.Dispose(); + IsDisposed = true; } public IUserDataDescriptor RegisterType(Type type) { - throw new NotImplementedException(); + return UserData.RegisterType(type); } - - public IUserDataDescriptor RegisterGenericType(Type type) - { - throw new NotImplementedException(); - } - - public IUserDataDescriptor GetTypeInfo(string typeName) - { - throw new NotImplementedException(); - } - - public IUserDataDescriptor GetGenericTypeInfo(string typeName, params string[] typeNameArgs) - { - throw new NotImplementedException(); - } - public void UnregisterType(Type type) { - throw new NotImplementedException(); + UserData.UnregisterType(type, true); } - public bool IsRegistered(Type type) + public object? GetGlobalTableValue(string tableName) { - throw new NotImplementedException(); - } + if (!IsRunning) { return null; } - public bool IsTargetType(object obj, string typeName) - { - throw new NotImplementedException(); - } - - public string TypeOf(object obj) - { - throw new NotImplementedException(); - } - - public object CreateStatic(string typeName) - { - throw new NotImplementedException(); - } - - public object CreateEnumTable(string typeName) - { - throw new NotImplementedException(); - } - - public FieldInfo FindFieldRecursively(Type type, string fieldName) - { - throw new NotImplementedException(); - } - - public void MakeFieldAccessible(IUserDataDescriptor descriptor, string fieldName) - { - throw new NotImplementedException(); - } - - public MethodInfo FindMethodRecursively(Type type, string methodName, Type[] types = null) - { - throw new NotImplementedException(); - } - - public void MakeMethodAccessible(IUserDataDescriptor descriptor, string methodName, string[] parameters = null) - { - throw new NotImplementedException(); - } - - public PropertyInfo FindPropertyRecursively(Type type, string propertyName) - { - throw new NotImplementedException(); - } - - public void MakePropertyAccessible(IUserDataDescriptor descriptor, string propertyName) - { - throw new NotImplementedException(); - } - - public void AddMethod(IUserDataDescriptor descriptor, string methodName, object function) - { - throw new NotImplementedException(); - } - - public void AddField(IUserDataDescriptor descriptor, string fieldName, DynValue value) - { - throw new NotImplementedException(); - } - - public void RemoveMember(IUserDataDescriptor descriptor, string memberName) - { - throw new NotImplementedException(); - } - - public bool HasMember(object obj, string memberName) - { - throw new NotImplementedException(); - } - - public DynValue CreateUserDataFromDescriptor(DynValue scriptObject, IUserDataDescriptor descriptor) - { - throw new NotImplementedException(); - } - - public DynValue CreateUserDataFromType(DynValue scriptObject, Type desiredType) - { - throw new NotImplementedException(); - } - - public Table GetObjectTable(object obj, string tableName) - { - throw new NotImplementedException(); - } - - public Table GetTable(string tableName) - { - throw new NotImplementedException(); - } - - public Table GetOrCreateObjectTable(object obj, string tableName) - { - throw new NotImplementedException(); - } - - public Table GetOrCreateTable(string tableName) - { - throw new NotImplementedException(); + return _script.Globals[tableName]; } } diff --git a/Barotrauma/BarotraumaShared/SharedSource/LuaCs/Services/Safe/ILuaDataService.cs b/Barotrauma/BarotraumaShared/SharedSource/LuaCs/Services/Safe/ILuaDataService.cs index 88cc45bdf..050a9329b 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/LuaCs/Services/Safe/ILuaDataService.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/LuaCs/Services/Safe/ILuaDataService.cs @@ -7,35 +7,5 @@ namespace Barotrauma.LuaCs.Services.Safe; /// public interface ILuaDataService : ILuaService { - /// - /// Returns stored table for the given object if it exists. - /// - /// - /// - /// The table data or null if none exists. - Table GetObjectTable(object obj, string tableName); - /// - /// Returns stored table data under the given name if it exists. - /// - /// - /// The table data or null if none exists. - Table GetTable(string tableName); - - /// - /// Returns stored table data for the given object or creates a new table if one doesn't exist. - /// - /// Note: tables are stored using weak references and will be automatically deleted when the object is - /// garbage collected. - /// - /// - /// - Table GetOrCreateObjectTable(object obj, string tableName); - - /// - /// Returns stored table data or creates a new table if one doesn't exist. - /// - /// - /// - Table GetOrCreateTable(string tableName); } diff --git a/Barotrauma/BarotraumaShared/SharedSource/LuaCs/Services/_Interfaces/ILuaScriptManagementService.cs b/Barotrauma/BarotraumaShared/SharedSource/LuaCs/Services/_Interfaces/ILuaScriptManagementService.cs index aad63020f..74be9298f 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/LuaCs/Services/_Interfaces/ILuaScriptManagementService.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/LuaCs/Services/_Interfaces/ILuaScriptManagementService.cs @@ -1,4 +1,6 @@ -using System; +#nullable enable + +using System; using System.Collections.Generic; using System.Collections.Immutable; using System.Reflection; @@ -14,7 +16,7 @@ public interface ILuaScriptManagementService : IReusableService { #region Script_Ops - Result GetGlobalTableValue(string tableName); + object? GetGlobalTableValue(string tableName); /// /// Parses and loads script sources (code) into a memory cache without executing it. @@ -57,62 +59,7 @@ public interface ILuaScriptManagementService : IReusableService #region Type_Registration IUserDataDescriptor RegisterType(Type type); - /// - /// [Deprecated]
- /// Use () instead. - /// Gets the type information for an already registered type. - ///
- /// The fully qualified name of the type and namespace. - /// The for the type, if registered. Null if none is found. - [Obsolete($"Use {nameof(GetTypeInfo)} instead.")] - IUserDataDescriptor RegisterType(string typeName) => GetTypeInfo(typeName); - IUserDataDescriptor RegisterGenericType(Type type); - /// - /// [Deprecated]
- /// Use () instead. - /// Gets the generic type information for an already registered type. - ///
- /// The fully qualified name of the generic type and namespace. - /// The fully qualified name of the template types. - /// The for the type, if registered. Null if none is found. - [Obsolete($"Use {nameof(GetGenericTypeInfo)} instead.")] - IUserDataDescriptor RegisterGenericType(string typeName, params string[] typeNameArgs) => GetGenericTypeInfo(typeName, typeNameArgs); - /// - /// Gets the type information for an already registered type. - /// - /// The fully qualified name of the type and namespace. - /// The for the type, if registered. Null if none is found. - IUserDataDescriptor GetTypeInfo(string typeName); - /// - /// Gets the generic type information for an already registered type. - /// - /// The fully qualified name of the generic type and namespace. - /// The fully qualified name of the template types. - /// The for the type, if registered. Null if none is found. - IUserDataDescriptor GetGenericTypeInfo(string typeName, params string[] typeNameArgs); void UnregisterType(Type type); #endregion - - #region Type_Checks_&Utilities - - bool IsRegistered(Type type); - bool IsTargetType(object obj, string typeName); - string TypeOf(object obj); - object CreateStatic(string typeName); - object CreateEnumTable(string typeName); - FieldInfo FindFieldRecursively(Type type, string fieldName); - void MakeFieldAccessible(IUserDataDescriptor descriptor, string fieldName); - MethodInfo FindMethodRecursively(Type type, string methodName, Type[] types = null); - void MakeMethodAccessible(IUserDataDescriptor descriptor, string methodName, string[] parameters = null); - PropertyInfo FindPropertyRecursively(Type type, string propertyName); - void MakePropertyAccessible(IUserDataDescriptor descriptor, string propertyName); - void AddMethod(IUserDataDescriptor descriptor, string methodName, object function); - void AddField(IUserDataDescriptor descriptor, string fieldName, DynValue value); - void RemoveMember(IUserDataDescriptor descriptor, string memberName); - bool HasMember(object obj, string memberName); - DynValue CreateUserDataFromDescriptor(DynValue scriptObject, IUserDataDescriptor descriptor); - DynValue CreateUserDataFromType(DynValue scriptObject, Type desiredType); - - #endregion }