The Bytecode Club
Log inJoin the club
Video Game Reverse Engineering

Struggling with _PixelSearch

Started by Snarg · Feb 10, 2015

7 replies133,016 views
Feb 10, 2015#1

I am attempting to re purpose some of the code in the bot, but I am running into issues with _PixelSearch. Specifically, I can not seem to get it to find the pixel I am looking for. I can not get it to find the pixel in the 'Train Troops' button. I am using an older version of BlueStacks and I don't have BS's resolution set to what you recommend however, that should not be the issue.
Let me apologize in advance to the wall of code but below is the code I am using. If the code worked, nothing should happen. But, I keep getting the 'Barracks is not available' messagebox instead.
If a super smart coder would like to take a look at this mess and let me know what I am doing wrong, I would appreciate it.

#include <GDIPlus.au3>
#include <WinAPIProc.au3>
#include <ScreenCapture.au3>
#include <ColorConstants.au3>
#include <Misc.au3>

Opt("MouseClickDelay", 10)
Opt("MouseClickDownDelay", 10)

Global $hBitmap; Image for pixel functions
Global $hHBitmap; Handle Image for Pixel Functions

Global $BSpos[2] ; Inside BlueStacks positions relative to the screen

Global $ichkBackground = 0

$Title = "BlueStacks App Player for Windows (beta-1)" ; Window name
$Full = WinGetTitle ($Title) ; Get The Full Title..
$HWnD = WinGetHandle ($Full) ; Get The Handle
WinActivate ($HWnD)
WinMove ($HWnD, "", 0, 0)

Global $RunState = True

;Barrak 01 - 131, 309
;Barrak 02 - 296, 46
;Barrak 03 - 838, 50
;Barrak 04 - 994, 314

HotKeySet ("{F7}", "Train")

While 1
   Sleep (100)
WEnd

Func Train()
   	While 1
			If _Sleep(500) Then ExitLoop

			Click(1, 1) ;Click Away

			If _Sleep(500) Then ExitLoop

			Click(131, 309) ;Click Barrack 01

			If _Sleep(500) Then ExitLoop

			Local $TrainPos = _PixelSearch(625, 457, 686, 520, Hex(0x885733, 6), 5) ;Finds Train Troops button
			If IsArray($TrainPos) = False Then
				;SetLog("Barrack " & $i + 1 & " is not available")
				MsgBox ($MB_SYSTEMMODAL, "Barracks is not available", "")
				If _Sleep(500) Then ExitLoop
			Else
				Click($TrainPos[0], $TrainPos[1]) ;Click Train Troops button
			EndIf
	WEnd
EndFunc   ;==>Train

Func Click($x, $y, $times = 1, $speed = 0)
   If $times <> 1 Then
	  For $i = 0 To ($times - 1)
		 ControlClick($HWnD, "", "", "left", "1", $x, $y)
		 If _Sleep($speed, False) Then ExitLoop
	  Next
   Else
	  ControlClick($HWnD, "", "", "left", "1", $x, $y)
   EndIf
EndFunc   ;==>Click

Func _Sleep($iDelay, $iSleep = True)
   Local $iBegin = TimerInit()
   While TimerDiff($iBegin) < $iDelay
	  If $RunState = False Then Return True
	  If $iSleep = True Then Sleep(100)
   WEnd
   Return False
EndFunc   ;==>_Sleep

