private async Task CleanContext(JobExecutionData jobExecutionData)
        {
            var key     = SchedulerService.BuildJobKey(jobExecutionData);
            var removed = _travianUser.ExecutionContext?.Commands?.RemoveAll(x => x.KeyGroup == key.Group && x.StartDateTime < DateTimeOffset.Now);

            if (removed > 0)
            {
                await _travianUserRepository.Update(_travianUser);
            }
        }
Example #2
0
 protected override async Task ExecuteJob(JobExecutionData jobExecutionData)
 {
     if (jobExecutionData != null)
     {
         await ExecuteJobScenario(new CancellationToken());
     }
     else
     {
         throw new ArgumentNullException(nameof(jobExecutionData), "The provided execution data is null");
     }
 }
        protected override async Task ExecuteJob(JobExecutionData jobExecutionData)
        {
            await CleanContext(jobExecutionData);

            try
            {
                var actions = await this._actionProvider.GetActionsForPlayer(_travianUser);

                if (actions != null && actions.Any())
                {
                    _logger.LogDebug($"Starting Prepare to attack command for BotUserName:[{_botUser.UserName}], TravianUserName:[{_travianUser.UserName}]");
                    var response = await _gameplayClient.ExecuteActions(_travianUser, actions);

                    if (response.Errors != null && response.Errors.Any(x => x != null))
                    {
                        var villagesNames = string.Join(", ", actions.Select(x => x.Village.Name));
                        await _bot.SendTextMessageAsync(_botUser.ChatId, $"The prepare command completed with errors");

                        _logger.LogError(LoggingEvents.BackgroundJobCreationException, string.Join(", ", response.Errors));
                        var notFound = response.Errors.Where(x => x.ErrorType == "NotFound");
                        if (notFound.Any())
                        {
                            foreach (var error in notFound)
                            {
                                await _bot.SendTextMessageAsync(_botUser.ChatId, error.ErrorMessage);
                            }
                        }
                    }
                    else
                    {
                        foreach (var action in actions)
                        {
                            var msg = $"The village {action.Village.Name} was prepared to attack with following action: [{action.Action.GetEnumDisplayName()}]";
                            if (action is SendResourcesAction)
                            {
                                var a = action as SendResourcesAction;
                                msg += $" to {a.To.Name}";
                            }

                            msg += ".";
                            await _bot.SendTextMessageAsync(_botUser.ChatId, msg);
                        }
                    }

                    _logger.LogDebug($"Prepare to attack command completed for player :[{_travianUser.UserName}]");
                }
            }
            catch (Exception exc)
            {
                _logger.LogError(LoggingEvents.BackgroundJobCreationException, exc, exc.Message);
            }
        }
