Пример #1
0
        public void Create(ProgressHandler progress)
        {
            string modFilePath = GetFolderPath() + System.IO.Path.DirectorySeparatorChar + "Mod" + System.IO.Path.DirectorySeparatorChar + this.ID + ".dll";

            if (!System.IO.File.Exists(modFilePath))
            {
                Debug.Log("Mod: " + ID, "Couldn't find the compiled mod dll at \"" + modFilePath + "\".", Debug.Type.ERROR);
                SetProgress(progress, "Error.FileNotFound");
                return;
            }

            string modInfoPath = GetFolderPath() + System.IO.Path.DirectorySeparatorChar + "ModInfo.xml";

            if (!System.IO.File.Exists(modInfoPath))
            {
                Debug.Log("Mod: " + ID, "Couldn't find the mod configuration at \"" + modInfoPath + "\".", Debug.Type.ERROR);
                SetProgress(progress, "Error.FileNotFound");
                return;
            }

            string libraryFolder  = Game.ModLibrary.GetLibraryFolder();
            string baseModLibPath = libraryFolder + System.IO.Path.DirectorySeparatorChar + "BaseModLib.dll";

            if (!System.IO.File.Exists(baseModLibPath))
            {
                Debug.Log("Mod: " + ID, "Couldn't find BaseModLib.dll at \"" + baseModLibPath + "\".", Debug.Type.ERROR);
                SetProgress(progress, "Error.FileNotFound");
                return;
            }

            ModuleDefinition modModule;
            ModuleDefinition baseModLib;

            try
            {
                SetProgress(progress, 0f, "Preparing");
                baseModLib = ModuleDefinition.ReadModule(baseModLibPath);
                SetProgress(progress, 5f);
                Utils.CustomAssemblyResolver assemblyResolver = new Utils.CustomAssemblyResolver();
                assemblyResolver.AddPath(ModAPI.Configurations.Configuration.GetPath("ModLib") + System.IO.Path.DirectorySeparatorChar + Game.GameConfiguration.ID + System.IO.Path.DirectorySeparatorChar);
                modModule = ModuleDefinition.ReadModule(modFilePath, new ReaderParameters()
                {
                    AssemblyResolver = assemblyResolver
                });
                SetProgress(progress, 10f);
            }
            catch (Exception e)
            {
                Debug.Log("Mod: " + ID, "One of the assemblies is corrupted: " + e.ToString(), Debug.Type.ERROR);
                SetProgress(progress, "Error.CorruptAssembly");
                return;
            }

            Mod mod = new Mod(this.Game, "");

            mod.header = new Mod.Header(mod, System.IO.File.ReadAllText(modInfoPath));
            mod.module = modModule;
            MemoryStream stream = new MemoryStream();

            mod.module.Write(stream);
            stream.Position    = 0;
            mod.originalModule = ModuleDefinition.ReadModule(stream);

            SetProgress(progress, 15f);

            try
            {
                Dictionary <MethodReference, MethodReference> baseModLibRemap = new Dictionary <MethodReference, MethodReference>();
                foreach (TypeDefinition baseModLibType in baseModLib.Types)
                {
                    foreach (MethodDefinition method in baseModLibType.Methods)
                    {
                        if (method.HasCustomAttributes && method.CustomAttributes[0].AttributeType.Name == "AddModname")
                        {
                            foreach (MethodDefinition method2 in baseModLibType.Methods)
                            {
                                if (!method2.HasCustomAttributes && method2.Name == method.Name && method2.Parameters.Count > method.Parameters.Count)
                                {
                                    bool add = true;
                                    for (int i = 0; i < method.Parameters.Count; i++)
                                    {
                                        ParameterDefinition param = method.Parameters[i];
                                        if (param.ParameterType.FullName != method2.Parameters[i].ParameterType.FullName)
                                        {
                                            add = false;
                                        }
                                    }
                                    if (add)
                                    {
                                        baseModLibRemap.Add(method, method2);
                                    }
                                }
                            }
                        }
                    }
                }
                SetProgress(progress, 20f, "FetchingTypes");

                Dictionary <string, string> injectableClasses = new Dictionary <string, string>();
                Dictionary <string, Dictionary <string, TypeDefinition> > assemblyTypes = new Dictionary <string, Dictionary <string, TypeDefinition> >();

                for (int i = 0; i < Game.GameConfiguration.IncludeAssemblies.Count; i++)
                {
                    string           assembly = libraryFolder + System.IO.Path.DirectorySeparatorChar + Game.ParsePath(Game.GameConfiguration.IncludeAssemblies[i]);
                    ModuleDefinition module   = ModuleDefinition.ReadModule(assembly);
                    string           key      = System.IO.Path.GetFileNameWithoutExtension(assembly);
                    assemblyTypes.Add(key, new Dictionary <string, TypeDefinition>());
                    foreach (TypeDefinition type in module.Types)
                    {
                        if (!ModLib.CheckName(type.Namespace, Game.GameConfiguration.ExcludeNamespaces) && !ModLib.CheckName(type.FullName, Game.GameConfiguration.ExcludeTypes) && !ModLib.CheckName(type.FullName, Game.GameConfiguration.NoFamily))
                        {
                            assemblyTypes[key].Add(type.FullName, type);
                            if (!injectableClasses.ContainsKey(type.FullName))
                            {
                                injectableClasses.Add(type.FullName, key);
                            }
                        }
                    }
                    SetProgress(progress, 20f + ((float)i / (float)Game.GameConfiguration.IncludeAssemblies.Count) * 30f);
                }

                SetProgress(progress, 50f, "ConvertingClasses");
                Dictionary <string, TypeDefinition> newClasses = new Dictionary <string, TypeDefinition>();
                for (int i = 0; i < modModule.Types.Count; i++)
                {
                    TypeDefinition type = modModule.Types[i];
                    if (type.FullName == "<Module>")
                    {
                        continue;
                    }

                    foreach (MethodDefinition method in type.Methods)
                    {
                        if (method != null && method.Body != null)
                        {
                            for (int j = 0; j < method.Body.Instructions.Count; j++)
                            {
                                ILProcessor methodIL = method.Body.GetILProcessor();

                                Instruction instruction = method.Body.Instructions[j];
                                if (instruction.OpCode == OpCodes.Call && instruction.Operand != null)
                                {
                                    foreach (KeyValuePair <MethodReference, MethodReference> map in baseModLibRemap)
                                    {
                                        if (((MethodReference)instruction.Operand).FullName == map.Key.FullName)
                                        {
                                            instruction.Operand = type.Module.Import(map.Value);
                                            Instruction newInstruction = methodIL.Create(OpCodes.Ldstr, ID);
                                            methodIL.InsertBefore(instruction, newInstruction);
                                        }
                                    }
                                }
                            }
                        }
                    }
                    string assemblyName = "";
                    if (type.BaseType != null && injectableClasses.ContainsKey(type.BaseType.FullName))
                    {
                        assemblyName = injectableClasses[type.BaseType.FullName];
                    }
                    if (assemblyName == "" || !assemblyTypes[assemblyName].ContainsKey(type.BaseType.FullName))
                    {
                        Mod.Header.AddClass addClass = new Mod.Header.AddClass(mod);
                        addClass.Type = type;
                        mod.header.AddAddClass(addClass);
                    }
                    else
                    {
                        foreach (Mono.Cecil.FieldDefinition field in type.Fields)
                        {
                            Mod.Header.AddField addField = new Mod.Header.AddField(mod);
                            addField.Field        = field;
                            addField.AssemblyName = assemblyName;
                            mod.header.AddAddField(addField);
                        }
                        foreach (MethodDefinition method in type.Methods)
                        {
                            if (method == null)
                            {
                                continue;
                            }
                            int priority = int.MaxValue;

                            if (method.CustomAttributes != null)
                            {
                                foreach (CustomAttribute attribute in method.CustomAttributes)
                                {
                                    if (attribute.AttributeType.Name == "Priority")
                                    {
                                        priority = (int)attribute.ConstructorArguments[0].Value;
                                    }
                                }
                            }

                            bool inject = false;

                            if (method.IsVirtual || method.IsStatic || method.IsConstructor)
                            {
                                foreach (MethodDefinition _m in assemblyTypes[assemblyName][type.BaseType.FullName].Methods)
                                {
                                    if (_m.Name == method.Name)
                                    {
                                        if ((_m.IsStatic && method.IsStatic) || (_m.IsConstructor && method.IsConstructor))
                                        {
                                            if (method.Parameters.Count == _m.Parameters.Count)
                                            {
                                                bool ok = true;
                                                for (int pi = 0; pi < _m.Parameters.Count; pi++)
                                                {
                                                    ParameterDefinition param = _m.Parameters[pi];
                                                    if (param.ParameterType.FullName != method.Parameters[pi].ParameterType.FullName)
                                                    {
                                                        ok = false;
                                                        break;
                                                    }
                                                }
                                                if (ok)
                                                {
                                                    inject = true;
                                                }
                                            }
                                        }
                                        else if (!_m.IsStatic && !method.IsStatic)
                                        {
                                            inject = true;
                                        }
                                        break;
                                    }
                                }
                            }

                            if (inject)
                            {
                                Mod.Header.InjectInto injectInto = new Mod.Header.InjectInto(mod);
                                injectInto.Method       = method;
                                injectInto.Priority     = priority;
                                injectInto.AssemblyName = assemblyName;
                                mod.header.AddInjectInto(injectInto);
                            }
                            else
                            {
                                Mod.Header.AddMethod addMethod = new Mod.Header.AddMethod(mod);
                                addMethod.Method       = method;
                                addMethod.AssemblyName = assemblyName;
                                mod.header.AddAddMethod(addMethod);
                            }
                        }
                    }
                    SetProgress(progress, 50f + ((float)i / (float)modModule.Types.Count) * 30f);
                }

                foreach (AssemblyNameReference aref in modModule.AssemblyReferences)
                {
                    if (aref.Name == "mscorlib" || aref.Name == "System")
                    {
                        aref.Version        = new System.Version("2.0.0.0");
                        aref.PublicKeyToken = new byte[] { 0xB7, 0x7A, 0x5C, 0x56, 0x19, 0x34, 0xE0, 0x89 };
                    }
                    if (aref.Name == "System.Core")
                    {
                        aref.Version        = new System.Version("3.5.0.0");
                        aref.PublicKeyToken = new byte[] { 0xB7, 0x7A, 0x5C, 0x56, 0x19, 0x34, 0xE0, 0x89 };
                    }
                    if (aref.Name == "System.Xml")
                    {
                        aref.Version        = new System.Version("2.0.0.0");
                        aref.PublicKeyToken = new byte[] { 0xB7, 0x7A, 0x5C, 0x56, 0x19, 0x34, 0xE0, 0x89 };
                    }
                }
            }
            catch (Exception e)
            {
                Debug.Log("Mod: " + ID, "An unexpected error occured while parsing the assembly: " + e.ToString(), Debug.Type.ERROR);
                SetProgress(progress, "Error.UnexpectedError");
                return;
            }


            string modResourcesPath = GetFolderPath() + System.IO.Path.DirectorySeparatorChar + "Resources/";

            if (!System.IO.Directory.Exists(modResourcesPath))
            {
                System.IO.Directory.CreateDirectory(modResourcesPath);
            }
            if (System.IO.Directory.GetFiles(modResourcesPath).Length > 0 || System.IO.Directory.GetDirectories(modResourcesPath).Length > 0)
            {
                ZipFile newZipFile = new ZipFile();
                newZipFile.AddDirectory(modResourcesPath);
                newZipFile.Comment = "Automaticlly created resources zip file.";
                mod.Resources      = newZipFile;
            }


            try
            {
                SetProgress(progress, 90f, "SavingMod");


                string modFolder = System.IO.Path.GetFullPath(Configuration.GetPath("mods") + System.IO.Path.DirectorySeparatorChar + Game.GameConfiguration.ID);

                if (!System.IO.Directory.Exists(modFolder))
                {
                    System.IO.Directory.CreateDirectory(modFolder);
                }

                mod.FileName = System.IO.Path.GetFullPath(modFolder + System.IO.Path.DirectorySeparatorChar + mod.UniqueID + ".mod");
                if (mod.Save())
                {
                    string key = mod.ID + "-" + mod.header.GetVersion();
                    if (Mod.Mods.ContainsKey(key))
                    {
                        if (Mod.Mods[key].FileName != mod.FileName)
                        {
                            Mod.Mods[key].Remove();
                        }
                        //Mod.Mods[key] = mod;
                    }

                    /*else
                     * {
                     *  Mod.Mods.Add(key, mod);
                     * }*/
                    SetProgress(progress, 100f, "Finish");
                }
                else
                {
                    Debug.Log("Mod: " + ID, "Could not save the mod.", Debug.Type.ERROR);
                    SetProgress(progress, "Error.Save");
                }
            }
            catch (Exception e)
            {
                Debug.Log("Mod: " + ID, "An error occured while saving the mod: " + e.ToString(), Debug.Type.ERROR);
                SetProgress(progress, "Error.Save");
            }
        }
