Advertisement
RexyBadDog

minecraft_fishing_bot.py

May 6th, 2023 (edited)
714
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 11.08 KB | Gaming | 0 0
  1. # TODO: add a way to stop the bot instead of CTRL + C
  2. # TODO: possible code duplication with x, y, h, w variables and window_dimensions[] in 'def capture_window(window_handle):' function
  3. #       maybe make a function that returns the x, y, h, w variables, but will lose the real time windows resizing functionality
  4. # Done: generate updated requirements.txt file
  5.  
  6. import os
  7. import sys
  8. import cv2
  9. import time
  10. import datetime
  11. import pytesseract
  12. import numpy
  13. import win32con
  14. import win32gui
  15. import pynput
  16. import win32ui
  17. from PIL import Image
  18.  
  19. phrase = "bobber splashes"
  20. pytesseract.pytesseract.tesseract_cmd = "C:\\Program Files\\Tesseract-OCR\\tesseract.exe"
  21.  
  22. # hotbar dictionary for key switwinch in Minecraft, the values are the number of items in the slot, or a keyword for the item
  23. # the slot 3 to 9 filled with a full stack - 1 becuase we need to reserve inventory space for the exp bottles. without it the inventory
  24. # will be filled with fishing drops
  25. hotbar = {
  26.     "1": 43,        # food slot
  27.     "2": "Rod",  # weapon slot
  28.     "3": 63,        # exp potion slot
  29.     "4": 63,        # exp potion slot
  30.     "5": 63,        # exp potion slot
  31.     "6": 63,        # exp potion slot
  32.     "7": 63,        # exp potion slot
  33.     "8": 63,        # exp potion slot
  34.     "9": 63         # exp potion slot
  35. }
  36.  
  37. # getting all the windows handles with the name "Minecraft" at the start into a list ::should be only ONE in the list!::
  38. def get_window_handles(winName):
  39.     def callback(handle, extra):
  40.         if win32gui.IsWindowVisible(handle) and win32gui.GetWindowText(handle)[0:9] == winName:
  41.             window_handles.append(handle)
  42.     window_handles = []
  43.     win32gui.EnumWindows(callback, None)
  44.     return window_handles
  45.  
  46. def capture_window(window_handle):
  47.     if window_handle is None:
  48.         window_handle = win32gui.GetDesktopWindow()
  49.     # getting Minecraft window dimensions into 4 variables for convenience of use
  50.     window_dimensions = win32gui.GetWindowRect(window_handle)
  51.     left = window_dimensions[0]
  52.     top = window_dimensions[1]
  53.     right = window_dimensions[2]
  54.     bottom = window_dimensions[3]
  55.     # setting the borders for the capture area (buttom-left side of the Minecraft window)
  56.     left_border = 8
  57.     right_border = 8
  58.     top_border = 30
  59.     bottom_border = 8
  60.     # calculating the capture area for cropping the screenshot
  61.     width = right - left - left_border - right_border
  62.     height = bottom - top - top_border - bottom_border
  63.     cropped_x = left_border
  64.     cropped_y = top_border
  65.     # capturing the screenshot based on the calculated dimensions
  66.     window_device_context = win32gui.GetWindowDC(window_handle)
  67.     device_context_object = win32ui.CreateDCFromHandle(window_device_context)
  68.     create_device_context = device_context_object.CreateCompatibleDC()
  69.     # creating a bitmap object for because the screenshot is a bitmap
  70.     data_bit_map = win32ui.CreateBitmap()
  71.     data_bit_map.CreateCompatibleBitmap(device_context_object, width, height)
  72.     create_device_context.SelectObject(data_bit_map)
  73.     # BitBlt is a Windows API function that copies the contents of one device context into another
  74.     create_device_context.BitBlt(
  75.         (0, 0),
  76.         (width, height),
  77.         device_context_object,
  78.         (cropped_x, cropped_y),
  79.         win32con.SRCCOPY,
  80.     )
  81.     # instead of saving the screenshot to a file, we can just get the raw data from the bitmap object
  82.     image = numpy.frombuffer(data_bit_map.GetBitmapBits(True), dtype="uint8")
  83.     # the 4 is for the number of color channels (RGB + alpha), may change it to 3 if the alpha channel is not needed
  84.     image.shape = (height, width, 4)
  85.     # releasing the device contexts and deleting the bitmap object, if we dont do this, we will get a memory leak
  86.     device_context_object.DeleteDC()
  87.     create_device_context.DeleteDC()
  88.     win32gui.ReleaseDC(window_handle, window_device_context)
  89.     win32gui.DeleteObject(data_bit_map.GetHandle())
  90.     return image
  91.  
  92. def type_a_command(command_string):
  93.     pynput.keyboard.Controller().press(pynput.keyboard.KeyCode.from_char("/"))
  94.     pynput.keyboard.Controller().release(pynput.keyboard.KeyCode.from_char("/"))
  95.     time.sleep(0.2)
  96.     pynput.keyboard.Controller().type(command_string[1:])
  97.     time.sleep(0.2)
  98.     pynput.keyboard.Controller().press(pynput.keyboard.Key.enter)
  99.     pynput.keyboard.Controller().release(pynput.keyboard.Key.enter)
  100.     time.sleep(0.2)
  101.     pynput.mouse.Controller().click(pynput.mouse.Button.left)
  102.     time.sleep(0.2)
  103.  
  104. def fill_exp_potions(hotbar):
  105.     # this function is for filling the empty bottles from the SlimeFun plugin with exp
  106.     if hotbar['3'] > 0:
  107.         hotbar['3'] = hotbar['3'] - 1
  108.         pynput.keyboard.Controller().type('3')
  109.         time.sleep(0.2)
  110.         pynput.mouse.Controller().click(pynput.mouse.Button.right)
  111.         time.sleep(0.2)
  112.     elif hotbar['4'] > 0:
  113.         hotbar['4'] = hotbar['4'] - 1
  114.         pynput.keyboard.Controller().type('4')
  115.         time.sleep(0.2)
  116.         pynput.mouse.Controller().click(pynput.mouse.Button.right)
  117.         time.sleep(0.2)
  118.     elif hotbar['5'] > 0:
  119.         hotbar['5'] = hotbar['5'] - 1
  120.         pynput.keyboard.Controller().type('5')
  121.         time.sleep(0.2)
  122.         pynput.mouse.Controller().click(pynput.mouse.Button.right)
  123.         time.sleep(0.2)
  124.     elif hotbar['6'] > 0:
  125.         hotbar['6'] = hotbar['6'] - 1
  126.         pynput.keyboard.Controller().type('6')
  127.         time.sleep(0.2)
  128.         pynput.mouse.Controller().click(pynput.mouse.Button.right)
  129.         time.sleep(0.2)
  130.     elif hotbar['7'] > 0:
  131.         hotbar['7'] = hotbar['7'] - 1
  132.         pynput.keyboard.Controller().type('7')
  133.         time.sleep(0.2)
  134.         pynput.mouse.Controller().click(pynput.mouse.Button.right)
  135.         time.sleep(0.2)
  136.     elif hotbar['8'] > 0:
  137.         hotbar['8'] = hotbar['8'] - 1
  138.         pynput.keyboard.Controller().type('8')
  139.         time.sleep(0.2)
  140.         pynput.mouse.Controller().click(pynput.mouse.Button.right)
  141.         time.sleep(0.2)
  142.     elif hotbar['9'] > 0:
  143.         hotbar['9'] = hotbar['9'] - 1
  144.         pynput.keyboard.Controller().type('9')
  145.         time.sleep(0.2)
  146.         pynput.mouse.Controller().click(pynput.mouse.Button.right)
  147.         time.sleep(0.2)
  148.     # switch back to fishing rod slot which is "2"
  149.     pynput.keyboard.Controller().type('2')
  150.     time.sleep(0.2)
  151.     #return hotbar
  152.  
  153. def eat(hotbar):
  154.     # this function is for eating food from the food slot in the hotbar
  155.     if hotbar['1'] > 0:
  156.         hotbar['1'] = hotbar['1'] - 1
  157.         pynput.keyboard.Controller().type('1')
  158.         time.sleep(0.2)
  159.         # eat
  160.         pynput.mouse.Controller().click(pynput.mouse.Button.right)
  161.         # switch back to fishing rod slot which is "2"
  162.         pynput.keyboard.Controller().type('2')
  163.     #return hotbar
  164.  
  165. def main():
  166.     fishing_count = 0
  167.     left_right = False
  168.     while True:
  169.         if len(get_window_handles("Minecraft")) == 0:
  170.             print("Error: no windows with the name \"Minecraft\" were found")
  171.             break
  172.         screenshot = capture_window(get_window_handles("Minecraft")[0])
  173.         x, y, w, h = (
  174.             # this will limit the capture area to the buttom-left side of the Minecraft window
  175.             screenshot.shape[1] * 3 // 4,
  176.             screenshot.shape[0] * 3 // 4,
  177.             screenshot.shape[1] // 4,
  178.             screenshot.shape[0] // 4,
  179.         )
  180.         screenshot = screenshot[y : y + h, x : x + w]
  181.         screenshot_filter = cv2.cvtColor(screenshot, cv2.COLOR_BGR2GRAY)
  182.         text = pytesseract.image_to_string(
  183.             cv2.threshold(screenshot_filter, 220, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)[1]
  184.         )
  185.         # print("debug: text value is: ", text)
  186.         if phrase in text.lower():
  187.             print("fish on, ", end=" ")
  188.             pynput.mouse.Controller().click(pynput.mouse.Button.right)
  189.             fishing_count += 1
  190.             print("bobber retrieved, num: {},".format(fishing_count) , end=" ")
  191.             time.sleep(0.4)
  192.             # fill exp bottles every 3 fishings
  193.             if (fishing_count % 3) == 0:
  194.                 time.sleep(0.5)
  195.                 fill_exp_potions(hotbar)
  196.                 time.sleep(0.9)
  197.             # eat every 10 fishings
  198.             # rotate the camera back and forth every fishing
  199.             if left_right:
  200.                 pynput.mouse.Controller().move(400, 0)
  201.                 left_right = False
  202.                 print("Moved to the Right")
  203.             else:
  204.                 pynput.mouse.Controller().move(-400, 0)
  205.                 left_right = True
  206.                 print("Moved to the Left")
  207.                 # executing the /balance command to track how much money you get from fishing (/jobs plugin)
  208.                 # type_a_command("/bal")
  209.             time.sleep(0.8)
  210.             pynput.mouse.Controller().click(pynput.mouse.Button.right)
  211.             print("bobbern thrown,", end=" ")
  212.             time.sleep(2.5)
  213.  
  214.         # converting the screenshot into grayscale and then back to BGR and finally trimming to the same color channels as the screenshot
  215.         screenshot_filter = cv2.cvtColor(screenshot, cv2.COLOR_BGR2GRAY)
  216.         screenshot_filter = cv2.cvtColor(screenshot_filter, cv2.COLOR_GRAY2BGR)
  217.         screenshot = screenshot[:,:,:3]
  218.         tess_view = cv2.threshold(cv2.cvtColor(screenshot, cv2.COLOR_BGR2GRAY), 128, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)[1]
  219.         tess_view = cv2.cvtColor(tess_view, cv2.COLOR_GRAY2BGR)
  220.  
  221.         """
  222.        # attempting adaptiveThreshold to see if the text readbilty from the screenshot is easier for the Tesseract
  223.        tess_view2 = cv2.adaptiveThreshold(cv2.cvtColor(screenshot, cv2.COLOR_BGR2GRAY),255,cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY,11,2)
  224.        tess_view2 = cv2.cvtColor(tess_view2, cv2.COLOR_GRAY2BGR)
  225.  
  226.        # testing print for image shapes , ALL image output have to be the same size AND same color format in order to stack in numpy imshow
  227.        print("screenshot\t", screenshot.shape)
  228.        print("screenshot_filter\t", screenshot_filter.shape)
  229.        print("teseract\t", tess_view.shape)
  230.        print("teseract2\t", tess_view2.shape)
  231.        """
  232.  
  233.         cv2.imshow("Computer Vision - ALL", numpy.vstack((
  234.             screenshot
  235.             ,screenshot_filter
  236.             ,tess_view
  237.             #,tess_view2
  238.             )))
  239.  
  240.         if cv2.waitKey(1) == ord("q"):
  241.             cv2.destroyAllWindows()
  242.             break
  243.  
  244.  
  245.  
  246. if __name__ == "__main__":
  247.     start_time = datetime.datetime.now().time()
  248.     end_time = datetime.datetime.now().time()
  249.     print("starting fishing at: {}".format(start_time))
  250.     try:
  251.         main()
  252.     except KeyboardInterrupt:
  253.         # execute the next lines after KeyboardInterrupt: Ctrl+C
  254.         end_time = datetime.datetime.now().time()
  255.         td_start = datetime.timedelta(hours=start_time.hour, minutes=start_time.minute, seconds=start_time.second)
  256.         td_end = datetime.timedelta(hours=end_time.hour, minutes=end_time.minute, seconds=end_time.second)
  257.         print("fished for: {} (hh:mm:ss)".format(td_end - td_start))
  258.         try:
  259.             sys.exit(130)
  260.         except SystemExit:
  261.             os._exit(130)
  262.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement