示例#1
0
        private static bool AddModEntryToVersionManifest(VersionManifest manifest, ModDef.ManifestEntry modEntry, bool addToDB = false)
        {
            if (modEntry.Path == null)
            {
                return(false);
            }

            VersionManifestAddendum addendum = null;

            if (!string.IsNullOrEmpty(modEntry.AddToAddendum))
            {
                addendum = manifest.GetAddendumByName(modEntry.AddToAddendum);

                // create the addendum if it doesn't exist
                if (addendum == null)
                {
                    Log($"\t\tCreated addendum: {modEntry.AddToAddendum}");
                    addendum = new VersionManifestAddendum(modEntry.AddToAddendum);
                    manifest.ApplyAddendum(addendum);
                }
            }

            // add to DB
            if (addToDB && Path.GetExtension(modEntry.Path).ToLower() == ".json")
            {
                var type = (BattleTechResourceType)Enum.Parse(typeof(BattleTechResourceType), modEntry.Type);
                using (var metadataDatabase = new MetadataDatabase())
                {
                    VersionManifestHotReload.InstantiateResourceAndUpdateMDDB(type, modEntry.Path, metadataDatabase);
                    Log($"\t\tAdding to MDDB! {type} {modEntry.Path}");
                }
            }

            // add assetbundle path so it can be changed when the assetbundle path is requested
            if (modEntry.Type == "AssetBundle")
            {
                ModAssetBundlePaths[modEntry.Id] = modEntry.Path;
            }

            // add to addendum instead of adding to manifest
            if (addendum != null)
            {
                Log($"\t\tAddOrUpdate => {modEntry.Id} ({modEntry.Type}) to addendum {addendum.Name}");
                addendum.AddOrUpdate(modEntry.Id, modEntry.Path, modEntry.Type, DateTime.Now, modEntry.AssetBundleName, modEntry.AssetBundlePersistent);
                return(true);
            }

            // not added to addendum, not added to jsonmerges
            Log($"\t\tAddOrUpdate => {modEntry.Id} ({modEntry.Type})");
            manifest.AddOrUpdate(modEntry.Id, modEntry.Path, modEntry.Type, DateTime.Now, modEntry.AssetBundleName, modEntry.AssetBundlePersistent);
            return(true);
        }
示例#2
0
        // ADDING TO VERSION MANIFEST
        private static bool AddModEntry(VersionManifest manifest, ModDef.ManifestEntry modEntry)
        {
            if (modEntry.Path == null)
            {
                return(false);
            }

            VersionManifestAddendum addendum = null;

            if (!string.IsNullOrEmpty(modEntry.AddToAddendum))
            {
                addendum = manifest.GetAddendumByName(modEntry.AddToAddendum);

                // create the addendum if it doesn't exist
                if (addendum == null)
                {
                    Log($"\t\tCreated addendum: {modEntry.AddToAddendum}");
                    addendum = new VersionManifestAddendum(modEntry.AddToAddendum);
                    manifest.ApplyAddendum(addendum);
                }
            }

            // add special handling for particular types
            switch (modEntry.Type)
            {
            case "AssetBundle":
                ModAssetBundlePaths[modEntry.Id] = modEntry.Path;
                break;

            case "Texture2D":
                ModTexture2Ds.Add(modEntry.Id);
                break;
            }

            // add to addendum instead of adding to manifest
            if (addendum != null)
            {
                Log($"\t\tAddOrUpdate => {modEntry.Id} ({modEntry.Type}) to addendum {addendum.Name}");
                addendum.AddOrUpdate(modEntry.Id, modEntry.Path, modEntry.Type, DateTime.Now, modEntry.AssetBundleName, modEntry.AssetBundlePersistent);
                return(true);
            }

            // not added to addendum, not added to jsonmerges
            Log($"\t\tAddOrUpdate => {modEntry.Id} ({modEntry.Type})");
            manifest.AddOrUpdate(modEntry.Id, modEntry.Path, modEntry.Type, DateTime.Now, modEntry.AssetBundleName, modEntry.AssetBundlePersistent);
            return(true);
        }
示例#3
0
文件: ModTek.cs 项目: janxious/ModTek
        // ADDING MOD CONTENT TO THE GAME
        private static void AddModEntry(VersionManifest manifest, ModDef.ManifestEntry modEntry)
        {
            if (modEntry.Path == null)
            {
                return;
            }

            VersionManifestAddendum addendum = null;

            if (!string.IsNullOrEmpty(modEntry.AddToAddendum))
            {
                addendum = manifest.GetAddendumByName(modEntry.AddToAddendum);

                if (addendum == null)
                {
                    Log($"\tCannot add {modEntry.Id} to {modEntry.AddToAddendum} because addendum doesn't exist in the manifest.");
                    return;
                }
            }

            // add special handling for particular types
            switch (modEntry.Type)
            {
            case "AssetBundle":
                ModAssetBundlePaths[modEntry.Id] = modEntry.Path;
                break;

            case "Texture2D":
                ModTexture2Ds.Add(modEntry.Id);
                break;
            }

            // add to addendum instead of adding to manifest
            if (addendum != null)
            {
                Log($"\tAdd/Replace: \"{GetRelativePath(modEntry.Path, ModsDirectory)}\" ({modEntry.Type}) [{addendum.Name}]");
            }
            else
            {
                Log($"\tAdd/Replace: \"{GetRelativePath(modEntry.Path, ModsDirectory)}\" ({modEntry.Type})");
            }

            // not added to addendum, not added to jsonmerges
            BTRLEntries.Add(modEntry);
            return;
        }