Func _PixelSearch($iLeft, $iTop, $iRight, $iBottom, $iColor, $iColorVariation)
	_CaptureRegion($iLeft, $iTop, $iRight, $iBottom)
	For $x = $iRight - $iLeft To 0 Step -1
		For $y = $iBottom - $iTop To 0 Step -1
			Local $nColor1 = $iColor
			Local $nColor2 = _PixelGetColor_GetPixel($x, $y)
			If _ColorCheckVariation($nColor1, $nColor2, $iColorVariation) Then
				Local $Pos[2] = [$iLeft + $x, $iTop + $y]
				Return $Pos
			EndIf
		Next
	Next
	Return 0
 EndFunc   ;==>_PixelSearch

 Func _CaptureRegion($iLeft = 0, $iTop = 0, $iRight = 860, $iBottom = 720, $ReturnBMP = False)
	_GDIPlus_BitmapDispose($hBitmap)
	_WinAPI_DeleteObject($hHBitmap)

	If $ichkBackground = 1 Then
		Local $iW = Number($iRight) - Number($iLeft), $iH = Number($iBottom) - Number($iTop)

		Local $hDC_Capture = _WinAPI_GetWindowDC(ControlGetHandle("BlueStacks App Player", "", "[CLASS:BlueStacksApp; INSTANCE:1]"))
		Local $hMemDC = _WinAPI_CreateCompatibleDC($hDC_Capture)
		$hHBitmap = _WinAPI_CreateCompatibleBitmap($hDC_Capture, $iW, $iH)
		Local $hObjectOld = _WinAPI_SelectObject($hMemDC, $hHBitmap)

		DllCall("user32.dll", "int", "PrintWindow", "hwnd", $HWnD, "handle", $hMemDC, "int", 0)
		_WinAPI_SelectObject($hMemDC, $hHBitmap)
		_WinAPI_BitBlt($hMemDC, 0, 0, $iW, $iH, $hDC_Capture, $iLeft, $iTop, 0x00CC0020)

		Global $hBitmap = _GDIPlus_BitmapCreateFromHBITMAP($hHBitmap)

		_WinAPI_DeleteDC($hMemDC)
		_WinAPI_SelectObject($hMemDC, $hObjectOld)
		_WinAPI_ReleaseDC($HWnD, $hDC_Capture)
	Else
		getBSPos()
		$hHBitmap = _ScreenCapture_Capture("", $iLeft + $BSpos[0], $iTop + $BSpos[1], $iRight + $BSpos[0], $iBottom + $BSpos[1])
		Global $hBitmap = _GDIPlus_BitmapCreateFromHBITMAP($hHBitmap)
	EndIf

	If $ReturnBMP Then Return $hBitmap
EndFunc   ;==>_CaptureRegion

Func getBSPos()
	$aPos = ControlGetPos($Title, "", "[CLASS:BlueStacksApp; INSTANCE:1]")
	$tPoint = DllStructCreate("int X;int Y")
	DllStructSetData($tPoint, "X", $aPos[0])
	DllStructSetData($tPoint, "Y", $aPos[1])
	_WinAPI_ClientToScreen(WinGetHandle(WinGetTitle($Title)), $tPoint)

	$BSpos[0] = DllStructGetData($tPoint, "X")
	$BSpos[1] = DllStructGetData($tPoint, "Y")
 EndFunc   ;==>getBSPos

 Func _PixelGetColor_GetPixel($iX, $iY)
	Local $aPixelColor = _GDIPlus_BitmapGetPixel($hBitmap, $iX, $iY)
	Return Hex($aPixelColor, 6)
 EndFunc   ;==>_PixelGetColor_GetPixel

 Func _ColorCheckVariation($nColor1, $nColor2, $sVari = 5)
	Local $Red1, $Red2, $Blue1, $Blue2, $Green1, $Green2

	$Red1 = Dec(StringMid(String($nColor1), 1, 2))
	$Blue1 = Dec(StringMid(String($nColor1), 3, 2))
	$Green1 = Dec(StringMid(String($nColor1), 5, 2))

	$Red2 = Dec(StringMid(String($nColor2), 1, 2))
	$Blue2 = Dec(StringMid(String($nColor2), 3, 2))
	$Green2 = Dec(StringMid(String($nColor2), 5, 2))

	If Abs($Blue1 - $Blue2) > $sVari Then Return False
	If Abs($Green1 - $Green2) > $sVari Then Return False
	If Abs($Red1 - $Red2) > $sVari Then Return False
	Return True
EndFunc   ;==>_ColorCheckVariation
Feb 10, 2015#2

Most likely you are not using the correct coords in your pixelsearch...
How did you get those coords?

Feb 10, 2015#3

Most likely you are not using the correct coords in your pixelsearch...
How did you get those coords?

I am using Control Viewer.

Feb 10, 2015#4

Snarg wrote:

Henk500 wrote:

Most likely you are not using the correct coords in your pixelsearch...
How did you get those coords?

I am using Control Viewer.

