コード例 #1
0
        public GameResultItemViewModel(Game game, VpdbRelease release, VpdbVersion version, VpdbTableFile tableFile, ICommand closeCommand)
        {
            Game = game;
            Version = version;
            Release = release;
            TableFile = tableFile;

            SelectResult.Subscribe(_ =>
            {
                GameManager.LinkRelease(Game, release, tableFile.Reference.Id);
                MessageManager.LogReleaseLinked(game, release, tableFile.Reference.Id);

                closeCommand.Execute(null);
            });
        }
コード例 #2
0
        public GameItemViewModel(Game game, IDependencyResolver resolver)
        {
            Game = game;

            _logger = resolver.GetService<ILogger>();
            _vpdbClient = resolver.GetService<IVpdbClient>();
            _gameManager = resolver.GetService<IGameManager>();
            _messageManager = resolver.GetService<IMessageManager>();
            var threadManager = resolver.GetService<IThreadManager>();

            // release identify
            IdentifyRelease = ReactiveCommand.CreateAsyncObservable(_ => _vpdbClient.Api.GetReleasesBySize(Game.FileSize, MatchThreshold).SubscribeOn(threadManager.WorkerScheduler));
            IdentifyRelease.Select(releases => releases
                .Select(release => new {release, release.Versions})
                .SelectMany(x => x.Versions.Select(version => new {x.release, version, version.Files}))
                .SelectMany(x => x.Files.Select(file => new GameResultItemViewModel(game, x.release, x.version, file, CloseResults)))
            ).Subscribe(x => {

                var releases = x as GameResultItemViewModel[] ?? x.ToArray();
                var numMatches = 0;
                _logger.Info("Found {0} releases for game to identify.", releases.Length);
                GameResultItemViewModel match = null;
                foreach (var vm in releases) {
                    if (game.Filename == vm.TableFile.Reference.Name && game.FileSize == vm.TableFile.Reference.Bytes) {
                        numMatches++;
                        match = vm;
                    }
                }
                _logger.Info("Found {0} identical match(es).", numMatches);

                // if file name and file size are identical, directly match.
                if (numMatches == 1 && match != null) {
                    _logger.Info("File name and size are equal to local release, linking.");
                    _gameManager.LinkRelease(match.Game, match.Release, match.TableFile.Reference.Id);
                    _messageManager.LogReleaseLinked(match.Game, match.Release, match.TableFile.Reference.Id);

                } else {
                    _logger.Info("View model updated with identified releases.");
                    IdentifiedReleases = releases;
                    HasExecuted = true;
                }
            }, exception => _vpdbClient.HandleApiError(exception, "identifying a game by file size"));

            //SyncToggled
            //	.Where(_ => Game.IsSynced && Game.HasRelease)
            //	.Subscribe(_ => { GameManager.Sync(Game); });

            // handle errors
            IdentifyRelease.ThrownExceptions.Subscribe(e => { _logger.Error(e, "Error matching game."); });

            // spinner
            IdentifyRelease.IsExecuting.ToProperty(this, vm => vm.IsExecuting, out _isExecuting);

            // result switch
            IdentifyRelease.Select(r => r.Count > 0).Subscribe(hasResults => { HasResults = hasResults; });

            // close button
            CloseResults.Subscribe(_ => { HasExecuted = false; });

            // identify button visibility
            this.WhenAny(
                vm => vm.HasExecuted,
                vm => vm.Game.HasRelease,
                vm => vm.IsExecuting,
                (hasExecuted, hasRelease, isExecuting) => !hasExecuted.Value && !hasRelease.Value && !isExecuting.Value
            ).ToProperty(this, vm => vm.ShowIdentifyButton, out _showIdentifyButton);
        }
コード例 #3
0
ファイル: GameManager.cs プロジェクト: freezy/vpdb-agent
 public IGameManager Sync(Game game)
 {
     _downloadManager.DownloadRelease(game.ReleaseId, game.FileId);
     return this;
 }
