diff options
Diffstat (limited to 'src/SMAPI/Framework')
7 files changed, 39 insertions, 27 deletions
diff --git a/src/SMAPI/Framework/ModLoading/AssemblyDefinitionResolver.cs b/src/SMAPI/Framework/ModLoading/AssemblyDefinitionResolver.cs index d85a9a28..33cd6ebd 100644 --- a/src/SMAPI/Framework/ModLoading/AssemblyDefinitionResolver.cs +++ b/src/SMAPI/Framework/ModLoading/AssemblyDefinitionResolver.cs @@ -36,15 +36,6 @@ namespace StardewModdingAPI.Framework.ModLoading /// <param name="parameters">The assembly reader parameters.</param> public override AssemblyDefinition Resolve(AssemblyNameReference name, ReaderParameters parameters) => this.ResolveName(name.Name) ?? base.Resolve(name, parameters); - /// <summary>Resolve an assembly reference.</summary> - /// <param name="fullName">The assembly full name (including version, etc).</param> - public override AssemblyDefinition Resolve(string fullName) => this.ResolveName(fullName) ?? base.Resolve(fullName); - - /// <summary>Resolve an assembly reference.</summary> - /// <param name="fullName">The assembly full name (including version, etc).</param> - /// <param name="parameters">The assembly reader parameters.</param> - public override AssemblyDefinition Resolve(string fullName, ReaderParameters parameters) => this.ResolveName(fullName) ?? base.Resolve(fullName, parameters); - /********* ** Private methods diff --git a/src/SMAPI/Framework/ModLoading/AssemblyLoader.cs b/src/SMAPI/Framework/ModLoading/AssemblyLoader.cs index 2fb2aba7..d41774a9 100644 --- a/src/SMAPI/Framework/ModLoading/AssemblyLoader.cs +++ b/src/SMAPI/Framework/ModLoading/AssemblyLoader.cs @@ -12,7 +12,7 @@ using StardewModdingAPI.Metadata; namespace StardewModdingAPI.Framework.ModLoading { /// <summary>Preprocesses and loads mod assemblies.</summary> - internal class AssemblyLoader + internal class AssemblyLoader : IDisposable { /********* ** Properties @@ -20,9 +20,6 @@ namespace StardewModdingAPI.Framework.ModLoading /// <summary>Encapsulates monitoring and logging.</summary> private readonly IMonitor Monitor; - /// <summary>Whether to enable developer mode logging.</summary> - private readonly bool IsDeveloperMode; - /// <summary>Metadata for mapping assemblies to the current platform.</summary> private readonly PlatformAssemblyMap AssemblyMap; @@ -32,6 +29,9 @@ namespace StardewModdingAPI.Framework.ModLoading /// <summary>A minimal assembly definition resolver which resolves references to known loaded assemblies.</summary> private readonly AssemblyDefinitionResolver AssemblyDefinitionResolver; + /// <summary>The objects to dispose as part of this instance.</summary> + private readonly HashSet<IDisposable> Disposables = new HashSet<IDisposable>(); + /********* ** Public methods @@ -39,13 +39,11 @@ namespace StardewModdingAPI.Framework.ModLoading /// <summary>Construct an instance.</summary> /// <param name="targetPlatform">The current game platform.</param> /// <param name="monitor">Encapsulates monitoring and logging.</param> - /// <param name="isDeveloperMode">Whether to enable developer mode logging.</param> - public AssemblyLoader(Platform targetPlatform, IMonitor monitor, bool isDeveloperMode) + public AssemblyLoader(Platform targetPlatform, IMonitor monitor) { this.Monitor = monitor; - this.IsDeveloperMode = isDeveloperMode; - this.AssemblyMap = Constants.GetAssemblyMap(targetPlatform); - this.AssemblyDefinitionResolver = new AssemblyDefinitionResolver(); + this.AssemblyMap = this.TrackForDisposal(Constants.GetAssemblyMap(targetPlatform)); + this.AssemblyDefinitionResolver = this.TrackForDisposal(new AssemblyDefinitionResolver()); // generate type => assembly lookup for types which should be rewritten this.TypeAssemblies = new Dictionary<string, Assembly>(); @@ -144,10 +142,26 @@ namespace StardewModdingAPI.Framework.ModLoading .FirstOrDefault(p => p.GetName().Name == shortName); } + /// <summary>Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.</summary> + public void Dispose() + { + foreach (IDisposable instance in this.Disposables) + instance.Dispose(); + } + /********* ** Private methods *********/ + /// <summary>Track an object for disposal as part of the assembly loader.</summary> + /// <typeparam name="T">The instance type.</typeparam> + /// <param name="instance">The disposable instance.</param> + private T TrackForDisposal<T>(T instance) where T : IDisposable + { + this.Disposables.Add(instance); + return instance; + } + /**** ** Assembly parsing ****/ @@ -166,9 +180,8 @@ namespace StardewModdingAPI.Framework.ModLoading // read assembly byte[] assemblyBytes = File.ReadAllBytes(file.FullName); - AssemblyDefinition assembly; - using (Stream readStream = new MemoryStream(assemblyBytes)) - assembly = AssemblyDefinition.ReadAssembly(readStream, new ReaderParameters(ReadingMode.Deferred) { AssemblyResolver = assemblyResolver }); + Stream readStream = this.TrackForDisposal(new MemoryStream(assemblyBytes)); + AssemblyDefinition assembly = this.TrackForDisposal(AssemblyDefinition.ReadAssembly(readStream, new ReaderParameters(ReadingMode.Immediate) { AssemblyResolver = assemblyResolver, InMemory = true })); // skip if already visited if (visitedAssemblyNames.Contains(assembly.Name.Name)) diff --git a/src/SMAPI/Framework/ModLoading/PlatformAssemblyMap.cs b/src/SMAPI/Framework/ModLoading/PlatformAssemblyMap.cs index f0a28b4a..01460dce 100644 --- a/src/SMAPI/Framework/ModLoading/PlatformAssemblyMap.cs +++ b/src/SMAPI/Framework/ModLoading/PlatformAssemblyMap.cs @@ -1,3 +1,4 @@ +using System; using System.Collections.Generic; using System.Linq; using System.Reflection; @@ -7,7 +8,7 @@ using StardewModdingAPI.Internal; namespace StardewModdingAPI.Framework.ModLoading { /// <summary>Metadata for mapping assemblies to the current <see cref="Platform"/>.</summary> - internal class PlatformAssemblyMap + internal class PlatformAssemblyMap : IDisposable { /********* ** Accessors @@ -50,7 +51,14 @@ namespace StardewModdingAPI.Framework.ModLoading // cache assembly metadata this.Targets = targetAssemblies; this.TargetReferences = this.Targets.ToDictionary(assembly => assembly, assembly => AssemblyNameReference.Parse(assembly.FullName)); - this.TargetModules = this.Targets.ToDictionary(assembly => assembly, assembly => ModuleDefinition.ReadModule(assembly.Modules.Single().FullyQualifiedName)); + this.TargetModules = this.Targets.ToDictionary(assembly => assembly, assembly => ModuleDefinition.ReadModule(assembly.Modules.Single().FullyQualifiedName, new ReaderParameters { InMemory = true })); + } + + /// <summary>Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.</summary> + public void Dispose() + { + foreach (ModuleDefinition module in this.TargetModules.Values) + module.Dispose(); } } } diff --git a/src/SMAPI/Framework/ModLoading/Rewriters/FieldReplaceRewriter.cs b/src/SMAPI/Framework/ModLoading/Rewriters/FieldReplaceRewriter.cs index 63358b39..806a074f 100644 --- a/src/SMAPI/Framework/ModLoading/Rewriters/FieldReplaceRewriter.cs +++ b/src/SMAPI/Framework/ModLoading/Rewriters/FieldReplaceRewriter.cs @@ -42,7 +42,7 @@ namespace StardewModdingAPI.Framework.ModLoading.Rewriters if (!this.IsMatch(instruction)) return InstructionHandleResult.None; - FieldReference newRef = module.Import(this.ToField); + FieldReference newRef = module.ImportReference(this.ToField); cil.Replace(instruction, cil.Create(instruction.OpCode, newRef)); return InstructionHandleResult.Rewritten; } diff --git a/src/SMAPI/Framework/ModLoading/Rewriters/FieldToPropertyRewriter.cs b/src/SMAPI/Framework/ModLoading/Rewriters/FieldToPropertyRewriter.cs index b1fa377a..e6ede9e3 100644 --- a/src/SMAPI/Framework/ModLoading/Rewriters/FieldToPropertyRewriter.cs +++ b/src/SMAPI/Framework/ModLoading/Rewriters/FieldToPropertyRewriter.cs @@ -50,7 +50,7 @@ namespace StardewModdingAPI.Framework.ModLoading.Rewriters return InstructionHandleResult.None; string methodPrefix = instruction.OpCode == OpCodes.Ldsfld || instruction.OpCode == OpCodes.Ldfld ? "get" : "set"; - MethodReference propertyRef = module.Import(this.Type.GetMethod($"{methodPrefix}_{this.PropertyName}")); + MethodReference propertyRef = module.ImportReference(this.Type.GetMethod($"{methodPrefix}_{this.PropertyName}")); cil.Replace(instruction, cil.Create(OpCodes.Call, propertyRef)); return InstructionHandleResult.Rewritten; diff --git a/src/SMAPI/Framework/ModLoading/Rewriters/MethodParentRewriter.cs b/src/SMAPI/Framework/ModLoading/Rewriters/MethodParentRewriter.cs index 974fcf4c..99bd9125 100644 --- a/src/SMAPI/Framework/ModLoading/Rewriters/MethodParentRewriter.cs +++ b/src/SMAPI/Framework/ModLoading/Rewriters/MethodParentRewriter.cs @@ -64,7 +64,7 @@ namespace StardewModdingAPI.Framework.ModLoading.Rewriters return InstructionHandleResult.None; MethodReference methodRef = (MethodReference)instruction.Operand; - methodRef.DeclaringType = module.Import(this.ToType); + methodRef.DeclaringType = module.ImportReference(this.ToType); return InstructionHandleResult.Rewritten; } diff --git a/src/SMAPI/Framework/ModLoading/Rewriters/TypeReferenceRewriter.cs b/src/SMAPI/Framework/ModLoading/Rewriters/TypeReferenceRewriter.cs index 74f2fcdd..5c7db902 100644 --- a/src/SMAPI/Framework/ModLoading/Rewriters/TypeReferenceRewriter.cs +++ b/src/SMAPI/Framework/ModLoading/Rewriters/TypeReferenceRewriter.cs @@ -135,7 +135,7 @@ namespace StardewModdingAPI.Framework.ModLoading.Rewriters { // root type if (type.FullName == this.FromTypeName) - return module.Import(this.ToType); + return module.ImportReference(this.ToType); // generic arguments if (type is GenericInstanceType genericType) |