Hey man :),
Your post caught my attention as I tried doing the same thing a few months ago in order to try to understand the language better, like yourself. I was however stopped in my tracks as my university course started :mad:.
I'm not sure how to go about making a bot which works in the background but I have attempted something that works in the foreground (in chrome like palavia).
The biggest problem that I faced- something so simple, was to grab a screenshot and search the screenshot for a couple of pixels in that order. Most methods were far too slow, sometimes they took a second or longer! After a few hours of researching I came across this project that somebody made which allowed me to search a screenshot for a bitmap in about ~50ms. (I can't find where I got the code from, but I still had it on my computer so I will attach it!)
I took some of the code, modified it so that it would work on my project, and tested it. After some trial and error I managed to make a bot which would fly around 1-7 take screenshots every second looking for a snippet of a bk. As soon as it was found it would autolock it, circle it, and shoot it.
However a few problems- I had no idea when the bk actually died, and also I struggled trying to find a way how I could check my health. More problems, this method worked, but as soon as I relogged/ jumped the port I would have to retake the snippet or it wouldn't find it.
So my bottleneck was still to take a darn screenshot and look for a darn snippet. Still have not been able to do this reliably. Bots like FsBot Lion run so smoothly, eventhough the boxes are sort of moving around. I don't get it, but well played to those developers.
If there are any good C# developers who are feeling a bit like :facepalm: right now please PM me or add onto this thread, I would love to know if there is something stupid I missed.
Goodluck- it is a lot harder than it looks!
Attached is a zip file containing the project. Unless you have a good plan for the screenshot/search I suggest you take a look. Code:
using System;
using System.Threading;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Drawing.Imaging;
using System.Runtime.InteropServices;
using System.Diagnostics;
namespace BitmapDetector
{
public partial class BitmapDetectorForm : Form
{
public BitmapDetectorForm()
{
InitializeComponent();
}
private void bitmap1Button_Click(object sender, EventArgs e)
{
bitmapOpenFileDialog.Filter = "BMP and PNG files (*.bmp, *.png)|*.bmp;*.png";
if (bitmapOpenFileDialog.ShowDialog() != DialogResult.OK)
return;
bitmap1TextBox.Text = bitmapOpenFileDialog.FileName;
}
private void bitmap2Button_Click(object sender, EventArgs e)
{
bitmapOpenFileDialog.Filter = "BMP and PNG files (*.bmp, *.png)|*.bmp;*.png";
if (bitmapOpenFileDialog.ShowDialog() != DialogResult.OK)
return;
bitmap2TextBox.Text = bitmapOpenFileDialog.FileName;
}
private void searchButton_Click(object sender, EventArgs e)
{
xTextBox.Text = ""; xTextBox.Refresh();
yTextBox.Text = ""; yTextBox.Refresh();
widthTextBox.Text = ""; widthTextBox.Refresh();
heightTextBox.Text = ""; heightTextBox.Refresh();
elapsedTimeLabel.Text = ""; elapsedTimeLabel.Refresh();
string validateMsg = validateData();
if (validateMsg != "")
{
MessageBox.Show(validateMsg, "Data error", MessageBoxButtons.OK, MessageBoxIcon.Warning);
return;
}
Bitmap bitmap1 = new Bitmap(bitmap1TextBox.Text);
Bitmap bitmap2 = new Bitmap(bitmap2TextBox.Text);
if (bitmap1.Width > bitmap2.Width || bitmap1.Height > bitmap2.Height)
{
Bitmap aux = bitmap2;
bitmap2 = bitmap1;
bitmap1 = aux;
}
if (bitmap1.Height > bitmap2.Height)
{
MessageBox.Show("None of the Bitmaps can contain the other.", "Data error", MessageBoxButtons.OK, MessageBoxIcon.Warning);
return;
}
this.Cursor = Cursors.WaitCursor;
Rectangle location = Rectangle.Empty;
Stopwatch stopWatch = new Stopwatch();
stopWatch.Start();
if (!autoToleranceCheckBox.Checked)
{
double tolerance = Convert.ToDouble(toleranceTrackBar.Value) / 100.0;
location = searchBitmap(bitmap1, bitmap2, tolerance);
}
else
{
location = autoSearchBitmap(bitmap1, bitmap2);
}
stopWatch.Stop();
if (location.Width != 0)
{
elapsedTimeLabel.Text = "Bitmap found in " + stopWatch.ElapsedMilliseconds + " ms.";
xTextBox.Text = location.X.ToString();
yTextBox.Text = location.Y.ToString();
widthTextBox.Text = bitmap1.Width.ToString();
heightTextBox.Text = bitmap1.Height.ToString();
}
else
{
elapsedTimeLabel.Text = "Bitmap not found.";
}
bitmap1.Dispose();
bitmap2.Dispose();
this.Cursor = Cursors.Default;
}
private string validateData()
{
if (bitmap1TextBox.Text == "")
return "You must choose a bitmap for Bitmap 1.";
if (bitmap2TextBox.Text == "")
return "You must choose a bitmap for Bitmap 2.";
return "";
}
private Rectangle autoSearchBitmap(Bitmap bitmap1, Bitmap bitmap2)
{
Rectangle location = Rectangle.Empty;
for (int i = 0; i <= toleranceTrackBar.Maximum; i++)
{
toleranceTrackBar.Value = i;
toleranceTrackBar.Refresh();
double tolerance = Convert.ToDouble(i) / 100.0;
location = searchBitmap(bitmap1, bitmap2, tolerance);
if (location.Width != 0)
break;
}
return location;
}
private Rectangle searchBitmap(Bitmap smallBmp, Bitmap bigBmp, double tolerance)
{
BitmapData smallData =
smallBmp.LockBits(new Rectangle(0, 0, smallBmp.Width, smallBmp.Height),
System.Drawing.Imaging.ImageLockMode.ReadOnly,
System.Drawing.Imaging.PixelFormat.Format24bppRgb) ;
BitmapData bigData =
bigBmp.LockBits(new Rectangle(0, 0, bigBmp.Width, bigBmp.Height),
System.Drawing.Imaging.ImageLockMode.ReadOnly,
System.Drawing.Imaging.PixelFormat.Format24bppRgb) ;
int smallStride = smallData.Stride;
int bigStride = bigData.Stride;
int bigWidth = bigBmp.Width;
int bigHeight = bigBmp.Height - smallBmp.Height + 1;
int smallWidth = smallBmp.Width * 3;
int smallHeight = smallBmp.Height;
Rectangle location = Rectangle.Empty;
int margin = Convert.ToInt32(255.0 * tolerance);
unsafe
{
byte* pSmall = (byte*)(void*)smallData.Scan0;
byte* pBig = (byte*)(void*)bigData.Scan0;
int smallOffset = smallStride - smallBmp.Width * 3;
int bigOffset = bigStride - bigBmp.Width * 3;
bool matchFound = true;
for (int y = 0; y < bigHeight; y++)
{
for (int x = 0; x < bigWidth; x++)
{
byte* pBigBackup = pBig;
byte* pSmallBackup = pSmall;
//Look for the small picture.
for (int i = 0; i < smallHeight; i++)
{
int j = 0;
matchFound = true;
for (j = 0; j < smallWidth; j++)
{
//With tolerance: pSmall value should be between margins.
int inf = pBig[0] - margin;
int sup = pBig[0] + margin;
if (sup < pSmall[0] || inf > pSmall[0])
{
matchFound = false;
break;
}
pBig++;
pSmall++;
}
if (!matchFound) break;
//We restore the pointers.
pSmall = pSmallBackup;
pBig = pBigBackup;
//Next rows of the small and big pictures.
pSmall += smallStride * (1 + i);
pBig += bigStride * (1 + i);
}
//If match found, we return.
if (matchFound)
{
location.X = x;
location.Y = y;
location.Width = smallBmp.Width;
location.Height = smallBmp.Height;
break;
}
//If no match found, we restore the pointers and continue.
else
{
pBig = pBigBackup;
pSmall = pSmallBackup;
pBig += 3;
}
}
if (matchFound) break;
pBig += bigOffset;
}
}
bigBmp.UnlockBits(bigData);
smallBmp.UnlockBits(smallData);
return location;
}
private void toleranceTrackBar_ValueChanged(object sender, EventArgs e)
{
toleranceValueLabel.Text = toleranceTrackBar.Value.ToString() + " %";
toleranceValueLabel.Refresh();
}
private void autoToleranceCheckBox_CheckedChanged(object sender, EventArgs e)
{
if (autoToleranceCheckBox.Checked)
{
toleranceTrackBar.Value = 0;
toleranceTrackBar.Enabled = false;
}
else
{
toleranceTrackBar.Enabled = true;
}
}
}
}