Exemplo n.º 1
0
        public void RebuildGameGrid()
        {
            Application.Current?.Dispatcher.Invoke(() =>
            {
                using (var tb = new TimedBlock($"RebuildGameGrid()"))
                {
                    var newFilteredGameIds = GameLibrary.GameLibrary.ListGames(titleFilter, filter, order, isOrderAscending);
                    var newFilteredGames   = newFilteredGameIds.Select(gameId => allGames.Single(game => game.ViewModel.GameId == gameId)).ToArray();

                    var xCount = (int)((windowSize.Width - Const.GridBorder) / (Const.GameControlSize.Width + Const.GridBorder));
                    var border = (int)(windowSize.Width - xCount * Const.GameControlSize.Width) / (xCount + 1);

                    //Log.WriteLine($"RebuildGameGrid(width={ windowSize.Width }, border={ border }, ")

                    for (var i = 0; i < newFilteredGames.Length; i++)
                    {
                        var newX = border + (int)(Const.GameControlSize.Width + border) * (i % xCount);
                        var newY = (int)(border - Const.GridBorder) + (int)(Const.GameControlSize.Height + border) * (i / xCount);
                        newFilteredGames[i].ViewModel.SetDestination(newX, newY);
                    }

                    FilteredGameIds = newFilteredGameIds;
                    FilteredGames   = newFilteredGames;

                    foreach (var gameControl in newFilteredGames)
                    {
                        gameControl.MoveToDestination(256);
                    }
                }
            });
        }
Exemplo n.º 2
0
        /// <summary>
        /// update play time from steam library
        /// </summary>
        /// <param name="steamApiKey"></param>
        /// <param name="steamId"></param>
        static void UpdatePlayTimeFromSteamLibrary()
        {
            using (var tb = new TimedBlock("UpdatePlayTimeFromSteamLibrary()"))
            {
                try
                {
                    var playTimes = SteamApi.ListPlayTimes(Settings.Default.SteamApiKey, Settings.Default.UserSteamId);
                    foreach (var playTime in playTimes)
                    {
                        var steamAppId = playTime.Key;
                        var game       = Games.Values
                                         .SingleOrDefault(g => g.Data
                                                          .SingleOrDefault(d => d is SteamDbInfoData && (d as SteamDbInfoData).AppId == steamAppId) != null);

                        if (game == null)
                        {
                            continue;
                        }

                        var steamData = game.CustomData <SteamDbInfoData>();
                        if (steamData != null)
                        {
                            steamData.PlayTimeForEver = playTime.Value;
                        }
                    }
                }
                catch (Exception ex)
                {
                    Log.WriteLine(ex.ToString());
                }
            }
        }
Exemplo n.º 3
0
        public static void PerformTaskOnGAThread(string blockName, Action taskBlock, long delayInSeconds)
        {
            if (endThread)
            {
                return;
            }

            lock (Instance.threadLock)
            {
                DateTime time = DateTime.Now;
                time = time.AddSeconds(delayInSeconds);

                TimedBlock timedBlock = new TimedBlock(time, taskBlock, blockName);
                Instance.AddTimedBlock(timedBlock);
                threadDeadline = time.AddSeconds(10);
#if WINDOWS_WSA || WINDOWS_UWP
                if (IsThreadFinished())
                {
                    StartThread();
                }
#else
                if (IsThreadFinished())
                {
                    if (Instance.thread != null)
                    {
                        Instance.thread.Join();
                    }
                    StartThread();
                }
#endif
            }
        }
Exemplo n.º 4
0
        public static void PerformTaskOnGAThread(string blockName, Action taskBlock, long delayInSeconds)
        {
            lock (Instance.threadLock)
            {
                DateTime time = DateTime.Now;
                time = time.AddSeconds(delayInSeconds);

                TimedBlock timedBlock = new TimedBlock(time, taskBlock, blockName);
                Instance.id2TimedBlockMap.Add(timedBlock.id, timedBlock);
                Instance.AddTimedBlock(timedBlock);
            }
        }
Exemplo n.º 5
0
            static void OnDespawned(TimedBlock instance)
            {
                Assert.That(instance._exclusiveTimer.IsRunning);
                instance._exclusiveTimer.Pause();

                foreach (var timer in instance._pausedTimers)
                {
                    Assert.That(!timer.IsRunning);
                    timer.Resume();
                }

                instance._pausedTimers.Clear();
            }
