Example #1
0
        public static void Init()
        {
            try {
                // TestRuntimeDetourHelper();

                Detourer = new MonoModDetourer()
                {
                    InputPath      = Assembly.GetExecutingAssembly().Location,
                    CleanupEnabled = false,
                    DependencyDirs =
                    {
                        ModRelinker.ManagedDirectory
                    }
                };

                Detourer.ReaderParameters.ReadSymbols = false;

                // DON'T. The assembly is already patched with the .mm.dlls in there!
                // Otherwise this code here wouldn't even run...
                // Modder.ReadMod(ModRelinker.ManagedDirectory);

                Detourer.Read();
                Detourer.MapDependencies();
            } catch (Exception e) {
                ModLogger.Log("rtpatcher", $"Failed initializing: {e}");
                return;
            }
        }
        public static void Init()
        {
            try {
                Modder = new MonoModder()
                {
                    InputPath      = Assembly.GetExecutingAssembly().Location,
                    CleanupEnabled = false,
                    DependencyDirs =
                    {
                        ModRelinker.ManagedDirectory
                    }
                };

                Modder.ReaderParameters.ReadSymbols = false;

                // DON'T. The assembly is already patched with the .mm.dlls in there!
                // Otherwise this code here wouldn't even run...
                // Modder.ReadMod(ModRelinker.ManagedDirectory);

                Modder.Read();
                Modder.MapDependencies();

                // Do black magic.
                HarmonyInstance.DEBUG = true;
                MMHarmony             = new MMHarmonyInstance(Modder, Assembly.GetExecutingAssembly());
            } catch (Exception e) {
                ModLogger.Log("rtpatcher", $"Failed initializing: {e}");
                return;
            }
        }
Example #3
0
        public static void LoadMod(GameModMetadata meta, Assembly asm)
        {
            ModContent.Crawl(null, asm);

            Type[] types;
            try {
                types = asm.GetTypes();
            } catch (Exception e) {
                e.LogDetailed();
                ModLogger.Log("loader", $"Failed reading assembly: {e}");
                return;
            }
            for (int i = 0; i < types.Length; i++)
            {
                Type type = types[i];
                if (!typeof(GameMod).IsAssignableFrom(type) || type.IsAbstract)
                {
                    continue;
                }

                GameMod mod = (GameMod)type.GetConstructor(_EmptyTypeArray).Invoke(_EmptyObjectArray);

                mod.Metadata = meta;

                Mods.Add(mod);
                _ModuleTypes.Add(type);
                _ModuleMethods.Add(new FastDictionary <string, MethodInfo>());
            }

            ModLogger.Log("loader", $"Mod {meta} initialized.");
        }
Example #4
0
        internal static GameModMetadata Parse(string archive, string directory, StreamReader reader)
        {
            GameModMetadata meta;

            try {
                meta = YamlHelper.Deserializer.Deserialize <GameModMetadata>(reader);
            } catch (Exception e) {
                ModLogger.Log("loader", "Failed parsing metadata.yaml: " + e);
                return(null);
            }
            if (meta == null)
            {
                ModLogger.Log("loader", "Failed parsing metadata.yaml: YamlDotNet returned null");
                return(null);
            }
            meta.Archive   = archive;
            meta.Directory = directory;

            if (!string.IsNullOrEmpty(directory))
            {
                meta.DLL = Path.Combine(directory, meta.DLL.Replace('/', Path.DirectorySeparatorChar).Replace('\\', Path.DirectorySeparatorChar));
                if (!string.IsNullOrEmpty(meta.PatchDLL))
                {
                    meta.PatchDLL = Path.Combine(directory, meta.PatchDLL.Replace('/', Path.DirectorySeparatorChar).Replace('\\', Path.DirectorySeparatorChar));
                }
            }

            // Add dependency to API 1.0 if missing.
            bool dependsOnAPI = false;

            foreach (GameModMetadata dep in meta.Dependencies)
            {
                if (dep.Name == "API")
                {
                    dep.Name     = "YLMAPI";
                    dependsOnAPI = true;
                    break;
                }
                if (dep.Name == "YLMAPI")
                {
                    dependsOnAPI = true;
                    break;
                }
            }
            if (!dependsOnAPI)
            {
                Debug.Log("WARNING: No dependency to API found in " + meta + "! Adding dependency to API 1.0...");
                meta.Dependencies.Insert(0, new GameModMetadata()
                {
                    Name    = "API",
                    Version = new Version(1, 0)
                });
            }

            return(meta);
        }