Example #4
0
        public async Task Execute(JobExecutionData jobExecutionData)
        {
            try
            {
                _botUser = await _botUserProvider.FindByNameAsync(jobExecutionData.TravianUser.BotUserName);

                _travianUser = jobExecutionData.TravianUser;
            }
            catch (Exception exc)
            {
                this._logger.LogError(LoggingEvents.BackgroundJobExecutingException, exc, "Unable to get parameters from JobExecutionContext.");
                return;
            }

            try
            {
                await ExecuteJob(jobExecutionData);
            }
            catch (Exception exc)
            {
                this._logger.LogError(LoggingEvents.BackgroundJobExecutingException, exc, "Unexpected error occurred during the job execution.");
            }
        }
        protected override async Task ExecuteJob(JobExecutionData jobExecutionData)
        {
            var allVillages = await _villageRepository.GetVillages(_travianUser.UserName);

            var buildVillages = allVillages
                                .Where(x => x.IsBuildFeatureOn)
                                .ToList();

            if (!buildVillages.Any())
            {
                await _bot.SendTextMessageAsync(_botUser.ChatId, $"No villages with build feature found for player {_travianUser.UserName}");

                return;
            }

            foreach (var village in buildVillages.Where(x => x.IsWaitingForResources))
            {
                // for villages waiting for resources next execution time is the time when resources must be delivered
                // if next execution time passed resources are expected to be delivered
                village.IsWaitingForResources = village.NextBuildingPlanExecutionTime.HasValue && village.NextBuildingPlanExecutionTime.Value > DateTimeOffset.Now;
            }

            BaseScenarioResult infos = null;

            try
            {
                var updateActions = buildVillages
                                    .Select(x => new GameAction {
                    Village = _mapper.Map <Village>(x)
                });
                infos = await _gameplayClient.ExecuteActions(_travianUser, updateActions);

                var update = infos.Villages.Select(x => _mapper.Map <VillageModel>(x));
                await _villageRepository.UpdateWatchInfo(update);
            }
            catch (Exception exc)
            {
                _logger.LogError(exc, exc.Message);
                await _bot.SendTextMessageAsync(_botUser.ChatId, $"Unable to update villages info for player {_travianUser.UserName}");

                return;
            }

            if (!infos?.Villages?.Any() ?? true)
            {
                await _bot.SendTextMessageAsync(_botUser.ChatId, $"No info was found for villages of {_travianUser.UserName}");

                return;
            }

            // suits only for rome or for player with travian plus. TODO: fix for other tribes
            var freeVillages = infos.Villages
                               .Where(x => x.CanBuild)
                               .ToList();

            var busyVillages = infos.Villages
                               .Where(x => !x.CanBuild)
                               .ToList();

            if (busyVillages?.Any() ?? false)
            {
                foreach (var village in busyVillages)
                {
                    // if village has less than 10% filled warehouse we should send there more resources
                    var limit = village.Warehourse * 0.1;
                    if (!village.Dorf1BuildTimeLeft.HasValue || village.Resources.Lumber < limit || village.Resources.Clay < limit ||
                        village.Resources.Iron < limit || village.Resources.Crop < village.Granary * 0.1)
                    {
                        await SendResources(allVillages.ToList(), village);
                    }
                }
            }

            var result = new BaseScenarioResult();

            if (!freeVillages?.Any() ?? true)
            {
                await _bot.SendTextMessageAsync(_botUser.ChatId, $"All villages with building feature of player {_travianUser.UserName} are busy.");

                await _bot.SendTextMessageAsync(_botUser.ChatId, $"Calculating next build command execution time for player {_travianUser.UserName}.");
            }
            else
            {
                var i            = 0;
                var allBuidlgins = await _buildingRepository.GetAllBuildings();

                while ((freeVillages?.Any() ?? false) && i++ < buildVillages.Count)
                {
                    var allActions = new List <BuildAction>();
                    foreach (var village in freeVillages)
                    {
                        var(hasMoreToBuild, actions) = await _actionProvider.GetBuildActions(village, allBuidlgins);

                        if (!hasMoreToBuild)
                        {
                            await _bot.SendTextMessageAsync(_botUser.ChatId, $"No actions needed for village {village.Name} of player {village.PlayerName}. Swithching off the Build Feature.");

                            try
                            {
                                var villageToUpdate = await _villageRepository.GetVillage(village.CoordinateX, village.CoordinateY);

                                villageToUpdate.IsBuildFeatureOn = false;
                                await _villageRepository.UpdateInfos(new List <VillageModel> {
                                    villageToUpdate
                                });
                            }
                            catch (Exception exc)
                            {
                                _logger.LogError(exc, exc.Message);
                                await _bot.SendTextMessageAsync(_botUser.ChatId, $"Unable to update {village.Name} of player {village.PlayerName}. Check Logs.");
                            }
                        }
                        else
                        {
                            allActions.AddRange(actions);
                        }
                    }

                    if (allActions.Any())
                    {
                        result = await _gameplayClient.ExecuteActions(_travianUser, allActions);

                        var buildErrors = result.Errors
                                          .Where(x => x is BuildScenarioError)
                                          .Cast <BuildScenarioError>();
                        if (buildErrors.Any())
                        {
                            var notEnoughRes = buildErrors
                                               .Where(x => (x as BuildScenarioError).BuildErrorType == BuildErrorType.NotEnoughResources);
                            if (notEnoughRes.Any())
                            {
                                foreach (var n in notEnoughRes)
                                {
                                    var updatedVillage = result.Villages.First(x => x.CoordinateX == n.Village.CoordinateX && x.CoordinateY == n.Village.CoordinateY);
                                    await SendResources(allVillages.ToList(), updatedVillage);
                                }
                            }

                            var noSpaceInQueue = buildErrors
                                                 .Where(x => (x as BuildScenarioError).BuildErrorType == BuildErrorType.NoSpaceInQueue);
                            if (noSpaceInQueue.Any())
                            {
                                foreach (var n in noSpaceInQueue)
                                {
                                    var errorVillage = result.Villages.First(x => x.CoordinateX == n.Village.CoordinateX && x.CoordinateY == n.Village.CoordinateY);
                                    errorVillage.CanBuild = false;
                                }
                            }
                        }

                        freeVillages = result.Villages.Where(x => x.CanBuild).ToList();
                    }
                }
            }

            var      max     = infos.Villages.Count > result.Villages.Count ? infos.Villages.Count : result.Villages.Count;
            TimeSpan nextRun = TimeSpan.MaxValue;

            for (var j = 0; j < max; j++)
            {
                if (j < infos.Villages.Count)
                {
                    if (infos.Villages[j].Dorf1BuildTimeLeft.HasValue &&
                        infos.Villages[j].Dorf1BuildTimeLeft.Value > TimeSpan.Zero &&
                        infos.Villages[j].Dorf1BuildTimeLeft.Value < nextRun)
                    {
                        nextRun = infos.Villages[j].Dorf1BuildTimeLeft.Value;
                    }
                }
                if (j < result.Villages.Count)
                {
                    if (result.Villages[j].Dorf1BuildTimeLeft.HasValue &&
                        result.Villages[j].Dorf1BuildTimeLeft.Value > TimeSpan.Zero &&
                        result.Villages[j].Dorf1BuildTimeLeft.Value < nextRun)
                    {
                        nextRun = result.Villages[j].Dorf1BuildTimeLeft.Value;
                    }
                }
            }

            if (nextRun < TimeSpan.MaxValue)
            {
                var waitingForResources = buildVillages
                                          ?.Where(x => x.IsWaitingForResources && x.NextBuildingPlanExecutionTime.HasValue)
                                          ?.Select(x => x.NextBuildingPlanExecutionTime.Value)
                                          ?.ToList();

                var nextRunDateTime          = DateTimeOffset.Now + nextRun;
                var nearestResourcesDelivery = (waitingForResources?.Any() ?? false) ? waitingForResources.Min() : DateTimeOffset.MaxValue;

                var cmd = _commandFactory.GetQueueableCommand(nameof(BuildCommand), _botUser.ChatId);
                cmd.Start = (nextRunDateTime < nearestResourcesDelivery ? nextRunDateTime : nearestResourcesDelivery) + TimeSpan.FromSeconds(2);
                await cmd.Execute();
            }
            else
            {
                await _bot.SendTextMessageAsync(_botUser.ChatId, $"Unable to calculate next build command execution time for player {_travianUser.UserName}");
            }
        }
Example #6
0
 protected abstract Task ExecuteJob(JobExecutionData jobExecutionData);