public static Bitmap GetTemtemWindowScreenshot() { //Pointer to the Temtem Window IntPtr temtemWindow; //Get the currently focused window IntPtr focused = User32.GetForegroundWindow(); //If we're not focusing a window if (focused == IntPtr.Zero) { return(null); } //Check if the focused window is Temtem StringBuilder windowName = new StringBuilder(100); User32.GetWindowText(focused, windowName, 100); User32.GetWindowThreadProcessId(focused, out uint focusedWindowProcessID); //Inline variable declaration string focusedWindowProcessName = Process.GetProcessById((int)focusedWindowProcessID).ProcessName; if (windowName.ToString().Equals(WINDOW_NAME) && focusedWindowProcessName.Equals(WINDOW_NAME)) { temtemWindow = focused; } else { //We aren't in the right window return(null); } IntPtr hdcWindow = User32.GetDC(temtemWindow); User32.POINT lpPoint = new User32.POINT(); User32.GetClientRect(temtemWindow, out User32.RECT bounds); User32.ClientToScreen(temtemWindow, ref lpPoint); try { Bitmap bmp = new Bitmap((bounds.right - bounds.left), (bounds.bottom - bounds.top)); using (Graphics g = Graphics.FromImage(bmp)) { g.CopyFromScreen(lpPoint.X, lpPoint.Y, 0, 0, bmp.Size); g.Flush(); } //Release the device context User32.ReleaseDC(temtemWindow, hdcWindow); return(bmp); } catch (ArgumentException) { //This only seems to happen when the window is closing and we end up with a 0 width, 0 height game window rectangle //No intricate handling is necessary here, just return null and don't process it return(null); } }
private List <Bitmap> GetOCRViewportImages(User32.POINT lpPoint, List <Rectangle> OCRViewports) { List <Bitmap> viewportImages = new List <Bitmap>(); OCRViewports.ForEach(viewport => { Bitmap viewportBitmap = new Bitmap(viewport.Width, viewport.Height, PixelFormat.Format32bppArgb); using (Graphics g = Graphics.FromImage(viewportBitmap)) { g.CopyFromScreen(lpPoint.X + viewport.X, lpPoint.Y + viewport.Y, 0, 0, viewport.Size); } viewportImages.Add(viewportBitmap); }); return(viewportImages); }
private List <Color> GetBattleDetectionColors(TemtemWindowData windowData, User32.POINT lpPoint) { List <Color> detectionSpotColors = new List <Color>(); using (Bitmap pixel = new Bitmap(1, 1, PixelFormat.Format32bppArgb)) { using (Graphics g = Graphics.FromImage(pixel)) { for (int i = 0; i < 4; i++) { g.CopyFromScreen(new Point(lpPoint.X + windowData.detectionSpots[i].X, lpPoint.Y + windowData.detectionSpots[i].Y), new Point(0, 0), pixel.Size); detectionSpotColors.Add(pixel.GetPixel(0, 0)); } } } return(detectionSpotColors); }
public void Detect() { //Pointer to the Temtem Window IntPtr temtemWindow; //Get the currently focused window IntPtr focused = User32.GetForegroundWindow(); //If we're not focusing a window if (focused == IntPtr.Zero) { return; } //Check if the focused window is Temtem StringBuilder windowName = new StringBuilder(100); User32.GetWindowText(focused, windowName, 100); User32.GetWindowThreadProcessId(focused, out uint focusedWindowProcessID); //Inline variable declaration string focusedWindowProcessName = Process.GetProcessById((int)focusedWindowProcessID).ProcessName; if (windowName.ToString().Equals(WINDOW_NAME) && focusedWindowProcessName.Equals(WINDOW_NAME)) { temtemWindow = focused; //Here we check if this is one of our already detected windows and if not we add it if (!temtemWindows.ContainsKey(focusedWindowProcessID)) { temtemWindows.Add(focusedWindowProcessID, new TemtemWindowData { detectionSpots = new List <Point>(), OCRViewports = new List <Rectangle>(), gameWindowSize = new Size(0, 0), detectedBattle = false }); } } else { //We aren't in the right window return; } IntPtr hdcWindow = User32.GetDC(temtemWindow); User32.POINT lpPoint = new User32.POINT(); User32.GetClientRect(temtemWindow, out User32.RECT bounds); User32.ClientToScreen(temtemWindow, ref lpPoint); ////Release the device context User32.ReleaseDC(temtemWindow, hdcWindow); Rectangle gameWindowRect = new Rectangle(lpPoint.X, lpPoint.Y, (bounds.right - bounds.left), (bounds.bottom - bounds.top)); if (gameWindowRect.Height == 0 || gameWindowRect.Width == 0) { //If the rectangle is 0 high or wide, we've got a closing/closed window or an error return; } //If the game window dimensions have changed we need to recalculate all the spots. //This shouldn't happen often if (!gameWindowRect.Size.Equals(temtemWindows[focusedWindowProcessID].gameWindowSize)) { temtemWindows[focusedWindowProcessID].gameWindowSize = gameWindowRect.Size; RecalculateDetectionElements(temtemWindows[focusedWindowProcessID], gameWindowRect); } if (temtemWindows[focusedWindowProcessID].detectedBattle == false) { //We'll only test for battle if we aren't in a battle List <Color> pixelColors = GetBattleDetectionColors(temtemWindows[focusedWindowProcessID], lpPoint); //We'll also get the OCR reading spots right here. It's a waste of resources if we aren't detecting battle, but is faster and more reliable when we do List <Bitmap> viewportImages = GetOCRViewportImages(lpPoint, temtemWindows[focusedWindowProcessID].OCRViewports); if (((ColorDistance(pixelColors[0], spot1RGB) < maxAllowedColorDistance && ColorDistance(pixelColors[1], spot2RGB) < maxAllowedColorDistance) || (ColorDistance(pixelColors[2], spot3RGB) < maxAllowedColorDistance && ColorDistance(pixelColors[3], spot4RGB) < maxAllowedColorDistance))) { temtemWindows[focusedWindowProcessID].detectedBattle = true; //Do OCR operation. The OCR controller will dispose of the images so we're ok List <string> results = ocrController.DoOCR(viewportImages); results.ForEach(result => { //Here we add the detected Temtem to the UI tableController.AddTemtem(result); }); } } else if (temtemWindows[focusedWindowProcessID].detectedBattle == true) { //If we're in battle we'll test for being out of battle List <Color> pixelColors = GetOutOfBattleDetectionColors(temtemWindows[focusedWindowProcessID], lpPoint); if (ColorDistance(pixelColors[0], spot5RGB) < maxAllowedColorDistance && ColorDistance(pixelColors[1], spot6RGB) < maxAllowedColorDistance) { //Set battle to false temtemWindows[focusedWindowProcessID].detectedBattle = false; } } }