Exemplo n.º 1
0
        /*********
        ** Public methods
        *********/
        /// <summary>Construct an instance.</summary>
        /// <param name="targetPlatform">The current game platform.</param>
        /// <param name="monitor">Encapsulates monitoring and logging.</param>
        /// <param name="paranoidMode">Whether to detect paranoid mode issues.</param>
        public AssemblyLoader(Platform targetPlatform, IMonitor monitor, bool paranoidMode)
        {
            this.Monitor      = monitor;
            this.ParanoidMode = paranoidMode;
            this.AssemblyMap  = this.TrackForDisposal(Constants.GetAssemblyMap(targetPlatform));
            this.AssemblyDefinitionResolver = this.TrackForDisposal(new AssemblyDefinitionResolver());
            this.AssemblyDefinitionResolver.AddSearchDirectory(Constants.ExecutionPath);
            this.AssemblyDefinitionResolver.AddSearchDirectory(Constants.InternalFilesPath);

            // generate type => assembly lookup for types which should be rewritten
            this.TypeAssemblies = new Dictionary <string, Assembly>();
            foreach (Assembly assembly in this.AssemblyMap.Targets)
            {
                ModuleDefinition module = this.AssemblyMap.TargetModules[assembly];
                foreach (TypeDefinition type in module.GetTypes())
                {
                    if (!type.IsPublic)
                    {
                        continue; // no need to rewrite
                    }
                    if (type.Namespace.Contains("<"))
                    {
                        continue; // ignore assembly metadata
                    }
                    this.TypeAssemblies[type.FullName] = assembly;
                }
            }
        }
Exemplo n.º 2
0
        /*********
        ** Public methods
        *********/
        /// <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)
        {
            this.Monitor                    = monitor;
            this.IsDeveloperMode            = isDeveloperMode;
            this.AssemblyMap                = Constants.GetAssemblyMap(targetPlatform);
            this.AssemblyDefinitionResolver = new AssemblyDefinitionResolver();

            // generate type => assembly lookup for types which should be rewritten
            this.TypeAssemblies = new Dictionary <string, Assembly>();
            foreach (Assembly assembly in this.AssemblyMap.Targets)
            {
                ModuleDefinition module = this.AssemblyMap.TargetModules[assembly];
                foreach (TypeDefinition type in module.GetTypes())
                {
                    if (!type.IsPublic)
                    {
                        continue; // no need to rewrite
                    }
                    if (type.Namespace.Contains("<"))
                    {
                        continue; // ignore assembly metadata
                    }
                    this.TypeAssemblies[type.FullName] = assembly;
                }
            }
        }
Exemplo n.º 3
0
        /// <summary>Preprocess and load an assembly.</summary>
        /// <param name="assemblyPath">The assembly file path.</param>
        /// <param name="assumeCompatible">Assume the mod is compatible, even if incompatible code is detected.</param>
        /// <returns>Returns the rewrite metadata for the preprocessed assembly.</returns>
        /// <exception cref="IncompatibleInstructionException">An incompatible CIL instruction was found while rewriting the assembly.</exception>
        public Assembly Load(string assemblyPath, bool assumeCompatible)
        {
            // get referenced local assemblies
            AssemblyParseResult[] assemblies;
            {
                AssemblyDefinitionResolver resolver             = new AssemblyDefinitionResolver();
                HashSet <string>           visitedAssemblyNames = new HashSet <string>(AppDomain.CurrentDomain.GetAssemblies().Select(p => p.GetName().Name)); // don't try loading assemblies that are already loaded
                assemblies = this.GetReferencedLocalAssemblies(new FileInfo(assemblyPath), visitedAssemblyNames, resolver).ToArray();
                if (!assemblies.Any())
                {
                    throw new InvalidOperationException($"Could not load '{assemblyPath}' because it doesn't exist.");
                }
                resolver.Add(assemblies.Select(p => p.Definition).ToArray());
            }

            // rewrite & load assemblies in leaf-to-root order
            bool     oneAssembly  = assemblies.Length == 1;
            Assembly lastAssembly = null;

            foreach (AssemblyParseResult assembly in assemblies)
            {
                bool changed = this.RewriteAssembly(assembly.Definition, assumeCompatible, logPrefix: "   ");
                if (changed)
                {
                    if (!oneAssembly)
                    {
                        this.Monitor.Log($"   Loading {assembly.File.Name}.dll (rewritten in memory)...", LogLevel.Trace);
                    }
                    using (MemoryStream outStream = new MemoryStream())
                    {
                        assembly.Definition.Write(outStream);
                        byte[] bytes = outStream.ToArray();
                        lastAssembly = Assembly.Load(bytes);
                    }
                }
                else
                {
                    if (!oneAssembly)
                    {
                        this.Monitor.Log($"   Loading {assembly.File.Name}.dll...", LogLevel.Trace);
                    }
                    lastAssembly = Assembly.UnsafeLoadFrom(assembly.File.FullName);
                }
            }

            // last assembly loaded is the root
            return(lastAssembly);
        }
