示例#1
0
        public async Task <PatchInfo[]> RunAsync(DownloadConfiguration downloadConfiguration, PatchCache patchCache, CancellationToken ct = default)
        {
            Progress.Progress        = 0;
            Progress.IsIndeterminate = true;

            App.Logger.Info(nameof(ComparePhase), "Fetching patches");
            var patches = await PatchInfo.FetchPatchInfosAsync(_InstallConfiguration, downloadConfiguration, ct);

            App.Logger.Info(nameof(ComparePhase), "Fetching cache data");
            var cacheData = await patchCache.SelectAllAsync();

            App.Logger.Info(nameof(ComparePhase), "Pre-fetching file times");
            var preFetchedFileTimes = await Task.Run(() => _PreFetchFileTimes());

            var workingPatches = patches
                                 .Select(p => new UpdateInfo
            {
                PatchInfo         = p,
                ShouldUpdate      = true,
                LastWriteFileTime = preFetchedFileTimes.ContainsKey(p.Name) ? preFetchedFileTimes[p.Name] : 0
            })
                                 .ToArray();

            var nextIndexAtomic     = 0;
            var progressValueAtomic = 0;

            var errorTokenSource    = new CancellationTokenSource();
            var combinedTokenSource = CancellationTokenSource.CreateLinkedTokenSource(ct, errorTokenSource.Token);

            App.Logger.Info(nameof(ComparePhase), "Comparing files");
            Progress.IsIndeterminate = false;

            void ProcessLoop()
            {
                try
                {
                    var pso2ExecutableFileName = Path.GetFileName(_InstallConfiguration.PSO2Executable);

                    while (true)
                    {
                        var index = Interlocked.Increment(ref nextIndexAtomic) - 1;
                        if (index >= workingPatches.Length)
                        {
                            return;
                        }

                        combinedTokenSource.Token.ThrowIfCancellationRequested();

                        try
                        {
                            ref var patch = ref workingPatches[index];

                            var relativeFilePath = patch.PatchInfo.Name
                                                   .Substring(0, patch.PatchInfo.Name.Length - 4)
                                                   .Replace('/', Path.DirectorySeparatorChar)
                                                   .ToLower();
                            var filePath = Path.Combine(_InstallConfiguration.PSO2BinDirectory, relativeFilePath);
                            var fileName = Path.GetFileName(relativeFilePath);

                            // skip this if mod files are not enabled so they are marked as invalid
                            if (Properties.Settings.Default.ModFilesEnabled)
                            {
                                // skip file if a file with the same name exists in the mods folder
                                if (Path.GetDirectoryName(filePath).ToLower() == _InstallConfiguration.DataWin32Directory.ToLower())
                                {
                                    var modFilePath = Path.Combine(_InstallConfiguration.ModsDirectory, fileName);
                                    if (File.Exists(modFilePath))
                                    {
                                        patch.ShouldUpdate = false;
                                        continue;
                                    }
                                }
                            }

                            if (!cacheData.ContainsKey(patch.PatchInfo.Name))
                            {
                                continue;
                            }

                            var cacheEntry = cacheData[patch.PatchInfo.Name];

                            if (patch.PatchInfo.Hash != cacheEntry.Hash)
                            {
                                continue;
                            }

                            // skip pso2.exe if the file is large address aware patched
                            if (fileName == pso2ExecutableFileName &&
                                File.Exists(filePath) &&
                                Properties.Settings.Default.LargeAddressAwareEnabled &&
                                LargeAddressAware.IsLargeAddressAwarePactchApplied(_InstallConfiguration, patch.PatchInfo.Hash))
                            {
                                patch.ShouldUpdate = false;
                                continue;
                            }

                            if (patch.LastWriteFileTime == 0)
                            {
                                patch.LastWriteFileTime = new FileInfo(filePath).LastWriteTimeUtc.ToFileTimeUtc();
                            }

                            patch.ShouldUpdate = patch.LastWriteFileTime != cacheEntry.LastWriteTime;
                        }
                        finally
                        {
                            Interlocked.Increment(ref progressValueAtomic);
                        }
                    }
                }
示例#2
0
        private async Task _InstallAsync(PatchCache patchCache, PluginInfo pluginInfo, CancellationToken ct = default)
        {
            App.Current.Logger.Info(nameof(EnglishPatchPhase), "Downloading english translation information");
            var translation = await TranslationInfo.FetchEnglishAsync(ct);

            App.Current.Logger.Info(nameof(EnglishPatchPhase), "Getting data from patch cache");
            var cacheData = await patchCache.SelectAllAsync();

            string CreateRelativePath(string path)
            {
                var root     = new Uri(_InstallConfiguration.PSO2BinDirectory);
                var relative = root.MakeRelativeUri(new Uri(path));

                return(relative.OriginalString);
            }

            bool Verify(string path, string hash)
            {
                var relative = CreateRelativePath(path);

                var info = new FileInfo(path);

                if (info.Exists == false)
                {
                    return(false);
                }

                if (cacheData.ContainsKey(relative) == false)
                {
                    return(false);
                }

                var data = cacheData[relative];

                if (data.Hash != hash)
                {
                    return(false);
                }

                if (data.LastWriteTime != info.LastWriteTimeUtc.ToFileTimeUtc())
                {
                    return(false);
                }

                return(true);
            }

            using (var client = new ArksLayerHttpClient())
            {
                async Task VerifyAndDownlodRar(string path, string downloadHash, Uri downloadPath)
                {
                    if (Verify(path, downloadHash) == false)
                    {
                        App.Current.Logger.Info(nameof(EnglishPatchPhase), $"Downloading \"{Path.GetFileName(downloadPath.LocalPath)}\"");
                        using (var response = await client.GetAsync(downloadPath))
                            using (var stream = await response.Content.ReadAsStreamAsync())
                                using (var archive = RarArchive.Open(stream))
                                {
                                    foreach (var file in archive.Entries.Where(e => !e.IsDirectory))
                                    {
                                        var filePath = Path.Combine(_InstallConfiguration.ArksLayer.PatchesDirectory, file.Key);

                                        using (var fs = File.Create(filePath, 4096, FileOptions.Asynchronous))
                                            await file.OpenEntryStream().CopyToAsync(fs);

                                        await patchCache.InsertUnderTransactionAsync(new[]
                                        {
                                            new PatchCacheEntry()
                                            {
                                                Name          = CreateRelativePath(filePath),
                                                Hash          = downloadHash,
                                                LastWriteTime = new FileInfo(filePath).LastWriteTimeUtc.ToFileTimeUtc()
                                            }
                                        });
                                    }
                                }
                    }
                }

                await VerifyAndDownlodRar(_InstallConfiguration.ArksLayer.EnglishBlockPatch, translation.BlockMD5, new Uri(translation.BlockPatch));
                await VerifyAndDownlodRar(_InstallConfiguration.ArksLayer.EnglishItemPatch, translation.ItemMD5, new Uri(translation.ItemPatch));
                await VerifyAndDownlodRar(_InstallConfiguration.ArksLayer.EnglishTextPatch, translation.TextMD5, new Uri(translation.TextPatch));
                await VerifyAndDownlodRar(_InstallConfiguration.ArksLayer.EnglishTitlePatch, translation.TitleMD5, new Uri(translation.TitlePatch));
            }

            App.Current.Logger.Info(nameof(EnglishPatchPhase), "Validating plugin dlls");

            await pluginInfo.PSO2BlockRenameDll.ValidateFileAsync(_InstallConfiguration.ArksLayer.PluginPSO2BlockRenameDll, ct);

            await pluginInfo.PSO2ItemTranslatorDll.ValidateFileAsync(_InstallConfiguration.ArksLayer.PluginPSO2ItemTranslatorDll, ct);

            await pluginInfo.PSO2TitleTranslatorDll.ValidateFileAsync(_InstallConfiguration.ArksLayer.PluginPSO2TitleTranslatorDll, ct);

            await pluginInfo.PSO2RAISERSystemDll.ValidateFileAsync(_InstallConfiguration.ArksLayer.PluginPSO2RAISERSystemDll, ct);
        }