Esempio n. 1
0
        /// <summary>
        /// Performs the patch process
        /// </summary>
        public void Patch()
        {
            // Load oxide assembly
            string oxidefilename = Path.Combine(System.Windows.Forms.Application.StartupPath, "Oxide.Core.dll");

            if (!File.Exists(oxidefilename))
            {
                throw new FileNotFoundException(string.Format("Failed to locate Oxide.dll assembly"));
            }
            AssemblyDefinition oxideassembly = AssemblyDefinition.ReadAssembly(oxidefilename);

            // CReate reader params
            ReaderParameters readerparams = new ReaderParameters();

            readerparams.AssemblyResolver = new AssemblyResolver {
                TargetDirectory = PatchProject.TargetDirectory
            };

            // Loop each manifest
            foreach (var manifest in PatchProject.Manifests)
            {
                // Get the assembly filename
                string filename = GetAssemblyFilename(manifest.AssemblyName, true);
                if (!File.Exists(filename))
                {
                    throw new FileNotFoundException(string.Format("Failed to locate target assembly {0}", manifest.AssemblyName), filename);
                }

                // Load it
                Log("Loading assembly {0}", manifest.AssemblyName);
                AssemblyDefinition assembly = AssemblyDefinition.ReadAssembly(filename, readerparams);

                // Loop each hook
                foreach (var hook in manifest.Hooks)
                {
                    // Check if it's flagged
                    if (hook.Flagged)
                    {
                        // Log
                        Log("Ignored hook {0} as it is flagged", hook.Name);
                    }
                    else
                    {
                        // Locate the method
                        MethodDefinition method;
                        try
                        {
                            var type = assembly.Modules
                                       .SelectMany((m) => m.GetTypes())
                                       .Single((t) => t.FullName == hook.TypeName);

                            method = type.Methods
                                     .Single((m) => Utility.GetMethodSignature(m).Equals(hook.Signature));
                        }
                        catch (Exception)
                        {
                            throw new Exception(string.Format("Failed to locate method {0}::{1} in assembly {2}", hook.TypeName, hook.Signature.Name, manifest.AssemblyName));
                        }

                        // Let the hook do it's work
                        ILWeaver weaver = new ILWeaver(method.Body);
                        weaver.Module = method.Module;
                        try
                        {
                            // Apply
                            hook.ApplyPatch(method, weaver, oxideassembly);
                            weaver.Apply(method.Body);

                            // Log
                            Log("Applied hook {0} to {1}::{2}", hook.Name, hook.TypeName, hook.Signature.Name);
                        }
                        catch (Exception ex)
                        {
                            Log("Failed to apply hook {0}", hook.Name);
                            Log("{0}", ex.ToString());
                        }
                    }
                }

                // Save it
                Log("Saving assembly {0}", manifest.AssemblyName);
                filename = GetAssemblyFilename(manifest.AssemblyName, false);
                assembly.Write(filename);
            }
        }
