metherul / Automaton

The open modpack platform.
Other
58 stars 14 forks source link

Crash when two of same mod are in source location #27

Closed metherul closed 6 years ago

metherul commented 6 years ago

Thanks to Gatonegro, Electraumatized and rodericktech.

bsleys commented 6 years ago

I ran into the same problem and found the issue is the code finds files based on file size and not name. More than one file can have the same size in the directory but not have the same name so I recommend the following changes to the code.

In PackHandler.cs change ValidateSourceLocation to the following:

/// <summary>
        /// Validate the source mod location for all required mod files, as generated by the optionals list.
        /// </summary>
        public static List<Mod> ValidateSourceLocation()
        {
            var sourceFiles = Directory.GetFiles(SourceLocation);
            var sourceFileInfos = sourceFiles.Select(x => new FileInfo(x));
//            var fileSizes = files.Select(x => new FileInfo(x).Length);
            var modPack = ModPack;
            var missingMods = new List<Mod>();

            foreach (var mod in modPack.Mods)
            {
                // Gets files from sourceLocation which match the size of the modPack mod
//                var filteredFileSizes = fileSizes.Where(x => x.ToString() == mod.FileSize);
                var matchingFiles = sourceFileInfos.Where(x => x.Name == mod.FileName);

                if (matchingFiles.Any())
                {
                    if ((matchingFiles.FirstOrDefault()?.Length ?? 0) != int.Parse(mod.FileSize))
                    {
                        //file name mathes but not file size
                        //add possible override option
                    }
                }
                else
                {
                    missingMods.Add(mod);
                }
            }

            Messenger.Default.Send(missingMods, MessengerToken.MissingMods);

            return missingMods;
        }

Note that right now nothing is done if the filename exists but the file size doesn't match. A future option would be warn the user of the possible problem and let then either fix or attempt the install with the existing file.

And in PackHandlerHelper.cs change GetSourceFiles to the following

 /// <summary>
        /// Gets a list of source file infos from the mod source location.
        /// </summary>
        /// <param name="mods">List of mods</param>
        /// <param name="sourceLocation">Mod source location</param>
        /// <returns></returns>
        public static List<FileInfo> GetSourceFiles(List<Mod> mods, string sourceLocation)
        {
            var sourceFiles = Directory.GetFiles(sourceLocation);
            var sourceFileInfos = sourceFiles.Select(x => new FileInfo(x));
            var matchingSourceFiles = new List<FileInfo>();

            foreach (var mod in mods)
            {
                var matchingFiles = sourceFileInfos.Where(x => x.Name == mod.FileName);
//                var matchingFiles = sourceFileInfos.Where(x => x.Length.ToString() == mod.FileSize || x.Name == mod.FileName);

                if (matchingFiles.Any())
                {
                    matchingSourceFiles.Add(matchingFiles.First());
                }
            }

            return matchingSourceFiles;
        }

Note the using .any() is more efficient than getting a full count() if just want to check if the count is 0 or not.

metherul commented 6 years ago

Heya! First off, cheers for the contribution and code snippets.

Advanced archive filtering / sorting / validation will be included in the Automaton rewrite. While it may not be too alike to your code, it follows the same principle -- instead of using filenames for identification (if .Length fails), there is a somewhat well optimized hashing functionality that I've been working on. There's not too much to share as of right now, but you'll be able to check it out in in upcoming commits to the branch.

Thanks!