Exemple #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");
            }
        }
Exemple #2
0
        public void Create(ProgressHandler progress)
        {
            var modFilePath = GetFolderPath() + Path.DirectorySeparatorChar + "Mod" + Path.DirectorySeparatorChar + Id + ".dll";

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

            var modInfoPath = GetFolderPath() + Path.DirectorySeparatorChar + "ModInfo.xml";

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

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

            if (!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);
                var assemblyResolver = new CustomAssemblyResolver();
                assemblyResolver.AddPath(Configuration.GetPath("ModLib") + Path.DirectorySeparatorChar + Game.GameConfiguration.Id +
                                         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, Debug.Type.Error);
                SetProgress(progress, "Error.CorruptAssembly");
                return;
            }

            var mod = new Mod(Game, "");

            mod.HeaderData = new Mod.Header(mod, File.ReadAllText(modInfoPath));
            mod.Module     = modModule;
            var stream = new MemoryStream();

            mod.Module.Write(stream);
            stream.Position    = 0;
            mod.OriginalModule = ModuleDefinition.ReadModule(stream);

            SetProgress(progress, 15f);

            try
            {
                var baseModLibRemap = new Dictionary <MethodReference, MethodReference>();
                foreach (var baseModLibType in baseModLib.Types)
                {
                    foreach (var method in baseModLibType.Methods)
                    {
                        if (method.HasCustomAttributes && method.CustomAttributes[0].AttributeType.Name == "AddModname")
                        {
                            foreach (var method2 in baseModLibType.Methods)
                            {
                                if (!method2.HasCustomAttributes && method2.Name == method.Name && method2.Parameters.Count > method.Parameters.Count)
                                {
                                    var add = true;
                                    for (var i = 0; i < method.Parameters.Count; i++)
                                    {
                                        var 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");

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

                for (var i = 0; i < Game.GameConfiguration.IncludeAssemblies.Count; i++)
                {
                    var assembly = libraryFolder + Path.DirectorySeparatorChar + Game.ParsePath(Game.GameConfiguration.IncludeAssemblies[i]);
                    var module   = ModuleDefinition.ReadModule(assembly);
                    var key      = Path.GetFileNameWithoutExtension(assembly);
                    assemblyTypes.Add(key, new Dictionary <string, TypeDefinition>());
                    foreach (var 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 + (i / (float)Game.GameConfiguration.IncludeAssemblies.Count) * 30f);
                }

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

                    foreach (var method in type.Methods)
                    {
                        if (method?.Body != null)
                        {
                            for (var j = 0; j < method.Body.Instructions.Count; j++)
                            {
                                var methodIl = method.Body.GetILProcessor();

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

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

                            var inject = false;

                            if (method.IsVirtual || method.IsStatic || method.IsConstructor)
                            {
                                foreach (var m in assemblyTypes[assemblyName][type.BaseType.FullName].Methods.Where(o => o.Name == method.Name))
                                {
                                    // Only compare methods with same parameter count
                                    if (method.Parameters.Count == m.Parameters.Count)
                                    {
                                        // No need to compare parameterless methods
                                        if (method.Parameters.Count == 0)
                                        {
                                            inject = true;
                                            break;
                                        }

                                        // Comapare parameters
                                        if (!m.Parameters.Where((param, pi) => param.ParameterType.FullName != method.Parameters[pi].ParameterType.FullName).Any())
                                        {
                                            inject = true;
                                            break;
                                        }
                                    }
                                }
                            }

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

                foreach (var 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, Debug.Type.Error);
                SetProgress(progress, "Error.UnexpectedError");
                return;
            }

            var modResourcesPath = GetFolderPath() + Path.DirectorySeparatorChar + "Resources/";

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

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

                var modFolder = Path.GetFullPath(Configuration.GetPath("mods") + Path.DirectorySeparatorChar + Game.GameConfiguration.Id);

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

                mod.FileName = Path.GetFullPath(modFolder + Path.DirectorySeparatorChar + mod.UniqueId + ".mod");
                if (mod.Save())
                {
                    var key = mod.Id + "-" + mod.HeaderData.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, Debug.Type.Error);
                SetProgress(progress, "Error.Save");
            }
        }