Exemplo n.º 6
0
        public static long ScheduleTimer(double interval, string blockName, Action callback)
        {
            lock (Instance.threadLock)
            {
                DateTime time = DateTime.Now;
                time = time.AddSeconds(interval);

                TimedBlock timedBlock = new TimedBlock(time, callback, blockName);
                Instance.id2TimedBlockMap.Add(timedBlock.id, timedBlock);
                Instance.AddTimedBlock(timedBlock);
                return(timedBlock.id);
            }
        }
Exemplo n.º 7
0
        public LauncherWindowViewModel2()
        {
            GameLibrary.GameLibrary.Load();

            using (var tb = new TimedBlock($"LauncherWindowViewModel2({ GameLibrary.GameLibrary.Games.Count })#CreateAllGameControls"))
            {
                // all controls must be created on STA thread, so better create controls for all games now
                allGames = GameLibrary.GameLibrary.Games
                           .Select(g =>
                {
                    var gc = new GameControl(g.Key, RebuildGameGrid, ProgressBarStartStop)
                    {
                        Width  = Const.GameControlSize.Width,
                        Height = Const.GameControlSize.Height,
                    };
                    gc.ViewModel.X = (int)Const.GridBorder + Rng.Next(0, (int)(windowSize.Width - Const.MinWindowSize.Width));
                    gc.ViewModel.Y = (int)Const.GridBorder + Rng.Next(0, (int)(windowSize.Height - Const.MinWindowSize.Height));

                    return(gc);
                })
                           .ToArray();
            }

            RebuildGameGrid();

            ProgressBarStartStop(true);

            // update games
            GameLibrary.GameLibrary.UpdateAll(
                (gameId) => GameUpdated(gameId),
                () =>
            {
                try
                {
                    ProgressBarStartStop(false);

                    Application.Current?.Dispatcher.Invoke(() =>
                    {
                        RebuildGameGrid();
                    });
                }
                catch (Exception ex)
                {
                    Log.WriteLine(ex.ToString());
                }
            });
        }
Exemplo n.º 8
0
        private void RebuildGameGrid()
        {
            Application.Current?.Dispatcher.Invoke(() =>
            {
                using (var tb = new TimedBlock($"RebuildGameGrid()"))
                {
                    FilteredGameIds = GameLibrary.GameLibrary.ListGames(titleFilter, filter, order, isOrderAscending);

                    var _filteredGameControls = new List <GameControl>();
                    foreach (var gameId in filteredGameIds)
                    {
                        _filteredGameControls.Add(allGameControls.Single(g => g.ViewModel.GameId == gameId));
                    }

                    FilteredGameControls = _filteredGameControls;
                }
            });
        }
Exemplo n.º 9
0
        /// <summary>
        /// update games with missing images / informations
        /// </summary>
        /// <param name="gameUpdated"></param>
        public static void UpdateAll(Action <string> gameUpdated, Action updateAllFinished)
        {
            try
            {
                // update only installed games with no data
                var gamesToUpdate = Games
                                    .Where(g => !g.Value.Removed && g.Value.Data.Length == 0)
                                    .Select(g => g.Key);

                Threading.ThreadAndForget(() =>
                {
                    using (var tb = new TimedBlock($"Update({ gamesToUpdate.Count() })"))
                    {
                        try
                        {
                            //foreach (var gameId in gamesToUpdate)
                            Parallel.ForEach(gamesToUpdate, gameId =>
                            {
                                if (UpdateGame(gameId))
                                {
                                    gameUpdated(gameId);
                                }
                            }
                                             );

                            UpdatePlayTimeFromSteamLibrary();
                            Save();

                            updateAllFinished();
                        }
                        catch (Exception ex)
                        {
                            Log.WriteLine(ex.ToString());
                        }
                    }
                });
            }
            catch (Exception ex)
            {
                Log.WriteLine(ex.ToString());
            }
        }
Exemplo n.º 10
0
            static void OnSpawned(
                IEnumerable <TimerInfo> timers, TimerInfo exclusiveTimer, TimedBlock instance)
            {
                Assert.That(instance._pausedTimers.IsEmpty());

                instance._exclusiveTimer = exclusiveTimer;

                foreach (var timer in timers)
                {
                    if (exclusiveTimer == timer)
                    {
                        Assert.That(!timer.IsRunning);
                        timer.Resume();
                    }
                    else if (timer.IsRunning)
                    {
                        timer.Pause();
                        instance._pausedTimers.Add(timer);
                    }
                }
            }
