예제 #1
0
        /// <summary>
        /// 安装(异步)
        /// </summary>
        /// <returns></returns
        public async Task <ForgeInstallerResultModel> InstallAsync()
        {
            using var archive = ZipFile.OpenRead(this.ForgeInstallerPackagePath);
            var processOutputs      = new List <string>();
            var processErrorOutputs = new List <string>();

            #region Get version.json

            OnProgressChanged(0.1, $"Installing Forge Loader - Initializing");

            var versionJson = await ZipFileHelper.GetStringFromJsonEntryAsync
                                  (archive.Entries.First(x => x.Name.Equals("version.json", StringComparison.OrdinalIgnoreCase)));

            var versionModel = JsonConvert.DeserializeObject <CoreModel>(versionJson);

            var versionJsonFile = new FileInfo
                                      ($"{PathHelper.GetVersionFolder(this.CoreLocator.Root, versionModel.Id)}{PathHelper.X}{versionModel.Id}.json");
            if (!versionJsonFile.Directory.Exists)
            {
                versionJsonFile.Directory.Create();
            }

            File.WriteAllText(versionJsonFile.FullName, versionJson);

            OnProgressChanged(0.15, $"Installing Forge Loader - Initializing");

            #endregion

            #region Get install_profile.json

            var forgeInstallProfile = await ZipFileHelper.GetObjectFromJsonEntryAsync <ForgeInstallProfileModel>
                                          (archive.Entries.First(x => x.Name.Equals("install_profile.json", StringComparison.OrdinalIgnoreCase)));

            var forgeVersion = forgeInstallProfile.Version.Replace("-forge-", "-");

            forgeInstallProfile.Data["BINPATCH"].Client = $"[net.minecraftforge:forge:{forgeVersion}:clientdata@lzma]";
            forgeInstallProfile.Data["BINPATCH"].Server = $"[net.minecraftforge:forge:{forgeVersion}:serverdata@lzma]";

            OnProgressChanged(0.2, $"Installing Forge Loader - Initialized");

            #endregion

            #region Get Lzma

            OnProgressChanged(0.3, $"Installing Forge Loader - Extracting Files");

            var clientLzma = archive.Entries.FirstOrDefault(e => e.FullName.Equals("data/client.lzma", StringComparison.OrdinalIgnoreCase));
            var serverLzma = archive.Entries.FirstOrDefault(e => e.FullName.Equals("data/server.lzma", StringComparison.OrdinalIgnoreCase));

            var clientLzmaFile = new FileInfo(GetMavenFilePath(forgeInstallProfile.Data["BINPATCH"].Client));
            var serverLzmaFile = new FileInfo(GetMavenFilePath(forgeInstallProfile.Data["BINPATCH"].Server));

            await ZipFileHelper.WriteAsync(clientLzma, clientLzmaFile.Directory.FullName, clientLzmaFile.Name);

            await ZipFileHelper.WriteAsync(serverLzma, serverLzmaFile.Directory.FullName, serverLzmaFile.Name);

            #endregion

            #region Extract Forge Jar

            var forgeJar = archive.Entries.FirstOrDefault
                               (e => e.FullName.Equals($"maven/net/minecraftforge/forge/{forgeVersion}/forge-{forgeVersion}.jar", StringComparison.OrdinalIgnoreCase));
            var forgeUniversalJar = archive.Entries.FirstOrDefault
                                        (e => e.FullName.Equals($"maven/net/minecraftforge/forge/{forgeVersion}/forge-{forgeVersion}-universal.jar", StringComparison.OrdinalIgnoreCase));

            if (forgeJar != default)
            {
                if (forgeUniversalJar != default)
                {
                    var fileUniversalJar = new FileInfo($"{PathHelper.GetLibrariesFolder(this.CoreLocator.Root)}{PathHelper.X}{forgeUniversalJar.FullName.Replace("maven/", "").Replace("/", PathHelper.X)}");
                    if (!fileUniversalJar.Directory.Exists)
                    {
                        fileUniversalJar.Directory.Create();
                    }

                    await ZipFileHelper.WriteAsync(forgeUniversalJar, fileUniversalJar.Directory.FullName);
                }

                var file = new FileInfo($"{PathHelper.GetLibrariesFolder(this.CoreLocator.Root)}{PathHelper.X}{forgeJar.FullName.Replace("maven/", "").Replace("/", PathHelper.X)}");
                if (!file.Directory.Exists)
                {
                    file.Directory.Create();
                }

                await ZipFileHelper.WriteAsync(forgeJar, file.Directory.FullName);
            }

            OnProgressChanged(0.4, $"Installing Forge Loader - Extracted");

            #endregion

            #region Parser Processor

            OnProgressChanged(0.4, $"Installing Forge Loader - Parsering Processor");

            var replaceValues = new Dictionary <string, string>
            {
                { "{SIDE}", "client" },
                { "{MINECRAFT_JAR}", $"{PathHelper.GetVersionFolder(this.CoreLocator.Root,this.McVersionId)}{PathHelper.X}{this.McVersionId}.jar" },
                { "{MINECRAFT_VERSION}", this.McVersion },
                { "{ROOT}", this.CoreLocator.Root },
                { "{INSTALLER}", this.ForgeInstallerPackagePath },
                { "{LIBRARY_DIR}", PathHelper.GetLibrariesFolder(this.CoreLocator.Root) },
                { "/", PathHelper.X }
            };
            var replaceArgs = forgeInstallProfile.Data.Select(x => ($"{{{x.Key}}}", x.Value.Client)).ToDictionary(k => k.Item1, v =>
            {
                if (v.Client.Contains("[") && v.Client.Contains("]"))
                {
                    return(GetMavenFilePath(v.Client));
                }

                return(v.Client);
            });

            for (int i = 0; i < forgeInstallProfile.Processors.Count; i++)
            {
                var processModel = forgeInstallProfile.Processors[i];

                if (processModel.Sides != null && !processModel.Sides.Any(s => s.Equals("client", StringComparison.OrdinalIgnoreCase)))
                {
                    forgeInstallProfile.Processors.RemoveAt(i);
                    continue;
                }
            }

            for (int i = 0; i < forgeInstallProfile.Processors.Count; i++)
            {
                var processModel = forgeInstallProfile.Processors[i];

                processModel.Args = StringHelper.Replace(processModel.Args, replaceValues).ToList();
                processModel.Args = StringHelper.Replace(processModel.Args, replaceArgs).ToList();

                processModel.Args = processModel.Args.Select(x =>
                {
                    if (x.Contains("[") && x.Contains("]"))
                    {
                        return($"{Path.Combine(PathHelper.GetLibrariesFolder(this.CoreLocator.Root), new Library { Name = x.TrimStart('[').TrimEnd(']') }.GetRelativePath())}");
                    }

                    return(x);
                }).ToList();

                if (processModel.Outputs != default)
                {
                    processModel.Outputs = processModel.Outputs.Select
                                               (x => (StringHelper.Replace(x.Key, replaceArgs), StringHelper.Replace(x.Value, replaceArgs))).ToDictionary(k => k.Item1, v => v.Item2);
                }

                forgeInstallProfile.Processors[i] = processModel;
            }

            OnProgressChanged(0.5, $"Installing Forge Loader - Parsered Processor");

            #endregion

            #region Download Libraries

            OnProgressChanged(0.5, $"Installing Forge Loader - Downloading Libraries");

            for (int i = 0; i < versionModel.Libraries.Count; i++)
            {
                if (versionModel.Libraries[i].Name == forgeInstallProfile.Path)
                {
                    versionModel.Libraries.Remove(versionModel.Libraries[i]);
                }
            }

            for (int i = 0; i < forgeInstallProfile.Libraries.Count; i++)
            {
                if (forgeInstallProfile.Libraries[i].Name == $"{forgeInstallProfile.Path}:universal")
                {
                    forgeInstallProfile.Libraries.Remove(forgeInstallProfile.Libraries[i]);
                }
            }

            async Task Download(IEnumerable <HttpDownloadRequest> requests)
            {
                var manyBlock    = new TransformManyBlock <IEnumerable <HttpDownloadRequest>, HttpDownloadRequest>(x => x);
                var blockOptions = new ExecutionDataflowBlockOptions
                {
                    BoundedCapacity        = DependencesCompleter.MaxThread,
                    MaxDegreeOfParallelism = DependencesCompleter.MaxThread
                };

                var actionBlock = new ActionBlock <HttpDownloadRequest>(async x =>
                {
                    try
                    {
                        if (!x.Directory.Exists)
                        {
                            x.Directory.Create();
                        }

                        var res = await HttpHelper.HttpDownloadAsync(x, x.FileName);
                        if (res.HttpStatusCode != HttpStatusCode.OK)
                        {
                            this.ErrorDownload.Add(x);
                        }
                    }
                    catch
                    {
                        throw;
                    }
                }, blockOptions);

                var linkOptions = new DataflowLinkOptions {
                    PropagateCompletion = true
                };

                _ = manyBlock.LinkTo(actionBlock, linkOptions);

                _ = manyBlock.Post(requests);
                manyBlock.Complete();

                await actionBlock.Completion;

                GC.Collect();
            }

            var downloadList = versionModel.Libraries.Union(forgeInstallProfile.Libraries).Select(x =>
            {
                var result = x.GetDownloadRequest(this.CoreLocator.Root, true);

                if (SystemConfiguration.Api.Url != new Mojang().Url)
                {
                    result.Url = result.Url.Replace("https://maven.minecraftforge.net", $"{SystemConfiguration.Api.Url}/maven");
                }

                return(result);
            });

            await Download(downloadList);

            //Try Again
            if (ErrorDownload.Count > 0)
            {
                await Download(ErrorDownload.Select(x =>
                {
                    x.Url = x.Url.Replace($"{SystemConfiguration.Api.Url}/maven", "https://maven.minecraftforge.net");
                    return(x);
                }));
            }

            OnProgressChanged(0.8, $"Installing Forge Loader - Downloaded Libraries");

            #endregion

            #region Run Process

            OnProgressChanged(0.8, $"Installing Forge Loader - Processing");

            foreach (var process in forgeInstallProfile.Processors)
            {
                string JarFile = $"{Path.Combine(PathHelper.GetLibrariesFolder(this.CoreLocator.Root), new Library { Name = process.Jar }.GetRelativePath())}";

                using var JarFileArchive = ZipFile.OpenRead(JarFile);

                var      libEntry  = JarFileArchive.Entries.FirstOrDefault(e => e.FullName.Equals("META-INF/MANIFEST.MF", StringComparison.OrdinalIgnoreCase));
                string[] lines     = (await ZipFileHelper.GetStringFromJsonEntryAsync(libEntry)).Split("\r\n");
                var      mainClass = lines.ToList().FirstOrDefault(x => x.Contains("Main-Class: ")).Replace("Main-Class: ", "");

                var libs = new List <string>()
                {
                    process.Jar
                }.Concat(process.Classpath);
                var classpath = libs.Select(x => $"{Path.Combine(PathHelper.GetLibrariesFolder(this.CoreLocator.Root), new Library { Name = x }.GetRelativePath())}");
                var parameter = new List <string>
                {
                    "-cp",
                    $"\"{string.Join(ArgumentsBuilder.Separator,classpath)}\"",
                    mainClass
                };

                parameter.AddRange(process.Args);

                var processContainer = new ProcessContainer(new ProcessStartInfo(JavaPath)
                {
                    Arguments        = string.Join(" ", parameter),
                    WorkingDirectory = this.CoreLocator.Root
                });

                processContainer.Start();
                await processContainer.Process.WaitForExitAsync();

                processOutputs.AddRange(processContainer.OutputData);
                processErrorOutputs.AddRange(processContainer.ErrorData);

                processContainer.Dispose();
            }

            OnProgressChanged(0.9, $"Installing Forge Loader - Processed");

            #endregion

            OnProgressChanged(1.0, $"Installing Forge Loader - Finished");

            if (processErrorOutputs.Count > 0)
            {
                return new ForgeInstallerResultModel
                       {
                           IsSuccessful       = false,
                           Message            = $"Failed Install Forge-{forgeVersion}!",
                           ProcessOutput      = processOutputs,
                           ProcessErrorOutput = processErrorOutputs
                       }
            }
            ;

            return(new ForgeInstallerResultModel
            {
                IsSuccessful = true,
                Message = $"Successfully Install Forge-{forgeVersion}!",
                ProcessOutput = processOutputs,
                ProcessErrorOutput = processErrorOutputs
            });
        }