I had some issues to... the x coordinate was not the coordinate i expected.
in my screenshot, $x=1 was the 3rd pixel.. I expected $x=1 to be the 2nd pixel ( and $x=0) the first pixel

Feb 10, 2015#5

I had some issues to... the x coordinate was not the coordinate i expected.
in my screenshot, $x=1 was the 3rd pixel.. I expected $x=1 to be the 2nd pixel ( and $x=0) the first pixel

I can understand that. There is a bit of an offset with the coordinates. But I gave it a decent sized search area with the pixel I am looking for just about in the middle of the box.

Local $TrainPos = _PixelSearch(625, 457, 686, 520, Hex(0x885733, 6), 5)

Here is my top left coordinates:

And here is my bottom right:

Do I have the coordinates wrong in the function call?

Feb 10, 2015#6

in captureregion, change this value with your BS resolution

.....$iRight = 860, $iBottom = 720....

Feb 10, 2015#7

in captureregion, change this value with your BS resolution

.....$iRight = 860, $iBottom = 720....

It's always the blatantly obvious, isn't it? Thank you.

Feb 10, 2015#8

(sigh) Still failing 🙁

Sorry for the wall of code, but here is the whole thing. All it should do is click a barracks and find the 'train troops' button.

#include <GDIPlus.au3>
#include <WinAPIProc.au3>
#include <ScreenCapture.au3>
#include <ColorConstants.au3>
#include <Misc.au3>

Opt("MouseClickDelay", 10)
Opt("MouseClickDownDelay", 10)

Global $hBitmap; Image for pixel functions
Global $hHBitmap; Handle Image for Pixel Functions

Global $BSpos[2] ; Inside BlueStacks positions relative to the screen

Global $ichkBackground = 0

$Title = "BlueStacks App Player for Windows (beta-1)" ; Window name
$Full = WinGetTitle ($Title) ; Get The Full Title..
$HWnD = WinGetHandle ($Full) ; Get The Handle
WinActivate ($HWnD)
WinMove ($HWnD, "", 0, 0)

Global $RunState = True

;Barrak 01 - 131, 309
;Barrak 02 - 296, 46
;Barrak 03 - 838, 50
;Barrak 04 - 994, 314

HotKeySet ("{F7}", "Train")

While 1
   Sleep (100)
WEnd

Func Train()
   	While 1
			If _Sleep(500) Then ExitLoop

			Click(1, 1) ;Click Away

			If _Sleep(500) Then ExitLoop

			Click(131, 309) ;Click Barrack 01

			If _Sleep(500) Then ExitLoop

			Local $TrainPos = _PixelSearch(625, 457, 686, 520, Hex(0x885733, 6), 5) ;Finds Train Troops button
			If IsArray($TrainPos) = False Then
				;SetLog("Barrack " & $i + 1 & " is not available")
				MsgBox ($MB_SYSTEMMODAL, "Barracks is not available", "")
				If _Sleep(500) Then ExitLoop
			Else
			    MsgBox ($MB_SYSTEMMODAL, "Found it!!", "")
				;Click($TrainPos[0], $TrainPos[1]) ;Click Train Troops button
			EndIf
	WEnd
EndFunc   ;==>Train

Func Click($x, $y, $times = 1, $speed = 0)
   If $times <> 1 Then
	  For $i = 0 To ($times - 1)
		 ControlClick($HWnD, "", "", "left", "1", $x, $y)
		 If _Sleep($speed, False) Then ExitLoop
	  Next
   Else
	  ControlClick($HWnD, "", "", "left", "1", $x, $y)
   EndIf
EndFunc   ;==>Click

Func _Sleep($iDelay, $iSleep = True)
   Local $iBegin = TimerInit()
   While TimerDiff($iBegin) < $iDelay
	  If $RunState = False Then Return True
	  If $iSleep = True Then Sleep(100)
   WEnd
   Return False
EndFunc   ;==>_Sleep

