//[TestCase(true, -1, -1)] public void TestSendWavesScenario(bool sendAll, int existing, int existing2, string villageName) { var action = new SendWavesAction { Action = GameActionType.SEND_ARMY, Village = new Village { Name = "Unexpected_Town_02" }, SendAll = sendAll, To = new Village { Name = villageName, CoordinateX = -151, CoordinateY = 118 }, Type = SendArmyType.ATTACK, UnitsToSend = new Dictionary <string, int> { { "Легионер", existing } }, Waves = 4 }; var send = new SendWavesScenario(provider, action); BaseScenarioResult result = new BaseScenarioResult(); Assert.DoesNotThrow(() => result = send.Execute(new ScenarioContext { Player = player })); Assert.AreEqual(4, result.Villages.Count); }
private BaseScenarioResult Login(ScenarioContext context) { if (context.Cookies != null && context.Cookies.Any()) { foreach (var cookie in context.Cookies) { _driver.Manage().Cookies.AddCookie(cookie); } } _driver.Navigate().GoToUrl(new Uri(context.Player.Uri, "/dorf1.php")); if (_driver.Url.Contains("login")) { var login = _driver.FindElement(By.XPath("//input[@name='name']")); var password = _driver.FindElement(By.XPath("//input[@name='password']")); login.SendKeys(context.Player.UserName); password.SendKeys(context.Player.Password); _driver.FindElement(By.Id("s1"))?.Click(); if (_driver.Url.Contains("login")) { var result = new BaseScenarioResult(); result.Errors.Add(new ScenarioError { ErrorMessage = "Unable to login. Try to update the cookies.", ErrorSource = nameof(BaseScenario), ErrorType = "Critical" }); return(result); } } return(null); }
public void TestFarmList() { var farm = new FindFarmTargetsScenario(provider); BaseScenarioResult result = new BaseScenarioResult(); Assert.DoesNotThrow(() => { result = farm.Execute(new ScenarioContext { Player = player }); }); var json = JsonConvert.SerializeObject(new { server = player.Uri.AbsolutePath, farmList = result.Villages }, new JsonSerializerSettings { ContractResolver = new CamelCasePropertyNamesContractResolver() }); var path = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "data\\farm.json"); using (var writer = File.CreateText(path)) { writer.Write(json); } }
private async Task <BaseScenarioResult> RunScenario(IScenario scenario, ScenarioContext context) { BaseScenarioResult result; try { result = await Task.Run(() => this._scenarioExecutor.ExecuteScenario(scenario, context)); result.Success = !result.Errors.Any(); } catch (Exception exc) { result = new BaseScenarioResult(); result.Errors.Add(new ScenarioError { ErrorMessage = $"Unable to execute scenario. Error code: {LoggingEvents.ScenarioException}", ErrorSource = $"{this.GetType().Name}::{MethodBase.GetCurrentMethod().Name}", ErrorType = "Critical" }); this._logger.LogError(LoggingEvents.ScenarioException, exc, exc.Message); } return(result); }
protected override BaseScenarioResult ExecuteVillageActions(ScenarioContext context) { var result = new BaseScenarioResult(); var village = GetVillageInfoScenario.UpdateInfo(_driver, _action.Village); village = CommonScenario.UpdateResources(_driver, context, _action.Village); result.Villages.Add(village); return(result); }
public Task <BaseScenarioResult> RunUpdateUserInfo(TravianUser user) { var player = _mapper.Map <Player>(user); var result = new BaseScenarioResult { Player = player }; return(Task.FromResult(result)); }
public Task <BaseScenarioResult> ExecuteActions <T>(TravianUser user, IEnumerable <T> actions) where T : GameAction { var player = _mapper.Map <Player>(user); var result = new BaseScenarioResult { Player = player }; return(Task.FromResult(result)); }
public async Task TestWatchScenario() { var factory = new ScenarioFactory(provider); var executor = new ScenarioExecutor(); var api = new GameplayApi(executor, factory, logger.Object); BaseScenarioResult result = await api.Watch(player); Assert.IsTrue(result.IsUserUnderAttack); Assert.IsTrue(result.Success); }
public async Task TestCheckReportsScenario() { var factory = new ScenarioFactory(provider); var executor = new ScenarioExecutor(); var api = new GameplayApi(executor, factory, logger.Object); BaseScenarioResult result = await api.Watch(player); Assert.IsTrue(result.IsUserUnderAttack); Assert.IsTrue(result.Success); Assert.AreEqual("No scan events found", result.Messages.FirstOrDefault()); }
public async Task TestIncomingAttackScenario() { var factory = new ScenarioFactory(provider); var executor = new ScenarioExecutor(); var api = new GameplayApi(executor, factory, logger.Object); BaseScenarioResult result = await api.Scan(player, false); Assert.IsTrue(result.IsUserUnderAttack); Assert.IsTrue(result.Villages.Count > 0); Assert.IsNotNull(result.Villages.FirstOrDefault()); Assert.IsTrue(result.Villages.FirstOrDefault().IsUnderAttack); Assert.IsTrue(result.Villages.FirstOrDefault().Attacks.Any()); }
protected sealed override BaseScenarioResult ExecuteScenario(ScenarioContext context) { var result = new BaseScenarioResult(); var villagesList = this._driver.FindElements(By.CssSelector("#sidebarBoxVillagelist .content ul li a")); Dictionary <string, Village> villagesLinks = new Dictionary <string, Village>(); foreach (var v in villagesList) { var name = v.FindElement(By.CssSelector("span.name")).Text; var village = new Village { Name = name, PlayerName = context.Player.UserName }; var xText = v.FindElement(By.ClassName("coordinateX")).Text; var yText = v.FindElement(By.ClassName("coordinateY")).Text; var successX = int.TryParse(Decode(xText), out int x); var successY = int.TryParse(Decode(yText), out int y); if (successX && successY) { village.CoordinateX = x; village.CoordinateY = y; } else { result.Errors.Add(new ScenarioError { ErrorSource = nameof(CommonScenario), ErrorMessage = $"Unable to parse coordinates for village {name}. Input values: x = [{xText}], y = [{yText}]", ErrorType = "UpdateInfo" }); } villagesLinks.Add(v.GetAttribute("href"), village); } foreach (var link in villagesLinks) { this._driver.Navigate().GoToUrl(link.Key); var villageResult = this.ExecuteInVillage(context, link.Value); villageResult = UpdateResources(_driver, context, villageResult); result.Villages.Add(villageResult); } result.IsUserUnderAttack = result.Villages.Any(x => x.IsUnderAttack || x.Attacks.Any()); return(result); }
protected override BaseScenarioResult ExecuteScenario(ScenarioContext context) { var result = new BaseScenarioResult(); var newReports = this._driver.FindElements(By.CssSelector("#n5.reports div.speechBubbleContainer")); if (newReports.Any()) { this._driver.Navigate().GoToUrl(new Uri(context.Player.Uri, "/berichte.php?t=3&opt=AAATABIA")); var reportsForm = this._driver.FindElement(By.Id("reportsForm")); var anchors = reportsForm.FindElements(By.CssSelector("table tbody tr td.sub.newMessage div a")); var links = new List <string>(); foreach (var anchor in anchors) { links.Add(anchor.GetAttribute("href")); } foreach (var link in links) { this._driver.Navigate().GoToUrl(link); var villageElem = this._driver.FindElement(By.CssSelector("#reportWrapper div.role.attacker div.troopHeadline a.village")); var userVillageElem = this._driver.FindElement(By.CssSelector("#reportWrapper div.role.defender div.troopHeadline a.village")); var timeElem = this._driver.FindElement(By.CssSelector("#reportWrapper div.time div.text")); var villageName = userVillageElem.Text; var villageUrl = villageElem.GetAttribute("href"); var scan = new Incoming { VillageName = villageName, DateTime = timeElem.Text.ToDateTimeOffset(), IntruderVillageUrl = villageUrl }; result.Scans.Add(scan); } foreach (var scan in result.Scans) { scan.IntruderDetails = ParseVillageDetailsFromUrl(scan.IntruderVillageUrl); } } if (!result.Scans.Any()) { result.Messages.Add("No scan events found"); } return(result); }
public void TestParseMessageScenario() { const string messageUrl = "https://ts2.travian.ru/messages.php?t=0&order=DESC&page=1&id=303073"; var parse = new ParseSpamTargetsScenario(provider); BaseScenarioResult result = new BaseScenarioResult(); Assert.DoesNotThrow(() => { result = parse.Execute(new ScenarioContext { Player = player, StartUrl = messageUrl }); }); Assert.NotNull(result.Villages); Assert.AreEqual(3, result.Villages.Count); Assert.AreEqual(-46, result.Villages.First().CoordinateX); Assert.AreEqual(33, result.Villages.First().CoordinateY); }
protected override BaseScenarioResult ExecuteVillageActions(ScenarioContext context) { var result = new BaseScenarioResult(); this._driver.Navigate().GoToUrl(new Uri(context.Player.Uri + "/dorf2.php")); // open market (g17) this._driver.FindElement(By.CssSelector("#village_map .g17 .level")).Click(); var send = this._driver.Url + "&t=5"; this._driver.Navigate().GoToUrl(send); int tradersAvailable = int.Parse(Decode(this._driver.FindElement(By.CssSelector(".merchantsAvailable")).Text)); int maxCarryingCapacity = int.Parse(this._driver.FindElement(By.Id("addRessourcesLink1")).Text); //int toSend = tradersAvailable * maxCarryingCapacity / 4; //var inputs = this._driver.FindElements(By.CssSelector("#send_select .val input")); //// TODO: distinguish the input fields and send resources from action property //foreach (var input in inputs) //{ // input.SendKeys(toSend.ToString()); //} _driver.FindElement(By.Id("r1")).SendKeys(_action.Resources.Lumber.ToString()); _driver.FindElement(By.Id("r2")).SendKeys(_action.Resources.Clay.ToString()); _driver.FindElement(By.Id("r3")).SendKeys(_action.Resources.Iron.ToString()); _driver.FindElement(By.Id("r4")).SendKeys(_action.Resources.Crop.ToString()); this._driver.FindElement(By.Id("xCoordInput")).SendKeys(_action.To.CoordinateX.ToString()); this._driver.FindElement(By.Id("yCoordInput")).SendKeys(_action.To.CoordinateY.ToString()); // prepare this._driver.FindElement(By.Id("enabledButton")).Click(); // TODO: add error if can't send // send this._driver.FindElement(By.Id("enabledButton")).Click(); result.Messages.Add($"Resources were sent from {_action.Village.Name} to {_action.To.Name}"); return(result); }
public void UpdateVillageDataTest() { var village = new Village { Name = "Unexpected_Town_15" }; var scenario = new GetVillageInfoScenario(provider); BaseScenarioResult result = new BaseScenarioResult(); Assert.DoesNotThrow(() => { result = scenario.Execute(new ScenarioContext { Player = player, Actions = new List <BuildAction>() }); }); Assert.NotNull(result.Villages); }
public BaseScenarioResult Execute(ScenarioContext context) { var result = new BaseScenarioResult(); _driver.Navigate().GoToUrl(new Uri(context.Player.Uri, "/dorf1.php")); _driver.Manage().Window.Maximize(); if (_driver.Url.Contains("login")) { var loginResult = Login(context); if (loginResult != null) { return(loginResult); } } else { var playerNameElem = _driver.FindElement(By.ClassName("playerName")); var a = playerNameElem.FindElements(By.XPath($"//a[contains(text(), '{context.Player.UserName}')]")); if (a == null || !a.Any()) { var loginResult = Login(context); if (loginResult != null) { return(loginResult); } } } var dismissCookieNoticeElems = _driver.FindElements(By.Id("dismissCookieNotice")); if (dismissCookieNoticeElems.Any()) { dismissCookieNoticeElems.First().Click(); } result = Proceed(context); result.Success = result.Errors.Count == 0; result.Cookies = _driver.Manage().Cookies.AllCookies.ToList(); return(result); }
protected override BaseScenarioResult ExecuteScenario(ScenarioContext context) { _driver.Navigate().GoToUrl(context.StartUrl); //var header = _driver.FindElement(By.CssSelector(".header.text")).Text.ToLower(); //if (header.Contains("spam") || header.Contains("спам")) //{ //} var targets = _driver.FindElements(By.CssSelector("#message a.bbCoordsLink")).Select(x => x.GetAttribute("href")).ToList(); var result = new BaseScenarioResult(); foreach (var target in targets) { var village = ParseVillageDetailsFromUrl(target); result.Villages.Add(village); } return(result); }
protected override BaseScenarioResult ExecuteScenario(ScenarioContext context) { var result = new BaseScenarioResult(); this._driver.FindElement(By.CssSelector("#n3 a")).Click(); var mapContainer = this._driver.FindElement(By.Id("mapContainer")); var action = new Actions(this._driver); int w = mapContainer.Size.Width / 9; int h = mapContainer.Size.Height / 7; int i = 0; int j = 1; action.MoveToElement(mapContainer) .MoveByOffset(-5 * w + w / 2, -4 * h + h / 2) .MoveByOffset(i * w + w / 2, j * h + h / 2) .Click() .Build() .Perform(); return(result); }
protected override BaseScenarioResult ExecuteVillageActions(ScenarioContext context) { this._driver.Navigate().GoToUrl(new Uri(context.Player.Uri, "/dorf2.php")); this._driver.FindElement(By.CssSelector("#village_map .g19 .level")).Click(); var result = new BaseScenarioResult(); foreach (var unit in this._action.UnitsToTrain) { var unitWrappers = this._driver.FindElements(By.XPath("//div[contains(@class, 'innerTroopWrapper') and .//a[text() = \'" + unit.Key + "\']]")); if (unitWrappers != null && unitWrappers.Any()) { if (unit.Value == (int)TrainArmyFlag.MAX) { var a = unitWrappers[0].FindElement(By.CssSelector("div.cta > a")); a.Click(); } else if (unit.Value > 0) { var input = unitWrappers[0].FindElement(By.CssSelector("input.text")); input.SendKeys(unit.Value.ToString()); } this._driver.FindElement(By.Id("s1")).Click(); result.Messages.Add($"Started to train {unit.Value} units of {unit.Key}"); } else { result.Errors.Add(new ScenarioError { ErrorMessage = $"Unable to find unit {unit.Key}", ErrorSource = nameof(TrainArmyScenario), ErrorType = "NotFound" }); } } return(result); }
protected sealed override BaseScenarioResult ExecuteScenario(ScenarioContext context) { var result = new BaseScenarioResult(); if (_action == null) { result.Errors.Add(new ScenarioError { ErrorMessage = "No actions found in scenario context.", ErrorSource = nameof(VillageScenario <T>) }); return(result); } var found = false; var villagesList = _driver.FindElements(By.CssSelector("#sidebarBoxVillagelist .content ul li a")); foreach (var v in villagesList) { var name = v.FindElement(By.CssSelector("span.name")).Text; if (this._action.Village.Name == name) { found = true; v.Click(); break; } } if (!found) { result.Errors.Add(new ScenarioError { ErrorMessage = $"Unable to find village {this._action.Village.Name}.", ErrorSource = nameof(VillageScenario <T>) }); return(result); } return(this.ExecuteVillageActions(context)); }
protected override BaseScenarioResult ExecuteScenario(ScenarioContext context) { // open statistics _driver.FindElement(By.Id("n4")).Click(); // go to last page _driver.FindElement(By.CssSelector("a.last")).Click(); var result = new BaseScenarioResult(); var maxPopulation = int.MaxValue; var targets = new List <string>(); while (targets.Count < Targets || maxPopulation > MaxPopulation) { var rows = GetRows(_driver.FindElement(By.CssSelector("table#player"))).OrderByDescending(x => x.rank) .Where(x => x.population >= MinPopulation && x.population <= MaxPopulation && string.IsNullOrWhiteSpace(x.alliance) && x.villages <= MaxVillages); if (rows.Any()) { maxPopulation = rows.Max(x => x.population); targets.AddRange(rows.Select(x => x.url)); } _driver.FindElement(By.CssSelector("a.previous")).Click(); } foreach (var target in targets) { _driver.Navigate().GoToUrl(target); var playerName = _driver.FindElement(By.CssSelector("#content h1.titleInHeader")).Text; var villagesList = _driver.FindElements(By.CssSelector("#villages tbody tr")); foreach (var v in villagesList) { var name = v.FindElement(By.CssSelector(".name a")).Text; var capital = v.FindElements(By.CssSelector(".name span")); var xText = v.FindElement(By.ClassName("coordinateX")).Text; var yText = v.FindElement(By.ClassName("coordinateY")).Text; var successX = int.TryParse(Decode(xText), out int x); var successY = int.TryParse(Decode(yText), out int y); var village = new Village { Name = name, PlayerName = playerName, IsCapital = capital.Count > 0 }; if (successX && successY) { village.CoordinateX = x; village.CoordinateY = y; } else { result.Errors.Add(new ScenarioError { ErrorSource = nameof(CommonScenario), ErrorMessage = $"Unable to parse coordinates for village {name}. Input values: x = [{xText}], y = [{yText}]", ErrorType = "UpdateInfo" }); } result.Villages.Add(village); } } return(result); }
protected override BaseScenarioResult ExecuteVillageActions(ScenarioContext context) { var result = new BaseScenarioResult(); var windows = new List <string>(); var uri = new Uri(context.Player.Uri + "/build.php?tt=2&id=39"); for (int i = 0; i < _action.Waves; i++) { if (i > 0) { OpenNewTab(uri.AbsoluteUri); WaitUntilElementExists(By.Id("xCoordInput")); } else { _driver.Navigate().GoToUrl(uri); } // go to army center tab 2 (send army) _driver.FindElement(By.Id("xCoordInput")).SendKeys(_action.To.CoordinateX.ToString()); _driver.FindElement(By.Id("yCoordInput")).SendKeys(_action.To.CoordinateY.ToString()); var options = _driver.FindElements(By.CssSelector("form div.option label")); if (options.Count != 3) { result.Errors.Add(new ScenarioError { ErrorMessage = "Can't find options to send army", ErrorSource = nameof(SendArmyScenario) }); } else { switch (_action.Type) { case SendArmyType.BACKUP: options[0].Click(); break; case SendArmyType.ATTACK: options[1].Click(); break; case SendArmyType.RAID: options[2].Click(); break; default: throw new Exception("Unknown send army type"); } } var table = _driver.FindElement(By.Id("troops")); foreach (var units in _action.UnitsToSend) { var tds = table.FindElements(By.XPath($"//td[img[@alt='{units.Key}']]")); if (tds.Any()) { var td = tds.First(); var a = td.FindElements(By.TagName("a")); if (!a.Any()) { continue; } if (units.Value == -1) { td.FindElement(By.TagName("a")).Click(); } else { td.FindElement(By.TagName("input")).SendKeys(units.Value.ToString()); } } } _driver.FindElement(By.Id("btn_ok")).Click(); } foreach (var w in _driver.WindowHandles) { _driver.SwitchTo().Window(w); _driver.FindElement(By.Id("btn_ok")).Click(); result.Villages.Add(_action.To); } return(result); }
private AbstractJob PrepareOneVillageTest(BaseScenarioResult buildScenarioResult, BaseScenarioResult infoScenarioResult) { var testVillage = PrepareTestOneVillage(isBuildingFeatureOn: true); var resultVillage = _serviceProviderBuilder.Mapper.Map <Village>(testVillage); var finishTime = TimeSpan.FromMinutes(30); resultVillage.Dorf1BuildTimeLeft = finishTime; resultVillage.CanBuild = true; resultVillage.Resources = new Resources { Lumber = 100, Clay = 100, Iron = 100, Crop = 100 }; resultVillage.Warehourse = 800; resultVillage.Granary = 800; var infoResult = Builder <BaseScenarioResult> .CreateNew() .With(x => x.Success = true) .With(x => x.Villages = new List <Village> { resultVillage }) .Build(); var actionProviderMock = new Mock <IActionProvider>(); actionProviderMock.Setup(x => x.GetBuildActions(resultVillage, It.IsAny <IEnumerable <BuildingModel> >())) .Returns(Task.FromResult((true, (IEnumerable <BuildAction>) new List <BuildAction> { new BuildAction { Village = resultVillage, BuildingId = "test", BuildingSlot = "test", Level = 1 } }))); _serviceProviderBuilder.WithService(actionProviderMock.Object); var buildActionResult = Builder <BaseScenarioResult> .CreateNew() .With(x => x.Success = true) .With(x => x.Villages = new List <Village> { Builder <Village> .CreateNew() .With(y => y.CanBuild = false) .With(y => y.Dorf1BuildTimeLeft = TimeSpan.FromMinutes(5)) .Build() }) .Build(); var gamePlayMock = new Mock <IGameplayClient>(); gamePlayMock.Setup(x => x.ExecuteActions(It.IsAny <TravianUser>(), It.IsAny <IEnumerable <GameAction> >())) .Returns(Task.FromResult(infoResult)); gamePlayMock.Setup(x => x.ExecuteActions(It.IsAny <TravianUser>(), It.IsAny <IEnumerable <BuildAction> >())) .Returns(Task.FromResult(buildActionResult)); _serviceProviderBuilder.WithService(gamePlayMock.Object); var cmd = new FakeCommand(); var cmdMock = new Mock <ICommandFactory>(); cmdMock.Setup(x => x.GetQueueableCommand(nameof(BuildCommand), It.IsAny <long>())) .Returns(cmd); _serviceProviderBuilder.WithService(cmdMock.Object); var job = new BuildingPlanExecutionJob(_serviceProviderBuilder.Build()); var data = new JobExecutionData { TravianUser = FakeDataProvider.GetUser(PlayerStatus.ALL_QUIET, true), JobType = typeof(BuildingPlanExecutionJob) }; return(job); }
protected override BaseScenarioResult ExecuteScenario(ScenarioContext context) { var result = new BaseScenarioResult(); this._driver.Navigate().GoToUrl(new Uri(context.Player.Uri, "/spieler.php")); var villagesList = _driver.FindElements(By.CssSelector("#villages tbody tr")); var details = new List <Village>(); foreach (var v in villagesList) { var name = v.FindElement(By.CssSelector(".name a")).Text; var capital = v.FindElements(By.CssSelector(".name span")); var xText = v.FindElement(By.ClassName("coordinateX")).Text; var yText = v.FindElement(By.ClassName("coordinateY")).Text; var successX = int.TryParse(Decode(xText), out int x); var successY = int.TryParse(Decode(yText), out int y); var village = new Village { Name = name, PlayerName = context.Player.UserName, IsCapital = capital.Count > 0 }; if (successX && successY) { village.CoordinateX = x; village.CoordinateY = y; } else { result.Errors.Add(new ScenarioError { ErrorSource = nameof(CommonScenario), ErrorMessage = $"Unable to parse coordinates for village {name}. Input values: x = [{xText}], y = [{yText}]", ErrorType = "UpdateInfo" }); } details.Add(village); } result.Villages = details; this._driver.Navigate().GoToUrl(new Uri(context.Player.Uri, "/dorf2.php")); var player = context.Player; var buildings = this._driver.FindElements(By.CssSelector(".buildingSlot")); if (buildings != null && buildings.Any()) { var building = buildings[0]; var classes = building.GetAttribute("class").Split(" "); var folk = classes[classes.Length - 1]; folk = folk.ToUpperInvariant(); if (Enum.TryParse(folk, out Tribe tribe)) { player.Tribe = tribe; } else { result.Errors.Add(new ScenarioError { ErrorMessage = $"Unable to parse the Tribe: {folk}", ErrorSource = nameof(UpdateUserInfoScenario) }); } } else { result.Errors.Add(new ScenarioError { ErrorMessage = "Unable to find any building to update the Tribe", ErrorSource = nameof(UpdateUserInfoScenario) }); } this._driver.Navigate().GoToUrl(new Uri(context.Player.Uri, "/options.php")); var timeZoneId = this._driver.FindElement(By.XPath("//select[@name='timezone']//option[@selected='selected']"))?.Text; if (string.IsNullOrEmpty(timeZoneId)) { result.Errors.Add(new ScenarioError { ErrorMessage = "Unable to find time zone id", ErrorSource = nameof(UpdateUserInfoScenario) }); } else { player.TimeZone = timeZoneId; } var allianceElems = _driver.FindElements(By.XPath("//a[contains(@href, 'allianz.php')]")); if (allianceElems.Any()) { player.Alliance = allianceElems.First().Text; } result.Player = player; return(result); }
private bool TryBuildNewBuilding(ref BaseScenarioResult result) { var slotQuery = string.IsNullOrWhiteSpace(_action.BuildingSlot) ? string.Empty : $" and contains(@class, '{_action.BuildingSlot}')"; var wrapper = _driver.FindElements(By.XPath($"//div[@id='village_map']/div[contains(@class, 'g0') {slotQuery}]"))?.FirstOrDefault(); IWebElement contract = null; if (wrapper == null) { result.Errors.Add(new ScenarioError { ErrorMessage = $"Unable to find building building id: {_action.BuildingId}, slot: {_action.BuildingSlot}", ErrorSource = nameof(BuildScenario) }); return(false); } var field = wrapper.FindElements(By.CssSelector("svg g.clickShape path"))?.FirstOrDefault(); if (field == null) { result.Errors.Add(new ScenarioError { ErrorMessage = $"Unable to find building building id: {_action.BuildingId}, slot: {_action.BuildingSlot}", ErrorSource = nameof(BuildScenario) }); return(false); } var script = field.GetAttribute("onclick"); _driver.ExecuteJavaScript <object>(script); //field.Click(); var id = _action.BuildingId.Replace("g", string.Empty); var container = WaitUntilElementExists(_driver, By.CssSelector("div.contentNavi.subNavi.tabWrapper .scrollingContainer"), 5); var nav = container.FindElements(By.CssSelector("div.content a")); if (nav == null || nav.Count != 3) { result.Errors.Add(new ScenarioError { ErrorMessage = $"Unable build new building with id: {_action.BuildingId}, slot: {_action.BuildingSlot}. Unable to locate navigation on new buildings page.", ErrorSource = nameof(BuildScenario) }); return(false); } var links = nav.Select(x => x.GetAttribute("href")).ToList(); for (int i = 0; i < links.Count && contract == null; i++) { _driver.Navigate().GoToUrl(links[i]); contract = _driver.FindElements(By.Id($"contract_building{id}"))?.FirstOrDefault(); } if (contract == null) { result.Errors.Add(new ScenarioError { ErrorMessage = $"Unable build new building with id: {_action.BuildingId}, slot: {_action.BuildingSlot}. Unable to locate navigation on new buildings page.", ErrorSource = nameof(BuildScenario) }); return(false); } var btn = contract.FindElements(By.CssSelector("div.contractLink button.green"))?.FirstOrDefault(); if (btn == null) { var errors = contract.FindElements(By.CssSelector("span.buildingCondition.error")); var errorsResult = new List <ScenarioError>(); foreach (var error in errors) { var condition = $"{error.FindElement(By.TagName("a")).Text} {error.FindElement(By.TagName("span")).Text}"; errorsResult.Add(new ScenarioError { ErrorMessage = $"Unable build new building with id: {_action.BuildingId}, slot: {_action.BuildingSlot}. Conditions not met: {condition}", ErrorSource = nameof(BuildScenario) }); } result.Errors.AddRange(errorsResult); return(false); } btn.Click(); return(true); }
private async Task WasUnderAttackScenario(BaseScenarioResult result) { if (result.Errors.Any()) { await _bot.SendTextMessageAsync( _botUser.ChatId, string.Join(", ", result.Errors)); return; } var currentVillagesData = await _villageRepository.GetVillages(_travianUser.UserName); var update = result.Villages.Select(x => _mapper.Map <VillageModel>(x)); var attacks = result.Villages .Where(x => x.Attacks != null) .SelectMany(x => x.Attacks) .Select(x => _mapper.Map <AttackModel>(x)) .OrderBy(x => x.DateTime) .ToList(); if (attacks != null && attacks.Any()) { var resultVillages = result.Villages.Select(x => _mapper.Map <VillageModel>(x)); var newAttacks = GetNewAttacks(resultVillages, currentVillagesData).ToList(); if (newAttacks.Any()) { await _bot.SendTextMessageAsync( _botUser.ChatId, $"New incoming attacks discovered for player [{_travianUser.UserName}]"); try { foreach (var newAttack in newAttacks) { var msg = ArmyEventReportBuilder .ForVillage(newAttack.VillageName, _travianUser.PlayerData.TimeZone) .WithNotification(newAttack) .ReportText; await _bot.SendTextMessageAsync( _botUser.ChatId, msg); } await _villageRepository.UpdateWatchInfo(update); foreach (var newAttack in newAttacks) { var cmd = _commandFactory.GetQueueableCommand(nameof(PrepareToAttackCommand), _botUser.ChatId); var attackDt = newAttack.DateTime; var diff = TimeSpan.FromMinutes(5); cmd.Start = attackDt - DateTimeOffset.UtcNow > diff ? attackDt - diff : DateTimeOffset.UtcNow; await cmd.Execute(); } } catch (Exception exc) { await _bot.SendTextMessageAsync( _botUser.ChatId, $"Unable to find or update army events for travian user [{_travianUser.UserName}]. Error code: [{LoggingEvents.DbOpertationException}]"); _logger.LogError(LoggingEvents.DbOpertationException, exc, $"BotUserName:[{_botUser.UserName}], TravianUserName:[{_travianUser.UserName}], error: {exc.Message}"); } } else { await _villageRepository.UpdateWatchInfo(update); } } else { await _villageRepository.UpdateWatchInfo(update); _travianUser.PlayerData.Status = PlayerStatus.ALL_QUIET; } }
private async Task <bool> WasQuietScenario(BaseScenarioResult result) { if (result.IsUserUnderAttack) { try { var scans = result.Scans; if (scans.Any()) { foreach (var scan in scans) { var scanReport = ScanReportBuilder .Create(_travianUser.UserName, _travianUser.PlayerData.TimeZone) .WithNotification(scan) .ReportText; await _bot.SendTextMessageAsync( _botUser.ChatId, scanReport); } _travianUser.PlayerData.Status = PlayerStatus.WAS_SCANNED; } else { _travianUser.PlayerData.Status = PlayerStatus.ALL_QUIET; } if (result.IsUserUnderAttack) { var attacks = result.Villages .SelectMany(x => x.Attacks) .OrderBy(x => x.DateTime) .ToList(); foreach (var attack in attacks) { var report = IncomingAttackReportBuilder.Create(_travianUser.UserName, _travianUser.PlayerData.TimeZone); report = report.WithNotification(attack); await _bot.SendTextMessageAsync( _botUser.ChatId, report.ReportText); } _travianUser.PlayerData.Status = PlayerStatus.UNDER_ATTACK; } } catch (Exception exc) { await _bot.SendTextMessageAsync( _botUser.ChatId, $"Unable to find any notification for travian user [{_travianUser.UserName}]. Error code: [{12}]"); _logger.LogError(12, $"BotUserName:[{_botUser.UserName}], TravianUserName:[{_travianUser.UserName}] " + $"{exc.Message}: \r\n {exc.StackTrace}"); } } if (!result.Success) { await _bot.SendTextMessageAsync( _botUser.ChatId, string.Join(", ", result.Errors)); } return(result.IsUserUnderAttack); }
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}"); } }
protected override BaseScenarioResult ExecuteVillageActions(ScenarioContext context) { var result = new BaseScenarioResult(); if (_action.To.Name == "send_to_any_natar") { this._driver.Navigate().GoToUrl(new Uri(context.Player.Uri + "/build.php?tt=99&id=39")); var natarRows = _driver.FindElements(By.XPath($"//tr[./td[@class='village' and ./a[text()[contains(., 'Натары')]]]]")).ToList(); var min = natarRows.OrderBy(x => double.Parse(x.FindElement(By.ClassName("distance")).Text)).FirstOrDefault(); var natars = min.FindElements(By.TagName("a")); // "//tr[//a[contains(text(), 'Натары')]]" if (natars.Any()) { natars.First().Click(); this._driver.FindElement(By.XPath("//a[contains(text(), 'Отправить войска')]")).Click(); } } else { // go to army center tab 2 (send army) this._driver.Navigate().GoToUrl(new Uri(context.Player.Uri + "/build.php?tt=2&id=39")); _driver.FindElement(By.Id("xCoordInput")).SendKeys(_action.To.CoordinateX.ToString()); _driver.FindElement(By.Id("yCoordInput")).SendKeys(_action.To.CoordinateY.ToString()); } var options = _driver.FindElements(By.CssSelector("form div.option label")); if (options.Count != 3) { result.Errors.Add(new ScenarioError { ErrorMessage = "Can't find options to send army", ErrorSource = nameof(SendArmyScenario) }); } else { switch (_action.Type) { case SendArmyType.BACKUP: options[0].Click(); break; case SendArmyType.ATTACK: options[1].Click(); break; case SendArmyType.RAID: options[2].Click(); break; default: throw new Exception("Unknown send army type"); } } if (_action.SendAll) { var links = _driver.FindElements(By.CssSelector("table#troops td a")); foreach (var l in links) { l.Click(); } } else { var table = _driver.FindElement(By.Id("troops")); foreach (var units in _action.UnitsToSend) { var tds = table.FindElements(By.XPath($"//td[img[@alt='{units.Key}']]")); if (tds.Any()) { var td = tds.First(); var a = td.FindElements(By.TagName("a")); if (!a.Any()) { continue; } if (units.Value == -1) { td.FindElement(By.TagName("a")).Click(); } else { td.FindElement(By.TagName("input")).SendKeys(units.Value.ToString()); } } } } // send _driver.FindElement(By.Id("btn_ok")).Click(); // if no troops choosen var errors = _driver.FindElements(By.ClassName("error")); if (errors.Any()) { result.Errors.Add(new ScenarioError { ErrorMessage = "no troops choosen", ErrorSource = nameof(SendArmyScenario) }); } else { // confirm _driver.FindElement(By.Id("btn_ok")).Click(); result.Villages.Add(_action.To); } return(result); }
protected override BaseScenarioResult ExecuteVillageActions(ScenarioContext context) { var result = new BaseScenarioResult(); _driver.FindElement(By.CssSelector("#navigation > .village.resourceView")).Click(); var field = _driver.FindElements(By.XPath($"//div[@id='resourceFieldContainer']/div[contains(@class, '{_action.BuildingId}') and contains(@class, '{_action.BuildingSlot}')]"))?.FirstOrDefault(); if (field == null) { _driver.FindElement(By.CssSelector("#navigation > .village.buildingView")).Click(); field = _driver.FindElements(By.XPath($"//div[@id='village_map']/div[contains(@class, '{_action.BuildingId}') and contains(@class, '{_action.BuildingSlot}')]/div"))?.FirstOrDefault(); if (field == null) { if (TryBuildNewBuilding(ref result)) { return(result); } else { result.Errors.Add(new ScenarioError { ErrorMessage = $"Unable to build new building.Building Id: {_action.BuildingId}, building slot: {_action.BuildingSlot}", ErrorType = "NEW_BUILDING_FAILED" }); return(result); } } } var css = field.GetAttribute("class"); if (css.Contains("good", StringComparison.OrdinalIgnoreCase)) { field.Click(); var btn = _driver.FindElements(By.CssSelector("div.upgradeButtonsContainer .section1 button.green")); if (btn.Any()) { btn.First().Click(); } } else if (css.Contains("notNow", StringComparison.OrdinalIgnoreCase)) { field.Click(); var contract = _driver.FindElements(By.Id("contract"))?.FirstOrDefault(); if (contract == null) { result.Errors.Add(new ScenarioError { ErrorMessage = $"Unable build new building with id: {_action.BuildingId}, slot: {_action.BuildingSlot}. Unable to locate contract.", ErrorSource = nameof(BuildScenario) }); return(result); } var blocked = _driver.FindElements(By.CssSelector("div.upgradeBlocked"))?.FirstOrDefault(); var blockCause = BuildErrorType.NoSpaceInQueue; if (blocked != null) { if (blocked?.FindElements(By.CssSelector("div.errorMessage"))?.Any() ?? false) { blockCause = BuildErrorType.NotEnoughResources; } } else { field.Click(); var btn = _driver.FindElements(By.CssSelector("div.upgradeButtonsContainer.section2Enabled .section1 button.green")); if (btn.Any()) { btn.First().Click(); return(result); } } var error = new BuildScenarioError { BuildErrorType = blockCause, Village = _action.Village }; if (blockCause == BuildErrorType.NotEnoughResources) { var resources = GetResourcesOnWarehouse(_driver); var contracts = _driver.FindElements(By.CssSelector("#contract div.resource span.value")).Select(x => int.Parse(x.Text.RemoveNonAsciiCharacters())).ToList(); if (contracts.Count != 5) { result.Errors.Add(new ScenarioError { ErrorMessage = $"Unable to find resources from contract for building building id: {_action.BuildingId}, slot: {_action.BuildingSlot}", ErrorSource = nameof(BuildScenario) }); } var diff = new Resources { Lumber = resources.Lumber - contracts[0], Clay = resources.Clay - contracts[1], Iron = resources.Iron - contracts[2], Crop = resources.Crop - contracts[3] }; error.ResourcesNeeded = diff; } result.Errors.Add(error); //if (errType != BuildErrorType.NotEnoughCropProduction) //{ // _driver.FindElement(By.Id("closeContentButton")).Click(); //} } else { var errType = css.Contains("underConstruction", StringComparison.OrdinalIgnoreCase) ? BuildErrorType.BuildingIsUnderConstruction : BuildErrorType.NotEnoughCropProduction; result.Errors.Add(new BuildScenarioError { BuildErrorType = errType, Village = _action.Village }); } var update = GetVillageInfoScenario.UpdateInfo(_driver, _action.Village); result.Villages.Add(update); return(result); }