示例#4
0
        internal static void TryAddToVersionManifest(VersionManifest manifest)
        {
            if (!hasLoadedMods)
            {
                LoadMods();
            }

            // there are no mods loaded, just return
            if (modLoadOrder == null || modLoadOrder.Count == 0)
            {
                return;
            }

            if (modEntries != null)
            {
                LogWithDate("Loading another manifest with already setup mod manifests.");
                foreach (var modEntry in modEntries)
                {
                    AddModEntryToVersionManifest(manifest, modEntry);
                }
                LogWithDate("Done.");
                return;
            }

            modEntries = new List <ModDef.ManifestEntry>();

            LogWithDate("Setting up mod manifests...");

            var breakMyGame = File.Exists(Path.Combine(ModDirectory, "break.my.game"));

            if (breakMyGame)
            {
                var mddPath       = Path.Combine(Path.Combine(StreamingAssetsDirectory, "MDD"), "MetadataDatabase.db");
                var mddBackupPath = mddPath + ".orig";

                Log($"\tBreak my game mode enabled! All new modded content (doesn't currently support merges) will be added to the DB.");

                if (!File.Exists(mddBackupPath))
                {
                    Log($"\t\tBacking up metadata database to {Path.GetFileName(mddBackupPath)}");
                    File.Copy(mddPath, mddBackupPath);
                }
            }

            var jsonMerges = new Dictionary <string, List <string> >();

            foreach (var modName in modLoadOrder)
            {
                if (!ModManifest.ContainsKey(modName))
                {
                    continue;
                }

                Log($"\t{modName}:");
                foreach (var modEntry in ModManifest[modName])
                {
                    // type being null means we have to figure out the type from the path (StreamingAssets)
                    if (modEntry.Type == null)
                    {
                        // TODO: + 16 is a little bizzare looking, it's the length of the substring + 1 because we want to get rid of it and the \
                        var relPath = modEntry.Path.Substring(modEntry.Path.LastIndexOf("StreamingAssets", StringComparison.Ordinal) + 16);
                        var fakeStreamingAssetsPath = Path.GetFullPath(Path.Combine(StreamingAssetsDirectory, relPath));

                        List <string> types;

                        if (TypeCache.ContainsKey(fakeStreamingAssetsPath))
                        {
                            types = TypeCache[fakeStreamingAssetsPath];
                        }
                        else
                        {
                            // get the type from the manifest
                            var matchingEntries = manifest.FindAll(x => Path.GetFullPath(x.FilePath) == fakeStreamingAssetsPath);
                            if (matchingEntries == null || matchingEntries.Count == 0)
                            {
                                Log($"\t\tCould not find an existing VersionManifest entry for {modEntry.Id}. Is this supposed to be a new entry? Don't put new entries in StreamingAssets!");
                                continue;
                            }

                            types = new List <string>();

                            foreach (var existingEntry in matchingEntries)
                            {
                                types.Add(existingEntry.Type);
                            }

                            TypeCache[fakeStreamingAssetsPath] = types;
                        }

                        if (Path.GetExtension(modEntry.Path).ToLower() == ".json" && modEntry.ShouldMergeJSON)
                        {
                            if (!TypeCache.ContainsKey(fakeStreamingAssetsPath))
                            {
                                Log($"\t\tUnable to determine type of {modEntry.Id}. Is there someone screwy with your this mod.json?");
                                continue;
                            }

                            if (!jsonMerges.ContainsKey(fakeStreamingAssetsPath))
                            {
                                jsonMerges[fakeStreamingAssetsPath] = new List <string>();
                            }

                            if (jsonMerges[fakeStreamingAssetsPath].Contains(modEntry.Path))
                            {
                                continue;
                            }

                            // this assumes that .json can only have a single type
                            modEntry.Type = TypeCache[fakeStreamingAssetsPath][0];

                            Log($"\t\tMerge => {modEntry.Id} ({modEntry.Type})");

                            jsonMerges[fakeStreamingAssetsPath].Add(modEntry.Path);
                            continue;
                        }

                        foreach (var type in types)
                        {
                            var subModEntry = new ModDef.ManifestEntry(modEntry, modEntry.Path, modEntry.Id);
                            subModEntry.Type = type;

                            if (AddModEntryToVersionManifest(manifest, subModEntry, breakMyGame))
                            {
                                modEntries.Add(modEntry);
                            }
                        }

                        continue;
                    }

                    // non-streamingassets json merges
                    if (Path.GetExtension(modEntry.Path).ToLower() == ".json" && modEntry.ShouldMergeJSON)
                    {
                        // have to find the original path for the manifest entry that we're merging onto
                        var matchingEntry = manifest.Find(x => x.Id == modEntry.Id);

                        if (matchingEntry == null)
                        {
                            Log($"\t\tCould not find an existing VersionManifest entry for {modEntry.Id}!");
                            continue;
                        }

                        if (!jsonMerges.ContainsKey(matchingEntry.FilePath))
                        {
                            jsonMerges[matchingEntry.FilePath] = new List <string>();
                        }

                        if (jsonMerges[matchingEntry.FilePath].Contains(modEntry.Path))
                        {
                            continue;
                        }

                        // this assumes that .json can only have a single type
                        modEntry.Type = matchingEntry.Type;

                        Log($"\t\tMerge => {modEntry.Id} ({modEntry.Type})");

                        jsonMerges[matchingEntry.FilePath].Add(modEntry.Path);
                        continue;
                    }

                    if (AddModEntryToVersionManifest(manifest, modEntry, breakMyGame))
                    {
                        modEntries.Add(modEntry);
                    }
                }
            }

            LogWithDate("Doing merges...");
            foreach (var jsonMerge in jsonMerges)
            {
                var cachePath  = JsonMergeCache.GetOrCreateCachedEntry(jsonMerge.Key, jsonMerge.Value);
                var cacheEntry = new ModDef.ManifestEntry(cachePath);

                cacheEntry.ShouldMergeJSON = false;
                cacheEntry.Type            = TypeCache[jsonMerge.Key][0];
                cacheEntry.Id = InferIDFromFileAndType(cachePath, cacheEntry.Type);

                if (AddModEntryToVersionManifest(manifest, cacheEntry, breakMyGame))
                {
                    modEntries.Add(cacheEntry);
                }
            }

            // write merge cache to disk
            JsonMergeCache.WriteCacheToDisk(Path.Combine(CacheDirectory, MERGE_CACHE_FILE_NAME));

            // write type cache to disk
            File.WriteAllText(Path.Combine(CacheDirectory, TYPE_CACHE_FILE_NAME), JsonConvert.SerializeObject(TypeCache, Formatting.Indented));

            LogWithDate("Done.");
            Log("");
        }