Example #5
0
 public static void LoadPatch(Stream stream)
 {
     try {
         ModLogger.Log("rtpatcher", "Loading new patch");
         Detourer.ReadMod(stream);
         ModLogger.Log("rtpatcher", $"Applied new patch {Detourer.Mods[Detourer.Mods.Count - 1].Assembly.Name.Name}");
     } catch (Exception e) {
         ModLogger.Log("rtpatcher", $"Failed patching: {e}");
         return;
     }
 }
Example #6
0
        public static void LoadMods()
        {
            Directory.CreateDirectory(ModsDirectory      = Path.Combine(ModAPI.GameDirectory, "Mods"));
            Directory.CreateDirectory(ModsCacheDirectory = Path.Combine(ModsDirectory, "Cache"));
            ModsBlacklistFile = Path.Combine(ModsDirectory, "blacklist.txt");

            ModLogger.Log("loader", "Loading game mods");

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

            if (File.Exists(ModsBlacklistFile))
            {
                blacklist = File.ReadAllLines(ModsBlacklistFile).Select(l => (l.StartsWith("#") ? "" : l).Trim()).ToList();
            }
            else
            {
                using (StreamWriter writer = File.CreateText(ModsBlacklistFile)) {
                    writer.WriteLine("# This is a blacklist file. Lines starting with # are ignored.");
                    writer.WriteLine("ExampleFolder");
                    writer.WriteLine("SomeMod.zip");
                }
            }

            string[] files = Directory.GetFiles(ModsDirectory);
            for (int i = 0; i < files.Length; i++)
            {
                string file = Path.GetFileName(files[i]);
                if (!file.EndsWith(".zip") || blacklist.Contains(file))
                {
                    continue;
                }
                LoadModZIP(file);
            }
            files = Directory.GetDirectories(ModsDirectory);
            for (int i = 0; i < files.Length; i++)
            {
                string file = Path.GetFileName(files[i]);
                if (file == "Cache" || blacklist.Contains(file))
                {
                    continue;
                }
                LoadModDir(file);
            }
        }
Example #7
0
 private static IEnumerator _ListMainScenes()
 {
     SceneInfo[] scenes;
     while ((scenes = ScenesInfo.Instance?.ScenesData?.LookupTable) == null)
     {
         yield return(null);
     }
     for (int i = 0; i < scenes.Length; i++)
     {
         SceneInfo scene = scenes[i];
         if (string.IsNullOrEmpty(scene.SceneName))
         {
             ModLogger.Log("main", $"Found nameless scene info: {i} {scene.HashID} {scene.Scene?.name ?? "null"}");
             continue;
         }
         AddScene(scene.SceneName);
         yield return(null);
     }
 }
 public static void LoadPatch(Stream stream)
 {
     try {
         ModLogger.Log("rtpatcher", "Loading new patch");
         // Reload main assembly.
         Modder.Module = null;
         Modder.Read();
         // Add new mod to mods list.
         Modder.ReadMod(stream);
         ModRelinker.AssemblyRelinkMap[Modder.Mods[Modder.Mods.Count - 1].Assembly.Name.Name] = ModRelinker.AssemblyRelinkedCache["Assembly-CSharp"];
         Modder.MapDependencies();
         // Auto-patch and then feed Harmony.
         ModLogger.Log("rtpatcher", $"Applying new patch {Modder.Mods[Modder.Mods.Count - 1].Assembly.Name.Name}");
         Modder.AutoPatch();
         MMHarmony.PatchAll();
     } catch (Exception e) {
         ModLogger.Log("rtpatcher", $"Failed patching: {e}");
         return;
     }
 }
Example #9
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));
        }
Example #10
0
        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);
            }
        }
Example #11
0
        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);
            }
        }