Exemplo n.º 11
0
            static void OnSpawned(
                TimerInfo exclusiveTimer, TimedBlock instance)
            {
                Assert.That(instance._pausedTimers.Count == 0);

                instance._exclusiveTimer = exclusiveTimer;

                foreach (var timer in _timers.Values)
                {
                    if (exclusiveTimer == timer)
                    {
                        Assert.That(!timer.IsRunning);
                        timer.Resume();
                    }
                    else if (timer.IsRunning)
                    {
                        timer.Pause();
                        instance._pausedTimers.Add(timer);
                    }
                }
            }
Exemplo n.º 12
0
        /// <summary>
        /// save current library and create backup of old library file
        /// </summary>
        public static void Save()
        {
            using (var tb = new TimedBlock($"Save({ GameLibraryFile })"))
            {
                try
                {
                    // backup old library
                    if (File.Exists(GameLibraryFile))
                    {
                        var newBackup = Utils.Compress(File.ReadAllText(GameLibraryFile));
                        File.WriteAllBytes(Path.Combine(BackupDirectory, GamesLibraryFileName + $"{ BackupExtension }{ DateTime.Now.ToString(TimestampFormat) }"), newBackup);

                        // keep only last week backup files
                        var oldBackupFiles = Directory.GetFiles(BackupDirectory, $"*{ BackupExtension }*");
                        foreach (var backupToDelete in BackupsOlderThan(7))
                        {
                            Log.WriteLine($"DeleteBackup({ backupToDelete })");
                            File.Delete(backupToDelete);
                        }
                    }

                    // save current library
                    File.WriteAllText(GameLibraryFile, Utils.GetFormattedXml(Utils.Serialize(Games)));

                    var stats = new string[]
                    {
                        $"{ nameof(IgdbComData) }={ Games.Count(g => g.Value.Data.Any(d => d is IgdbComData)) }",
                        $"{ nameof(SteamDbInfoData) }={ Games.Count(g => g.Value.Data.Any(d => d is SteamDbInfoData)) }",
                        $"{ nameof(SteamCryoTankNetData) }={ Games.Count(g => g.Value.Data.Any(d => d is SteamCryoTankNetData)) }",
                        $"{ nameof(SalenautsComData) }={ Games.Count(g => g.Value.Data.Any(d => d is SalenautsComData)) }",
                        $"{ nameof(UserData) }={ Games.Count(g => g.Value.Data.Any(d => d is UserData)) }",
                    };
                    Log.WriteLine($"GameDataStats(All={ Games.Count }, { string.Join(", ", stats) })");
                }
                catch (Exception ex)
                {
                    Log.WriteLine(ex.ToString());
                }
            }
        }
Exemplo n.º 13
0
        /// <summary>
        /// load existing game images to cache
        /// </summary>
        /// <returns></returns>
        static bool LoadGameImages()
        {
            using (var tb = new TimedBlock($"LoadGameImages({ Games.Count })"))
            {
                try
                {
                    GameImageCache.Clear();

                    Parallel.ForEach(Games.Keys, gameId =>
                    {
                        UpdateGameImageCache(gameId, Games[gameId].Image);
                    });

                    return(true);
                }
                catch (Exception ex)
                {
                    Log.WriteLine(ex.ToString());
                }
            }

            return(false);
        }
Exemplo n.º 14
0
 private void AddTimedBlock(TimedBlock timedBlock)
 {
     this.blocks.Enqueue(timedBlock.deadline.Ticks, timedBlock);
 }
