Пример #1
0
        internal static List <string> GetTypesFromCacheOrManifest(VersionManifest manifest, string path)
        {
            if (typeCache.ContainsKey(path))
            {
                return(typeCache[path]);
            }

            // get the type from the manifest
            var matchingEntries = manifest.FindAll(x => Path.GetFullPath(x.FilePath) == path);

            if (matchingEntries == null || matchingEntries.Count == 0)
            {
                return(null);
            }

            var types = new List <string>();

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

            typeCache[path] = types;
            return(typeCache[path]);
        }
Пример #2
0
        //Is it possible for this to ever return more than 1 type for a entry in the manifest?
        //    Based on the output file the answer is yes. Prefab+Assetbundle | Texture2D+Sprite are examples
        //Can a manifest entry even have more than one type?
        //    Multiple entries with the same ID could have different types in their entry
        public List <string> GetTypes(string id, VersionManifest manifest = null)
        {
            if (entries.ContainsKey(id))
            {
                return(entries[id]);
            }

            if (manifest != null)
            {
                // get the types from the manifest
                var matchingEntries = manifest.FindAll(x => x.Id == id);
                if (matchingEntries == null || matchingEntries.Count == 0)
                {
                    return(null);
                }

                var types = new List <string>();

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

                entries[id] = types;
                return(entries[id]);
            }

            return(null);
        }
Пример #3
0
        internal static List <string> GetTypesFromCacheOrManifest(VersionManifest manifest, string id)
        {
            var types = GetTypesFromCache(id);

            if (types != null)
            {
                return(types);
            }

            // get the types from the manifest
            var matchingEntries = manifest.FindAll(x => x.Id == id);

            if (matchingEntries == null || matchingEntries.Count == 0)
            {
                return(null);
            }

            types = new List <string>();

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

            typeCache[id] = types;
            return(typeCache[id]);
        }
Пример #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
        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");
        }