コード例 #4
0
ファイル: GameManager.cs プロジェクト: freezy/vpdb-agent
        /// <summary>
        /// Applies table script changes from a previous version to an updated version.
        /// </summary>
        /// <param name="game">Game where to apply changes to</param>
        /// <param name="baseFileName">File name of the previous version</param>
        /// <param name="fileToPatchId">File ID of the updated version</param>
        private void PatchGame(Game game, string baseFileName, string fileToPatchId)
        {
            // todo create log message when something goes wrong.

            var baseFileId = game.PreviousFileId;
            _logger.Info("Patching file {0} with changes from file {1}", fileToPatchId, baseFileId);

            // get table scripts for original files
            var baseFile = _databaseManager.GetTableFile(game.ReleaseId, baseFileId).Reference;
            var fileToPatch = _databaseManager.GetTableFile(game.ReleaseId, fileToPatchId).Reference;
            var originalBaseScript = (string)baseFile?.Metadata["table_script"];
            var originalScriptToPatch = (string)fileToPatch?.Metadata["table_script"];
            if (originalBaseScript == null || originalScriptToPatch == null) {
                _logger.Warn("Got no script for file {0}, aborting.", originalBaseScript == null ? baseFileId : fileToPatchId);
                return;
            }

            // get script from local (potentially modified) table file
            var localBaseFilePath = Path.Combine(game.Platform.TablePath, baseFileName);
            var localBaseScript = _visualPinballManager.GetTableScript(localBaseFilePath);
            if (localBaseScript == null) {
                _logger.Warn("Error reading table script from {0}.", localBaseFilePath);
                return;
            }

            if (localBaseScript == originalBaseScript) {
                _logger.Info("No changes between old local and remote version, so nothing to patch. We're done patching.");
                return;
            }
            _logger.Info("Script changes between old local and old remote table detected, so let's merge those changes!");

            // sanity check: compare extracted script from vpdb with our own
            var localFilePathToPatch = Path.Combine(game.Platform.TablePath, game.Filename);
            var localScriptToPatch = _visualPinballManager.GetTableScript(localFilePathToPatch);
            if (localScriptToPatch != originalScriptToPatch) {
                _logger.Error("Script in metadata ({0} bytes) is not identical to what we've extracted from the download ({1} bytes).", originalScriptToPatch.Length, localScriptToPatch.Length);
                return;
            }

            // we need line arrays for the merge tool
            var originalBaseScriptLines = originalBaseScript.Split('\n');
            var originalScriptToPatchLines = originalScriptToPatch.Split('\n');
            var localBaseScriptLines = localBaseScript.Split('\n');

            // do the three-way merge
            var result = Diff.Diff3Merge(localBaseScriptLines, originalBaseScriptLines, originalScriptToPatchLines, true);
            var patchedScriptLines = new List<string>();
            var failed = 0;
            var succeeded = 0;
            foreach (var okBlock in result.Select(block => block as Diff.MergeOkResultBlock)) {
                if (okBlock != null) {
                    succeeded++;
                    patchedScriptLines.AddRange(okBlock.ContentLines);
                } else {
                    failed++;
                }
            }
            if (failed > 0) {
                _logger.Warn("Merge failed ({0} block(s) ok, {1} block(s) conflicted. Needs manual resolving", succeeded, failed);
                return;
            }
            var patchedScript = string.Join("\n", patchedScriptLines);
            _logger.Info("Successfully merged changes - {0} block(s) applied.", succeeded);

            // save script to table
            try {
                _visualPinballManager.SetTableScript(localFilePathToPatch, patchedScript);
            } catch (Exception e) {
                _logger.Error(e, "Error writing patched script back to table file.");
                return;
            }
            game.PatchedTableScript = patchedScript;

            _logger.Info("Successfully wrote back script to table file.");
        }
コード例 #5
0
ファイル: GameManager.cs プロジェクト: freezy/vpdb-agent
        public void LinkRelease(Game game, VpdbRelease release, string fileId)
        {
            // update in case we didn't catch the last version.
            _vpdbClient.Api.GetRelease(release.Id).Subscribe(updatedRelease => {
                _logger.Info("Linking {0} to {1} ({2})", game, release, fileId);
                _databaseManager.AddOrUpdateRelease(release);
                game.ReleaseId = release.Id;
                game.FileId = fileId;
                _databaseManager.Save();

            }, exception => _vpdbClient.HandleApiError(exception, "retrieving release details during linking"));
        }