Exemplo n.º 1
0
        // ran by BTML
        public static void Init()
        {
            ModDirectory = Path.GetFullPath(Path.Combine(Path.GetDirectoryName(VersionManifestUtilities.MANIFEST_FILEPATH), @"..\..\..\Mods\"));
            logPath      = Path.Combine(ModDirectory, "ModTek.log");

            // create log file, overwritting if it's already there
            using (var logWriter = File.CreateText(logPath))
                logWriter.WriteLine("ModTek -- {0}", DateTime.Now);

            // init harmony and patch the stuff that comes with ModTek (contained in Patches.cs)
            var harmony = HarmonyInstance.Create("io.github.mpstark.ModTek");

            harmony.PatchAll(Assembly.GetExecutingAssembly());

            // find all sub-directories that have a mod.json file
            var modDirectories = Directory.GetDirectories(ModDirectory).Where(x => File.Exists(Path.Combine(x, MOD_JSON_NAME)));

            if (modDirectories.Count() == 0)
            {
                Log("No ModTek-compatable mods found.");
            }

            // create ModDef objects for each mod.json file, building a dependancy graph
            var modDefs = new List <ModDef>();

            foreach (var modDirectory in modDirectories)
            {
                ModDef modDef     = null;
                var    modDefPath = Path.Combine(modDirectory, MOD_JSON_NAME);

                try
                {
                    modDef = JsonConvert.DeserializeObject <ModDef>(File.ReadAllText(modDefPath));
                }
                catch (Exception e)
                {
                    Log("Caught exception while parsing {1} at path {0}", modDefPath, MOD_JSON_NAME);
                    Log("Exception: {0}", e.ToString());
                    continue;
                }

                if (modDef == null)
                {
                    Log("ModDef found in {0} not valid.", modDefPath);
                    continue;
                }

                if (!modDef.Enabled)
                {
                    Log("{0} disabled, skipping load.", modDef.Name);
                    continue;
                }

                modDef.Directory = Path.GetDirectoryName(modDefPath);
                modDefs.Add(modDef);
                Log("Loaded ModDef for {0}.", modDef.Name);

                // TODO: build some sort of dependacy graph
            }

            // TODO: load mods in the correct order
            foreach (var modDef in modDefs)
            {
                LoadMod(modDef);
            }
        }
Exemplo n.º 2
0
        public static void LoadMod(ModDef modDef)
        {
            var potentialAdditions = new Dictionary <string, ModDef.ManifestEntry>();

            LogWithDate($"Loading {modDef.Name}");

            // load out of the manifest
            // TODO: actually ignore the modDef specified files/directories
            if (modDef.Manifest != null && modDef.Manifest.Count > 0)
            {
                foreach (var entry in modDef.Manifest)
                {
                    var entryPath = Path.Combine(modDef.Directory, entry.Path);

                    if (string.IsNullOrEmpty(entry.Path) || string.IsNullOrEmpty(entry.Type))
                    {
                        LogWithDate($"{modDef.Name} has a manifest entry that is missing its type or path! Aborting load.");
                        return;
                    }

                    if (Directory.Exists(entryPath))
                    {
                        // path is a directory, add all the files there
                        var files = Directory.GetFiles(entryPath);
                        foreach (var filePath in files)
                        {
                            var id = InferIDFromFileAndType(filePath, entry.Type);

                            if (potentialAdditions.ContainsKey(id))
                            {
                                LogWithDate($"{modDef.Name}'s manifest has a file at {filePath}, but it's inferred ID is already used by this mod! Aborting load.");
                                return;
                            }

                            potentialAdditions.Add(id, new ModDef.ManifestEntry(entry.Type, filePath));
                        }
                    }
                    else if (File.Exists(entryPath))
                    {
                        // path is a file, add the single entry
                        var id = entry.Id ?? InferIDFromFileAndType(entryPath, entry.Type);

                        if (potentialAdditions.ContainsKey(id))
                        {
                            LogWithDate($"{modDef.Name}'s manifest has a file at {entryPath}, but it's inferred ID is already used by this mod! Aborting load.");
                            return;
                        }

                        potentialAdditions.Add(id, new ModDef.ManifestEntry(entry.Type, entryPath));
                    }
                    else
                    {
                        // wasn't a file and wasn't a path, must not exist
                        LogWithDate($"{modDef.Name} has a manifest entry {entryPath}, but it's missing! Aborting load.");
                        return;
                    }
                }
            }

            // load mod dll
            if (modDef.DLL != null)
            {
                var    dllPath    = Path.Combine(modDef.Directory, modDef.DLL);
                string typeName   = null;
                var    methodName = "Init";

                if (!File.Exists(dllPath))
                {
                    LogWithDate($"{modDef.Name} has a DLL specified ({dllPath}), but it's missing! Aborting load.");
                    return;
                }

                if (modDef.DLLEntryPoint != null)
                {
                    var pos = modDef.DLLEntryPoint.LastIndexOf('.');
                    if (pos == -1)
                    {
                        methodName = modDef.DLLEntryPoint;
                    }
                    else
                    {
                        typeName   = modDef.DLLEntryPoint.Substring(0, pos - 1);
                        methodName = modDef.DLLEntryPoint.Substring(pos + 1);
                    }
                }

                LogWithDate($"Using BTML to load dll {Path.GetFileName(dllPath)} with entry path {typeName ?? "NoNameSpecified"}.{methodName}");

                BTModLoader.LoadDLL(dllPath, methodName, typeName,
                                    new object[] { modDef.Directory, modDef.Settings.ToString(Formatting.None) });
            }

            // actually add the additions, since we successfully got through loading the other stuff
            if (potentialAdditions.Count > 0)
            {
                // TODO, this kvp is the weirdest thing
                foreach (var additionKvp in potentialAdditions)
                {
                    Log($"\tWill load manifest entry -- id: {additionKvp.Key} type: {additionKvp.Value.Type} path: {additionKvp.Value.Path}");
                    NewManifestEntries[additionKvp.Key] = additionKvp.Value;
                }
            }

            LogWithDate($"Loaded {modDef.Name}");
        }
Exemplo n.º 3
0
        private static void LoadMod(ModDef modDef)
        {
            var potentialAdditions = new List <ModDef.ManifestEntry>();

            LogWithDate($"Loading {modDef.Name}");

            // load out of the manifest
            if (modDef.LoadImplicitManifest && modDef.Manifest.All(x => Path.GetFullPath(Path.Combine(modDef.Directory, x.Path)) != Path.GetFullPath(Path.Combine(modDef.Directory, "StreamingAssets"))))
            {
                modDef.Manifest.Add(new ModDef.ManifestEntry("StreamingAssets", true));
            }

            foreach (var entry in modDef.Manifest)
            {
                // handle prefabs; they have potential internal path to assetbundle
                if (entry.Type == "Prefab" && !string.IsNullOrEmpty(entry.AssetBundleName))
                {
                    if (!potentialAdditions.Any(x => x.Type == "AssetBundle" && x.Id == entry.AssetBundleName))
                    {
                        Log($"\t{modDef.Name} has a Prefab that's referencing an AssetBundle that hasn't been loaded. Put the assetbundle first in the manifest!");
                        return;
                    }

                    entry.Id = Path.GetFileNameWithoutExtension(entry.Path);
                    potentialAdditions.Add(entry);
                    continue;
                }

                if (string.IsNullOrEmpty(entry.Path) && string.IsNullOrEmpty(entry.Type) && entry.Path != "StreamingAssets")
                {
                    Log($"\t{modDef.Name} has a manifest entry that is missing its path or type! Aborting load.");
                    return;
                }

                var entryPath = Path.Combine(modDef.Directory, entry.Path);
                if (Directory.Exists(entryPath))
                {
                    // path is a directory, add all the files there
                    var files = Directory.GetFiles(entryPath, "*", SearchOption.AllDirectories);
                    foreach (var filePath in files)
                    {
                        var childModDef = new ModDef.ManifestEntry(entry, filePath, InferIDFromFileAndType(filePath, entry.Type));
                        potentialAdditions.Add(childModDef);
                    }
                }
                else if (File.Exists(entryPath))
                {
                    // path is a file, add the single entry
                    entry.Id   = entry.Id ?? InferIDFromFileAndType(entryPath, entry.Type);
                    entry.Path = entryPath;
                    potentialAdditions.Add(entry);
                }
                else if (entry.Path != "StreamingAssets")
                {
                    // path is not streamingassets and it's missing
                    Log($"\tMissing Entry: Manifest specifies file/directory of {entry.Type} at path {entry.Path}, but it's not there. Continuing to load.");
                }
            }

            // load mod dll
            if (modDef.DLL != null)
            {
                var    dllPath    = Path.Combine(modDef.Directory, modDef.DLL);
                string typeName   = null;
                var    methodName = "Init";

                if (!File.Exists(dllPath))
                {
                    Log($"\t{modDef.Name} has a DLL specified ({dllPath}), but it's missing! Aborting load.");
                    return;
                }

                if (modDef.DLLEntryPoint != null)
                {
                    var pos = modDef.DLLEntryPoint.LastIndexOf('.');
                    if (pos == -1)
                    {
                        methodName = modDef.DLLEntryPoint;
                    }
                    else
                    {
                        typeName   = modDef.DLLEntryPoint.Substring(0, pos);
                        methodName = modDef.DLLEntryPoint.Substring(pos + 1);
                    }
                }

                Log($"\tUsing BTML to load dll {Path.GetFileName(dllPath)} with entry path {typeName ?? "NoNameSpecified"}.{methodName}");

                BTModLoader.LoadDLL(dllPath, methodName, typeName,
                                    new object[] { modDef.Directory, modDef.Settings.ToString(Formatting.None) });
            }

            // actually add the additions, since we successfully got through loading the other stuff
            if (potentialAdditions.Count > 0)
            {
                foreach (var addition in potentialAdditions)
                {
                    Log($"\tNew Entry: {addition.Path.Replace(ModDirectory, "")}");
                }

                ModManifest[modDef.Name] = potentialAdditions;
            }
        }
Exemplo n.º 4
0
        public static void LoadMod(ModDef modDef)
        {
            var potentialAdditions = new List <ModDef.ManifestEntry>();

            LogWithDate($"Loading {modDef.Name}");

            // load out of the manifest
            if (modDef.LoadImplicitManifest && modDef.Manifest.All(x => Path.GetFullPath(Path.Combine(modDef.Directory, x.Path)) != Path.GetFullPath(Path.Combine(modDef.Directory, "StreamingAssets"))))
            {
                modDef.Manifest.Add(new ModDef.ManifestEntry("StreamingAssets", true));
            }

            foreach (var entry in modDef.Manifest)
            {
                var entryPath = Path.Combine(modDef.Directory, entry.Path);

                if (string.IsNullOrEmpty(entry.Path) && (string.IsNullOrEmpty(entry.Type) || entry.Path == "StreamingAssets"))
                {
                    Log($"\t{modDef.Name} has a manifest entry that is missing its path! Aborting load.");
                    return;
                }

                if (Directory.Exists(entryPath))
                {
                    // path is a directory, add all the files there
                    var files = Directory.GetFiles(entryPath, "*", SearchOption.AllDirectories);
                    foreach (var filePath in files)
                    {
                        var childModDef = new ModDef.ManifestEntry(entry, filePath, InferIDFromFileAndType(filePath, entry.Type));
                        potentialAdditions.Add(childModDef);
                    }
                }
                else if (File.Exists(entryPath))
                {
                    // path is a file, add the single entry
                    entry.Id   = entry.Id ?? InferIDFromFileAndType(entryPath, entry.Type);
                    entry.Path = entryPath;
                    potentialAdditions.Add(entry);
                }
                else
                {
                    // wasn't a file and wasn't a path, must not exist

                    // TODO: what to do with manifest entries that aren't implicit that are missing?

                    //Log($"\t{modDef.Name} has a manifest entry {entryPath}, but it's missing! Aborting load.");
                    //return;
                }
            }

            // load mod dll
            if (modDef.DLL != null)
            {
                var    dllPath    = Path.Combine(modDef.Directory, modDef.DLL);
                string typeName   = null;
                var    methodName = "Init";

                if (!File.Exists(dllPath))
                {
                    Log($"\t{modDef.Name} has a DLL specified ({dllPath}), but it's missing! Aborting load.");
                    return;
                }

                if (modDef.DLLEntryPoint != null)
                {
                    var pos = modDef.DLLEntryPoint.LastIndexOf('.');
                    if (pos == -1)
                    {
                        methodName = modDef.DLLEntryPoint;
                    }
                    else
                    {
                        typeName   = modDef.DLLEntryPoint.Substring(0, pos);
                        methodName = modDef.DLLEntryPoint.Substring(pos + 1);
                    }
                }

                Log($"\tUsing BTML to load dll {Path.GetFileName(dllPath)} with entry path {typeName ?? "NoNameSpecified"}.{methodName}");

                BTModLoader.LoadDLL(dllPath, methodName, typeName,
                                    new object[] { modDef.Directory, modDef.Settings.ToString(Formatting.None) });
            }

            // actually add the additions, since we successfully got through loading the other stuff
            if (potentialAdditions.Count > 0)
            {
                foreach (var addition in potentialAdditions)
                {
                    Log($"\tNew Entry: {addition.Path.Replace(ModDirectory, "")}");
                }

                ModManifest[modDef.Name] = potentialAdditions;
            }
        }
Exemplo n.º 5
0
        internal static IEnumerator <ProgressReport> LoadMoadsLoop()
        {
            // Only want to run this function once -- it could get submitted a few times
            if (hasLoadedMods)
            {
                yield break;
            }

            stopwatch.Start();

            string sliderText = "Loading Mods";

            Log("");
            LogWithDate("Pre-loading mods...");
            yield return(new ProgressReport(0, sliderText, "Pre-loading mods..."));

            // find all sub-directories that have a mod.json file
            var modDirectories = Directory.GetDirectories(ModsDirectory)
                                 .Where(x => File.Exists(Path.Combine(x, MOD_JSON_NAME))).ToArray();

            if (modDirectories.Length == 0)
            {
                hasLoadedMods = true;
                Log("No ModTek-compatable mods found.");
                yield break;
            }

            // create ModDef objects for each mod.json file
            var modDefs = new Dictionary <string, ModDef>();

            foreach (var modDirectory in modDirectories)
            {
                ModDef modDef;
                var    modDefPath = Path.Combine(modDirectory, MOD_JSON_NAME);

                try
                {
                    modDef = ModDef.CreateFromPath(modDefPath);
                }
                catch (Exception e)
                {
                    Log($"Caught exception while parsing {MOD_JSON_NAME} at path {modDefPath}");
                    Log($"\t{e.Message}");
                    continue;
                }

                if (!modDef.Enabled)
                {
                    Log($"Will not load {modDef.Name} because it's disabled.");
                    continue;
                }

                if (modDefs.ContainsKey(modDef.Name))
                {
                    Log($"Already loaded a mod named {modDef.Name}. Skipping load from {modDef.Directory}.");
                    continue;
                }

                modDefs.Add(modDef.Name, modDef);
            }

            PropagateConflictsForward(modDefs);
            modLoadOrder = GetLoadOrder(modDefs, out var willNotLoad);

            int modLoaded = 0;

            // lists guarentee order
            foreach (var modName in modLoadOrder)
            {
                var modDef = modDefs[modName];
                yield return(new ProgressReport(
                                 (float)modLoaded++ / (float)modLoadOrder.Count,
                                 sliderText,
                                 string.Format("Loading Mod: {0} {1}", modDef.Name, modDef.Version)
                                 ));

                try
                {
                    LoadMod(modDef);
                }
                catch (Exception e)
                {
                    Log($"Tried to load mod: {modDef.Name}, but something went wrong. Make sure all of your JSON is correct!");
                    Log($"\t{e.Message}");
                }
            }

            foreach (var modDef in willNotLoad)
            {
                Log($"Will not load {modDef}. It's lacking a dependancy or a conflict loaded before it.");
            }

            stopwatch.Stop();
            Log("");
            LogWithDate($"Done pre-load mods. Elapsed running time: {stopwatch.Elapsed.TotalSeconds} seconds\n");
            Log("----------\n");

            // write out harmony summary
            PrintHarmonySummary(HarmonySummaryPath);

            // write out load order
            File.WriteAllText(LoadOrderPath, JsonConvert.SerializeObject(modLoadOrder, Formatting.Indented));

            hasLoadedMods = true;

            yield break;
        }
Exemplo n.º 6
0
 private static bool AreDependanciesResolved(ModDef modDef, HashSet <string> loaded)
 {
     return(!(modDef.DependsOn.Count != 0 && modDef.DependsOn.Intersect(loaded).Count() != modDef.DependsOn.Count ||
              modDef.ConflictsWith.Count != 0 && modDef.ConflictsWith.Intersect(loaded).Any()));
 }
Exemplo n.º 7
0
        internal static IEnumerator <ProgressReport> LoadMoadsLoop()
        {
            stopwatch.Start();

            Log("");
            yield return(new ProgressReport(1, "Initializing Mods", ""));

            // find all sub-directories that have a mod.json file
            var modDirectories = Directory.GetDirectories(ModsDirectory)
                                 .Where(x => File.Exists(Path.Combine(x, MOD_JSON_NAME))).ToArray();

            if (modDirectories.Length == 0)
            {
                Log("No ModTek-compatable mods found.");
                yield break;
            }

            // create ModDef objects for each mod.json file
            var modDefs = new Dictionary <string, ModDef>();

            foreach (var modDirectory in modDirectories)
            {
                ModDef modDef;
                var    modDefPath = Path.Combine(modDirectory, MOD_JSON_NAME);

                try
                {
                    modDef = ModDef.CreateFromPath(modDefPath);
                }
                catch (Exception e)
                {
                    Log($"Caught exception while parsing {MOD_JSON_NAME} at path {modDefPath}");
                    Log($"\t{e.Message}");
                    continue;
                }

                if (!modDef.Enabled)
                {
                    Log($"Will not load {modDef.Name} because it's disabled.");
                    continue;
                }

                if (modDefs.ContainsKey(modDef.Name))
                {
                    Log($"Already loaded a mod named {modDef.Name}. Skipping load from {modDef.Directory}.");
                    continue;
                }

                modDefs.Add(modDef.Name, modDef);
            }

            Log("");
            modLoadOrder = GetLoadOrder(modDefs, out var willNotLoad);
            foreach (var modName in willNotLoad)
            {
                Log($"Will not load {modName} because it's lacking a dependancy or a conflict loaded before it.");
            }
            Log("");

            // lists guarentee order
            var modLoaded = 0;

            foreach (var modName in modLoadOrder)
            {
                var modDef = modDefs[modName];
                yield return(new ProgressReport(modLoaded++ / ((float)modLoadOrder.Count), "Initializing Mods", $"{modDef.Name} {modDef.Version}"));

                try
                {
                    LoadMod(modDef);
                }
                catch (Exception e)
                {
                    Log($"Tried to load mod: {modDef.Name}, but something went wrong. Make sure all of your JSON is correct!");
                    Log($"\t{e.Message}");
                }
            }

            PrintHarmonySummary(HarmonySummaryPath);
            WriteJsonFile(LoadOrderPath, modLoadOrder);
            stopwatch.Stop();

            yield break;
        }