Esempio n. 2
0
        /// <summary>
        /// Performs the patch process
        /// </summary>
        public void Patch(bool console)
        {
            // Load oxide assembly
            string oxidefilename = Path.Combine(System.Windows.Forms.Application.StartupPath, "Oxide.Core.dll");

            if (!File.Exists(oxidefilename))
            {
                throw new FileNotFoundException(string.Format("Failed to locate Oxide.dll assembly"));
            }
            AssemblyDefinition oxideassembly = AssemblyDefinition.ReadAssembly(oxidefilename);

            if (PatchProject == null)
            {
                return;
            }
            // CReate reader params
            ReaderParameters readerparams = new ReaderParameters();

            readerparams.AssemblyResolver = new AssemblyResolver {
                TargetDirectory = PatchProject.TargetDirectory
            };
            DateTime now = DateTime.Now;

            WriteToLog("----------------------------------------");
            WriteToLog(now.ToShortDateString() + " " + now.ToString("hh:mm:ss tt zzz"));
            WriteToLog("----------------------------------------");
            // Loop each manifest
            foreach (var manifest in PatchProject.Manifests)
            {
                // Get the assembly filename
                string filename;
                if (!console)
                {
                    filename = GetAssemblyFilename(manifest.AssemblyName, true);
                    if (!File.Exists(filename))
                    {
                        WriteToLog(string.Format("Failed to locate target assembly {0}", manifest.AssemblyName));
                        throw new FileNotFoundException(string.Format("Failed to locate target assembly {0}", manifest.AssemblyName), filename);
                    }
                }
                else
                {
                    filename = GetAssemblyFilename(manifest.AssemblyName, true);
                    if (!File.Exists(filename))
                    {
                        filename = GetAssemblyFilename(manifest.AssemblyName, false);
                        if (!File.Exists(filename))
                        {
                            WriteToLog(string.Format("Failed to locate target assembly {0}", manifest.AssemblyName));
                            throw new FileNotFoundException(string.Format("Failed to locate target assembly {0}", manifest.AssemblyName), filename);
                        }
                        else
                        {
                            System.IO.File.Copy(filename, Path.GetFileNameWithoutExtension(filename) + "_Original" + Path.GetExtension(filename), true);
                            filename = Path.GetFileNameWithoutExtension(filename) + "_Original" + Path.GetExtension(filename);
                        }
                    }
                }

                // Load it
                if (console)
                {
                    Console.WriteLine(string.Format("Loading assembly {0}", manifest.AssemblyName));
                }
                else
                {
                    Log("Loading assembly {0}", manifest.AssemblyName);
                }
                WriteToLog(string.Format("Loading assembly {0}", manifest.AssemblyName));
                AssemblyDefinition assembly = AssemblyDefinition.ReadAssembly(filename, readerparams);

                var baseHooks = (from hook in manifest.Hooks where hook.BaseHook != null select hook.BaseHook).ToList();

                // Loop each hook
                foreach (var hook in manifest.Hooks)
                {
                    if (baseHooks.Contains(hook))
                    {
                        continue;
                    }
                    // Check if it's flagged
                    if (hook.Flagged)
                    {
                        // Log
                        if (console)
                        {
                            Console.WriteLine(string.Format("Ignored hook {0} as it is flagged", hook.Name));
                        }
                        else
                        {
                            Log("Ignored hook {0} as it is flagged", hook.Name);
                        }
                        WriteToLog(string.Format("Ignored hook {0} as it is flagged", hook.Name));
                    }
                    else
                    {
                        // Locate the method
                        MethodDefinition method;
                        try
                        {
                            var type = assembly.Modules
                                       .SelectMany((m) => m.GetTypes())
                                       .Single((t) => t.FullName == hook.TypeName);

                            method = type.Methods
                                     .Single((m) => Utility.GetMethodSignature(m).Equals(hook.Signature));
                        }
                        catch (Exception)
                        {
                            WriteToLog(string.Format("Failed to locate method {0}::{1} in assembly {2}", hook.TypeName, hook.Signature.Name, manifest.AssemblyName));
                            throw new Exception(string.Format("Failed to locate method {0}::{1} in assembly {2}", hook.TypeName, hook.Signature.Name, manifest.AssemblyName));
                        }

                        // Let the hook do it's work
                        var weaver = new ILWeaver(method.Body)
                        {
                            Module = method.Module
                        };
                        try
                        {
                            // Apply
                            bool patchApplied = hook.PreparePatch(method, weaver, oxideassembly, console) && hook.ApplyPatch(method, weaver, oxideassembly, console);
                            if (patchApplied)
                            {
                                weaver.Apply(method.Body);
                            }
                            else
                            {
                                if (console)
                                {
                                    Console.WriteLine(string.Format("The injection index specified for {0} is invalid!", hook.Name));
                                }
                                WriteToLog(string.Format("The injection index specified for {0} is invalid!", hook.Name));
                                hook.Flagged = true;
                            }

                            // Log
                            if (console)
                            {
                                if (patchApplied)
                                {
                                    Console.WriteLine(string.Format("Applied hook {0} to {1}::{2}", hook.Name, hook.TypeName, hook.Signature.Name));
                                    WriteToLog(string.Format("Applied hook {0} to {1}::{2}", hook.Name, hook.TypeName, hook.Signature.Name));
                                }
                                else
                                {
                                    Console.WriteLine(string.Format("Failed to apply hook {0}", hook.Name));
                                    WriteToLog(string.Format("Failed to apply hook {0}", hook.Name));
                                }
                            }
                            else
                            {
                                if (patchApplied)
                                {
                                    Log("Applied hook {0} to {1}::{2}", hook.Name, hook.TypeName, hook.Signature.Name);
                                    WriteToLog(string.Format("Applied hook {0} to {1}::{2}", hook.Name, hook.TypeName, hook.Signature.Name));
                                }
                                else
                                {
                                    Log("Failed to apply hook {0}", hook.Name);
                                    WriteToLog(string.Format("Failed to apply hook {0}", hook.Name));
                                }
                            }
                        }
                        catch (Exception ex)
                        {
                            if (console)
                            {
                                Console.WriteLine(string.Format("Failed to apply hook {0}", hook.Name));
                                Console.WriteLine(ex.ToString());
                            }
                            else
                            {
                                Log("Failed to apply hook {0}", hook.Name);
                                Log("{0}", ex.ToString());
                            }
                            WriteToLog(string.Format("Failed to apply hook {0}", hook.Name));
                            WriteToLog(ex.ToString());
                        }
                    }
                }

                // Save it
                if (console)
                {
                    Console.WriteLine(string.Format("Saving assembly {0}", manifest.AssemblyName));
                }
                else
                {
                    Log("Saving assembly {0}", manifest.AssemblyName);
                }
                WriteToLog(string.Format("Saving assembly {0}", manifest.AssemblyName));
                filename = GetAssemblyFilename(manifest.AssemblyName, false);
                assembly.Write(filename);
            }
        }