Exemplo n.º 15
0
        /// <summary>
        /// Attempt to reuse the pip graph from a previous run
        /// </summary>
        private GraphReuseResult AttemptToReuseGraph(
            LoggingContext outerLoggingContext,
            int maxDegreeOfParallelism,
            GraphFingerprint graphFingerprint,
            IReadOnlyDictionary <string, string> properties,
            CacheInitializationTask cacheInitializationTask,
            JournalState journalState,
            EngineState engineState)
        {
            Contract.Ensures(Contract.Result <GraphReuseResult>() != null);

            GraphCacheCheckStatistics cacheGraphStats = CheckGraphCacheReuse(
                outerLoggingContext,
                maxDegreeOfParallelism,
                graphFingerprint,
                properties,
                cacheInitializationTask,
                journalState,
                out var serializer,
                out var inputChanges);

            // There are 3 cases in which we should reload the graph
            //   - we have a graph cache hit
            //   - the build is configured to reload the graph no matter what
            //   - graph patching is enabled and the reason for cache miss was 'SpecFileChanges'
            var shouldReload =
                cacheGraphStats.WasHit ||
                Configuration.Cache.CachedGraphPathToLoad.IsValid ||
                PartialReloadCondition(Configuration.FrontEnd, cacheGraphStats);

            if (!shouldReload)
            {
                return(GraphReuseResult.CreateForNoReuse(inputChanges));
            }

            bool fullReload = !PartialReloadCondition(Configuration.FrontEnd, cacheGraphStats);

            // Now we actually reload the graph
            var reloadStats = default(GraphCacheReloadStatistics);

            using (var tb = TimedBlock <EmptyStruct, GraphCacheReloadStatistics> .Start(
                       outerLoggingContext,
                       Statistics.GraphCacheReload,
                       (context, emptyStruct) =>
            {
                if (fullReload)
                {
                    Logger.Log.ReloadingPipGraphStart(context);
                }
                else
                {
                    Logger.Log.PartiallyReloadingEngineState(context);
                }
            },
                       default(EmptyStruct),
                       (context, graphCacheCheckStatistics) =>
            {
                Logger.Log.PartiallyReloadingEngineStateComplete(context, graphCacheCheckStatistics);
                m_enginePerformanceInfo.GraphReloadDurationMs = graphCacheCheckStatistics.ElapsedMilliseconds;
            },
                       () => reloadStats))
            {
                var reuseResult = fullReload
                    ? ReloadEngineSchedule(
                    serializer,
                    cacheInitializationTask,
                    journalState,
                    tb.LoggingContext,
                    engineState,
                    inputChanges,
                    graphFingerprint?.ExactFingerprint.BuildEngineHash.ToString())
                    : ReloadPipGraphOnly(serializer, tb.LoggingContext, engineState, inputChanges);

                // Set telemetry statistics
                reloadStats.SerializedFileSizeBytes = serializer.BytesDeserialized;
                reloadStats.Success = !reuseResult.IsNoReuse;

                return(reuseResult);
            }
        }