Пример #2
0
        public void Create(ProgressHandler progress = null)
        {
            string libraryPath = GetLibraryFolder();

            System.IO.Directory.CreateDirectory(libraryPath);

            /** Remove old files **/
            SetProgress(progress, 0, "RemovingOldFiles");
            string[] oldFiles     = System.IO.Directory.GetFiles(libraryPath);
            int      removedFiles = 0;

            foreach (string file in oldFiles)
            {
                System.IO.FileAttributes attr = System.IO.File.GetAttributes(@file);
                if ((attr & System.IO.FileAttributes.Directory) == System.IO.FileAttributes.Directory)
                {
                    System.IO.Directory.Delete(file, true);
                }
                else
                {
                    System.IO.File.Delete(file);
                }
                removedFiles++;
            }
            Debug.Log("Modlib: " + this.Game.GameConfiguration.ID, "Removed " + removedFiles + " files and directories.");
            SetProgress(progress, 1f, "CreatingModToolkit");

            string baseModLibPath = Configurations.Configuration.GetPath("Libraries") + System.IO.Path.DirectorySeparatorChar + "BaseModLib.dll";

            if (!System.IO.File.Exists(baseModLibPath))
            {
                Debug.Log("Modlib: " + this.Game.GameConfiguration.ID, "Couldn't find BaseModLib.dll.", Debug.Type.ERROR);
                SetProgress(progress, "Error.BaseModLibNotFound");
                return;
            }

            ModuleDefinition baseModLib = ModuleDefinition.ReadModule(baseModLibPath);

            foreach (TypeDefinition type in baseModLib.Types)
            {
                List <string> ChangeMethods = new List <string>();
                foreach (MethodDefinition method in type.Methods)
                {
                    if (method.HasCustomAttributes)
                    {
                        if (method.CustomAttributes[0].AttributeType.Name == "AddModname")
                        {
                            ChangeMethods.Add(method.Name);
                        }
                    }
                }
                foreach (MethodDefinition method in type.Methods)
                {
                    if (ChangeMethods.Contains(method.Name))
                    {
                        method.IsPrivate           = false;
                        method.IsFamily            = false;
                        method.IsAssembly          = false;
                        method.IsFamilyAndAssembly = false;
                        method.IsPublic            = true;
                        Debug.Log("Modlib: " + this.Game.GameConfiguration.ID, "Changed the accessibility of " + method.FullName + " in BaseModLib.dll");
                    }
                }
            }

            byte[] mscorlibPublicKeyToken  = new byte[] { 0x7C, 0xEC, 0x85, 0xD7, 0xBE, 0xA7, 0x79, 0x8E };
            byte[] systemXmlPublicKeyToken = new byte[] { 0x31, 0xBF, 0x38, 0x56, 0xAD, 0x36, 0x4E, 0x35 };
            foreach (AssemblyNameReference assemblyReference in baseModLib.AssemblyReferences)
            {
                if ((assemblyReference.Name.StartsWith("System") || assemblyReference.Name.StartsWith("mscorlib")))
                {
                    assemblyReference.Version = new System.Version("2.0.5.0");
                    if (assemblyReference.Name == "System.Xml.Linq")
                    {
                        assemblyReference.PublicKeyToken = systemXmlPublicKeyToken;
                    }
                    else
                    {
                        assemblyReference.PublicKeyToken = mscorlibPublicKeyToken;
                    }

                    Debug.Log("ModLib: " + this.Game.GameConfiguration.ID, "Changed assembly reference token of " + assemblyReference.Name + " in BaseModLib.dll.");
                }
            }

            CreationTime  = DateTime.Now;
            GameVersion   = Game.BackupVersion.ID;
            ModAPIVersion = ModAPI.Version.Descriptor;

            XDocument metaXML     = new XDocument();
            XElement  rootElement = new XElement("Meta");

            rootElement.Add(new XElement("GameVersion", GameVersion));
            rootElement.Add(new XElement("ModAPIVersion", ModAPIVersion));
            rootElement.Add(new XElement("CreationTime", CreationTime.Ticks + ""));
            metaXML.Add(rootElement);
            EmbeddedResource metaResource = new EmbeddedResource("Meta", ManifestResourceAttributes.Public, System.Text.Encoding.UTF8.GetBytes(metaXML.ToString()));

            baseModLib.Resources.Add(metaResource);

            baseModLib.Write(libraryPath + System.IO.Path.DirectorySeparatorChar + "BaseModLib.dll");
            Debug.Log("ModLib: " + this.Game.GameConfiguration.ID, "Successfully parsed BaseModLib.dll and copied in mod library.");

            SetProgress(progress, 5f, "ModifyingAssemblies");
            Utils.CustomAssemblyResolver assemblyResolver = new Utils.CustomAssemblyResolver();
            assemblyResolver.AddPath(ModAPI.Configurations.Configuration.GetPath("OriginalGameFiles") + System.IO.Path.DirectorySeparatorChar + Game.GameConfiguration.ID + System.IO.Path.DirectorySeparatorChar);
            assemblyResolver.AddPath(libraryPath);

            List <string> SearchFolders = new List <string>();

            for (int i = 0; i < Game.GameConfiguration.IncludeAssemblies.Count; i++)
            {
                string assemblyPath = ModAPI.Configurations.Configuration.GetPath("OriginalGameFiles") + System.IO.Path.DirectorySeparatorChar + Game.GameConfiguration.ID + System.IO.Path.DirectorySeparatorChar + Game.ParsePath(Game.GameConfiguration.IncludeAssemblies[i]);
                string folder       = System.IO.Path.GetDirectoryName(assemblyPath);
                if (!SearchFolders.Contains(folder))
                {
                    Debug.Log("ModLib: " + this.Game.GameConfiguration.ID, "Added folder \"" + folder + "\" to assembly resolver.");
                    SearchFolders.Add(folder);
                }
            }
            for (int i = 0; i < Game.GameConfiguration.CopyAssemblies.Count; i++)
            {
                string assemblyPath = ModAPI.Configurations.Configuration.GetPath("OriginalGameFiles") + System.IO.Path.DirectorySeparatorChar + Game.GameConfiguration.ID + System.IO.Path.DirectorySeparatorChar + Game.ParsePath(Game.GameConfiguration.CopyAssemblies[i]);
                string folder       = System.IO.Path.GetDirectoryName(assemblyPath);
                if (!SearchFolders.Contains(folder))
                {
                    Debug.Log("ModLib: " + this.Game.GameConfiguration.ID, "Added folder \"" + folder + "\" to assembly resolver.");
                    SearchFolders.Add(folder);
                }
            }
            for (int i = 0; i < SearchFolders.Count; i++)
            {
                assemblyResolver.AddPath(SearchFolders[i]);
            }

            for (int i = 0; i < Game.GameConfiguration.IncludeAssemblies.Count; i++)
            {
                string assemblyPath = ModAPI.Configurations.Configuration.GetPath("OriginalGameFiles") + System.IO.Path.DirectorySeparatorChar + Game.GameConfiguration.ID + System.IO.Path.DirectorySeparatorChar + Game.ParsePath(Game.GameConfiguration.IncludeAssemblies[i]);
                if (System.IO.File.Exists(assemblyPath))
                {
                    try
                    {
                        ModuleDefinition module = ModuleDefinition.ReadModule(assemblyPath, new ReaderParameters()
                        {
                            AssemblyResolver = assemblyResolver
                        });
                        foreach (TypeDefinition type in module.Types)
                        {
                            if (!CheckName(type.Namespace, Game.GameConfiguration.ExcludeNamespaces) && !CheckName(type.Name, Game.GameConfiguration.ExcludeTypes) && !CheckName(type.FullName, Game.GameConfiguration.NoFamily))
                            {
                                if (type.IsAbstract && type.IsSealed)
                                {
                                    type.IsAbstract        = false;
                                    type.IsSealed          = false;
                                    type.IsBeforeFieldInit = true;

                                    MethodDefinition constructor = new MethodDefinition(".ctor", MethodAttributes.SpecialName | MethodAttributes.RTSpecialName | MethodAttributes.Public | MethodAttributes.HideBySig, type.Module.TypeSystem.Void);
                                    type.Methods.Add(constructor);
                                }

                                foreach (MethodDefinition m in type.Methods)
                                {
                                    if (!m.IsConstructor)
                                    {
                                        if (!m.IsGetter && !m.IsSetter && !m.IsStatic)
                                        {
                                            m.IsVirtual = true;
                                        }
                                        if (m.IsPrivate)
                                        {
                                            m.IsFamily = true;
                                        }
                                        Debug.Log("ModLib: " + this.Game.GameConfiguration.ID, "Changed private method " + m.FullName + " to protectded");
                                    }
                                }
                                foreach (FieldDefinition f in type.Fields)
                                {
                                    if (f.IsPrivate)
                                    {
                                        f.IsFamily = true;
                                        Debug.Log("ModLib: " + this.Game.GameConfiguration.ID, "Changed private field " + f.FullName + " to protectded");
                                    }
                                }
                            }
                        }
                        string savePath = System.IO.Path.GetFullPath(libraryPath + System.IO.Path.DirectorySeparatorChar + Game.ParsePath(Game.GameConfiguration.IncludeAssemblies[i]));
                        System.IO.Directory.CreateDirectory(System.IO.Path.GetDirectoryName(savePath));
                        module.Write(savePath);
                        Debug.Log("ModLib: " + this.Game.GameConfiguration.ID, "Saved modified \"" + module.Name + "\".");
                    }
                    catch (Exception e)
                    {
                        Debug.Log("ModLib: " + this.Game.GameConfiguration.ID, "File couldnt be parsed: \"" + assemblyPath + "\". Exception: " + e.ToString(), Debug.Type.ERROR);
                        SetProgress(progress, "Error.ModifyAssemblyException");
                        return;
                    }
                    Debug.Log("ModLib: " + this.Game.GameConfiguration.ID, "Successfully parsed file: \"" + assemblyPath + "\" and copied in mod library.");
                }
                else
                {
                    SetProgress(progress, "Error.ModifyAssemblyFileNotFound");
                    Debug.Log("ModLib: " + this.Game.GameConfiguration.ID, "File not found: \"" + assemblyPath + "\".", Debug.Type.ERROR);
                    return;
                }
                SetProgress(progress, 5f + ((float)i / (float)Game.GameConfiguration.IncludeAssemblies.Count) * 75f);
            }

            SetProgress(progress, 80f, "CopyingAssemblies");

            for (int i = 0; i < Game.GameConfiguration.CopyAssemblies.Count; i++)
            {
                string copyFrom = Configurations.Configuration.GetPath("OriginalGameFiles") + System.IO.Path.DirectorySeparatorChar + Game.GameConfiguration.ID + System.IO.Path.DirectorySeparatorChar + Game.ParsePath(Game.GameConfiguration.CopyAssemblies[i]);
                string copyTo   = System.IO.Path.GetFullPath(libraryPath + System.IO.Path.DirectorySeparatorChar + Game.ParsePath(Game.GameConfiguration.CopyAssemblies[i]));

                if (System.IO.File.Exists(copyFrom))
                {
                    System.IO.Directory.CreateDirectory(System.IO.Path.GetDirectoryName(copyTo));
                    System.IO.File.Copy(copyFrom, copyTo, true);
                }
                else
                {
                    SetProgress(progress, "Error.CopyAssemblyFileNotFound");
                    Debug.Log("ModLib: " + this.Game.GameConfiguration.ID, "File not found: \"" + copyFrom + "\".", Debug.Type.ERROR);
                    return;
                }
                SetProgress(progress, 80f + ((float)i / (float)Game.GameConfiguration.CopyAssemblies.Count) * 20f);
            }
            Exists = true;
            SetProgress(progress, 100f, "Finish");
        }