public async Task UpdateGameState(Guid gameId, ContentQuery query = null) {
            _stateHandler.SelectedGameId = gameId;

            var gameContext = _locator.GetGameContext();
            var game = await gameContext.FindGameOrThrowAsync(gameId).ConfigureAwait(false);
            if (query == null)
                game.CleanupContent();

            await _setup.HandleGameContentsWhenNeeded(query, game.Id).ConfigureAwait(false);
        }
        async Task ProcessGame(Game game, ContentQuery filterFunc, CancellationToken ct) {
            var invalidContent = game.Contents.Where(x => x.GameId == Guid.Empty).ToArray();
            if (invalidContent.Any())
                invalidContent.ForEach(x => x.FixGameId(game.Id));

            var stats = await GetHashStats(game, ct).ConfigureAwait(false);
            if (!stats.ShouldSyncBecauseHashes && !stats.ShouldSyncBecauseVersion && (filterFunc == null))
                return;
            var onlineContent = await GetContent(game, stats.Hashes).ConfigureAwait(false);
            ProcessContents(game, onlineContent, filterFunc);
            game.RefreshCollections();

            var si = game.SyncInfo;
            var dt = Tools.Generic.GetCurrentUtcDateTime;
            si.ApiHashes = stats.Hashes;
            si.LastSync = dt;
            si.LastSyncVersion = Consts.SyncVersion;
        }
 public async Task SyncContent(IReadOnlyCollection<Game> games, ContentQuery filterFunc = null) {
     if (Common.Flags.Verbose)
         MainLog.Logger.Info($"Syncing content for games: {string.Join(", ", games.Select(x => x.Id))}");
     foreach (var g in games)
         await ProcessGame(g, filterFunc, CancellationToken.None).ConfigureAwait(false);
 }
 private static Dictionary<Guid, ModClientApiJsonV3WithGameId> GetTheDesiredMods(Game game,
     ContentQuery filterFunc,
     IDictionary<Guid, ModClientApiJsonV3WithGameId> onlineContent) {
     var desired = onlineContent.Where(x => filterFunc.IsMatch(x.Value));
     var dependencyChain = new Dictionary<Guid, ModClientApiJsonV3WithGameId>();
     GetRelatedContent(game, desired.Select(x => x.Value), dependencyChain, onlineContent);
     return dependencyChain;
 }
        private static Dictionary<Guid, ModClientApiJsonV3WithGameId> GetDesiredModList(Game game,
            IDictionary<Guid, ModClientApiJsonV3WithGameId> onlineContent, ContentQuery filterFunc,
            Dictionary<Guid, ModNetworkContent> currentContent) {
            if (filterFunc != null)
                return GetTheDesiredMods(game, filterFunc, onlineContent);

            var localMods =
                game.LocalContent.OfType<ModLocalContent>()
                    .Select(
                        x =>
                            onlineContent.Values.FirstOrDefault(
                                c => c.PackageName.Equals(x.PackageName, StringComparison.CurrentCultureIgnoreCase)))
                    .Where(x => x != null);
            var ids = currentContent.Keys.Concat(localMods.Select(x => x.Id)).Distinct();
            return GetTheDesiredMods(game, new ContentQuery {Ids = ids.ToList()}, onlineContent);
        }
        static void UpdateContents(Game game, IDictionary<Guid, ModClientApiJsonV3WithGameId> onlineContent,
            IDictionary<ModClientApiJsonV3WithGameId, ModNetworkContent> content, ContentQuery filterFunc = null) {
            var currentContent = game.NetworkContent.OfType<ModNetworkContent>().ToDictionary(x => x.Id, x => x);
            var desiredModsList = GetDesiredModList(game, onlineContent, filterFunc, currentContent);
            var mapping = desiredModsList.Keys
                .Where(onlineContent.ContainsKey)
                .Select(
                    x =>
                        new {
                            DTO = onlineContent[x],
                            Existing = currentContent.ContainsKey(x) ? currentContent[x] : null
                        });

            foreach (var c in mapping) {
                var dto = c.DTO;
                var theGame = SetupGameStuff.GameSpecs.Select(x => x.Value).FindOrThrow(c.DTO.GameId);
                if (c.Existing == null) {
                    var nc = dto.MapTo<ModNetworkContent>();
                    content[dto] = nc;
                    game.Contents.Add(nc);
                } else {
                    c.Existing.UpdateVersionInfo(dto.GetVersion(), dto.UpdatedVersion);
                    dto.MapTo(c.Existing);
                    content[dto] = c.Existing;
                }
                if (c.DTO.GameId != game.Id)
                    content[dto].HandleOriginalGame(c.DTO.GameId, theGame.Slug, game.Id);
            }
        }
 static void ProcessContents(Game game, IDictionary<Guid, ModClientApiJsonV3WithGameId> onlineContent,
     ContentQuery filterFunc) {
     // TODO: If we timestamp the DTO's, and save the timestamp also in our database,
     // then we can simply update data only when it has actually changed and speed things up.
     // The only thing to remember is when there are schema changes / new fields etc, either all timestamps need updating
     // or the syncer needs to take it into account..
     var mapping = new Dictionary<ModClientApiJsonV3WithGameId, ModNetworkContent>();
     UpdateContents(game, onlineContent, mapping, filterFunc);
     HandleDependencies(game, mapping);
     if (filterFunc == null)
         game.ProcessLocalContent();
 }
 public static Task HandleGameContentsWhenNeeded(this ISetupGameStuff This,
         ContentQuery query = null, params Guid[] gameIds)
     => This.HandleGameContentsWhenNeeded(gameIds, query);
        public async Task HandleGameContentsWhenNeeded(IReadOnlyCollection<Guid> gameIds, ContentQuery query = null) {
            if (Common.Flags.Verbose)
                MainLog.Logger.Info($"Handling game contents for {string.Join(", ", gameIds)}");

            var gc = _locator.GetGameContext();
            await gc.Load(gameIds).ConfigureAwait(false);

            var games = gc.Games.Where(x => gameIds.Contains(x.Id) && x.InstalledState.IsInstalled).ToArray();
            await
                _networkContentSyncer.SyncContent(games, query).ConfigureAwait(false);
            //if (shouldEmitEvents) await new StatusChanged(Status.Preparing, new ProgressInfo(progress: 50)).Raise().ConfigureAwait(false);
            await SynchronizeCollections(games).ConfigureAwait(false);
            foreach (var g in games)
                await g.RefreshState().ConfigureAwait(false);
        }