Skip to content

Commit

Permalink
- Initial migration of AssemblyManager to services.
Browse files Browse the repository at this point in the history
- Config and Networking interface creation.
  • Loading branch information
TBN-MapleWheels committed Sep 28, 2024
1 parent 08ff760 commit e4eb463
Show file tree
Hide file tree
Showing 8 changed files with 230 additions and 144 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
namespace Barotrauma.Configuration;

public interface IConfigBase
{

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
namespace Barotrauma.Configuration;

public interface IConfigVar : IConfigBase
{

}
7 changes: 4 additions & 3 deletions Barotrauma/BarotraumaShared/SharedSource/LuaCs/LuaCsSetup.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
using System.Reflection;
using System.Runtime.Loader;
using System.Xml.Linq;
using Barotrauma.LuaCs.Services;
using Barotrauma.Networking;

namespace Barotrauma
Expand Down Expand Up @@ -99,7 +100,7 @@ public static bool IsRunningInsideWorkshop
public CsPackageManager PluginPackageManager => _pluginPackageManager ??= new CsPackageManager(AssemblyManager, this);

public LuaCsModStore ModStore { get; private set; }
private LuaRequire require { get; set; }
private LuaRequire Require { get; set; }
public LuaCsSetupConfig Config { get; private set; }
public MoonSharpVsCodeDebugServer DebugServer { get; private set; }
public bool IsInitialized { get; private set; }
Expand Down Expand Up @@ -394,7 +395,7 @@ public void Initialize(bool forceEnableCs = false)
Lua.Options.CheckThreadAccess = false;
Script.GlobalOptions.ShouldPCallCatchException = (Exception ex) => { return true; };

require = new LuaRequire(Lua);
Require = new LuaRequire(Lua);

Game = new LuaGame();
Networking = new LuaCsNetworking();
Expand Down Expand Up @@ -430,7 +431,7 @@ public void Initialize(bool forceEnableCs = false)

Lua.Globals["dofile"] = (Func<string, Table, string, DynValue>)DoFile;
Lua.Globals["loadfile"] = (Func<string, Table, string, DynValue>)LoadFile;
Lua.Globals["require"] = (Func<string, Table, DynValue>)require.Require;
Lua.Globals["require"] = (Func<string, Table, DynValue>)Require.Require;

Lua.Globals["dostring"] = (Func<string, Table, string, DynValue>)Lua.DoString;
Lua.Globals["load"] = (Func<string, Table, string, DynValue>)Lua.LoadString;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
using System;

namespace Barotrauma.LuaCs.Networking;

public partial interface INetCallback
{
public ushort CallbackId { get; }
}

#if SERVER
public partial interface INetCallback
{

}
#endif
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading;
using Barotrauma.LuaCs.Services;
using Barotrauma.Steam;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,14 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Loader;
using Barotrauma.LuaCs.Services;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
// ReSharper disable ConditionIsAlwaysTrueOrFalse

[assembly: InternalsVisibleTo("CompiledAssembly")]

namespace Barotrauma;
namespace Barotrauma.LuaCs;

/// <summary>
/// AssemblyLoadContext to compile from syntax trees in memory and to load from disk/file. Provides dependency resolution.
Expand All @@ -31,11 +32,11 @@ public class MemoryFileAssemblyContextLoader : AssemblyLoadContext
// internal
private readonly Dictionary<string, AssemblyDependencyResolver> _dependencyResolvers = new(); // path-folder, resolver
protected bool IsResolving; //this is to avoid circular dependency lookup.
private AssemblyManager _assemblyManager;
private IAssemblyManagementService _assemblyManager;
public bool IsTemplateMode { get; set; }
public bool IsDisposed { get; private set; }

public MemoryFileAssemblyContextLoader(AssemblyManager assemblyManager) : base(isCollectible: true)
public MemoryFileAssemblyContextLoader(IAssemblyManagementService assemblyManager) : base(isCollectible: true)
{
this._assemblyManager = assemblyManager;
this.IsDisposed = false;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
// ReSharper disable EventNeverSubscribedTo.Global
// ReSharper disable InconsistentNaming

namespace Barotrauma;
namespace Barotrauma.LuaCs.Services;

/***
* Note: This class was written to be thread-safe in order to allow parallelization in loading in the future if the need
Expand All @@ -25,36 +25,14 @@ namespace Barotrauma;
/// Provides functionality for the loading, unloading and management of plugins implementing IAssemblyPlugin.
/// All plugins are loaded into their own AssemblyLoadContext along with their dependencies.
/// </summary>
public class AssemblyManager
public class AssemblyManager : IAssemblyManagementService
{
#region ExternalAPI

/// <summary>
/// Called when an assembly is loaded.
/// </summary>

public event Action<Assembly> OnAssemblyLoaded;

/// <summary>
/// Called when an assembly is marked for unloading, before unloading begins. You should use this to cleanup
/// any references that you have to this assembly.
/// </summary>
public event Action<Assembly> OnAssemblyUnloading;

/// <summary>
/// Called whenever an exception is thrown. First arg is a formatted message, Second arg is the Exception.
/// </summary>
public event Action<string, Exception> OnException;

/// <summary>
/// For unloading issue debugging. Called whenever MemoryFileAssemblyContextLoader [load context] is unloaded.
/// </summary>
public event Action<Guid> OnACLUnload;


/// <summary>
/// [DEBUG ONLY]
/// Returns a list of the current unloading ACLs.
/// </summary>
public ImmutableList<WeakReference<MemoryFileAssemblyContextLoader>> StillUnloadingACLs
{
get
Expand All @@ -70,12 +48,6 @@ public ImmutableList<WeakReference<MemoryFileAssemblyContextLoader>> StillUnload
}
}
}


// ReSharper disable once MemberCanBePrivate.Global
/// <summary>
/// Checks if there are any AssemblyLoadContexts still in the process of unloading.
/// </summary>
public bool IsCurrentlyUnloading
{
get
Expand All @@ -95,21 +67,6 @@ public bool IsCurrentlyUnloading
}
}
}

// Old API compatibility
public IEnumerable<Type> GetSubTypesInLoadedAssemblies<T>()
{
return GetSubTypesInLoadedAssemblies<T>(false);
}


/// <summary>
/// Allows iteration over all non-interface types in all loaded assemblies in the AsmMgr that are assignable to the given type (IsAssignableFrom).
/// Warning: care should be used when using this method in hot paths as performance may be affected.
/// </summary>
/// <typeparam name="T">The type to compare against</typeparam>
/// <param name="rebuildList">Forces caches to clear and for the lists of types to be rebuilt.</param>
/// <returns>An Enumerator for matching types.</returns>
public IEnumerable<Type> GetSubTypesInLoadedAssemblies<T>(bool rebuildList)
{
Type targetType = typeof(T);
Expand Down Expand Up @@ -165,14 +122,6 @@ public IEnumerable<Type> GetSubTypesInLoadedAssemblies<T>(bool rebuildList)
OpsLockLoaded.ExitReadLock();
}
}

/// <summary>
/// Tries to get types assignable to type from the ACL given the Guid.
/// </summary>
/// <param name="id"></param>
/// <param name="types"></param>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
public bool TryGetSubTypesFromACL<T>(Guid id, out IEnumerable<Type> types)
{
Type targetType = typeof(T);
Expand All @@ -188,13 +137,6 @@ public bool TryGetSubTypesFromACL<T>(Guid id, out IEnumerable<Type> types)
types = null;
return false;
}

/// <summary>
/// Tries to get types from the ACL given the Guid.
/// </summary>
/// <param name="id"></param>
/// <param name="types"></param>
/// <returns></returns>
public bool TryGetSubTypesFromACL(Guid id, out IEnumerable<Type> types)
{
if (TryGetACL(id, out var acl))
Expand All @@ -206,14 +148,6 @@ public bool TryGetSubTypesFromACL(Guid id, out IEnumerable<Type> types)
types = null;
return false;
}


/// <summary>
/// Allows iteration over all types, including interfaces, in all loaded assemblies in the AsmMgr who's names match the string.
/// Note: Will return the by-reference equivalent type if the type name is prefixed with "out " or "ref ".
/// </summary>
/// <param name="typeName">The string name of the type to search for.</param>
/// <returns>An Enumerator for matching types. List will be empty if bad params are supplied.</returns>
public IEnumerable<Type> GetTypesByName(string typeName)
{
List<Type> types = new();
Expand Down Expand Up @@ -299,12 +233,6 @@ void TypesListHelper()
}
}
}

/// <summary>
/// Allows iteration over all types (including interfaces) in all loaded assemblies managed by the AsmMgr.
/// Warning: High usage may result in performance issues.
/// </summary>
/// <returns>An Enumerator for iteration.</returns>
public IEnumerable<Type> GetAllTypesInLoadedAssemblies()
{
OpsLockLoaded.EnterReadLock();
Expand All @@ -325,13 +253,6 @@ public IEnumerable<Type> GetAllTypesInLoadedAssemblies()
OpsLockLoaded.ExitReadLock();
}
}

/// <summary>
/// Returns a list of all loaded ACLs.
/// WARNING: References to these ACLs outside of the AssemblyManager should be kept in a WeakReference in order
/// to avoid causing issues with unloading/disposal.
/// </summary>
/// <returns></returns>
public IEnumerable<LoadedACL> GetAllLoadedACLs()
{
OpsLockLoaded.EnterReadLock();
Expand All @@ -358,36 +279,14 @@ public IEnumerable<LoadedACL> GetAllLoadedACLs()

#region InternalAPI

/// <summary>
/// [Unsafe] Warning: only for use in nested threading functions. Requires care to manage access.
/// Does not make any guarantees about the state of the ACL after the list has been returned.
/// </summary>
/// <returns></returns>
[MethodImpl(MethodImplOptions.Synchronized | MethodImplOptions.NoInlining)]
internal ImmutableList<LoadedACL> UnsafeGetAllLoadedACLs()
ImmutableList<LoadedACL> IAssemblyManagementService.UnsafeGetAllLoadedACLs()
{
if (LoadedACLs.IsEmpty)
return ImmutableList<LoadedACL>.Empty;
return LoadedACLs.Select(kvp => kvp.Value).ToImmutableList();
}

/// <summary>
/// Used by content package and plugin management to stop unloading of a given ACL until all plugins have gracefully closed.
/// </summary>
public event System.Func<LoadedACL, bool> IsReadyToUnloadACL;

/// <summary>
/// Compiles an assembly from supplied references and syntax trees into the specified AssemblyContextLoader.
/// A new ACL will be created if the Guid supplied is Guid.Empty.
/// </summary>
/// <param name="compiledAssemblyName"></param>
/// <param name="syntaxTree"></param>
/// <param name="externalMetadataReferences"></param>
/// <param name="compilationOptions"></param>
/// <param name="friendlyName">A non-unique name for later reference. Optional, set to null if unused.</param>
/// <param name="id">The guid of the assembly </param>
/// <param name="externFileAssemblyRefs"></param>
/// <returns></returns>
public AssemblyLoadingSuccessState LoadAssemblyFromMemory([NotNull] string compiledAssemblyName,
[NotNull] IEnumerable<SyntaxTree> syntaxTree,
IEnumerable<MetadataReference> externalMetadataReferences,
Expand Down Expand Up @@ -440,31 +339,13 @@ public AssemblyLoadingSuccessState LoadAssemblyFromMemory([NotNull] string compi

return state;
}

/// <summary>
/// Switches the ACL with the given Guid to Template Mode, which disables assembly name resolution for any assemblies loaded in it.
/// These ACLs are intended to be used to host Assemblies for information only and not for code execution.
/// WARNING: This process is irreversible.
/// </summary>
/// <param name="guid">Guid of the ACL.</param>
/// <returns>Whether or not an ACL was found with the given ID.</returns>
public bool SetACLToTemplateMode(Guid guid)
{
if (!TryGetACL(guid, out var acl))
return false;
acl.Acl.IsTemplateMode = true;
return true;
}

/// <summary>
/// Tries to load all assemblies at the supplied file paths list into the ACl with the given Guid.
/// If the supplied Guid is Empty, then a new ACl will be created and the Guid will be assigned to it.
/// </summary>
/// <param name="filePaths">List of assemblies to try and load.</param>
/// <param name="friendlyName">A non-unique name for later reference. Optional.</param>
/// <param name="id">Guid of the ACL or Empty if none specified. Guid of ACL will be assigned to this var.</param>
/// <returns>Operation success messages.</returns>
/// <exception cref="ArgumentNullException"></exception>
public AssemblyLoadingSuccessState LoadAssembliesFromLocations([NotNull] IEnumerable<string> filePaths,
string friendlyName, ref Guid id)
{
Expand Down Expand Up @@ -507,9 +388,7 @@ public AssemblyLoadingSuccessState LoadAssembliesFromLocations([NotNull] IEnumer

return AssemblyLoadingSuccessState.ACLLoadFailure;
}


[MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.Synchronized)]
[MethodImpl(MethodImplOptions.NoInlining)]
public bool TryBeginDispose()
{
OpsLockLoaded.EnterWriteLock();
Expand Down Expand Up @@ -563,8 +442,6 @@ public bool TryBeginDispose()
OpsLockLoaded.ExitWriteLock();
}
}


[MethodImpl(MethodImplOptions.NoInlining)]
public bool FinalizeDispose()
{
Expand Down Expand Up @@ -606,15 +483,7 @@ public bool FinalizeDispose()

return isUnloaded;
}

/// <summary>
/// Tries to retrieve the LoadedACL with the given ID or null if none is found.
/// WARNING: External references to this ACL with long lifespans should be kept in a WeakReference
/// to avoid causing unloading/disposal issues.
/// </summary>
/// <param name="id">GUID of the ACL.</param>
/// <param name="acl">The found ACL or null if none was found.</param>
/// <returns>Whether or not an ACL was found.</returns>

[MethodImpl(MethodImplOptions.NoInlining)]
public bool TryGetACL(Guid id, out LoadedACL acl)
{
Expand Down Expand Up @@ -865,6 +734,11 @@ internal void ClearTypesList()
}

#endregion

public void Dispose()
{
TryBeginDispose();
}
}

public static class AssemblyExtensions
Expand Down
Loading

0 comments on commit e4eb463

Please sign in to comment.