예제 #1
0
파일: ModLoader.cs 프로젝트: YLMAPI/YLMAPI
        public static void LoadModZIP(string archive)
        {
            if (!File.Exists(archive))
            {
                // Probably a mod in the mod directory
                archive = Path.Combine(ModsDirectory, archive);
            }
            if (!File.Exists(archive))
            {
                // It just doesn't exist.
                return;
            }

            ModLogger.Log("loader", $"Loading mod .zip: {archive}");

            GameModMetadata meta = null;
            Assembly        asm  = null;

            using (ZipFile zip = ZipFile.Read(archive)) {
                Texture2D icon = null;
                // First read the metadata, ...
                foreach (ZipEntry entry in zip.Entries)
                {
                    if (entry.FileName == "metadata.yaml")
                    {
                        using (MemoryStream ms = new MemoryStream()) {
                            entry.Extract(ms);
                            ms.Seek(0, SeekOrigin.Begin);
                            using (StreamReader reader = new StreamReader(ms))
                                meta = GameModMetadata.Parse(archive, "", reader);
                        }
                        continue;
                    }
                    if (entry.FileName == "icon.png")
                    {
                        icon      = new Texture2D(2, 2);
                        icon.name = "icon";
                        using (MemoryStream ms = new MemoryStream()) {
                            entry.Extract(ms);
                            ms.Seek(0, SeekOrigin.Begin);
                            icon.LoadImage(ms.GetBuffer());
                        }
                        icon.filterMode = FilterMode.Point;
                        continue;
                    }
                }

                if (meta != null)
                {
                    // In case the icon appears before the metadata in the .zip
                    if (icon != null)
                    {
                        meta.Icon = icon;
                    }

                    // ... then check if the mod runs on this profile ...
                    if (meta.ProfileID > ModAPI.Profile.Id)
                    {
                        ModLogger.Log("loader", "Mod meant for an in-dev YLMAPI version!");
                        return;
                    }

                    // ... then check if the dependencies are loaded ...
                    foreach (GameModMetadata dep in meta.Dependencies)
                    {
                        if (!DependencyLoaded(dep))
                        {
                            ModLogger.Log("loader", $"Dependency {dep} of mod {meta} not loaded!");
                            return;
                        }
                    }

                    // ... then add an AssemblyResolve handler for all the .zip-ped libraries
                    AppDomain.CurrentDomain.AssemblyResolve += meta._GenerateModAssemblyResolver();
                }

                // ... then the patch (if any) ...
                if (!string.IsNullOrEmpty(meta?.PatchDLL))
                {
                    foreach (ZipEntry entry in zip.Entries)
                    {
                        string entryName = entry.FileName.Replace("\\", "/");
                        if (entryName != meta.PatchDLL)
                        {
                            continue;
                        }

                        using (MemoryStream ms = new MemoryStream()) {
                            entry.Extract(ms);
                            ms.Seek(0, SeekOrigin.Begin);
                            ModRuntimePatcher.LoadPatch(ms);
                        }

                        break;
                    }
                }

                // ... then everything else
                foreach (ZipEntry entry in zip.Entries)
                {
                    string entryName = entry.FileName.Replace("\\", "/");
                    if (meta != null && entryName == meta.DLL)
                    {
                        using (MemoryStream ms = new MemoryStream()) {
                            entry.Extract(ms);
                            ms.Seek(0, SeekOrigin.Begin);
                            if (meta.Prelinked)
                            {
                                asm = Assembly.Load(ms.GetBuffer());
                            }
                            else
                            {
                                asm = meta.GetRelinkedAssembly(ms);
                            }
                        }
                    }

                    ModContent.AddMapping(entryName, new AssetMetadata(archive, entryName)
                    {
                        AssetType = entry.IsDirectory ? typeof(AssetTypeDirectory) : null
                    });
                }
            }

            if (meta != null && asm != null)
            {
                LoadMod(meta, asm);
            }
        }