示例#5
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;
            }
        }
示例#6
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;
            }
        }
示例#7
0
        internal static IEnumerator <ProgressReport> BuildCachedManifestLoop(VersionManifest manifest)
        {
            stopwatch.Start();

            // there are no mods loaded, just return
            if (modLoadOrder == null || modLoadOrder.Count == 0)
            {
                yield break;
            }

            string loadingModText = "Loading Mod Manifests";

            yield return(new ProgressReport(0.0f, loadingModText, "Setting up mod manifests..."));

            LogWithDate("Setting up mod manifests...");

            var jsonMerges = new Dictionary <string, List <string> >();

            modEntries = new List <ModDef.ManifestEntry>();
            int modCount = 0;

            var manifestMods = modLoadOrder.Where(name => modManifest.ContainsKey(name)).ToList();

            foreach (var modName in manifestMods)
            {
                Log($"\t{modName}:");
                yield return(new ProgressReport((float)modCount++ / (float)manifestMods.Count, loadingModText, string.Format("Loading manifest for {0}", modName)));

                foreach (var modEntry in modManifest[modName])
                {
                    // type being null means we have to figure out the type from the path (StreamingAssets)
                    if (modEntry.Type == null)
                    {
                        // TODO: + 16 is a little bizzare looking, it's the length of the substring + 1 because we want to get rid of it and the \
                        var relPath = modEntry.Path.Substring(modEntry.Path.LastIndexOf("StreamingAssets", StringComparison.Ordinal) + 16);
                        var fakeStreamingAssetsPath = Path.GetFullPath(Path.Combine(StreamingAssetsDirectory, relPath));

                        var types = GetTypesFromCacheOrManifest(manifest, fakeStreamingAssetsPath);

                        if (types == null)
                        {
                            Log($"\t\tCould not find an existing VersionManifest entry for {modEntry.Id}. Is this supposed to be a new entry? Don't put new entries in StreamingAssets!");
                            continue;
                        }

                        if (Path.GetExtension(modEntry.Path).ToLower() == ".json" && modEntry.ShouldMergeJSON)
                        {
                            if (!jsonMerges.ContainsKey(fakeStreamingAssetsPath))
                            {
                                jsonMerges[fakeStreamingAssetsPath] = new List <string>();
                            }

                            if (jsonMerges[fakeStreamingAssetsPath].Contains(modEntry.Path))
                            {
                                continue;
                            }

                            // this assumes that .json can only have a single type
                            // typeCache will always contain this path
                            modEntry.Type = typeCache[fakeStreamingAssetsPath][0];

                            Log($"\t\tMerge => {modEntry.Id} ({modEntry.Type})");

                            jsonMerges[fakeStreamingAssetsPath].Add(modEntry.Path);
                            continue;
                        }

                        foreach (var type in types)
                        {
                            var subModEntry = new ModDef.ManifestEntry(modEntry, modEntry.Path, modEntry.Id);
                            subModEntry.Type = type;

                            if (AddModEntry(manifest, subModEntry))
                            {
                                modEntries.Add(subModEntry);
                            }
                        }

                        continue;
                    }

                    // get "fake" entries that don't actually go into the game's VersionManifest
                    // add videos to be loaded from an external path
                    switch (modEntry.Type)
                    {
                    case "Video":
                        var fileName = Path.GetFileName(modEntry.Path);
                        if (fileName != null && File.Exists(modEntry.Path))
                        {
                            Log($"\t\tVideo => {fileName}");
                            ModVideos.Add(fileName, modEntry.Path);
                        }
                        continue;

                    case "AdvancedJSONMerge":
                        var targetFileRelative = AdvancedJSONMerger.GetTargetFile(modEntry.Path);
                        var targetFile         = ResolvePath(targetFileRelative);

                        // need to add the types of the file to the typeCache, so that they can be used later
                        // this actually returns the type, but we don't actually care about that right now
                        GetTypesFromCacheOrManifest(manifest, targetFile);

                        if (!jsonMerges.ContainsKey(targetFile))
                        {
                            jsonMerges[targetFile] = new List <string>();
                        }

                        if (jsonMerges[targetFile].Contains(modEntry.Path))
                        {
                            continue;
                        }

                        Log($"\t\tAdvancedJSONMerge => {modEntry.Id} ({modEntry.Type})");
                        jsonMerges[targetFile].Add(modEntry.Path);
                        continue;
                    }

                    // non-streamingassets json merges
                    if (Path.GetExtension(modEntry.Path)?.ToLower() == ".json" && modEntry.ShouldMergeJSON)
                    {
                        // have to find the original path for the manifest entry that we're merging onto
                        var matchingEntry = manifest.Find(x => x.Id == modEntry.Id);

                        if (matchingEntry == null)
                        {
                            Log($"\t\tCould not find an existing VersionManifest entry for {modEntry.Id}!");
                            continue;
                        }

                        if (!jsonMerges.ContainsKey(matchingEntry.FilePath))
                        {
                            jsonMerges[matchingEntry.FilePath] = new List <string>();
                        }

                        if (jsonMerges[matchingEntry.FilePath].Contains(modEntry.Path))
                        {
                            continue;
                        }

                        // this assumes that .json can only have a single type
                        modEntry.Type = matchingEntry.Type;

                        if (!typeCache.ContainsKey(matchingEntry.FilePath))
                        {
                            typeCache[matchingEntry.FilePath] = new List <string>();
                            typeCache[matchingEntry.FilePath].Add(modEntry.Type);
                        }

                        Log($"\t\tMerge => {modEntry.Id} ({modEntry.Type})");

                        jsonMerges[matchingEntry.FilePath].Add(modEntry.Path);
                        continue;
                    }

                    if (AddModEntry(manifest, modEntry))
                    {
                        modEntries.Add(modEntry);
                    }
                }
            }

            yield return(new ProgressReport(100.0f, "JSON", "Writing JSON file to disk"));

            // write type cache to disk
            WriteJsonFile(TypeCachePath, typeCache);

            // perform merges into cache
            LogWithDate("Doing merges...");
            yield return(new ProgressReport(0.0f, "Merges", "Doing Merges..."));

            int mergeCount = 0;

            foreach (var jsonMerge in jsonMerges)
            {
                yield return(new ProgressReport((float)mergeCount++ / jsonMerges.Count, "Merges", string.Format("Merging {0}", jsonMerge.Key)));

                var cachePath = jsonMergeCache.GetOrCreateCachedEntry(jsonMerge.Key, jsonMerge.Value);

                // something went wrong (the parent json prob had errors)
                if (cachePath == null)
                {
                    continue;
                }

                var cacheEntry = new ModDef.ManifestEntry(cachePath);

                cacheEntry.ShouldMergeJSON = false;
                cacheEntry.Type            = typeCache[jsonMerge.Key][0]; // this assumes only one type for each json file
                cacheEntry.Id = InferIDFromFile(cachePath);

                if (AddModEntry(manifest, cacheEntry))
                {
                    modEntries.Add(cacheEntry);
                }
            }

            yield return(new ProgressReport(100.0f, "Merge Cache", "Writing Merge Cache to disk"));

            // write merge cache to disk
            jsonMergeCache.WriteCacheToDisk(Path.Combine(CacheDirectory, MERGE_CACHE_FILE_NAME));

            LogWithDate("Adding to DB...");

            // check if files removed from DB cache
            var rebuildDB          = false;
            var replacementEntries = new List <VersionManifestEntry>();
            var removeEntries      = new List <string>();

            string dbText = "Syncing Database";

            yield return(new ProgressReport(0.0f, dbText, ""));

            foreach (var kvp in dbCache)
            {
                var path = kvp.Key;

                if (File.Exists(path))
                {
                    continue;
                }

                Log($"\tNeed to remove DB entry from file in path: {path}");

                // file is missing, check if another entry exists with same filename in manifest
                var fileName      = Path.GetFileName(path);
                var existingEntry = manifest.Find(x => Path.GetFileName(x.FilePath) == fileName);

                if (existingEntry == null)
                {
                    Log("\t\tHave to rebuild DB, no existing entry in VersionManifest matches removed entry");
                    rebuildDB = true;
                    break;
                }

                replacementEntries.Add(existingEntry);
                removeEntries.Add(path);
            }

            // add removed entries replacements to db
            dbText = "Cleaning Database";
            yield return(new ProgressReport(100.0f, dbText, ""));

            if (!rebuildDB)
            {
                // remove old entries
                foreach (var removeEntry in removeEntries)
                {
                    dbCache.Remove(removeEntry);
                }

                using (var metadataDatabase = new MetadataDatabase())
                {
                    foreach (var replacementEntry in replacementEntries)
                    {
                        if (AddModEntryToDB(metadataDatabase, Path.GetFullPath(replacementEntry.FilePath), replacementEntry.Type))
                        {
                            Log($"\t\tReplaced DB entry with an existing entry in path: {Path.GetFullPath(replacementEntry.FilePath)}");
                        }
                    }
                }
            }

            // if an entry has been removed and we cannot find a replacement, have to rebuild the mod db
            if (rebuildDB)
            {
                if (File.Exists(ModMDDBPath))
                {
                    File.Delete(ModMDDBPath);
                }

                File.Copy(MDDBPath, ModMDDBPath);
                dbCache = new Dictionary <string, DateTime>();
            }

            // add needed files to db
            dbText = "Populating Database";
            int addCount = 0;

            yield return(new ProgressReport(0.0f, dbText, ""));

            using (var metadataDatabase = new MetadataDatabase())
            {
                foreach (var modEntry in modEntries)
                {
                    if (modEntry.AddToDB && AddModEntryToDB(metadataDatabase, modEntry.Path, modEntry.Type))
                    {
                        yield return(new ProgressReport((float)addCount / (float)modEntries.Count, dbText, string.Format("Added {0}", modEntry.Path)));

                        Log($"\tAdded/Updated {modEntry.Id} ({modEntry.Type})");
                    }
                    addCount++;
                }
            }

            // write db/type cache to disk
            WriteJsonFile(DBCachePath, dbCache);

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

            // Cache the completed manifest
            ModTek.cachedManifest = manifest;

            try
            {
                if (manifest != null && ModTek.modEntries != null)
                {
                    ModTek.modtekOverrides = manifest.Entries.Where(e => ModTek.modEntries.Any(m => e.Id == m.Id))
                                             // ToDictionary expects distinct keys, so take the last entry of each Id
                                             .GroupBy(ks => ks.Id)
                                             .Select(v => v.Last())
                                             .ToDictionary(ks => ks.Id);
                }
                Logger.Log("Built {0} modtek overrides", ModTek.modtekOverrides.Count());
            }
            catch (Exception e)
            {
                Logger.Log("Failed to build overrides {0}", e);
            }

            yield break;
        }