Func _PixelSearch($iLeft, $iTop, $iRight, $iBottom, $iColor, $iColorVariation)
	_CaptureRegion($iLeft, $iTop, $iRight, $iBottom)
	For $x = $iRight - $iLeft To 0 Step -1
		For $y = $iBottom - $iTop To 0 Step -1
			Local $nColor1 = $iColor
			Local $nColor2 = _PixelGetColor_GetPixel($x, $y)
			If _ColorCheckVariation($nColor1, $nColor2, $iColorVariation) Then
				Local $Pos[2] = [$iLeft + $x, $iTop + $y]
				Return $Pos
			EndIf
		Next
	Next
	Return 0
 EndFunc   ;==>_PixelSearch

 Func _CaptureRegion($iLeft = 0, $iTop = 0, $iRight = 599, $iBottom = 1065, $ReturnBMP = False)
	_GDIPlus_BitmapDispose($hBitmap)
	_WinAPI_DeleteObject($hHBitmap)

	If $ichkBackground = 1 Then
		Local $iW = Number($iRight) - Number($iLeft), $iH = Number($iBottom) - Number($iTop)

		Local $hDC_Capture = _WinAPI_GetWindowDC(ControlGetHandle("BlueStacks App Player", "", "[CLASS:BlueStacksApp; INSTANCE:1]"))
		Local $hMemDC = _WinAPI_CreateCompatibleDC($hDC_Capture)
		$hHBitmap = _WinAPI_CreateCompatibleBitmap($hDC_Capture, $iW, $iH)
		Local $hObjectOld = _WinAPI_SelectObject($hMemDC, $hHBitmap)

		DllCall("user32.dll", "int", "PrintWindow", "hwnd", $HWnD, "handle", $hMemDC, "int", 0)
		_WinAPI_SelectObject($hMemDC, $hHBitmap)
		_WinAPI_BitBlt($hMemDC, 0, 0, $iW, $iH, $hDC_Capture, $iLeft, $iTop, 0x00CC0020)

		Global $hBitmap = _GDIPlus_BitmapCreateFromHBITMAP($hHBitmap)

		_WinAPI_DeleteDC($hMemDC)
		_WinAPI_SelectObject($hMemDC, $hObjectOld)
		_WinAPI_ReleaseDC($HWnD, $hDC_Capture)
	Else
		getBSPos()
		$hHBitmap = _ScreenCapture_Capture("", $iLeft + $BSpos[0], $iTop + $BSpos[1], $iRight + $BSpos[0], $iBottom + $BSpos[1])
		Global $hBitmap = _GDIPlus_BitmapCreateFromHBITMAP($hHBitmap)
	EndIf

	If $ReturnBMP Then Return $hBitmap
EndFunc   ;==>_CaptureRegion

Func getBSPos()
	$aPos = ControlGetPos($Title, "", "[CLASS:BlueStacksApp; INSTANCE:1]")
	$tPoint = DllStructCreate("int X;int Y")
	DllStructSetData($tPoint, "X", $aPos[0])
	DllStructSetData($tPoint, "Y", $aPos[1])
	_WinAPI_ClientToScreen(WinGetHandle(WinGetTitle($Title)), $tPoint)

	$BSpos[0] = DllStructGetData($tPoint, "X")
	$BSpos[1] = DllStructGetData($tPoint, "Y")
 EndFunc   ;==>getBSPos

 Func _PixelGetColor_GetPixel($iX, $iY)
	Local $aPixelColor = _GDIPlus_BitmapGetPixel($hBitmap, $iX, $iY)
	Return Hex($aPixelColor, 6)
 EndFunc   ;==>_PixelGetColor_GetPixel

 Func _ColorCheckVariation($nColor1, $nColor2, $sVari = 5)
	Local $Red1, $Red2, $Blue1, $Blue2, $Green1, $Green2

	$Red1 = Dec(StringMid(String($nColor1), 1, 2))
	$Blue1 = Dec(StringMid(String($nColor1), 3, 2))
	$Green1 = Dec(StringMid(String($nColor1), 5, 2))

	$Red2 = Dec(StringMid(String($nColor2), 1, 2))
	$Blue2 = Dec(StringMid(String($nColor2), 3, 2))
	$Green2 = Dec(StringMid(String($nColor2), 5, 2))

	If Abs($Blue1 - $Blue2) > $sVari Then Return False
	If Abs($Green1 - $Green2) > $sVari Then Return False
	If Abs($Red1 - $Red2) > $sVari Then Return False
	Return True
EndFunc   ;==>_ColorCheckVariation
Got something to add?

Log in to post a reply.

Join the conversation