예제 #2
0
        public static Assembly GetRelinkedAssembly(this GameModMetadata meta, Stream stream, MissingDependencyResolver depResolver = null)
        {
            string name               = Path.GetFileName(meta.DLL);
            string cachedName         = meta.Name + "." + name.Substring(0, name.Length - 3) + "dll";
            string cachedPath         = Path.Combine(ModLoader.ModsCacheDirectory, cachedName);
            string cachedChecksumPath = Path.Combine(ModLoader.ModsCacheDirectory, cachedName + ".sum");

            string[] checksums = new string[2];
            using (MD5 md5 = MD5.Create()) {
                if (GameChecksum == null)
                {
                    using (FileStream fs = File.OpenRead(Assembly.GetAssembly(typeof(ModRelinker)).Location))
                        GameChecksum = md5.ComputeHash(fs).ToHexadecimalString();
                }
                checksums[0] = GameChecksum;

                string modPath = meta.Archive;
                if (modPath.Length == 0)
                {
                    modPath = meta.DLL;
                }
                using (FileStream fs = File.OpenRead(modPath))
                    checksums[1] = md5.ComputeHash(fs).ToHexadecimalString();
            }

            if (File.Exists(cachedPath) && File.Exists(cachedChecksumPath) &&
                checksums.ChecksumsEqual(File.ReadAllLines(cachedChecksumPath)))
            {
                return(Assembly.LoadFrom(cachedPath));
            }

            if (depResolver == null)
            {
                depResolver = _GenerateModDependencyResolver(meta);
            }

            using (MonoModder modder = new MonoModder()
            {
                Input = stream,
                OutputPath = cachedPath,
                CleanupEnabled = false,
                RelinkModuleMap = AssemblyRelinkMap,
                DependencyDirs =
                {
                    ManagedDirectory
                },
                MissingDependencyResolver = depResolver,
                RelinkMap = ModRuntimePatcher.Detourer.RelinkMap
            })
                try {
                    modder.ReaderParameters.ReadSymbols          = false;
                    modder.WriterParameters.WriteSymbols         = false;
                    modder.WriterParameters.SymbolWriterProvider = null;

                    modder.Read();
                    modder.MapDependencies();
                    modder.AutoPatch();
                    modder.Write();
                } catch (Exception e) {
                    ModLogger.Log("relinker", $"Failed relinking {meta}: {e}");
                    return(null);
                }

            return(Assembly.LoadFrom(cachedPath));
        }
예제 #3
0
파일: ModLoader.cs 프로젝트: YLMAPI/YLMAPI
        public static void LoadModDir(string dir)
        {
            if (!Directory.Exists(dir))
            {
                // Probably a mod in the mod directory
                dir = Path.Combine(ModsDirectory, dir);
            }
            if (!Directory.Exists(dir))
            {
                // It just doesn't exist.
                return;
            }

            ModLogger.Log("loader", $"Loading mod directory: {dir}");

            GameModMetadata meta = null;
            Assembly        asm  = null;

            // First read the metadata, ...
            string metaPath = Path.Combine(dir, "metadata.yaml");

            if (File.Exists(metaPath))
            {
                using (StreamReader reader = new StreamReader(metaPath))
                    meta = GameModMetadata.Parse("", dir, reader);
            }

            if (meta != null)
            {
                // ... then check if the mod runs on this profile ...
                if (meta.ProfileID > ModAPI.Profile.Id)
                {
                    ModLogger.Log("loader", "Mod meant for an in-dev YLMAPI version!");
                    return;
                }

                // ... then check if the dependencies are loaded ...
                foreach (GameModMetadata dep in meta.Dependencies)
                {
                    if (!DependencyLoaded(dep))
                    {
                        ModLogger.Log("loader", $"Dependency {dep} of mod {meta} not loaded!");
                        return;
                    }
                }

                // ... then add an AssemblyResolve handler for all the .zip-ped libraries
                AppDomain.CurrentDomain.AssemblyResolve += meta._GenerateModAssemblyResolver();
            }

            // ... then everything else
            ModContent.Crawl(null, dir);
            if (meta == null || !File.Exists(meta.DLL))
            {
                return;
            }
            if (!string.IsNullOrEmpty(meta.PatchDLL) && File.Exists(meta.PatchDLL))
            {
                using (Stream stream = File.OpenRead(meta.PatchDLL))
                    ModRuntimePatcher.LoadPatch(stream);
            }
            if (meta.Prelinked)
            {
                asm = Assembly.LoadFrom(meta.DLL);
            }
            else
            {
                using (FileStream fs = File.OpenRead(meta.DLL))
                    asm = meta.GetRelinkedAssembly(fs);
            }

            if (asm != null)
            {
                LoadMod(meta, asm);
            }
        }