Exemplo n.º 16
0
        /// <summary>
        /// Check if pip graph can be reused.
        ///
        /// There are 3 opportunities to determine a graph match. The applicability of each depends on the distributed build roles.
        ///   (1) from engine cache,
        ///   (2) from content cache, and
        ///   (3) from master node (if running on a worker node in a distributed build)
        /// </summary>
        private GraphCacheCheckStatistics CheckGraphCacheReuse(
            LoggingContext outerLoggingContext,
            int maxDegreeOfParallelism,
            GraphFingerprint graphFingerprint,
            IReadOnlyDictionary <string, string> properties,
            CacheInitializationTask cacheInitializationTask,
            JournalState journalState,
            out EngineSerializer serializer,
            out InputTracker.InputChanges inputChanges)
        {
            serializer   = CreateEngineSerializer(outerLoggingContext);
            inputChanges = null;
            var cacheGraphStats = default(GraphCacheCheckStatistics);

            using (var timeBlock = TimedBlock <EmptyStruct, GraphCacheCheckStatistics> .Start(
                       outerLoggingContext,
                       Statistics.GraphCacheReuseCheck,
                       (context, emptyStruct) => Logger.Log.CheckingForPipGraphReuseStart(context),
                       default(EmptyStruct),
                       (loggingContext, stats) =>
            {
                Logger.Log.CheckingForPipGraphReuseComplete(loggingContext, stats);

                // On misses we want to give the user a message for why there was a miss
                if (!stats.WasHit)
                {
                    Contract.Assume(stats.MissReason != GraphCacheMissReason.NoMiss);
                    Logger.Log.GraphNotReusedDueToChangedInput(loggingContext, stats.MissMessageForConsole, stats.MissDescription);
                }

                m_enginePerformanceInfo.GraphCacheCheckDurationMs = stats.ElapsedMilliseconds;
                m_enginePerformanceInfo.GraphCacheCheckJournalEnabled = stats.JournalEnabled;
            },
                       () => cacheGraphStats))
            {
                var loggingContext = timeBlock.LoggingContext;
                var effectiveEnvironmentVariables = FrontEndEngineImplementation.PopulateFromEnvironmentAndApplyOverrides(properties);
                var availableMounts = MountsTable.CreateAndRegister(loggingContext, Context, Configuration, m_initialCommandLineConfiguration.Startup.Properties);

                if (!AddConfigurationMountsAndCompleteInitialization(loggingContext, availableMounts))
                {
                    return(cacheGraphStats);
                }

                cacheGraphStats.JournalEnabled = journalState.IsEnabled;

                // ************************************************************
                // 1. Engine cache check:
                // ************************************************************
                // * Single machine builds
                // Distributed builds rely on the graph being available via the cache for it to be shared between master
                // and workers. So even if the master could have had a hit from the engine cache, it must be ignored
                // since the workers would not be able to retrieve it.
                if (!HasExplicitlyLoadedGraph(Configuration.Cache) &&
                    !Configuration.Schedule.ForceUseEngineInfoFromCache &&
                    Configuration.Distribution.BuildRole == DistributedBuildRoles.None)
                {
                    Contract.Assume(
                        graphFingerprint != null,
                        "When looking up a cached graph on a distributed master or single-machine build, a graph fingerprint must be computed");

                    InputTracker.MatchResult engineCacheMatchResult = CheckIfAvailableInputsToGraphMatchPreviousRun(
                        loggingContext,
                        serializer,
                        graphFingerprint: graphFingerprint,
                        availableEnvironmentVariables: effectiveEnvironmentVariables,
                        availableMounts: availableMounts,
                        journalState: journalState,
                        maxDegreeOfParallelism: maxDegreeOfParallelism);
                    cacheGraphStats.ObjectDirectoryHit        = engineCacheMatchResult.Matches;
                    cacheGraphStats.ObjectDirectoryMissReason = engineCacheMatchResult.MissType;
                    cacheGraphStats.MissReason        = engineCacheMatchResult.MissType;
                    cacheGraphStats.MissDescription   = engineCacheMatchResult.FirstMissIdentifier;
                    cacheGraphStats.WasHit            = engineCacheMatchResult.Matches;
                    cacheGraphStats.InputFilesChecked = engineCacheMatchResult.FilesChecked;

                    // Checking the engine cache may have used a FileChangeTracker and provided information about
                    // files/ContentHash pairs that were unchanged from the previous run. Hold onto this information as it may
                    // be useful when eventually parsing files.
                    // The FileChangeTracker is now up to date. All changed files have been removed from it. It can be reused
                    // for a future build with the same fingerprint, though it may be tracking extra files, for example if
                    // a spec was removed since the previous build.
                    inputChanges = engineCacheMatchResult.InputChanges;
                }

                var shouldTryContentCache =
                    !cacheGraphStats.WasHit &&
                    Configuration.Distribution.BuildRole != DistributedBuildRoles.Worker &&
                    Configuration.Cache.AllowFetchingCachedGraphFromContentCache &&
                    !HasExplicitlyLoadedGraph(Configuration.Cache) &&
                    (!Configuration.FrontEnd.UseSpecPublicFacadeAndAstWhenAvailable.HasValue ||
                     !Configuration.FrontEnd.UseSpecPublicFacadeAndAstWhenAvailable.Value);

                // ************************************************************
                // 2. Content cache check:
                // ************************************************************
                // * Single machine builds that missed earlier
                // * Distributed masters
                // This is the only valid place for the master to get a hit since it must be in the cache for the
                // workers to get it.
                if (shouldTryContentCache)
                {
                    // Since an in-place match did not succeed, we need a readied cache to try again.
                    // TODO: This logs an error if it fails. We are assuming some later thing will ensure that, if failed,
                    //       the engine fails overall.
                    Possible <CacheInitializer> possibleCacheInitializerForFallback = cacheInitializationTask.GetAwaiter().GetResult();
                    if (possibleCacheInitializerForFallback.Succeeded)
                    {
                        CacheInitializer cacheInitializerForFallback = possibleCacheInitializerForFallback.Result;
                        using (EngineCache cacheForFallback = cacheInitializerForFallback.CreateCacheForContext())
                        {
                            var cacheGraphProvider = new CachedGraphProvider(
                                loggingContext,
                                Context,
                                cacheForFallback,
                                FileContentTable,
                                maxDegreeOfParallelism);

                            var cachedGraphDescriptor =
                                cacheGraphProvider.TryGetPipGraphCacheDescriptorAsync(graphFingerprint, effectiveEnvironmentVariables, availableMounts.MountsByName).Result;

                            if (cachedGraphDescriptor == null)
                            {
                                // There was no matching fingerprint in the cache. Record the status for logging before returning.
                                cacheGraphStats.CacheMissReason = GraphCacheMissReason.FingerprintChanged;
                                SetMissReasonIfUnset(ref cacheGraphStats, cacheGraphStats.CacheMissReason);
                                return(cacheGraphStats);
                            }

                            var fetchEngineScheduleContent = EngineSchedule.TryFetchFromCacheAsync(
                                loggingContext,
                                Context,
                                cacheForFallback,
                                cachedGraphDescriptor,
                                serializer,
                                FileContentTable,
                                m_tempCleaner).Result;

                            if (!fetchEngineScheduleContent)
                            {
                                cacheGraphStats.CacheMissReason = GraphCacheMissReason.NoPreviousRunToCheck;
                                SetMissReasonIfUnset(ref cacheGraphStats, cacheGraphStats.CacheMissReason);
                                return(cacheGraphStats);
                            }

                            // If a distributed master, take note of the graph fingerprint
                            if (Configuration.Distribution.BuildRole == DistributedBuildRoles.Master)
                            {
                                Contract.Assert(cachedGraphDescriptor != null);
                                m_masterService.CachedGraphDescriptor = cachedGraphDescriptor;
                            }

                            Logger.Log.FetchedSerializedGraphFromCache(outerLoggingContext);

                            cacheGraphStats.CacheMissReason = GraphCacheMissReason.NoMiss;
                            cacheGraphStats.MissReason      = cacheGraphStats.CacheMissReason;
                            cacheGraphStats.WasHit          = true;
                        }
                    }
                    else
                    {
                        cacheGraphStats.CacheMissReason = GraphCacheMissReason.CacheFailure;
                        SetMissReasonIfUnset(ref cacheGraphStats, cacheGraphStats.CacheMissReason);
                        return(cacheGraphStats);
                    }
                }

                // ************************************************************
                // 3. Query distributed master
                // ************************************************************
                // * Distributed workers only
                if (Configuration.Distribution.BuildRole == DistributedBuildRoles.Worker)
                {
                    Contract.Assume(
                        graphFingerprint == null,
                        "Distributed workers should request a graph fingerprint from the master (not compute one locally)");
                    Possible <CacheInitializer> possibleCacheInitializerForWorker = cacheInitializationTask.GetAwaiter().GetResult();
                    Contract.Assume(possibleCacheInitializerForWorker.Succeeded, "Workers must have a valid cache");
                    CacheInitializer cacheInitializerForWorker = possibleCacheInitializerForWorker.Result;

                    using (EngineCache cacheForWorker = cacheInitializerForWorker.CreateCacheForContext())
                    {
                        PipGraphCacheDescriptor schedulerStateDescriptor;
                        if (!m_workerService.TryGetBuildScheduleDescriptor(out schedulerStateDescriptor) ||
                            !EngineSchedule.TryFetchFromCacheAsync(
                                outerLoggingContext,
                                Context,
                                cacheForWorker,
                                schedulerStateDescriptor,
                                serializer,
                                FileContentTable,
                                m_tempCleaner).Result)
                        {
                            cacheGraphStats.CacheMissReason = GraphCacheMissReason.NoFingerprintFromMaster;
                            cacheGraphStats.MissReason      = cacheGraphStats.CacheMissReason;
                            return(cacheGraphStats);
                        }

                        AsyncOut <AbsolutePath> symlinkFileLocation = new AsyncOut <AbsolutePath>();
                        if (!SymlinkDefinitionFileProvider.TryFetchWorkerSymlinkFileAsync(
                                outerLoggingContext,
                                Context.PathTable,
                                cacheForWorker,
                                Configuration.Layout,
                                m_workerService,
                                symlinkFileLocation).Result)
                        {
                            cacheGraphStats.CacheMissReason = GraphCacheMissReason.NoFingerprintFromMaster;
                            cacheGraphStats.MissReason      = cacheGraphStats.CacheMissReason;
                            return(cacheGraphStats);
                        }

                        m_workerSymlinkDefinitionFile = symlinkFileLocation.Value;

                        // Success. Populate the stats
                        cacheGraphStats.WasHit          = true;
                        cacheGraphStats.WorkerHit       = true;
                        cacheGraphStats.MissReason      = GraphCacheMissReason.NoMiss;
                        cacheGraphStats.CacheMissReason = GraphCacheMissReason.NoMiss;
                    }
                }
            }

            return(cacheGraphStats);
        }
