public static T BuildError <T>(ScanInfo info) where T : ScanResult, new() { return(new T() { Error = true, ScanInfo = info }); }
public ScanResultItem ParseResultWindowRareItem(string fileName, ScanInfo scanInfo, AndroidConnector android) { ScanResultItem exchangeInfo = new ScanResultItem() { Found = true, ScanInfo = scanInfo }; using (var image = Image.Load <Rgba32>(fileName)) { image.Clone(ctx => ctx.Crop(new Rectangle(996, 159, 549, 66))).Save($"itemname.png"); string itemName = GetTextFromImage("itemname.png"); if ( (!scanInfo.RealName.Contains("★") && itemName.ToLower() != scanInfo.RealName.ToLower()) || (scanInfo.RealName.Contains("★") && !itemName.Contains("*") && itemName.ToLower() != "andrei card" && itemName.ToLower() != "zipper beartcard" && itemName.ToLower() != "archer skeletontcard" ) ) { if (scanInfo.RealName.Contains("★")) { Console.WriteLine("Star card not found"); } scanInfo.Message = "Something is wrong, names do NOT match"; return(ScanResult.BuildError <ScanResultItem>(scanInfo)); } exchangeInfo.Price = int.Parse(GetPrice(image), CultureInfo.InvariantCulture); string amount = GetAmount(image); if (amount == "") { scanInfo.Message = "Could not find the right amount"; return(ScanResult.BuildError <ScanResultItem>(scanInfo)); } exchangeInfo.Amount = int.Parse(amount, CultureInfo.InvariantCulture); exchangeInfo.SnapTime = GetSnapTime(image); exchangeInfo.Found = true; } return(exchangeInfo); }
private async static void RunScanner() { //status.SetStatus("Starting up", "Checking if in exchange"); //if (!await scanner.IsExchangeOpen(androidConnection)) //{ // status.SetStatus("Restarting RO", ""); // await scanner.RestartRo(androidConnection); // status.SetStatus("Opening Exchange", ""); // await scanner.OpenExchange(androidConnection, 0); //} //status.SetStatus("Starting up", "Started up"); int errorCount = 0; int majorErrorcount = 0; /* { * ScanInfo scanInfo = new ScanInfo() * { * RealName = "Eye of Dullahan", * SearchName = "Eye of Dullahan", * SearchIndex = -1, * Override = false * }; * * List<ScanResultEquip> exchangeInfo = await scanner.ScanEquip(androidConnection, scanInfo); * }*/ using (HttpClient client = new HttpClient()) { while (true) { CancelScan = false; if (Restart) { CurrentStatus = Status.Restarting; status.SetStatus("Restarting RO", ""); await scanner.RestartRo(androidConnection); status.SetStatus("Opening Exchange", ""); await scanner.OpenExchange(androidConnection, 0); Restart = false; CurrentStatus = Status.Idle; } if (CurrentStatus == Status.Idle) { status.SetStatus("Idle", ""); await Task.Delay(1000); continue; } Program.status.SetStatus("Finding new item to scan", ""); HttpRequestMessage request; if (CurrentStatus == Status.Equip) { request = new HttpRequestMessage(HttpMethod.Get, $"{ApiEndPoint}/api/scanner/nextscanequip"); } else if (CurrentStatus == Status.Rare) { request = new HttpRequestMessage(HttpMethod.Get, $"{ApiEndPoint}/api/scanner/nextscanitem"); } else { continue; } request.Headers.Add("Accept", "application/json"); request.Headers.Add("User-Agent", "BorfRoScanner"); var response = client.SendAsync(request).Result; if (response.IsSuccessStatusCode) { using var responseStream = await response.Content.ReadAsStreamAsync(); var options = new JsonSerializerOptions { IgnoreNullValues = true }; var data = await JsonSerializer.DeserializeAsync <NextScanItemResponse>(responseStream, options); Program.status.SetStatus("Scanning item", ""); Program.status.SetItem(data.name); ScanInfo scanInfo = new ScanInfo() { RealName = data.name, SearchName = data.scanname, SearchIndex = data.scanindex, Override = data.@override }; if (data.scanname == "") { scanInfo.SearchName = data.name; if (scanInfo.SearchName.Contains("[")) { scanInfo.SearchName = scanInfo.SearchName.Substring(0, scanInfo.SearchName.IndexOf("[")); } } if (data.type.ToLower().StartsWith("equipment")) { Stopwatch sw = new Stopwatch(); sw.Start(); List <ScanResultEquip> exchangeInfo = await scanner.ScanEquip(androidConnection, scanInfo); sw.Stop(); log.Log(scanInfo.RealName, $"Found Item in {sw.Elapsed.TotalSeconds} seconds\n{exchangeInfo}\n"); bool error = exchangeInfo.Any(e => e.Error); status.SetStatus("Done Scanning", "Posting results"); request = new HttpRequestMessage(HttpMethod.Post, $"{ApiEndPoint}/api/scanner/result"); request.Headers.Add("Accept", "application/json"); request.Headers.Add("User-Agent", "BorfRoScanner"); request.Content = new StringContent(JsonSerializer.Serialize(new { data.id, error = error, results = exchangeInfo, clientId = hostname }), Encoding.UTF8, "application/json"); try { response = await client.SendAsync(request); } catch (Exception e) { Console.WriteLine(e); } } else { Stopwatch sw = new Stopwatch(); sw.Start(); ScanResultItem exchangeInfo = await scanner.ScanRareItem(androidConnection, scanInfo); sw.Stop(); log.Log(scanInfo.RealName, $"Found Item in {sw.Elapsed.TotalSeconds} seconds\n{exchangeInfo}\n"); request = new HttpRequestMessage(HttpMethod.Post, $"{ApiEndPoint}/api/scanner/result"); request.Headers.Add("Accept", "application/json"); request.Headers.Add("User-Agent", "BorfRoScanner"); request.Content = new StringContent(JsonSerializer.Serialize(new { data.id, price = exchangeInfo.Price, amount = exchangeInfo.Amount, error = exchangeInfo.Error, errormsg = exchangeInfo.ScanInfo.Message, snapping = exchangeInfo.Snapping, snapTime = exchangeInfo.SnapTime, ScanIndex = exchangeInfo.ScanInfo.SearchIndex }), Encoding.UTF8, "application/json"); response = await client.SendAsync(request); if (exchangeInfo.Error) { errorCount++; Console.WriteLine("Error scanning card!"); Console.WriteLine(exchangeInfo.ScanInfo.Message); } else { errorCount = 0; majorErrorcount = 0; } } } if (errorCount > 10) { Console.WriteLine("Got over 10 errors, increasing major errors..."); if (majorErrorcount > 2) { CurrentStatus = Status.Idle; } else { Restart = true; Console.WriteLine("Too many errors, restarting game"); majorErrorcount++; errorCount = 0; } } } } }
public async Task <ScanResultItem> ScanRareItem(AndroidConnector android, ScanInfo scanInfo) { Console.WriteLine("- Opening search window"); await CloseSearch(android); await ClickSearchButton(android); await ClickSearchBox(android); string itemName = scanInfo.SearchName; if (itemName.Contains("★")) { itemName = itemName.Substring(0, itemName.IndexOf("★")).Trim(); } await android.Text(itemName); await ClickSearchWindowSearchButton(android); //to close text input await ClickSearchWindowSearchButton(android); Console.WriteLine("- Scanning search result"); await android.Screenshot("searchresult.png"); List <int> indices = FindSearchResult("searchresult.png", scanInfo); if (indices.Count == 0) { //TODO: do something with item0.png - item9.png Console.WriteLine("- Error, could not find item"); await CloseSearch(android); return(ScanResult.BuildError <ScanResultItem>(scanInfo)); } if (indices[0] != scanInfo.SearchIndex) { if (scanInfo.SearchIndex != -1) { Console.WriteLine("- Warning, search index not correct"); } scanInfo.SearchIndex = indices[0]; } for (int i = 0; i < indices.Count; i++) { await ClickSearchWindowIndex(android, indices[i]); await Task.Delay(1500); // the UI needs some time to load the card Console.WriteLine("- Checking if any items are on sale"); await android.Screenshot("shopitems.png"); using (var image = Image.Load <Rgba32>("shopitems.png")) image.Clone(ctx => ctx.Crop(new Rectangle(975, 505, 368, 64))).Save($"nosale.png"); bool nosale = false; if (GetTextFromImage("nosale.png").ToLower().Contains("currently")) { nosale = true; Console.WriteLine("- No items currently on sale"); if (i + 1 >= indices.Count) { return new ScanResultItem() { Found = false, ScanInfo = scanInfo } } ; } if (!nosale) { await ClickShopItem(android, 0); // these items should only give 1 item result await ClickShopBuyButton(android); await Task.Delay(1500); // the UI needs some time to load the card Console.WriteLine("- Scanning item"); await android.Screenshot("shopresult.png"); await ClickShopCloseItem(android); ScanResultItem priceInfo = ParseResultWindowRareItem("shopresult.png", scanInfo, android); if (!priceInfo.Error || i + 1 >= indices.Count) { priceInfo.Error = false; return(priceInfo); } } scanInfo.Message = ""; Console.WriteLine("Item does not match, or not found on exchange with multiple items, trying to rescan it"); await CloseSearch(android); await ClickSearchButton(android); await ClickSearchBox(android); await android.Text(itemName); await ClickSearchWindowSearchButton(android); //to close text input await ClickSearchWindowSearchButton(android); } return(null); } }
private async Task <bool> ScanPage(List <Image <Rgba32> > images, AndroidConnector android, ScanInfo scanInfo, List <ScanResultEquip> result) { string codename = scanInfo.RealName.ToLower(); codename = codename.Replace(" ", "_"); codename = codename.Replace("[1]", "1s"); codename = codename.Replace("[2]", "2s"); using (var image = Image.Load <Rgba32>("shopitems.png")) { //first, look for the top blue line of the item box (RGB(171, 210, 243) if not scrolled half a pixel) int starty = FindFirstResult(image); Program.log.Log(scanInfo.RealName, $"Item list starting at {starty}"); await ClickShopItem(android, 0, starty - 230); //go through all 8 pictures for (int ii = 0; ii < 8; ii++) { int newstarty = FindFirstResult(image); if (newstarty != starty) { Program.log.Log(scanInfo.RealName, $"Scrolled a bit, adjusting"); starty = newstarty; } if (starty + 180 * (ii / 2) + 132 > 902) { continue; } //make a capture of the item, so we don't scan items twice var subImage = image.Clone(ctx => ctx.Crop(new Rectangle(595 + 600 * (ii % 2), starty + 180 * (ii / 2), 400, 132))); if (TestIfScanned(subImage, images)) { Program.log.Log(scanInfo.RealName, $"Item {ii} already scanned, skipping"); continue; } images.Add(subImage); subImage.Save($"unknown/unknown{Directory.GetFiles("unknown").Length}.png"); //click it as visualisation await ClickShopItem(android, ii, starty - 230); //check if item has multiple on sale. If it does, we don't have to scan it because it won't have an enchantment var rect = new Rectangle(694 + 600 * (ii % 2), starty + 103 + 180 * (ii / 2), 33, 28); using (var amountImage = image.Clone(ctx => ctx.Crop(rect))) { //image.Clone(ctx => ctx.Crop(rect)).Save($"unknown/unknown{Directory.GetFiles("unknown").Length}.png"); if (!File.Exists($"data/equip_br/{codename}.png")) { if (!Directory.Exists($"data/equip_br/{codename}")) { Directory.CreateDirectory($"data/equip_br/{codename}"); } amountImage.Save($"data/equip_br/{codename}/{Directory.GetFiles($"data/equip_br/{codename}/").Length}.png"); } else { using (var noamount = Image.Load <Rgba32>($"data/equip_br/{codename}.png")) { int dist = ImageDistance(amountImage, noamount); if (dist > 100) { Program.log.Log(scanInfo.RealName, $"Item {ii} has an amount, not scanning. Distance {dist}"); Console.WriteLine($"- Item {ii} has an amount, not scanning! Distance {dist}"); continue; } } } } //scan item for price and enchantments await Task.Delay(100); Console.WriteLine($"- Scanning item {ii}"); await ClickShopBuyButton(android); await Task.Delay(1000); Console.WriteLine("- Scanning item"); await android.Screenshot("shopresult.png"); ScanResultEquip priceInfo = await ParseResultWindowEquip("shopresult.png", scanInfo, android); result.Add(priceInfo); await Task.Delay(100); await ClickShopCloseItem(android); if (priceInfo.Error) //if error, last one is found { return(true); } } } return(false); }
public async Task <List <ScanResultEquip> > ScanEquip(AndroidConnector android, ScanInfo scanInfo) { List <ScanResultEquip> result = new List <ScanResultEquip>(); if (scanInfo.RealName.Contains("[1]")) { scanInfo.Slots = 1; } if (scanInfo.RealName.Contains("[2]")) { scanInfo.Slots = 2; } if (scanInfo.SearchName.Contains("[")) { scanInfo.SearchName = scanInfo.SearchName.Substring(0, scanInfo.SearchName.IndexOf("[")).Trim(); } scanInfo.Equip = true; Program.status.SetSubStatus("Opening search window"); await CloseSearch(android); await ClickSearchButton(android); await ClickSearchBox(android); await android.Text(scanInfo.SearchName); await ClickSearchWindowSearchButton(android); //to close text input await ClickSearchWindowSearchButton(android); Program.status.SetSubStatus("Scanning search result"); await android.Screenshot("searchresult.png"); using (var image = Image.Load <Rgba32>("searchresult.png")) using (var cmp = Image.Load <Rgba32>("data/bigerror.png")) if (ImageDistance(image.Clone(c => c.Crop(new Rectangle(650, 150, 700, 200))), cmp) < 100) { Program.Restart = true; return(null); } List <int> indices = FindSearchResult("searchresult.png", scanInfo); if (indices.Count == 1 && indices[0] == -1) { await android.Swipe(1100, 863, 1100, 355, 200); await Task.Delay(500); await android.Screenshot("searchresult.png"); indices = FindSearchResult("searchresult.png", scanInfo); } await Task.Delay(500); if (indices.Count == 0) { //TODO: do something with item0.png - item9.png Program.status.SetSubStatus("- Error, could not find item"); await CloseSearch(android); return(new List <ScanResultEquip>() { ScanResult.BuildError <ScanResultEquip>(scanInfo) }); } if (indices[0] != scanInfo.SearchIndex) { if (scanInfo.SearchIndex != -1) { Program.log.Log(scanInfo.RealName, "Warning, search index not correct"); } scanInfo.SearchIndex = indices[0]; } for (int i = 0; i < indices.Count; i++) { await ClickSearchWindowIndex(android, indices[i]); await Task.Delay(2500); Program.status.SetSubStatus("Checking for sales"); await android.Screenshot("shopitems.png"); using (var image = Image.Load <Rgba32>("shopitems.png")) image.Clone(ctx => ctx.Crop(new Rectangle(975, 505, 368, 64))).Save($"nosale.png"); bool onSale = true; if (GetTextFromImage("nosale.png").ToLower().Contains("currently")) { onSale = false; Program.log.Log(scanInfo.RealName, "Currently not for sale"); if (i + 1 >= indices.Count) { return new List <ScanResultEquip>() { new ScanResultEquip() { Found = false, ScanInfo = scanInfo } } } ; } if (onSale) { var images = new List <Image <Rgba32> >(); int subPage = 0; while (!Program.CancelScan) { Program.log.Log(scanInfo.RealName, "Scanning page " + subPage); int foundResults = images.Count; bool done = await ScanPage(images, android, scanInfo, result); if (foundResults == images.Count) { Program.log.Log(scanInfo.RealName, "No new items found in last sweep, done"); break; } if (subPage % 2 == 0) { await SwipeDown(android); } else if (await NextPage(android)) { break; } await android.Screenshot("shopitems.png"); subPage++; } Program.status.SetSubStatus("done scanning"); foreach (var img in images) { img.Dispose(); } return(result); } //this should not happen scanInfo.Message = ""; Console.WriteLine("Item does not match, or not found on exchange with multiple items, trying to rescan it"); await CloseSearch(android); await ClickSearchButton(android); await ClickSearchBox(android); await android.Text(scanInfo.SearchName); await ClickSearchWindowSearchButton(android); //to close text input await ClickSearchWindowSearchButton(android); } return(null); }
private List <int> FindSearchResult(string imageName, ScanInfo info) { if (info.Override) { return new List <int>() { info.SearchIndex } } ; List <int> resultIds = new List <int>(); string itemName = info.RealName; bool star = itemName.Contains("★"); if (star) { itemName = itemName.Substring(0, itemName.IndexOf("★")); } string matchItemName = itemName .Replace(".", "") .ToLower() .Trim(new char[] { '\r', '\n', '\t', ' ', '.' }); List <string> results = new List <string>(); List <int> searchOrder = Enumerable.Range(0, SearchResultPositions.Length).ToList(); if (info != null && info.SearchIndex != -1) { searchOrder.Swap(0, info.SearchIndex); } using (var image = Image.Load(imageName)) { foreach (int i in searchOrder) { image.Clone(ctx => ctx.Crop(new Rectangle(SearchResultPositions[i].X, SearchResultPositions[i].Y, 313, 83))).Save($"item{i}.png"); string result = GetTextFromImage($"item{i}.png"); if (result == "") { continue; } results.Add(result); result = result .Replace(".", "") .ToLower() .Trim(new char[] { '\r', '\n', '\t', ' ', '.' }); if (result.EndsWith(" bi") && info.RealName.ToLower().Contains("blueprint")) { result = result.Substring(0, result.Length - 1) + "l"; } if (!star) { if (matchItemName.IndexOf(result) == 0) { resultIds.Add(i); } } else { if (matchItemName.IndexOf(result) == 0 && result != matchItemName + " card") { resultIds.Add(i); } else if ((matchItemName + " *card").IndexOf(result) == 0) { resultIds.Add(i); } else if ((matchItemName + "*card").IndexOf(result) == 0) { resultIds.Add(i); } else if ((matchItemName + " * card").IndexOf(result) == 0) { resultIds.Add(i); } else if ((matchItemName + "izcard").IndexOf(result) == 0) { resultIds.Add(i); } else if ((matchItemName + " iv").IndexOf(result) == 0) { resultIds.Add(i); } } } } if (resultIds.Count == 0) { info.Message = $"Could not find item {itemName}, results were ({string.Join(", ", results)})"; } return(resultIds); }
public async Task <ScanResultEquip> ParseResultWindowEquip(string fileName, ScanInfo scanInfo, AndroidConnector android) { ScanResultEquip exchangeInfo = new ScanResultEquip() { Found = true, ScanInfo = scanInfo }; using (var image = Image.Load <Rgba32>(fileName)) { image.Clone(ctx => ctx.Crop(new Rectangle(996, 159, 549, 66))).Save($"itemname.png"); string itemName = GetTextFromImage("itemname.png"); if (itemName.ToLower() != scanInfo.RealName.ToLower()) { scanInfo.Message = $"Something is wrong, names do NOT match. Expected {scanInfo.RealName.ToLower()} but got {itemName.ToLower()}"; return(ScanResult.BuildError <ScanResultEquip>(scanInfo)); } exchangeInfo.Price = int.Parse(GetPriceEquip(image), CultureInfo.InvariantCulture); exchangeInfo.SnapTime = GetSnapTime(image); int i = 0; //scan for multiple items bool enchanted = false; bool foundRefine = false; while (!Program.CancelScan) { using (var image2 = Image.Load <Rgba32>(fileName)) image2.Clone(ctx => ctx.Crop(new Rectangle(383, 261, 553, 453))).Save($"enchant{i}.png"); string hasEnchant = GetTextFromImage($"enchant{i}.png"); Console.WriteLine($"- Text Read: \n\n{hasEnchant}\n\n"); if (hasEnchant.ToLower().Contains("refine ") && !foundRefine && !enchanted && hasEnchant.ToLower().IndexOf("refine ") != hasEnchant.ToLower().IndexOf("refine +6 effective")) { string refine = hasEnchant.ToLower(); refine = refine.Replace("\r\n", "\n"); while (refine.Contains("\n\n")) { refine = refine.Replace("\n\n", "\n"); } refine = refine.Substring(refine.IndexOf("\nrefine ") + 8).Trim(); if (refine.IndexOf("\n") > 0) { refine = refine.Substring(0, refine.IndexOf("\n")).Trim(); } Console.WriteLine(refine); int refineLevel = 0; if (refine.Contains("/")) { try { refineLevel = int.Parse(refine.Substring(0, refine.IndexOf("/"))); foundRefine = true; } catch (FormatException e) { scanInfo.Message = "Something is wrong, error parsing refine level: " + refine; Console.WriteLine(e); return(ScanResult.BuildError <ScanResultEquip>(scanInfo)); } } if (refine.Contains("atk+")) { int atk = int.Parse(refine.Substring(refine.IndexOf("atk+") + 4)); foundRefine = true; //TODO: check if atk matches refineLevel } exchangeInfo.RefinementLevel = refineLevel; } if (hasEnchant.ToLower().Contains("enchanted")) { enchanted = true; } if (hasEnchant.ToLower().Contains("equipment upgrade")) { if (enchanted) { MemoryStream ms = new MemoryStream(); var jpegEncoder = new SixLabors.ImageSharp.Formats.Jpeg.JpegEncoder { Quality = 10 }; using (var image2 = Image.Load <Rgba32>($"enchant{i}.png")) image2.Clone(ctx => ctx.Resize(new ResizeOptions { Size = image2.Size() / 2 })).SaveAsJpeg(ms, jpegEncoder); exchangeInfo.EnchantmentImage = System.Convert.ToBase64String(ms.GetBuffer()); if (!hasEnchant.ToLower().Contains("enchanted")) { Console.WriteLine("Scrolled too far"); exchangeInfo.Enchantments = new List <string>() { "scrolled too far" }; break; } hasEnchant = hasEnchant.ToLower(); hasEnchant = hasEnchant.Replace("\r\n", "\n"); while (hasEnchant.Contains("\n\n")) { hasEnchant = hasEnchant.Replace("\n\n", "\n"); } hasEnchant = hasEnchant.Substring(hasEnchant.IndexOf("enchanted attribute:") + 20).Trim(); hasEnchant = hasEnchant.Substring(0, hasEnchant.IndexOf("equipment upgrade")).Trim(); hasEnchant = hasEnchant.Replace("mapr ", "maxhp "); exchangeInfo.Enchantments = hasEnchant.Split("\n", 4).ToList(); } break; } if (hasEnchant.ToLower().Contains("exchange price")) { Console.WriteLine("Scrolled wayyyyyy too far"); break; } await android.Swipe(555, 500, 555, 300, 500); await Task.Delay(100); await android.Tap(1500, 960); await android.Screenshot(fileName); i++; } exchangeInfo.Found = true; } return(exchangeInfo); }