Exemplo n.º 4
0
        /// <summary>Preprocess and load an assembly.</summary>
        /// <param name="mod">The mod for which the assembly is being loaded.</param>
        /// <param name="assemblyPath">The assembly file path.</param>
        /// <param name="assumeCompatible">Assume the mod is compatible, even if incompatible code is detected.</param>
        /// <returns>Returns the rewrite metadata for the preprocessed assembly.</returns>
        /// <exception cref="IncompatibleInstructionException">An incompatible CIL instruction was found while rewriting the assembly.</exception>
        public Assembly Load(IModMetadata mod, string assemblyPath, bool assumeCompatible)
        {
            // get referenced local assemblies
            AssemblyParseResult[] assemblies;
            {
                AssemblyDefinitionResolver resolver             = new AssemblyDefinitionResolver();
                HashSet <string>           visitedAssemblyNames = new HashSet <string>(AppDomain.CurrentDomain.GetAssemblies().Select(p => p.GetName().Name)); // don't try loading assemblies that are already loaded
                assemblies = this.GetReferencedLocalAssemblies(new FileInfo(assemblyPath), visitedAssemblyNames, resolver).ToArray();
            }

            // validate load
            if (!assemblies.Any() || assemblies[0].Status == AssemblyLoadStatus.Failed)
            {
                throw new SAssemblyLoadFailedException(!File.Exists(assemblyPath)
                    ? $"Could not load '{assemblyPath}' because it doesn't exist."
                    : $"Could not load '{assemblyPath}'."
                                                       );
            }
            if (assemblies.Last().Status == AssemblyLoadStatus.AlreadyLoaded) // mod assembly is last in dependency order
            {
                throw new SAssemblyLoadFailedException($"Could not load '{assemblyPath}' because it was already loaded. Do you have two copies of this mod?");
            }

            // rewrite & load assemblies in leaf-to-root order
            bool             oneAssembly    = assemblies.Length == 1;
            Assembly         lastAssembly   = null;
            HashSet <string> loggedMessages = new HashSet <string>();

            foreach (AssemblyParseResult assembly in assemblies)
            {
                if (assembly.Status == AssemblyLoadStatus.AlreadyLoaded)
                {
                    continue;
                }

                bool changed = this.RewriteAssembly(mod, assembly.Definition, assumeCompatible, loggedMessages, logPrefix: "   ");
                if (changed)
                {
                    if (!oneAssembly)
                    {
                        this.Monitor.Log($"   Loading {assembly.File.Name} (rewritten in memory)...", LogLevel.Trace);
                    }
                    using (MemoryStream outStream = new MemoryStream())
                    {
                        assembly.Definition.Write(outStream);
                        byte[] bytes = outStream.ToArray();
                        lastAssembly = Assembly.Load(bytes);
                    }
                }
                else
                {
                    if (!oneAssembly)
                    {
                        this.Monitor.Log($"   Loading {assembly.File.Name}...", LogLevel.Trace);
                    }
                    lastAssembly = Assembly.UnsafeLoadFrom(assembly.File.FullName);
                }
            }

            // last assembly loaded is the root
            return(lastAssembly);
        }