public BotStepReport Step( Int64 time, BrowserService browserService) { lock (Lock) { var report = new BotStepReport(); var timeCal = report.StartTimeCal = DateTime.Now; var breakDurationRemaining = BreakEndTimeCal - DateTime.Now; try { if (0 < breakDurationRemaining?.TotalSeconds) { return(report); } report.BreakActiveNot = true; var browser = browserService?.BrowserProcessCreatedLast?.Invoke()?.BrowserConnection; var browserDocument = browser?.Document?.Result; report.browserDocumentAvailable = null != browserDocument; if (null == browserDocument) { throw new ArgumentNullException("browserDocument"); } { // GetElementFromXPath(Dom.VillageDropDownControllerXPath) failed for some users without reason being discovered yet. // Test whether GetElementFromXPath yields any element at all. var anyElementFromGetElementFromXPath = browserDocument?.GetElementFromXPath("//*"); if (null == anyElementFromGetElementFromXPath) { throw new ArgumentNullException("AnyElementFromGetElementFromXPath"); } } report.AnyElementFromGetElementFromXPathSucceeded = true; var villageDropDownControllerElem = browserDocument.GetElementFromXPath(Dom.VillageDropDownControllerXPath)?.Result; if (null == villageDropDownControllerElem) { throw new ArgumentNullException("VillageDropDownControllerElem"); } var villageDropDownInfoEval = villageDropDownControllerElem?.JavascriptCallFunction(Dom.JsGetInfoFromVillageDropDownControllerElement); var villageDropDownInfoEvalError = villageDropDownInfoEval?.Error?.ToString(); if (0 < villageDropDownInfoEvalError?.Length) { throw new Exception("VillageDropDownInfoEvalError: " + villageDropDownInfoEvalError); } var villageDropDownInfoSerial = villageDropDownInfoEval?.Result?.value?.ToString(); if (null == villageDropDownInfoSerial) { throw new ArgumentNullException("VillageDropDownInfoSerial"); } var villageDropDownInfo = villageDropDownInfoSerial?.FromVillageDropDownControllerInfoParse(); report.VillageSelected = villageDropDownInfo?.selectedVillageData; var villageSelectedId = report.VillageSelected?.villageId; if (null == villageSelectedId) { throw new ArgumentNullException("VillageSelectedId"); } var locationHref = browserDocument?.locationHref; if (locationHref.RegexMatchSuccessIgnoreCase(TwStruct.Static.GameEnterUrlIndicatorRegexPattern)) { GameEnterUrlMeasurementLast = new PropertyGenTimespanInt64 <string>(locationHref, time); } var farmEnableSetVillageId = report.FarmEnableSetVillageId = villageDropDownInfo?.villagesParsed?.Values()?.Select(village => village?.data?.villageId)?.WhereNotNullSelectValue() ?.Where(villageId => !(time - UnitCountSufficientNotLastTimeFromVillageId?.TryGetValueNullable(villageId) < 1000 * 60 * 3)) ?.ToArray(); var reportHandlingPlannedFromReportId = new Func <Int64, ReportHandlingPlanned>(reportId => this.ReportHandlingPlannedFromReportId(reportId, farmEnableSetVillageId)); var listReportToOpen = (ReportSummaryFromId.Values?.OrderByDescending(reportSummary => reportSummary?.time_created ?? 0)) ?.Where(reportSummary => reportHandlingPlannedFromReportId(reportSummary.id ?? -1)?.Open ?? false) ?.ToArray(); var measurementOutgoingUnitsLastTime = MeasurementOutgoingUnitsLastFromVillageId.TryGetValueOrDefault(villageSelectedId.Value)?.End; var measurementOutgoingUnitsLastAge = time - measurementOutgoingUnitsLastTime; var measureListReportDue = !(measurementOutgoingUnitsLastTime < MeasurementListReportLastTime); if (!(measurementOutgoingUnitsLastAge < 1000 * 60) && (!(measurementOutgoingUnitsLastAge < 1000 * 60 * 5) || (!(0 < listReportToOpen?.Length) && !measureListReportDue))) { var unitListControllerElem = browserDocument.GetElementFromXPath(Dom.ListUnitControllerXPath)?.Result; var measureListMovement = report.MeasureListMovement = new BotStepMeasureListMovement(); if (null != unitListControllerElem) { var unitListInfoEval = unitListControllerElem.JavascriptCallFunction(Dom.JsGetInfoFromUnitListControllerElement); var unitListInfoEvalSerial = unitListInfoEval?.Result?.value?.ToString(); if (null == unitListInfoEvalSerial) { throw new ArgumentNullException("UnitListInfoEvalSerial"); } var unitListInfo = unitListInfoEvalSerial.DeserializeFromString <UnitListControllerInfo>(); var villageId = unitListInfo?.villageId; if (villageId.HasValue && null != unitListInfo?.outgoingArmies) { MeasurementOutgoingUnitsLastFromVillageId[villageId.Value] = new Bib3.PropertyGenTimespanInt64 <UnitListControllerCommand[]>(unitListInfo?.outgoingArmies, time); } return(report); } var openUnitsElem = browserDocument.GetElementFromXPath(Dom.openUnitsXPath)?.Result; if (null == openUnitsElem) { throw new ArgumentNullException("openUnitsElem"); } openUnitsElem.click(); return(report); } var openListReportElem = browserDocument.GetElementFromXPath(Dom.openListReportXPath)?.Result; if (measureListReportDue) { var measureListReport = report.MeasureListReport = new BotStepMeasureListReportSummary { ListReportCount = 0, }; var listPageAttempt = measureListReport.ListPageAttempt = new List <BotStepMeasureListReportSummaryPageAttempt>(); var listReportControllerElem = browserDocument.GetElementFromXPath(Dom.ListReportControllerXPath)?.Result; if (null != listReportControllerElem) { var paginationSetButtonSetLimit = browserDocument?.GetListElementFromXPath(Dom.ListReportControllerXPath + Dom.PaginationSetLimitButtonXPath)?.Result?.ToArray(); var paginationButtonSetLimit = paginationSetButtonSetLimit?.OrderByDescending(button => button?.innerText?.RegexMatchIfSuccess(@"\d+")?.Value?.TryParseInt() ?? -1)?.FirstOrDefault(); paginationButtonSetLimit?.click(); Thread.Sleep(1444); while (true) { var pageAttemptFailedCount = listPageAttempt.Count(page => !(page.Success ?? false)); if (1 < pageAttemptFailedCount) { break; } var pageAttemptReport = new BotStepMeasureListReportSummaryPageAttempt(); var pageIndex = (listPageAttempt .Where(pageAttempt => pageAttempt?.Success ?? false) .Select(pageAttempt => pageAttempt.PageIndex) .WhereNotDefault() .LastOrDefault() + 1) ?? 0; pageAttemptReport.PageIndex = pageIndex; try { if (0 < pageIndex) { var pageId = pageIndex + 1; var loadPageButton = browserDocument?.GetElementFromXPath(Dom.ListReportControllerXPath + Dom.ReportPageLoadButtonXPathFromPageId(pageId))?.Result; loadPageButton?.click(); Thread.Sleep(1444); } var listReportSummaryEval = listReportControllerElem.JavascriptCallFunction(Dom.JsGetListReportSummaryFromControllerElement); var listReportSummarySerial = listReportSummaryEval?.Result?.value?.ToString(); var listReportSummary = listReportSummarySerial.DeserializeFromString <ReportListReportSummary[]>() ?.OrderBy(reportSummary => reportSummary?.time_created) ?.ToArray(); pageAttemptReport.ReportIdNewCount = pageAttemptReport.ReportIdOverlapCount = 0; foreach (var reportSummary in listReportSummary.EmptyIfNull()) { var reportId = reportSummary.id; if (!(reportId.HasValue && reportSummary.IsGoodEnoughForMemorization())) { continue; } if (ReportSummaryFromId.ContainsKey(reportId.Value)) { ++pageAttemptReport.ReportIdOverlapCount; continue; } ++pageAttemptReport.ReportIdNewCount; ReportSummaryFromId[reportId.Value] = reportSummary; } measureListReport.ListReportCount += pageAttemptReport.ReportIdNewCount; pageAttemptReport.Success = 0 < pageAttemptReport.ReportIdNewCount; } finally { listPageAttempt.Add(pageAttemptReport); if (pageAttemptReport.Success ?? false) { ++pageIndex; } } } MeasurementListReportLastTime = time; return(report); } openListReportElem.click(); return(report); } foreach (var reportSummary in listReportToOpen.EmptyIfNull()) { var reportId = reportSummary.id; var reportHandlingPlanned = reportHandlingPlannedFromReportId(reportId ?? -1); var openReportReport = report.OpenReport = new BotStepOpenReport { ReportSummary = reportSummary, ReportHandlingPlanned = reportHandlingPlanned, }; var listReportControllerElem = browserDocument.GetElementFromXPath(Dom.ListReportControllerXPath)?.Result; if (null == listReportControllerElem) { openReportReport.OpenListReport = true; openListReportElem?.click(); Thread.Sleep(1111); listReportControllerElem = browserDocument.GetElementFromXPath(Dom.ListReportControllerXPath)?.Result; } if (null == listReportControllerElem) { throw new ArgumentNullException("ListReportControllerElem"); } listReportControllerElem.JavascriptCallFunction(reportId.Value.JsFunctionShowReportWithIdOnReportsController()); Thread.Sleep(1111); var reportControllerElem = browserDocument.GetElementFromXPath(Dom.ReportControllerXPath)?.Result; var reportDetailEval = reportControllerElem.JavascriptCallFunction(Dom.JsGetReportDetailFromControllerElement); var reportDetailSerial = reportDetailEval?.Result?.value?.ToString(); var reportDetail = reportDetailSerial.DeserializeFromString <ReportControllerReport>(); ReportDetailFromId[reportId.Value] = new PropertyGenTimespanInt64 <ReportControllerReport>(reportDetail, time); openReportReport.ReportHandlingPlanned = reportHandlingPlanned = reportHandlingPlannedFromReportId(reportId.Value); var reportAttUnits = reportDetail?.ReportAttack?.attUnits?.SubsetPropertyInt()?.ToArray(); if (!(0 < reportAttUnits?.Values()?.Sum())) { return(report); } var targetVillageId = reportHandlingPlanned?.TargetVillageId; if (!(reportHandlingPlanned?.AttackAgain ?? false) || !targetVillageId.HasValue) { return(report); } var attackAgainReport = openReportReport.AttackAgain = new BotStepAttack(); var attVillageId = reportDetail?.ReportAttack?.attVillageId; if (!(report.VillageSelected?.villageId == attVillageId)) { attackAgainReport.VillageSwitchTo = attVillageId; villageDropDownControllerElem.JavascriptCallFunction(Dom.JsFunctionVillageSelectOnVillageDropDownController(attVillageId.Value)); return(report); } reportControllerElem.JavascriptCallFunction(Dom.JsAttackAgainFromReportControllerElement); Thread.Sleep(1111); var modalCustomArmyControllerElem = browserDocument.GetElementFromXPath(Dom.ModalCustomArmyControllerXPath)?.Result; var availableUnitsSerial = modalCustomArmyControllerElem.JavascriptCallFunction(Dom.JsGetAvailableUnitsFromControllerElement)?.Result?.value?.ToString(); var availableUnits = attackAgainReport.AvailableUnits = availableUnitsSerial.DeserializeFromString <JObject>().SubsetPropertyInt()?.ToArray(); var lackingUnits = attackAgainReport.LackingUnits = reportAttUnits ?.Select(attUnit => new KeyValuePair <string, Int64>( attUnit.Key, attUnit.Value - availableUnits?.ValueFromKeyOrDefault(attUnit.Key) ?? 0)) ?.Where(lacking => 0 < lacking.Value) ?.OrderByDescending(lacking => lacking.Value) ?.ToArray(); if (0 < lackingUnits?.Values()?.Sum()) { UnitCountSufficientNotLastTimeFromVillageId[villageSelectedId.Value] = time; return(report); } attackAgainReport.UnitCountSufficient = true; var sendArmyButtonElement = browserDocument.GetElementFromXPath("//*[@ng-click=\"sendArmy('attack')\"]")?.Result; ArmySentLastTimeFromTargetVillageId[targetVillageId.Value] = time; Statistics.AttackSentCount++; sendArmyButtonElement?.click(); attackAgainReport.Completed = true; return(report); } report.BreakStartReason = "no more reports to open"; } catch (Exception Exception) { report.Exception = Exception; } finally { if (report.BreakActiveNot) { report.BrowserUsageFailed = !report.AnyElementFromGetElementFromXPathSucceeded; ListStepBrowserUsageFailed.Enqueue(new PropertyGenTimespanInt64 <bool>(report.BrowserUsageFailed, time)); ListStepBrowserUsageFailed.ListeKürzeBegin(ListStepBrowserUsageFailedRetainLength); } var browserAge = DateTime.Now - browserService?.BrowserProcessCreatedLast?.Invoke()?.StartTimeCal; var requestBrowserProcessStartByAge = !(browserAge?.TotalSeconds < BrowserRestartAge) && breakDurationRemaining?.TotalSeconds < 15; report.RequestBrowserProcessStart = ListStepBrowserUsageFailedRetainLength <= ListStepBrowserUsageFailed.Count && ListStepBrowserUsageFailed.Count / 2 < ListStepBrowserUsageFailed.Count(failed => failed.Value) ? "Browser usage failed" : (requestBrowserProcessStartByAge ? ("browser age " + browserAge?.ToString()) : null); Statistics.ReportSummaryReadCount = ReportSummaryFromId.Count; Statistics.ReportDetailReadCount = ReportDetailFromId.Count; Statistics.AttackSentVillageCount = ArmySentLastTimeFromTargetVillageId.Count; report.Statistics = Statistics; if (0 < report.BreakStartReason?.Length) { MeasurementOutgoingUnitsLastFromVillageId.Clear(); UnitCountSufficientNotLastTimeFromVillageId.Clear(); report.BreakEndTimeCal = BreakEndTimeCal = DateTime.Now + TimeSpan.FromSeconds( new Random((int)Bib3.Glob.StopwatchZaitMiliSictInt()).Next().SictUmgebrocen(BreakDurationMin, BreakDurationMax)); } var stepLastReportAtTime = new PropertyGenTimespanInt64 <BotStepReport>(report, time); StepLastReport = stepLastReportAtTime; if (report.BreakActiveNot) { StepBeforeBreakLastReport = stepLastReportAtTime; Statistics.BotStepCount++; } } return(report); } }