示例#8
0
        internal static void AddModEntries(VersionManifest manifest)
        {
            if (!hasLoadedMods)
            {
                LoadMods();
            }

            stopwatch.Start();

            // there are no mods loaded, just return
            if (modLoadOrder == null || modLoadOrder.Count == 0)
            {
                return;
            }

            if (modEntries != null)
            {
                LogWithDate("Loading another manifest with already setup mod manifests.");
                foreach (var modEntry in modEntries)
                {
                    AddModEntry(manifest, modEntry);
                }

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

            LogWithDate("Setting up mod manifests...");

            var jsonMerges = new Dictionary <string, List <string> >();

            modEntries = new List <ModDef.ManifestEntry>();
            foreach (var modName in modLoadOrder)
            {
                if (!modManifest.ContainsKey(modName))
                {
                    continue;
                }

                Log($"\t{modName}:");
                foreach (var modEntry in modManifest[modName])
                {
                    // type being null means we have to figure out the type from the path (StreamingAssets)
                    if (modEntry.Type == null)
                    {
                        // TODO: + 16 is a little bizzare looking, it's the length of the substring + 1 because we want to get rid of it and the \
                        var relPath = modEntry.Path.Substring(modEntry.Path.LastIndexOf("StreamingAssets", StringComparison.Ordinal) + 16);
                        var fakeStreamingAssetsPath = Path.GetFullPath(Path.Combine(StreamingAssetsDirectory, relPath));

                        List <string> types;

                        if (typeCache.ContainsKey(fakeStreamingAssetsPath))
                        {
                            types = typeCache[fakeStreamingAssetsPath];
                        }
                        else
                        {
                            // get the type from the manifest
                            var matchingEntries = manifest.FindAll(x => Path.GetFullPath(x.FilePath) == fakeStreamingAssetsPath);
                            if (matchingEntries == null || matchingEntries.Count == 0)
                            {
                                Log($"\t\tCould not find an existing VersionManifest entry for {modEntry.Id}. Is this supposed to be a new entry? Don't put new entries in StreamingAssets!");
                                continue;
                            }

                            types = new List <string>();

                            foreach (var existingEntry in matchingEntries)
                            {
                                types.Add(existingEntry.Type);
                            }

                            typeCache[fakeStreamingAssetsPath] = types;
                        }

                        if (Path.GetExtension(modEntry.Path).ToLower() == ".json" && modEntry.ShouldMergeJSON)
                        {
                            if (!typeCache.ContainsKey(fakeStreamingAssetsPath))
                            {
                                Log($"\t\tUnable to determine type of {modEntry.Id}. Is there someone screwy with your this mod.json?");
                                continue;
                            }

                            if (!jsonMerges.ContainsKey(fakeStreamingAssetsPath))
                            {
                                jsonMerges[fakeStreamingAssetsPath] = new List <string>();
                            }

                            if (jsonMerges[fakeStreamingAssetsPath].Contains(modEntry.Path))
                            {
                                continue;
                            }

                            // this assumes that .json can only have a single type
                            modEntry.Type = typeCache[fakeStreamingAssetsPath][0];

                            Log($"\t\tMerge => {modEntry.Id} ({modEntry.Type})");

                            jsonMerges[fakeStreamingAssetsPath].Add(modEntry.Path);
                            continue;
                        }

                        foreach (var type in types)
                        {
                            var subModEntry = new ModDef.ManifestEntry(modEntry, modEntry.Path, modEntry.Id);
                            subModEntry.Type = type;

                            if (AddModEntry(manifest, subModEntry))
                            {
                                modEntries.Add(subModEntry);
                            }
                        }

                        continue;
                    }

                    // get "fake" entries that don't actually go into the game's VersionManifest
                    // add videos to be loaded from an external path
                    if (modEntry.Type == "Video")
                    {
                        var fileName = Path.GetFileName(modEntry.Path);
                        if (fileName != null && File.Exists(modEntry.Path))
                        {
                            Log($"\t\tVideo => {fileName}");
                            ModVideos.Add(fileName, modEntry.Path);
                        }

                        continue;
                    }

                    // non-streamingassets json merges
                    if (Path.GetExtension(modEntry.Path)?.ToLower() == ".json" && modEntry.ShouldMergeJSON)
                    {
                        // have to find the original path for the manifest entry that we're merging onto
                        var matchingEntry = manifest.Find(x => x.Id == modEntry.Id);

                        if (matchingEntry == null)
                        {
                            Log($"\t\tCould not find an existing VersionManifest entry for {modEntry.Id}!");
                            continue;
                        }

                        if (!jsonMerges.ContainsKey(matchingEntry.FilePath))
                        {
                            jsonMerges[matchingEntry.FilePath] = new List <string>();
                        }

                        if (jsonMerges[matchingEntry.FilePath].Contains(modEntry.Path))
                        {
                            continue;
                        }

                        // this assumes that .json can only have a single type
                        modEntry.Type = matchingEntry.Type;

                        if (!typeCache.ContainsKey(matchingEntry.FilePath))
                        {
                            typeCache[matchingEntry.FilePath] = new List <string>();
                            typeCache[matchingEntry.FilePath].Add(modEntry.Type);
                        }

                        Log($"\t\tMerge => {modEntry.Id} ({modEntry.Type})");

                        jsonMerges[matchingEntry.FilePath].Add(modEntry.Path);
                        continue;
                    }

                    if (AddModEntry(manifest, modEntry))
                    {
                        modEntries.Add(modEntry);
                    }
                }
            }

            // write type cache to disk
            WriteJsonFile(TypeCachePath, typeCache);

            // perform merges into cache
            LogWithDate("Doing merges...");
            foreach (var jsonMerge in jsonMerges)
            {
                var cachePath = jsonMergeCache.GetOrCreateCachedEntry(jsonMerge.Key, jsonMerge.Value);

                // something went wrong (the parent json prob had errors)
                if (cachePath == null)
                {
                    continue;
                }

                var cacheEntry = new ModDef.ManifestEntry(cachePath);

                cacheEntry.ShouldMergeJSON = false;
                cacheEntry.Type            = typeCache[jsonMerge.Key][0];
                cacheEntry.Id = InferIDFromFile(cachePath);

                if (AddModEntry(manifest, cacheEntry))
                {
                    modEntries.Add(cacheEntry);
                }
            }

            // write merge cache to disk
            jsonMergeCache.WriteCacheToDisk(Path.Combine(CacheDirectory, MERGE_CACHE_FILE_NAME));

            LogWithDate("Adding to DB...");

            // check if files removed from DB cache
            var rebuildDB          = false;
            var replacementEntries = new List <VersionManifestEntry>();
            var removeEntries      = new List <string>();

            foreach (var kvp in dbCache)
            {
                var path = kvp.Key;

                if (File.Exists(path))
                {
                    continue;
                }

                Log($"\tNeed to remove DB entry from file in path: {path}");

                // file is missing, check if another entry exists with same filename in manifest
                var fileName      = Path.GetFileName(path);
                var existingEntry = manifest.Find(x => Path.GetFileName(x.FilePath) == fileName);

                if (existingEntry == null)
                {
                    Log("\t\tHave to rebuild DB, no existing entry in VersionManifest matches removed entry");
                    rebuildDB = true;
                    break;
                }

                replacementEntries.Add(existingEntry);
                removeEntries.Add(path);
            }

            // add removed entries replacements to db
            if (!rebuildDB)
            {
                // remove old entries
                foreach (var removeEntry in removeEntries)
                {
                    dbCache.Remove(removeEntry);
                }

                using (var metadataDatabase = new MetadataDatabase())
                {
                    foreach (var replacementEntry in replacementEntries)
                    {
                        if (AddModEntryToDB(metadataDatabase, Path.GetFullPath(replacementEntry.FilePath), replacementEntry.Type))
                        {
                            Log($"\t\tReplaced DB entry with an existing entry in path: {Path.GetFullPath(replacementEntry.FilePath)}");
                        }
                    }
                }
            }

            // if an entry has been removed and we cannot find a replacement, have to rebuild the mod db
            if (rebuildDB)
            {
                if (File.Exists(ModDBPath))
                {
                    File.Delete(ModDBPath);
                }

                File.Copy(Path.Combine(Path.Combine(StreamingAssetsDirectory, "MDD"), MDD_FILE_NAME), ModDBPath);
                dbCache = new Dictionary <string, DateTime>();
            }

            // add needed files to db
            using (var metadataDatabase = new MetadataDatabase())
            {
                foreach (var modEntry in modEntries)
                {
                    if (modEntry.AddToDB && AddModEntryToDB(metadataDatabase, modEntry.Path, modEntry.Type))
                    {
                        Log($"\tAdded/Updated {modEntry.Id} ({modEntry.Type})");
                    }
                }
            }

            // write db/type cache to disk
            WriteJsonFile(DBCachePath, dbCache);

            stopwatch.Stop();
            Log("");
            LogWithDate($"Done. Elapsed running time: {stopwatch.Elapsed.TotalSeconds} seconds\n");
        }
示例#9
0
文件: ModTek.cs 项目: janxious/ModTek
        internal static IEnumerator <ProgressReport> BuildModManifestEntriesLoop()
        {
            stopwatch.Start();

            // there are no mods loaded, just return
            if (modLoadOrder == null || modLoadOrder.Count == 0)
            {
                yield break;
            }

            Log("");

            var jsonMerges   = new Dictionary <string, List <string> >();
            var manifestMods = modLoadOrder.Where(name => entriesByMod.ContainsKey(name)).ToList();

            var entryCount = 0;
            var numEntries = 0;

            entriesByMod.Do(entries => numEntries += entries.Value.Count);

            foreach (var modName in manifestMods)
            {
                Log($"{modName}:");

                foreach (var modEntry in entriesByMod[modName])
                {
                    yield return(new ProgressReport(entryCount++ / ((float)numEntries), $"Loading {modName}", modEntry.Id));

                    // type being null means we have to figure out the type from the path (StreamingAssets)
                    if (modEntry.Type == null)
                    {
                        // TODO: + 16 is a little bizzare looking, it's the length of the substring + 1 because we want to get rid of it and the \
                        var relPath = modEntry.Path.Substring(modEntry.Path.LastIndexOf("StreamingAssets", StringComparison.Ordinal) + 16);
                        var fakeStreamingAssetsPath = Path.GetFullPath(Path.Combine(StreamingAssetsDirectory, relPath));
                        if (!File.Exists(fakeStreamingAssetsPath))
                        {
                            Log($"\tCould not find a file at {fakeStreamingAssetsPath} for {modName} {modEntry.Id}. NOT LOADING THIS FILE");
                            continue;
                        }

                        var types = GetTypesFromCacheOrManifest(CachedVersionManifest, modEntry.Id);
                        if (types == null)
                        {
                            Log($"\tCould not find an existing VersionManifest entry for {modEntry.Id}. Is this supposed to be a new entry? Don't put new entries in StreamingAssets!");
                            continue;
                        }

                        // this is getting merged later and then added to the BTRL entries then
                        if (Path.GetExtension(modEntry.Path).ToLower() == ".json" && modEntry.ShouldMergeJSON)
                        {
                            if (!jsonMerges.ContainsKey(modEntry.Id))
                            {
                                jsonMerges[modEntry.Id] = new List <string>();
                            }

                            if (jsonMerges[modEntry.Id].Contains(modEntry.Path)) // TODO: is this necessary?
                            {
                                continue;
                            }

                            // this assumes that .json can only have a single type
                            // typeCache will always contain this path
                            modEntry.Type = GetTypesFromCache(modEntry.Id)[0];

                            Log($"\tMerge: \"{GetRelativePath(modEntry.Path, ModsDirectory)}\" ({modEntry.Type})");

                            jsonMerges[modEntry.Id].Add(modEntry.Path);
                            continue;
                        }

                        foreach (var type in types)
                        {
                            var subModEntry = new ModDef.ManifestEntry(modEntry, modEntry.Path, modEntry.Id);
                            subModEntry.Type = type;
                            AddModEntry(CachedVersionManifest, subModEntry);

                            // clear json merges for this entry, mod is overwriting the original file, previous mods merges are tossed
                            if (jsonMerges.ContainsKey(modEntry.Id))
                            {
                                jsonMerges.Remove(modEntry.Id);
                                Log($"\t\tHad merges for {modEntry.Id} but had to toss, since original file is being replaced");
                            }
                        }

                        continue;
                    }

                    // get "fake" entries that don't actually go into the game's VersionManifest
                    // add videos to be loaded from an external path
                    switch (modEntry.Type)
                    {
                    case "Video":
                        var fileName = Path.GetFileName(modEntry.Path);
                        if (fileName != null && File.Exists(modEntry.Path))
                        {
                            Log($"\tVideo: \"{GetRelativePath(modEntry.Path, ModsDirectory)}\"");
                            ModVideos.Add(fileName, modEntry.Path);
                        }
                        continue;

                    case "AdvancedJSONMerge":
                        var id = AdvancedJSONMerger.GetTargetID(modEntry.Path);

                        // need to add the types of the file to the typeCache, so that they can be used later
                        // if merging onto a file added by another mod, the type is already in the cache
                        var types = GetTypesFromCacheOrManifest(CachedVersionManifest, id);

                        if (!jsonMerges.ContainsKey(id))
                        {
                            jsonMerges[id] = new List <string>();
                        }

                        if (jsonMerges[id].Contains(modEntry.Path))     // TODO: is this necessary?
                        {
                            continue;
                        }

                        Log($"\tAdvancedJSONMerge: \"{GetRelativePath(modEntry.Path, ModsDirectory)}\" ({types[0]})");
                        jsonMerges[id].Add(modEntry.Path);
                        continue;
                    }

                    // non-streamingassets json merges
                    if (Path.GetExtension(modEntry.Path)?.ToLower() == ".json" && modEntry.ShouldMergeJSON)
                    {
                        // have to find the original path for the manifest entry that we're merging onto
                        var matchingEntry = GetEntryFromCachedOrBTRLEntries(modEntry.Id);

                        if (matchingEntry == null)
                        {
                            Log($"\tCould not find an existing VersionManifest entry for {modEntry.Id}!");
                            continue;
                        }

                        var matchingPath = Path.GetFullPath(matchingEntry.FilePath);

                        if (!jsonMerges.ContainsKey(modEntry.Id))
                        {
                            jsonMerges[modEntry.Id] = new List <string>();
                        }

                        if (jsonMerges[modEntry.Id].Contains(modEntry.Path)) // TODO: is this necessary?
                        {
                            continue;
                        }

                        Log($"\tMerge: \"{GetRelativePath(modEntry.Path, ModsDirectory)}\" ({modEntry.Type})");

                        // this assumes that .json can only have a single type
                        modEntry.Type = matchingEntry.Type;
                        TryAddTypeToCache(modEntry.Id, modEntry.Type);
                        jsonMerges[modEntry.Id].Add(modEntry.Path);
                        continue;
                    }

                    AddModEntry(CachedVersionManifest, modEntry);
                    TryAddTypeToCache(modEntry.Id, modEntry.Type);

                    // clear json merges for this entry, mod is overwriting the original file, previous mods merges are tossed
                    if (jsonMerges.ContainsKey(modEntry.Id))
                    {
                        jsonMerges.Remove(modEntry.Id);
                        Log($"\t\tHad merges for {modEntry.Id} but had to toss, since original file is being replaced");
                    }
                }
            }

            WriteJsonFile(TypeCachePath, typeCache);

            // perform merges into cache
            Log("");
            LogWithDate("Doing merges...");
            yield return(new ProgressReport(1, "Merging", ""));

            var mergeCount = 0;

            foreach (var id in jsonMerges.Keys)
            {
                var existingEntry = GetEntryFromCachedOrBTRLEntries(id);
                if (existingEntry == null)
                {
                    Log($"\tHave merges for {id} but cannot find an original file! Skipping.");
                    continue;
                }

                var originalPath = Path.GetFullPath(existingEntry.FilePath);
                var mergePaths   = jsonMerges[id];

                if (!jsonMergeCache.HasCachedEntry(originalPath, mergePaths))
                {
                    yield return(new ProgressReport(mergeCount++ / ((float)jsonMerges.Count), "Merging", id));
                }

                var cachePath = jsonMergeCache.GetOrCreateCachedEntry(originalPath, mergePaths);

                // something went wrong (the parent json prob had errors)
                if (cachePath == null)
                {
                    continue;
                }

                var cacheEntry = new ModDef.ManifestEntry(cachePath)
                {
                    ShouldMergeJSON = false,
                    Type            = GetTypesFromCache(id)[0], // this assumes only one type for each json file
                    Id = id
                };

                AddModEntry(CachedVersionManifest, cacheEntry);
            }

            jsonMergeCache.WriteCacheToDisk(Path.Combine(CacheDirectory, MERGE_CACHE_FILE_NAME));

            Log("");
            Log("Syncing Database");
            yield return(new ProgressReport(1, "Syncing Database", ""));

            // check if files removed from DB cache
            var rebuildDB          = false;
            var replacementEntries = new List <VersionManifestEntry>();
            var removeEntries      = new List <string>();

            foreach (var path in dbCache.Keys)
            {
                var absolutePath = ResolvePath(path, GameDirectory);

                // check if the file in the db cache is still used
                if (BTRLEntries.Exists(x => x.Path == absolutePath))
                {
                    continue;
                }

                Log($"\tNeed to remove DB entry from file in path: {path}");

                // file is missing, check if another entry exists with same filename in manifest or in BTRL entries
                var fileName      = Path.GetFileName(path);
                var existingEntry = BTRLEntries.FindLast(x => Path.GetFileName(x.Path) == fileName)?.GetVersionManifestEntry()
                                    ?? CachedVersionManifest.Find(x => Path.GetFileName(x.FilePath) == fileName);

                if (existingEntry == null)
                {
                    Log("\t\tHave to rebuild DB, no existing entry in VersionManifest matches removed entry");
                    rebuildDB = true;
                    break;
                }

                replacementEntries.Add(existingEntry);
                removeEntries.Add(path);
            }

            // add removed entries replacements to db
            if (!rebuildDB)
            {
                // remove old entries
                foreach (var removeEntry in removeEntries)
                {
                    dbCache.Remove(removeEntry);
                }

                using (var metadataDatabase = new MetadataDatabase())
                {
                    foreach (var replacementEntry in replacementEntries)
                    {
                        if (AddModEntryToDB(metadataDatabase, Path.GetFullPath(replacementEntry.FilePath), replacementEntry.Type))
                        {
                            Log($"\t\tReplaced DB entry with an existing entry in path: {Path.GetFullPath(replacementEntry.FilePath)}");
                        }
                    }
                }
            }

            // if an entry has been removed and we cannot find a replacement, have to rebuild the mod db
            if (rebuildDB)
            {
                if (File.Exists(ModMDDBPath))
                {
                    File.Delete(ModMDDBPath);
                }

                File.Copy(MDDBPath, ModMDDBPath);
                dbCache = new Dictionary <string, DateTime>();
            }

            // add needed files to db
            var addCount = 0;

            using (var metadataDatabase = new MetadataDatabase())
            {
                foreach (var modEntry in BTRLEntries)
                {
                    if (modEntry.AddToDB && AddModEntryToDB(metadataDatabase, modEntry.Path, modEntry.Type))
                    {
                        yield return(new ProgressReport(addCount / ((float)BTRLEntries.Count), "Populating Database", modEntry.Id));

                        Log($"\tAdded/Updated {modEntry.Id} ({modEntry.Type})");
                    }
                    addCount++;
                }
            }

            // write db/type cache to disk
            WriteJsonFile(DBCachePath, dbCache);

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

            yield break;
        }