|
|
@@ -11,12 +11,12 @@ from PIL import Image
|
|
|
client = AdbClient(host="127.0.0.1", port=5037)
|
|
|
device = client.device("192.168.178.32:5555")
|
|
|
|
|
|
-# template positions
|
|
|
-close_sub_fights = cv2.imread('templates/close_sub_fights.jpg')
|
|
|
-close_fight = cv2.imread('templates/close_fight.jpg')
|
|
|
-fight_button = cv2.imread('templates/i.jpg')
|
|
|
-end_of_log = cv2.imread('templates/end_of_log.jpg')
|
|
|
-end_of_log2 = cv2.imread('templates/end_of_log2.jpg')
|
|
|
+# templates
|
|
|
+close_sub_fights = cv2.imread("templates/close_sub_fights.jpg")
|
|
|
+close_fight = cv2.imread("templates/close_fight.jpg")
|
|
|
+fight_button = cv2.imread("templates/i.jpg")
|
|
|
+end_of_log = cv2.imread("templates/end_of_log.jpg")
|
|
|
+end_of_log2 = cv2.imread("templates/end_of_log2.jpg")
|
|
|
|
|
|
# cursor positions
|
|
|
fight_scroll_top = "2200 626"
|
|
|
@@ -27,160 +27,172 @@ close_details = "2175 450"
|
|
|
close_titan_fight = "2650 570"
|
|
|
defense_log = "350 870"
|
|
|
|
|
|
+
|
|
|
def non_max_suppression(boxes, overlapThresh):
|
|
|
- if len(boxes) == 0:
|
|
|
- return []
|
|
|
+ if len(boxes) == 0:
|
|
|
+ return []
|
|
|
+
|
|
|
+ # Convert to float
|
|
|
+ boxes = np.array(boxes, dtype="float")
|
|
|
|
|
|
- # Convert to float
|
|
|
- boxes = np.array(boxes, dtype="float")
|
|
|
+ # Initialize the list of picked indexes
|
|
|
+ pick = []
|
|
|
|
|
|
- # Initialize the list of picked indexes
|
|
|
- pick = []
|
|
|
+ # Grab the coordinates of the bounding boxes
|
|
|
+ x1 = boxes[:, 0]
|
|
|
+ y1 = boxes[:, 1]
|
|
|
+ x2 = boxes[:, 2]
|
|
|
+ y2 = boxes[:, 3]
|
|
|
|
|
|
- # Grab the coordinates of the bounding boxes
|
|
|
- x1 = boxes[:,0]
|
|
|
- y1 = boxes[:,1]
|
|
|
- x2 = boxes[:,2]
|
|
|
- y2 = boxes[:,3]
|
|
|
+ # Compute the area of the bounding boxes and sort by bottom-right y-coordinate
|
|
|
+ area = (x2 - x1 + 1) * (y2 - y1 + 1)
|
|
|
+ idxs = np.argsort(y2)
|
|
|
|
|
|
- # Compute the area of the bounding boxes and sort by bottom-right y-coordinate
|
|
|
- area = (x2 - x1 + 1) * (y2 - y1 + 1)
|
|
|
- idxs = np.argsort(y2)
|
|
|
+ # Keep looping while some indexes still remain in the indexes list
|
|
|
+ while len(idxs) > 0:
|
|
|
+ # Grab the last index in the indexes list and add the index value to the list of picked indexes
|
|
|
+ last = len(idxs) - 1
|
|
|
+ i = idxs[last]
|
|
|
+ pick.append(i)
|
|
|
|
|
|
- # Keep looping while some indexes still remain in the indexes list
|
|
|
- while len(idxs) > 0:
|
|
|
- # Grab the last index in the indexes list and add the index value to the list of picked indexes
|
|
|
- last = len(idxs) - 1
|
|
|
- i = idxs[last]
|
|
|
- pick.append(i)
|
|
|
+ # Find the largest (x, y) coordinates for the start of the bounding box and the smallest (x, y)
|
|
|
+ # coordinates for the end of the bounding box
|
|
|
+ xx1 = np.maximum(x1[i], x1[idxs[:last]])
|
|
|
+ yy1 = np.maximum(y1[i], y1[idxs[:last]])
|
|
|
+ xx2 = np.minimum(x2[i], x2[idxs[:last]])
|
|
|
+ yy2 = np.minimum(y2[i], y2[idxs[:last]])
|
|
|
|
|
|
- # Find the largest (x, y) coordinates for the start of the bounding box and the smallest (x, y)
|
|
|
- # coordinates for the end of the bounding box
|
|
|
- xx1 = np.maximum(x1[i], x1[idxs[:last]])
|
|
|
- yy1 = np.maximum(y1[i], y1[idxs[:last]])
|
|
|
- xx2 = np.minimum(x2[i], x2[idxs[:last]])
|
|
|
- yy2 = np.minimum(y2[i], y2[idxs[:last]])
|
|
|
+ # Compute the width and height of the bounding box
|
|
|
+ w = np.maximum(0, xx2 - xx1 + 1)
|
|
|
+ h = np.maximum(0, yy2 - yy1 + 1)
|
|
|
|
|
|
- # Compute the width and height of the bounding box
|
|
|
- w = np.maximum(0, xx2 - xx1 + 1)
|
|
|
- h = np.maximum(0, yy2 - yy1 + 1)
|
|
|
+ # Compute the ratio of overlap
|
|
|
+ overlap = (w * h) / area[idxs[:last]]
|
|
|
|
|
|
- # Compute the ratio of overlap
|
|
|
- overlap = (w * h) / area[idxs[:last]]
|
|
|
+ # Delete all indexes from the index list that have overlap greater than the threshold
|
|
|
+ idxs = np.delete(
|
|
|
+ idxs, np.concatenate(([last], np.where(overlap > overlapThresh)[0]))
|
|
|
+ )
|
|
|
|
|
|
- # Delete all indexes from the index list that have overlap greater than the threshold
|
|
|
- idxs = np.delete(idxs, np.concatenate(([last], np.where(overlap > overlapThresh)[0])))
|
|
|
+ # Return only the bounding boxes that were picked
|
|
|
+ return boxes[pick].astype("int")
|
|
|
|
|
|
- # Return only the bounding boxes that were picked
|
|
|
- return boxes[pick].astype("int")
|
|
|
|
|
|
def screen_has_changed(prev_screenshot, threshold=0.01):
|
|
|
- # Take a new screenshot
|
|
|
- current_screenshot = device.screencap()
|
|
|
+ # Take a new screenshot
|
|
|
+ current_screenshot = device.screencap()
|
|
|
|
|
|
- # Convert to NumPy arrays
|
|
|
- prev_img = np.frombuffer(prev_screenshot, dtype=np.uint8)
|
|
|
- current_img = np.frombuffer(current_screenshot, dtype=np.uint8)
|
|
|
+ # Convert to NumPy arrays
|
|
|
+ prev_img = np.frombuffer(prev_screenshot, dtype=np.uint8)
|
|
|
+ current_img = np.frombuffer(current_screenshot, dtype=np.uint8)
|
|
|
|
|
|
- # Load images
|
|
|
- prev_img = cv2.imdecode(prev_img, cv2.IMREAD_COLOR)
|
|
|
- current_img = cv2.imdecode(current_img, cv2.IMREAD_COLOR)
|
|
|
+ # Load images
|
|
|
+ prev_img = cv2.imdecode(prev_img, cv2.IMREAD_COLOR)
|
|
|
+ current_img = cv2.imdecode(current_img, cv2.IMREAD_COLOR)
|
|
|
|
|
|
- # Calculate absolute difference
|
|
|
- diff = cv2.absdiff(prev_img, current_img)
|
|
|
- non_zero_count = np.count_nonzero(diff)
|
|
|
+ # Calculate absolute difference
|
|
|
+ diff = cv2.absdiff(prev_img, current_img)
|
|
|
+ non_zero_count = np.count_nonzero(diff)
|
|
|
|
|
|
- # print(f"diff: {non_zero_count} > {threshold * diff.size} = {non_zero_count > threshold * diff.size}")
|
|
|
+ # print(f"diff: {non_zero_count} > {threshold * diff.size} = {non_zero_count > threshold * diff.size}")
|
|
|
+
|
|
|
+ # Check if the difference is greater than the threshold
|
|
|
+ return non_zero_count > threshold * diff.size
|
|
|
|
|
|
- # Check if the difference is greater than the threshold
|
|
|
- return non_zero_count > threshold * diff.size
|
|
|
|
|
|
def save_screenshot():
|
|
|
- # Take a screenshot
|
|
|
- result = device.screencap()
|
|
|
+ # Take a screenshot
|
|
|
+ result = device.screencap()
|
|
|
+
|
|
|
+ timestamp = datetime.datetime.now().strftime("%Y%m%d_%H%M%S")
|
|
|
+ image = Image.open(io.BytesIO(result))
|
|
|
+ jpeg_filename = f"/mnt/t/nextcloud/InstantUpload/Herowars/{timestamp}.jpg"
|
|
|
|
|
|
- timestamp = datetime.datetime.now().strftime("%Y%m%d_%H%M%S")
|
|
|
- image = Image.open(io.BytesIO(result))
|
|
|
- jpeg_filename = f"/mnt/t/nextcloud/InstantUpload/Herowars/{timestamp}.jpg"
|
|
|
+ image = image.convert("RGB") # Convert to RGB mode for JPEG
|
|
|
+ with open(jpeg_filename, "wb") as fp:
|
|
|
+ image.save(fp, format="JPEG", quality=85) # Adjust quality as needed
|
|
|
|
|
|
- image = image.convert('RGB') # Convert to RGB mode for JPEG
|
|
|
- with open(jpeg_filename, "wb") as fp:
|
|
|
- image.save(fp, format='JPEG', quality=85) # Adjust quality as needed
|
|
|
+ time.sleep(0.5)
|
|
|
|
|
|
- time.sleep(0.5)
|
|
|
|
|
|
def wait_for_screen_change():
|
|
|
- # Usage example
|
|
|
- prev_screenshot = device.screencap()
|
|
|
+ # Usage example
|
|
|
+ prev_screenshot = device.screencap()
|
|
|
+
|
|
|
+ while not screen_has_changed(prev_screenshot):
|
|
|
+ time.sleep(0.1) # Polling interval
|
|
|
|
|
|
- while not screen_has_changed(prev_screenshot):
|
|
|
- time.sleep(0.1) # Polling interval
|
|
|
|
|
|
def tap(location):
|
|
|
- device.shell(f"input tap {location}")
|
|
|
- time.sleep(1)
|
|
|
+ device.shell(f"input tap {location}")
|
|
|
+ time.sleep(1)
|
|
|
+
|
|
|
|
|
|
def swipe(start, end):
|
|
|
- device.shell(f"input swipe {start} {end} 1000")
|
|
|
- time.sleep(0.5)
|
|
|
+ device.shell(f"input swipe {start} {end} 1000")
|
|
|
+ time.sleep(0.5)
|
|
|
+
|
|
|
|
|
|
def tap_button(template):
|
|
|
- button = find_templates(template)
|
|
|
- if len(button) == 0:
|
|
|
- return
|
|
|
- tap(f"{button[0][0]} {button[0][1]}")
|
|
|
+ button = find_templates(template)
|
|
|
+ if len(button) == 0:
|
|
|
+ return
|
|
|
+ tap(f"{button[0][0]} {button[0][1]}")
|
|
|
+
|
|
|
|
|
|
def is_end_of_log():
|
|
|
- templates = find_templates(end_of_log)
|
|
|
- if (len(templates) == 0):
|
|
|
- templates = find_templates(end_of_log2)
|
|
|
+ templates = find_templates(end_of_log)
|
|
|
+ if len(templates) == 0:
|
|
|
+ templates = find_templates(end_of_log2)
|
|
|
|
|
|
- result = len(templates) > 0
|
|
|
+ result = len(templates) > 0
|
|
|
|
|
|
- if result:
|
|
|
- print("reached end of guild war log!")
|
|
|
+ if result:
|
|
|
+ print("reached end of guild war log!")
|
|
|
+
|
|
|
+ return result
|
|
|
|
|
|
- return result
|
|
|
|
|
|
def find_templates(template_image):
|
|
|
- screenshot = device.screencap()
|
|
|
- target_image = Image.open(BytesIO(screenshot))
|
|
|
+ screenshot = device.screencap()
|
|
|
+ target_image = Image.open(BytesIO(screenshot))
|
|
|
+
|
|
|
+ # Convert the image to a NumPy array and then to BGR format (which OpenCV uses)
|
|
|
+ target_image = np.array(target_image)
|
|
|
+ target_image = cv2.cvtColor(target_image, cv2.COLOR_RGB2BGR)
|
|
|
|
|
|
- # Convert the image to a NumPy array and then to BGR format (which OpenCV uses)
|
|
|
- target_image = np.array(target_image)
|
|
|
- target_image = cv2.cvtColor(target_image, cv2.COLOR_RGB2BGR)
|
|
|
+ w, h = template_image.shape[:-1]
|
|
|
|
|
|
- w, h = template_image.shape[:-1]
|
|
|
+ # Template matching
|
|
|
+ result = cv2.matchTemplate(target_image, template_image, cv2.TM_CCOEFF_NORMED)
|
|
|
|
|
|
- # Template matching
|
|
|
- result = cv2.matchTemplate(target_image, template_image, cv2.TM_CCOEFF_NORMED)
|
|
|
+ # Define a threshold
|
|
|
+ threshold = 0.9 # Adjust this threshold based on your requirements
|
|
|
|
|
|
- # Define a threshold
|
|
|
- threshold = 0.9 # Adjust this threshold based on your requirements
|
|
|
+ # Finding all locations where match exceeds threshold
|
|
|
+ locations = np.where(result >= threshold)
|
|
|
+ locations = list(zip(*locations[::-1]))
|
|
|
|
|
|
- # Finding all locations where match exceeds threshold
|
|
|
- locations = np.where(result >= threshold)
|
|
|
- locations = list(zip(*locations[::-1]))
|
|
|
+ # Create list of rectangles
|
|
|
+ rectangles = [(*loc, loc[0] + w, loc[1] + h) for loc in locations]
|
|
|
|
|
|
- # Create list of rectangles
|
|
|
- rectangles = [(*loc, loc[0] + w, loc[1] + h) for loc in locations]
|
|
|
+ # Apply non-maximum suppression to remove overlaps
|
|
|
+ rectangles = non_max_suppression(rectangles, 0.3)
|
|
|
|
|
|
- # Apply non-maximum suppression to remove overlaps
|
|
|
- rectangles = non_max_suppression(rectangles, 0.3)
|
|
|
+ # Initialize an empty list to store coordinates
|
|
|
+ coordinates = []
|
|
|
|
|
|
- # Initialize an empty list to store coordinates
|
|
|
- coordinates = []
|
|
|
+ for startX, startY, endX, endY in rectangles:
|
|
|
+ # Calculate the center coordinates
|
|
|
+ centerX = round(startX + (endX - startX) / 2)
|
|
|
+ centerY = round(startY + (endY - startY) / 2)
|
|
|
|
|
|
- for (startX, startY, endX, endY) in rectangles:
|
|
|
- # Calculate the center coordinates
|
|
|
- centerX = round(startX + (endX - startX) / 2)
|
|
|
- centerY = round(startY + (endY - startY) / 2)
|
|
|
+ # Append the coordinate pair to the list
|
|
|
+ coordinates.append((centerX, centerY))
|
|
|
|
|
|
- # Append the coordinate pair to the list
|
|
|
- coordinates.append((centerX, centerY))
|
|
|
+ # Sort the coordinates by y value in ascending order
|
|
|
+ return sorted(coordinates, key=lambda x: x[1])
|
|
|
|
|
|
- # Sort the coordinates by y value in ascending order
|
|
|
- return sorted(coordinates, key=lambda x: x[1])
|
|
|
|
|
|
def find_max_y_pair(coordinates):
|
|
|
# find the coordinate pair with the maximum y value
|
|
|
@@ -188,40 +200,43 @@ def find_max_y_pair(coordinates):
|
|
|
|
|
|
return f"{result[0]} {result[1]}"
|
|
|
|
|
|
+
|
|
|
def take_fight_screenshots():
|
|
|
- save_screenshot()
|
|
|
+ save_screenshot()
|
|
|
+
|
|
|
+ # # if you desperately need submits
|
|
|
+ # tap(damage_taken)
|
|
|
+ # save_screenshot()
|
|
|
|
|
|
- # # if you desperately need submits
|
|
|
- # tap(damage_taken)
|
|
|
- # save_screenshot()
|
|
|
+ tap_button(close_fight)
|
|
|
+ time.sleep(1)
|
|
|
|
|
|
- tap_button(close_fight)
|
|
|
- time.sleep(1)
|
|
|
|
|
|
def process_war_log():
|
|
|
- buttons = find_templates(fight_button)
|
|
|
-
|
|
|
- if len(buttons) == 0:
|
|
|
- swipe(fight_scroll_bottom, fight_scroll_top)
|
|
|
- return
|
|
|
-
|
|
|
- # process all found buttons
|
|
|
- for pair in buttons:
|
|
|
- tap(f"{pair[0]} {pair[1]}")
|
|
|
- sub_buttons = find_templates(fight_button)
|
|
|
- if (len(sub_buttons) == 0):
|
|
|
- take_fight_screenshots()
|
|
|
- else:
|
|
|
- for pair2 in sub_buttons:
|
|
|
- tap(f"{pair2[0]} {pair2[1]}")
|
|
|
- take_fight_screenshots()
|
|
|
- tap_button(close_sub_fights)
|
|
|
-
|
|
|
- swipe(find_max_y_pair(buttons), fight_scroll_top)
|
|
|
+ buttons = find_templates(fight_button)
|
|
|
+
|
|
|
+ if len(buttons) == 0:
|
|
|
+ swipe(fight_scroll_bottom, fight_scroll_top)
|
|
|
+ return
|
|
|
+
|
|
|
+ # process all found buttons
|
|
|
+ for pair in buttons:
|
|
|
+ tap(f"{pair[0]} {pair[1]}")
|
|
|
+ sub_buttons = find_templates(fight_button)
|
|
|
+ if len(sub_buttons) == 0:
|
|
|
+ take_fight_screenshots()
|
|
|
+ else:
|
|
|
+ for pair2 in sub_buttons:
|
|
|
+ tap(f"{pair2[0]} {pair2[1]}")
|
|
|
+ take_fight_screenshots()
|
|
|
+ tap_button(close_sub_fights)
|
|
|
+
|
|
|
+ swipe(find_max_y_pair(buttons), fight_scroll_top)
|
|
|
+
|
|
|
|
|
|
# start
|
|
|
while not is_end_of_log():
|
|
|
- process_war_log();
|
|
|
+ process_war_log()
|
|
|
|
|
|
# possible duplicates here, but necessary to be sure to get the last fights
|
|
|
-process_war_log();
|
|
|
+process_war_log()
|