Esempio n. 3
0
        /// <summary>
        /// Performs the patch process
        /// </summary>
        public void Patch()
        {
            // Load oxide assembly
            string oxidefilename = Path.Combine(System.Windows.Forms.Application.StartupPath, "Oxide.Core.dll");

            if (!File.Exists(oxidefilename))
            {
                throw new FileNotFoundException("Failed to locate Oxide.Core.dll assembly");
            }
            AssemblyDefinition oxideassembly = AssemblyDefinition.ReadAssembly(oxidefilename);

            if (PatchProject == null)
            {
                return;
            }
            // CReate reader params
            ReaderParameters readerparams = new ReaderParameters();

            readerparams.AssemblyResolver = new AssemblyResolver {
                TargetDirectory = PatchProject.TargetDirectory
            };
            DateTime now = DateTime.Now;

            WriteToLog("----------------------------------------");
            WriteToLog(now.ToShortDateString() + " " + now.ToString("hh:mm:ss tt zzz"));
            WriteToLog("----------------------------------------");
            // Loop each manifest
            foreach (var manifest in PatchProject.Manifests)
            {
                // Get the assembly filename
                string filename;
                if (!IsConsole)
                {
                    filename = GetAssemblyFilename(manifest.AssemblyName, true);
                    if (!File.Exists(filename))
                    {
                        WriteToLog(string.Format("Failed to locate target assembly {0}", manifest.AssemblyName));
                        throw new FileNotFoundException(string.Format("Failed to locate target assembly {0}", manifest.AssemblyName), filename);
                    }
                }
                else
                {
                    filename = GetAssemblyFilename(manifest.AssemblyName, true);
                    if (!File.Exists(filename))
                    {
                        filename = GetAssemblyFilename(manifest.AssemblyName, false);
                        if (!File.Exists(filename))
                        {
                            WriteToLog(string.Format("Failed to locate target assembly {0}", manifest.AssemblyName));
                            throw new FileNotFoundException(string.Format("Failed to locate target assembly {0}", manifest.AssemblyName), filename);
                        }
                        else
                        {
                            System.IO.File.Copy(filename, Path.GetFileNameWithoutExtension(filename) + "_Original" + Path.GetExtension(filename), true);
                            filename = Path.GetFileNameWithoutExtension(filename) + "_Original" + Path.GetExtension(filename);
                        }
                    }
                }

                // Load it
                Log("Loading assembly {0}", manifest.AssemblyName);
                AssemblyDefinition assembly = AssemblyDefinition.ReadAssembly(filename, readerparams);

                var baseHooks  = (from hook in manifest.Hooks where hook.BaseHook != null select hook.BaseHook).ToList();
                var cloneHooks = manifest.Hooks.Where(hook => hook.BaseHook != null).ToDictionary(hook => hook.BaseHook);

                // Loop each hook
                foreach (var hook in manifest.Hooks)
                {
                    var cloneFlagged = false;
                    if (cloneHooks.ContainsKey(hook))
                    {
                        cloneFlagged = cloneHooks[hook].Flagged;
                    }

                    if (baseHooks.Contains(hook) && !hook.Flagged && !cloneFlagged)
                    {
                        continue;
                    }
                    // Check if it's flagged
                    if (hook.BaseHook != null)
                    {
                        if (hook.BaseHook.Flagged)
                        {
                            Log("Ignored hook {0} as its base hook {1} is flagged", hook.Name, hook.BaseHook.Name);
                            continue;
                        }
                    }
                    if (hook.Flagged)
                    {
                        // Log
                        Log("Ignored hook {0} as it is flagged", hook.Name);
                    }
                    else
                    {
                        // Locate the method
                        MethodDefinition method;
                        try
                        {
                            var type = assembly.Modules
                                       .SelectMany((m) => m.GetTypes())
                                       .Single((t) => t.FullName == hook.TypeName);

                            method = type.Methods
                                     .Single((m) => Utility.GetMethodSignature(m).Equals(hook.Signature));
                        }
                        catch (Exception)
                        {
                            WriteToLog(string.Format("Failed to locate method {0}::{1} in assembly {2}", hook.TypeName, hook.Signature.Name, manifest.AssemblyName));
                            throw new Exception(string.Format("Failed to locate method {0}::{1} in assembly {2}", hook.TypeName, hook.Signature.Name, manifest.AssemblyName));
                        }

                        // Let the hook do it's work
                        var weaver = new ILWeaver(method.Body)
                        {
                            Module = method.Module
                        };
                        try
                        {
                            // Apply
                            bool patchApplied = hook.PreparePatch(method, weaver, oxideassembly, this) && hook.ApplyPatch(method, weaver, oxideassembly, this);
                            if (patchApplied)
                            {
                                weaver.Apply(method.Body);
                                var bhook = hook;
                                if (bhook.BaseHook != null)
                                {
                                    var patchedHooks = new List <string> {
                                        hook.Name
                                    };
                                    while (bhook.BaseHook != null)
                                    {
                                        bhook = bhook.BaseHook;
                                        patchedHooks.Add(bhook.Name);
                                    }
                                    patchedHooks.Reverse();
                                    Log("Applied hooks {0} to {1}::{2}", string.Join(", ", patchedHooks), bhook.TypeName, bhook.Signature.Name);
                                }
                                else
                                {
                                    Log("Applied hook {0} to {1}::{2}", hook.Name, hook.TypeName, hook.Signature.Name);
                                }
                            }
                            else
                            {
                                Log("Failed to apply hook {0}, invalid injection index specified!", hook.Name);
                                hook.Flagged = true;
                            }
                        }
                        catch (Exception ex)
                        {
                            Log("Failed to apply hook {0}", hook.Name);
                            Log(ex.ToString());
                        }
                    }
                }

                // Loop each access modifier
                foreach (var modifier in manifest.Modifiers)
                {
                    if (modifier.Flagged)
                    {
                        // Log
                        Log($"Ignored modifier changes to {modifier.Name} as it is flagged");
                    }
                    else
                    {
                        switch (modifier.Type)
                        {
                        case ModifierType.Field:
                            FieldDefinition field;
                            try
                            {
                                var type = assembly.Modules.SelectMany(m => m.GetTypes()).Single(t => t.FullName == modifier.TypeName);
                                field = type.Fields.Single(m => Utility.GetModifierSignature(m).Equals(modifier.Signature));
                            }
                            catch (Exception)
                            {
                                WriteToLog($"Failed to locate field {modifier.TypeName}::{modifier.Signature.Name} in assembly {manifest.AssemblyName}");
                                throw new Exception($"Failed to locate field {modifier.TypeName}::{modifier.Signature.Name} in assembly {manifest.AssemblyName}");
                            }

                            if (modifier.Signature.Exposure[0] != modifier.TargetExposure[0])
                            {
                                switch (modifier.Signature.Exposure[0])
                                {
                                case Exposure.Private:
                                    field.Attributes -= FieldAttributes.Private;
                                    break;

                                case Exposure.Protected:
                                    field.Attributes -= FieldAttributes.Family;
                                    break;

                                case Exposure.Public:
                                    field.Attributes -= FieldAttributes.Public;
                                    break;

                                case Exposure.Internal:
                                    field.Attributes -= FieldAttributes.Assembly;
                                    break;
                                }

                                switch (modifier.TargetExposure[0])
                                {
                                case Exposure.Private:
                                    field.Attributes |= FieldAttributes.Private;
                                    break;

                                case Exposure.Protected:
                                    field.Attributes |= FieldAttributes.Family;
                                    break;

                                case Exposure.Public:
                                    field.Attributes |= FieldAttributes.Public;
                                    break;

                                case Exposure.Internal:
                                    field.Attributes |= FieldAttributes.Assembly;
                                    break;
                                }
                            }

                            switch (modifier.TargetExposure.Length)
                            {
                            case 1:
                                if (field.IsStatic)
                                {
                                    field.Attributes -= FieldAttributes.Static;
                                }
                                break;

                            case 2:
                                if (!field.IsStatic)
                                {
                                    field.Attributes |= FieldAttributes.Static;
                                }
                                break;
                            }

                            Log($"Applied modifier changes to field {modifier.TypeName}::{modifier.Name}");
                            break;

                        case ModifierType.Method:
                            MethodDefinition method;
                            try
                            {
                                var type = assembly.Modules.SelectMany(m => m.GetTypes()).Single(t => t.FullName == modifier.TypeName);
                                method = type.Methods.Single(m => Utility.GetModifierSignature(m).Equals(modifier.Signature));
                            }
                            catch (Exception)
                            {
                                WriteToLog($"Failed to locate method {modifier.TypeName}::{modifier.Signature.Name} in assembly {manifest.AssemblyName}");
                                throw new Exception($"Failed to locate method {modifier.TypeName}::{modifier.Signature.Name} in assembly {manifest.AssemblyName}");
                            }

                            if (modifier.Signature.Exposure[0] != modifier.TargetExposure[0])
                            {
                                switch (modifier.Signature.Exposure[0])
                                {
                                case Exposure.Private:
                                    method.Attributes -= MethodAttributes.Private;
                                    break;

                                case Exposure.Protected:
                                    method.Attributes -= MethodAttributes.Family;
                                    break;

                                case Exposure.Public:
                                    method.Attributes -= MethodAttributes.Public;
                                    break;

                                case Exposure.Internal:
                                    method.Attributes -= MethodAttributes.Assembly;
                                    break;
                                }

                                switch (modifier.TargetExposure[0])
                                {
                                case Exposure.Private:
                                    method.Attributes |= MethodAttributes.Private;
                                    break;

                                case Exposure.Protected:
                                    method.Attributes |= MethodAttributes.Family;
                                    break;

                                case Exposure.Public:
                                    method.Attributes |= MethodAttributes.Public;
                                    break;

                                case Exposure.Internal:
                                    method.Attributes |= MethodAttributes.Assembly;
                                    break;
                                }
                            }

                            switch (modifier.TargetExposure.Length)
                            {
                            case 1:
                                if (method.IsStatic)
                                {
                                    method.Attributes -= MethodAttributes.Static;
                                }
                                break;

                            case 2:
                                if (!method.IsStatic)
                                {
                                    method.Attributes |= MethodAttributes.Static;
                                }
                                break;
                            }

                            Log($"Applied modifier changes to method {modifier.TypeName}::{modifier.Signature.Name}");
                            break;

                        case ModifierType.Property:
                            PropertyDefinition property;
                            try
                            {
                                var type = assembly.Modules.SelectMany(m => m.GetTypes()).Single(t => t.FullName == modifier.TypeName);
                                property = type.Properties.Single(m => Utility.GetModifierSignature(m).Equals(modifier.Signature));
                            }
                            catch (Exception)
                            {
                                WriteToLog($"Failed to locate property {modifier.TypeName}::{modifier.Signature.Name} in assembly {manifest.AssemblyName}");
                                throw new Exception($"Failed to locate property {modifier.TypeName}::{modifier.Signature.Name} in assembly {manifest.AssemblyName}");
                            }

                            if (property.GetMethod != null && modifier.Signature.Exposure[0] != modifier.TargetExposure[0])
                            {
                                switch (modifier.Signature.Exposure[0])
                                {
                                case Exposure.Private:
                                    property.GetMethod.Attributes -= MethodAttributes.Private;
                                    break;

                                case Exposure.Protected:
                                    property.GetMethod.Attributes -= MethodAttributes.Family;
                                    break;

                                case Exposure.Public:
                                    property.GetMethod.Attributes -= MethodAttributes.Public;
                                    break;

                                case Exposure.Internal:
                                    property.GetMethod.Attributes -= MethodAttributes.Assembly;
                                    break;
                                }

                                switch (modifier.TargetExposure[0])
                                {
                                case Exposure.Private:
                                    property.GetMethod.Attributes |= MethodAttributes.Private;
                                    break;

                                case Exposure.Protected:
                                    property.GetMethod.Attributes |= MethodAttributes.Family;
                                    break;

                                case Exposure.Public:
                                    property.GetMethod.Attributes |= MethodAttributes.Public;
                                    break;

                                case Exposure.Internal:
                                    property.GetMethod.Attributes |= MethodAttributes.Assembly;
                                    break;
                                }
                            }

                            if (property.SetMethod != null && modifier.Signature.Exposure[1] != modifier.TargetExposure[1])
                            {
                                switch (modifier.Signature.Exposure[1])
                                {
                                case Exposure.Private:
                                    property.SetMethod.Attributes -= MethodAttributes.Private;
                                    break;

                                case Exposure.Protected:
                                    property.SetMethod.Attributes -= MethodAttributes.Family;
                                    break;

                                case Exposure.Public:
                                    property.SetMethod.Attributes -= MethodAttributes.Public;
                                    break;

                                case Exposure.Internal:
                                    property.SetMethod.Attributes -= MethodAttributes.Assembly;
                                    break;
                                }

                                switch (modifier.TargetExposure[1])
                                {
                                case Exposure.Private:
                                    property.SetMethod.Attributes |= MethodAttributes.Private;
                                    break;

                                case Exposure.Protected:
                                    property.SetMethod.Attributes |= MethodAttributes.Family;
                                    break;

                                case Exposure.Public:
                                    property.SetMethod.Attributes |= MethodAttributes.Public;
                                    break;

                                case Exposure.Internal:
                                    property.SetMethod.Attributes |= MethodAttributes.Assembly;
                                    break;
                                }
                            }

                            switch (modifier.TargetExposure.Length)
                            {
                            case 1:
                                if (property.GetMethod != null && property.GetMethod.IsStatic)
                                {
                                    property.GetMethod.Attributes -= MethodAttributes.Static;
                                }
                                if (property.SetMethod != null && property.SetMethod.IsStatic)
                                {
                                    property.SetMethod.Attributes -= MethodAttributes.Static;
                                }
                                break;

                            case 2:
                                if (property.GetMethod != null && property.SetMethod == null && !property.GetMethod.IsStatic)
                                {
                                    property.GetMethod.Attributes |= MethodAttributes.Static;
                                }
                                break;

                            case 3:
                                if (property.GetMethod != null && !property.GetMethod.IsStatic)
                                {
                                    property.GetMethod.Attributes |= MethodAttributes.Static;
                                }
                                if (property.SetMethod != null && !property.SetMethod.IsStatic)
                                {
                                    property.SetMethod.Attributes |= MethodAttributes.Static;
                                }
                                break;
                            }

                            Log($"Applied modifier changes to property {modifier.TypeName}::{modifier.Name}");
                            break;

                        case ModifierType.Type:
                            TypeDefinition typedef;
                            try
                            {
                                typedef = assembly.Modules.SelectMany(m => m.GetTypes()).Single(t => t.FullName == modifier.TypeName);
                            }
                            catch (Exception)
                            {
                                WriteToLog($"Failed to locate type {modifier.TypeName} in assembly {manifest.AssemblyName}");
                                throw new Exception($"Failed to locate type {modifier.TypeName} in assembly {manifest.AssemblyName}");
                            }

                            if (modifier.Signature.Exposure[0] != modifier.TargetExposure[0])
                            {
                                switch (modifier.Signature.Exposure[0])
                                {
                                case Exposure.Private:
                                    if (typedef.IsNested)
                                    {
                                        typedef.Attributes -= TypeAttributes.NestedPrivate;
                                    }
                                    else
                                    {
                                        typedef.Attributes -= TypeAttributes.NotPublic;
                                    }
                                    break;

                                case Exposure.Public:
                                    if (typedef.IsNested)
                                    {
                                        typedef.Attributes -= TypeAttributes.NestedPublic;
                                    }
                                    else
                                    {
                                        typedef.Attributes -= TypeAttributes.Public;
                                    }
                                    break;
                                }

                                switch (modifier.TargetExposure[0])
                                {
                                case Exposure.Private:
                                    if (typedef.IsNested)
                                    {
                                        typedef.Attributes |= TypeAttributes.NestedPrivate;
                                    }
                                    else
                                    {
                                        typedef.Attributes |= TypeAttributes.NotPublic;
                                    }
                                    break;

                                case Exposure.Public:
                                    if (typedef.IsNested)
                                    {
                                        typedef.Attributes |= TypeAttributes.NestedPublic;
                                    }
                                    else
                                    {
                                        typedef.Attributes |= TypeAttributes.Public;
                                    }
                                    break;
                                }
                            }

                            switch (modifier.TargetExposure.Length)
                            {
                            case 1:
                                if (typedef.IsAbstract && typedef.IsSealed)
                                {
                                    typedef.Attributes -= TypeAttributes.Abstract | TypeAttributes.Sealed;
                                }
                                break;

                            case 2:
                                if (!typedef.IsAbstract && !typedef.IsSealed)
                                {
                                    typedef.Attributes |= TypeAttributes.Abstract | TypeAttributes.Sealed;
                                }
                                break;
                            }

                            Log($"Applied modifier changes to type {modifier.TypeName}");
                            break;
                        }
                    }
                }

                // Loop each additional field
                foreach (var field in manifest.Fields)
                {
                    if (field.Flagged)
                    {
                        Log($"Ignored adding field {field.TypeName}::{field.Name} as it is flagged");
                        continue;
                    }

                    if (string.IsNullOrEmpty(field.FieldType))
                    {
                        Log($"Ignored adding field {field.TypeName}::{field.Name} as it has no target type");
                        continue;
                    }

                    var fieldData = field.FieldType.Split('|');

                    var target = assembly.MainModule.GetType(field.TypeName);
                    var newFieldAssemblyFile = Path.Combine(PatchProject.TargetDirectory, $"{fieldData[0].Replace(".dll", "")}.dll");
                    var newFieldAssembly     = AssemblyDefinition.ReadAssembly(newFieldAssemblyFile);
                    if (newFieldAssembly == null)
                    {
                        Log($"Failed to add field {field.TypeName}::{field.Name}, the Assembly '{fieldData[0]}' could not be found");
                        continue;
                    }

                    var newFieldType = newFieldAssembly.MainModule.GetType(fieldData[1]);
                    if (newFieldType == null)
                    {
                        Log($"Failed to add field {field.TypeName}::{field.Name}, the type '{fieldData[1]}' could not be found");
                        continue;
                    }

                    var newField = new FieldDefinition(field.Name, FieldAttributes.Public | FieldAttributes.NotSerialized, assembly.MainModule.Import(newFieldType))
                    {
                        Constant    = null,
                        HasConstant = false
                    };

                    target.Fields.Add(newField);

                    Log($"Applied new field {field.Name} to {field.TypeName}");
                }

                // Save it
                Log("Saving assembly {0}", manifest.AssemblyName);
                filename = GetAssemblyFilename(manifest.AssemblyName, false);
                assembly.Write(filename);
            }
        }