Exemplo n.º 17
0
        /// <summary>
        /// load game library from xml and add new games
        /// </summary>
        /// <returns>games to update (without images)</returns>
        static bool LoadGames(string libraryToLoad = null)
        {
            using (var tb = new TimedBlock($"LoadGames({ libraryToLoad })"))
            {
                try
                {
                    Games.Clear();

                    // deserialize library
                    DeserializeLibrary(libraryToLoad);

                    if (!string.IsNullOrEmpty(GamesDirectory))
                    {
                        // add new games from current games folder
                        foreach (var gameShortcut in Directory.GetFiles(GamesDirectory, "*.*", SearchOption.AllDirectories))
                        {
                            var fileInfo = new FileInfo(gameShortcut);

                            if (!SupportedGameExtensions.Contains(fileInfo.Extension.ToLower()))
                            {
                                continue;
                            }

                            var gameTitle = fileInfo.Name.Replace(fileInfo.Extension, string.Empty);
                            var gameId    = GetGameId(gameTitle);

                            if (!Games.ContainsKey(gameId))
                            {
                                var newGameInfo =
                                    new GameInfo
                                {
                                    Title    = gameTitle,
                                    Shortcut = gameShortcut,
                                    Added    = DateTime.Now,
                                };

                                // add new game
                                Games.AddOrUpdate(gameId, newGameInfo, (key, oldGameInfo) => newGameInfo);
                            }

                            // update game shortcut everytime
                            Games[gameId].Shortcut = gameShortcut;
                        }
                    }

                    // mark games with not-existing shortcuts as removed
                    foreach (var game in Games.Where(g => g.Value.Shortcut != null && !File.Exists(g.Value.Shortcut)))
                    {
                        game.Value.Shortcut = null;
                    }

                    return(true);
                }
                catch (Exception ex)
                {
                    Log.WriteLine(ex.ToString());
                }
            }

            return(false);
        }
