diff --git a/Robust.Client/Console/Commands/ListAssembliesCommand.cs b/Robust.Client/Console/Commands/ListAssembliesCommand.cs new file mode 100644 index 000000000..339223099 --- /dev/null +++ b/Robust.Client/Console/Commands/ListAssembliesCommand.cs @@ -0,0 +1,32 @@ +using System.Linq; +using System.Runtime.Loader; +using System.Text; +using JetBrains.Annotations; +using Robust.Client.Interfaces.Console; + +namespace Robust.Client.Console.Commands +{ + [UsedImplicitly] + internal sealed class ListAssembliesCommand : IConsoleCommand + { + public string Command => "lsasm"; + public string Description => "Lists loaded assemblies by load context."; + public string Help => Command; + + public bool Execute(IDebugConsole console, string[] args) + { + var sb = new StringBuilder(); + foreach (var context in AssemblyLoadContext.All) + { + sb.AppendFormat("{0}:\n", context.Name); + foreach (var assembly in context.Assemblies.OrderBy(a => a.FullName)) + { + sb.AppendFormat(" {0}\n", assembly.FullName); + } + } + + console.AddLine(sb.ToString()); + return false; + } + } +} diff --git a/Robust.Client/ContentStart.cs b/Robust.Client/ContentStart.cs index 17a01a1de..b54a49639 100644 --- a/Robust.Client/ContentStart.cs +++ b/Robust.Client/ContentStart.cs @@ -7,7 +7,7 @@ namespace Robust.Client #if FULL_RELEASE throw new System.InvalidOperationException("ContentStart is not available on a full release."); #else - GameController.Start(args); + GameController.Start(args, true); #endif } } diff --git a/Robust.Client/GameController.cs b/Robust.Client/GameController.cs index 03416f2fe..d4e951968 100644 --- a/Robust.Client/GameController.cs +++ b/Robust.Client/GameController.cs @@ -71,6 +71,7 @@ namespace Robust.Client #pragma warning restore 649 private CommandLineArgs _commandLineArgs; + private bool _disableAssemblyLoadContext; public bool LoadConfigAndUserData { get; set; } = true; @@ -136,6 +137,10 @@ namespace Robust.Client _fontManager.Initialize(); + // Disable load context usage on content start. + // This prevents Content.Client being loaded twice and things like csi blowing up because of it. + _modLoader.SetUseLoadContext(!_disableAssemblyLoadContext); + //identical code for server in baseserver if (!_modLoader.TryLoadAssembly(_resourceManager, $"Content.Shared")) { diff --git a/Robust.Client/GameController/GameController.Standalone.cs b/Robust.Client/GameController/GameController.Standalone.cs index 16d9b813f..36e1c4299 100644 --- a/Robust.Client/GameController/GameController.Standalone.cs +++ b/Robust.Client/GameController/GameController.Standalone.cs @@ -23,7 +23,7 @@ namespace Robust.Client Start(args); } - public static void Start(string[] args) + public static void Start(string[] args, bool contentStart = false) { if (_hasStarted) { @@ -34,11 +34,11 @@ namespace Robust.Client if (CommandLineArgs.TryParse(args, out var parsed)) { - ParsedMain(parsed); + ParsedMain(parsed, contentStart); } } - private static void ParsedMain(CommandLineArgs args) + private static void ParsedMain(CommandLineArgs args, bool contentStart) { IoCManager.InitThread(); @@ -48,6 +48,7 @@ namespace Robust.Client var gc = (GameController) IoCManager.Resolve(); gc.SetCommandLineArgs(args); + gc._disableAssemblyLoadContext = contentStart; if (!gc.Startup()) { Logger.Fatal("Failed to start game controller!"); diff --git a/Robust.Shared/ContentPack/IModLoader.cs b/Robust.Shared/ContentPack/IModLoader.cs index c3ae97f65..d9a81c15f 100644 --- a/Robust.Shared/ContentPack/IModLoader.cs +++ b/Robust.Shared/ContentPack/IModLoader.cs @@ -44,5 +44,7 @@ namespace Robust.Shared.ContentPack /// Sets the testing callbacks that will be passed to . /// void SetModuleBaseCallbacks(ModuleTestingCallbacks testingCallbacks); + + void SetUseLoadContext(bool useLoadContext); } } diff --git a/Robust.Shared/ContentPack/ModLoader.cs b/Robust.Shared/ContentPack/ModLoader.cs index 87349580e..feb45ebf7 100644 --- a/Robust.Shared/ContentPack/ModLoader.cs +++ b/Robust.Shared/ContentPack/ModLoader.cs @@ -78,6 +78,8 @@ namespace Robust.Shared.ContentPack private static int _modLoaderId; + private bool _useLoadContext; + public ModLoader() { var id = Interlocked.Increment(ref _modLoaderId); @@ -88,6 +90,11 @@ namespace Robust.Shared.ContentPack _loadContext.Resolving += ResolvingAssembly; } + public void SetUseLoadContext(bool useLoadContext) + { + _useLoadContext = useLoadContext; + } + public virtual void LoadGameAssembly(Stream assembly, Stream symbols = null) where T : GameShared { @@ -101,7 +108,15 @@ namespace Robust.Shared.ContentPack assembly.Position = 0; - var gameAssembly = _loadContext.LoadFromStream(assembly, symbols); + Assembly gameAssembly; + if (_useLoadContext) + { + gameAssembly = _loadContext.LoadFromStream(assembly, symbols); + } + else + { + gameAssembly = Assembly.Load(assembly.CopyToArray(), symbols.CopyToArray()); + } InitMod(gameAssembly); } @@ -118,7 +133,16 @@ namespace Robust.Shared.ContentPack if (!AssemblyTypeChecker.CheckAssembly(diskPath)) return; - InitMod(_loadContext.LoadFromAssemblyPath(diskPath)); + Assembly assembly; + if (_useLoadContext) + { + assembly = _loadContext.LoadFromAssemblyPath(diskPath); + } + else + { + assembly = Assembly.LoadFrom(diskPath); + } + InitMod(assembly); } protected void InitMod(Assembly assembly) where T : GameShared