Exemplo n.º 1
0
        /// <summary>
        /// Loads the bundled dictionary from disk.
        /// </summary>
        /// <param name="ct">A cancellation to open.</param>
        /// <returns>A loaded ListfileDictionary.</returns>
        private static Task <ListfileDictionary> LoadDictionaryAsync(CancellationToken ct)
        {
            return(Task.Run
                   (
                       () =>
            {
                var dict = new ListfileDictionary();
                dict.LoadFromStream(File.OpenRead("Dictionary/dictionary.dic"), ct);

                return dict;
            },
                       ct
                   ));
        }
Exemplo n.º 2
0
        /// <summary>
        /// Attempts to load a game in a specified path, returning a <see cref="PackageGroup"/> object with the
        /// packages in the path and an <see cref="OptimizedNodeTree"/> with a fully qualified node tree of the
        /// package group.
        /// If no packages are found, then this method will return null in both fields.
        /// </summary>
        /// <param name="gameAlias">The alias of the game at the path.</param>
        /// <param name="gamePath">The path to load as a game.</param>
        /// <param name="ct">A cancellation token.</param>
        /// <param name="progress">An <see cref="IProgress{GameLoadingProgress}"/> object for progress reporting.</param>
        /// <returns>A tuple with a package group and a node tree for the requested game.</returns>
        public async Task <(PackageGroup packageGroup, OptimizedNodeTree nodeTree)> LoadGameAsync(
            string gameAlias,
            string gamePath,
            CancellationToken ct,
            IProgress <GameLoadingProgress> progress = null)
        {
            progress?.Report(new GameLoadingProgress
            {
                CompletionPercentage = 0.0f,
                State = GameLoadingState.SettingUp,
                Alias = gameAlias
            });

            List <string> packagePaths = Directory.EnumerateFiles
                                         (
                gamePath,
                "*",
                SearchOption.AllDirectories
                                         )
                                         .Where(p => p.EndsWith(".mpq", StringComparison.InvariantCultureIgnoreCase))
                                         .OrderBy(p => p)
                                         .ToList();

            if (packagePaths.Count == 0)
            {
                return(null, null);
            }

            string packageSetHash      = GeneratePathSetHash(packagePaths);
            string packageTreeFilename = $".{packageSetHash}.tree";
            string packageTreeFilePath = Path.Combine(gamePath, packageTreeFilename);

            PackageGroup      packageGroup = new PackageGroup(packageSetHash);
            OptimizedNodeTree nodeTree     = null;

            bool generateTree = true;

            if (File.Exists(packageTreeFilePath))
            {
                progress?.Report(new GameLoadingProgress
                {
                    CompletionPercentage = 0,
                    State = GameLoadingState.LoadingNodeTree,
                    Alias = gameAlias
                });

                try
                {
                    // Load tree
                    nodeTree     = new OptimizedNodeTree(packageTreeFilePath);
                    generateTree = false;
                }
                catch (NodeTreeNotFoundException)
                {
                    Log.Error("No file for the node tree found at the given location.");
                }
                catch (UnsupportedNodeTreeVersionException)
                {
                    Log.Info("Unsupported node tree version present. Deleting and regenerating.");
                    File.Delete(packageTreeFilePath);
                }
            }

            if (generateTree)
            {
                // Internal counters for progress reporting
                double completedSteps = 0;
                double totalSteps     = packagePaths.Count * 2;

                // Load packages
                List <(string packageName, IPackage package)> packages = new List <(string packageName, IPackage package)>();
                foreach (string packagePath in packagePaths)
                {
                    ct.ThrowIfCancellationRequested();

                    progress?.Report(new GameLoadingProgress
                    {
                        CompletionPercentage = completedSteps / totalSteps,
                        State = GameLoadingState.LoadingPackages,
                        Alias = gameAlias
                    });

                    try
                    {
                        PackageInteractionHandler package = await PackageInteractionHandler.LoadAsync(packagePath);

                        packages.Add((Path.GetFileNameWithoutExtension(packagePath), package));
                    }
                    catch (FileLoadException fex)
                    {
                        Log.Warn($"Failed to load archive {Path.GetFileNameWithoutExtension(packagePath)}: {fex.Message}");
                    }

                    ++completedSteps;
                }

                // Load dictionary if neccesary
                if (this.Dictionary == null)
                {
                    progress?.Report(new GameLoadingProgress
                    {
                        CompletionPercentage = completedSteps / totalSteps,
                        State = GameLoadingState.LoadingDictionary,
                        Alias = gameAlias
                    });

                    this.Dictionary = await LoadDictionaryAsync(ct);
                }

                // Generate node tree
                MultiPackageNodeTreeBuilder multiBuilder = new MultiPackageNodeTreeBuilder(this.Dictionary);
                foreach (var packageInfo in packages)
                {
                    ct.ThrowIfCancellationRequested();

                    progress?.Report(new GameLoadingProgress
                    {
                        CompletionPercentage = completedSteps / totalSteps,
                        State = GameLoadingState.BuildingNodeTree,
                        Alias = gameAlias
                    });

                    await multiBuilder.ConsumePackageAsync(packageInfo.packageName, packageInfo.package, ct);

                    packageGroup.AddPackage((PackageInteractionHandler)packageInfo.package);

                    ++completedSteps;
                }

                // Build node tree
                multiBuilder.Build();

                // Save it to disk
                File.WriteAllBytes(packageTreeFilePath, multiBuilder.CreateTree());

                nodeTree = new OptimizedNodeTree(packageTreeFilePath);
            }
            else
            {
                progress?.Report(new GameLoadingProgress
                {
                    CompletionPercentage = 1,
                    State = GameLoadingState.LoadingPackages,
                    Alias = gameAlias
                });

                // Load packages
                packageGroup = await PackageGroup.LoadAsync(gameAlias, packageSetHash, gamePath, ct, progress);
            }

            progress?.Report(new GameLoadingProgress
            {
                CompletionPercentage = 1,
                State = GameLoadingState.Loading,
                Alias = gameAlias
            });

            return(packageGroup, nodeTree);
        }