Exemplo n.º 18
0
        /// <summary>
        /// fix differences in old vs new library
        /// </summary>
        /// <param name="oldLibrary"></param>
        /// <param name="newLibrary"></param>
        /// <returns></returns>
        static ConcurrentDictionary <string, GameInfo> FixLibrary(string oldLibrary, ConcurrentDictionary <string, GameInfo> newLibrary)
        {
            using (var tb = new TimedBlock($"FixLibrary({ (string.IsNullOrEmpty(oldLibrary) ? "null" : oldLibrary) }, { newLibrary.Count })"))
            {
                try
                {
                    var oldLibraryXml = new XmlDocument();

                    if (!string.IsNullOrEmpty(oldLibrary))
                    {
                        oldLibraryXml.Load(oldLibrary);
                    }

                    var nsmgr = new XmlNamespaceManager(oldLibraryXml.NameTable);
                    nsmgr.AddNamespace("a", "http://schemas.microsoft.com/2003/10/Serialization/Arrays");
                    nsmgr.AddNamespace("i", "http://www.w3.org/2001/XMLSchema-instance");
                    nsmgr.AddNamespace("d3p1", "http://schemas.datacontract.org/2004/07/GameLibrary");
                    nsmgr.AddNamespace("d4p1", "http://schemas.datacontract.org/2004/07/GameLibrary.GameDataProviders");

                    foreach (var newGame in newLibrary)
                    {
                        if (newGame.Value.LastDataUpdate == null)
                        {
                            newGame.Value.LastDataUpdate = new ConcurrentDictionary <string, DateTime>();
                        }

                        else
                        {
                            // remove last update values of missing data
                            var lastUpdateKeys = newGame.Value.LastDataUpdate.Keys.ToArray();
                            foreach (var lastUpdateKey in lastUpdateKeys)
                            {
                                if (!newGame.Value.Data.Any(d => d.DataType == lastUpdateKey))
                                {
                                    newGame.Value.LastDataUpdate.TryRemove(lastUpdateKey, out DateTime value);
                                }
                            }
                        }

                        // merge old library
                        if (!string.IsNullOrEmpty(oldLibrary))
                        {
                            var oldGame = oldLibraryXml.DocumentElement
                                          .SelectSingleNode($"/a:ArrayOfKeyValueOfstringGameInfo7FtjRveh/a:KeyValueOfstringGameInfo7FtjRveh[a:Key='{ newGame.Key }']/a:Value", nsmgr);
                            if (oldGame == null)
                            {
                                Log.WriteLine($"deserializedGame { newGame.Value.Title } not found in old library");
                                continue;
                            }

                            var steamDbData = newGame.Value.CustomData <SteamDbInfoData>();
                            if (steamDbData != null)
                            {
                                if (Int32.TryParse(oldGame.SelectSingleNode($"d3p1:Data/d4p1:GameData[@i:type='d4p1:SteamDbInfoData']/d4p1:MetacriticScore", nsmgr)?.InnerText ?? string.Empty, out int rating))
                                {
                                    steamDbData.Rating = rating;
                                }

                                steamDbData.Summary = steamDbData.Summary ?? oldGame.SelectSingleNode($"d3p1:Data/d4p1:GameData[@i:type='d4p1:SteamDbInfoData']/d4p1:Description", nsmgr)?.InnerText;
                                if (steamDbData.Summary == string.Empty)
                                {
                                    steamDbData.Summary = null;
                                }

                                steamDbData.AppId = steamDbData.AppId ?? oldGame.SelectSingleNode($"d3p1:Data/d4p1:GameData[@i:type='d4p1:SteamDbInfoData']/d4p1:AppId", nsmgr)?.InnerText;

                                steamDbData.SourceGameTitle = steamDbData.SourceGameTitle ?? oldGame.SelectSingleNode($"d3p1:Data/d4p1:GameData[@i:type='d4p1:SteamDbInfoData']/d4p1:SourceGameTitle", nsmgr)?.InnerText;
                                if (steamDbData.SourceGameTitle == string.Empty)
                                {
                                    steamDbData.SourceGameTitle = null;
                                }

                                if (bool.TryParse(oldGame.SelectSingleNode($"d3p1:Data/d4p1:GameData[@i:type='d4p1:SteamDbInfoData']/d4p1:GamepadFriendly", nsmgr)?.InnerText ?? string.Empty, out bool gf))
                                {
                                    steamDbData.GamepadFriendly = gf;
                                }
                            }

                            var salenautsComData = newGame.Value.CustomData <SalenautsComData>();
                            if (salenautsComData != null)
                            {
                                salenautsComData.SourceGameTitle = salenautsComData.SourceGameTitle ?? oldGame.SelectSingleNode($"d3p1:Data/d4p1:GameData[@i:type='d4p1:SalenautsComData']/d4p1:SourceGameTitle", nsmgr)?.InnerText;
                                if (salenautsComData.SourceGameTitle == string.Empty)
                                {
                                    salenautsComData.SourceGameTitle = null;
                                }
                            }

                            var userData = newGame.Value.CustomData <UserData>();
                            if (userData != null)
                            {
                                userData.SourceGameTitle = userData.SourceGameTitle ?? oldGame.SelectSingleNode($"d3p1:Data/d4p1:GameData[@i:type='d4p1:UserData']/d4p1:SourceGameTitle", nsmgr)?.InnerText;
                                if (userData.SourceGameTitle == string.Empty)
                                {
                                    userData.SourceGameTitle = null;
                                }

                                if (userData.SourceGameTitle == null)
                                {
                                    userData.SourceGameTitle = newGame.Value.Title;
                                }

                                if (bool.TryParse(oldGame.SelectSingleNode($"d3p1:Data/d4p1:GameData[@i:type='d4p1:UserData']/d4p1:GamepadFriendly", nsmgr)?.InnerText ?? string.Empty, out bool gf))
                                {
                                    userData.GamepadFriendly = gf;
                                }
                            }
                        }
                    }

                    return(newLibrary);
                }
                catch (Exception ex)
                {
                    Log.WriteLine(ex.ToString());
                    return(null);
                }
            }
        }