예제 #2
0
        /// <summary>
        /// 安装(异步)
        /// </summary>
        /// <returns></returns>
        public async Task <ForgeInstallerResultModel> InstallAsync()
        {
            using var archive = ZipFile.OpenRead(this.ForgeInstallerPackagePath);

            #region Get install_profile.json

            OnProgressChanged(0.1, $"Installing Forge Loader - Initializing");

            var forgeInstallProfile = await ZipFileHelper.GetObjectFromJsonEntryAsync <LegacyForgeInstallProfileModel>
                                          (archive.Entries.First(x => x.Name.Equals("install_profile.json", StringComparison.OrdinalIgnoreCase)));

            #endregion

            #region Get version.json

            var versionJsonFile = new FileInfo
                                      ($"{PathHelper.GetVersionFolder(this.CoreLocator.Root, forgeInstallProfile.Install.Target)}{PathHelper.X}{forgeInstallProfile.Install.Target}.json");
            if (!versionJsonFile.Directory.Exists)
            {
                versionJsonFile.Directory.Create();
            }

            File.WriteAllText(versionJsonFile.FullName, forgeInstallProfile.VersionInfo.ToString());

            OnProgressChanged(0.2, $"Installing Forge Loader - Initialized");

            #endregion

            #region Extract Forge Jar

            OnProgressChanged(0.3, $"Installing Forge Loader - Extracting Files");

            var legacyJarEntry = archive.Entries.FirstOrDefault(e => e.Name.Equals(forgeInstallProfile.Install.FilePath, StringComparison.OrdinalIgnoreCase));
            var model          = JsonConvert.DeserializeObject <CoreModel>(forgeInstallProfile.VersionInfo.ToString());

            var lib     = model.Libraries.First(x => x.Name.StartsWith("net.minecraftforge:forge", StringComparison.OrdinalIgnoreCase));
            var fileLib = new FileInfo(Path.Combine(PathHelper.GetLibrariesFolder(this.CoreLocator.Root), lib.GetRelativePath()));
            await ZipFileHelper.WriteAsync(legacyJarEntry, fileLib.Directory.FullName, fileLib.Name);

            OnProgressChanged(0.4, $"Installing Forge Loader - Extracted");

            #endregion

            #region Download Libraries

            OnProgressChanged(0.5, $"Installing Forge Loader - Downloading Libraries");

            async Task Download(IEnumerable <HttpDownloadRequest> requests)
            {
                var manyBlock    = new TransformManyBlock <IEnumerable <HttpDownloadRequest>, HttpDownloadRequest>(x => x);
                var blockOptions = new ExecutionDataflowBlockOptions
                {
                    BoundedCapacity        = DependencesCompleter.MaxThread,
                    MaxDegreeOfParallelism = DependencesCompleter.MaxThread
                };

                var actionBlock = new ActionBlock <HttpDownloadRequest>(async x =>
                {
                    try
                    {
                        if (!x.Directory.Exists)
                        {
                            x.Directory.Create();
                        }

                        var res = await HttpHelper.HttpDownloadAsync(x, x.FileName);
                        if (res.HttpStatusCode != HttpStatusCode.OK)
                        {
                            this.ErrorDownload.Add(x);
                        }
                    }
                    catch
                    {
                        throw;
                    }
                }, blockOptions);

                var linkOptions = new DataflowLinkOptions {
                    PropagateCompletion = true
                };

                _ = manyBlock.LinkTo(actionBlock, linkOptions);

                _ = manyBlock.Post(requests);
                manyBlock.Complete();

                await actionBlock.Completion;

                GC.Collect();
            }

            var downloadList = model.Libraries.Select(x => x.GetDownloadRequest(this.CoreLocator.Root)).ToList();
            downloadList.Remove(downloadList.First(x => x.Url.Equals(lib.GetDownloadRequest(this.CoreLocator.Root).Url)));

            await Download(downloadList);

            //Try Again
            if (ErrorDownload.Count > 0)
            {
                await Download(ErrorDownload.Select(x =>
                {
                    x.Url = x.Url.Replace($"{SystemConfiguration.Api.Url}/maven", "https://maven.minecraftforge.net");
                    return(x);
                }));
            }

            OnProgressChanged(0.8, $"Installing Forge Loader - Downloaded Libraries");

            #endregion

            OnProgressChanged(1.0, $"Installing Forge Loader - Finished");

            return(new ForgeInstallerResultModel
            {
                IsSuccessful = true,
                Message = $"Successfully Install {forgeInstallProfile.Install.Target}!"
            });
        }