|
|
@@ -0,0 +1,210 @@
|
|
|
+import cv2
|
|
|
+import time
|
|
|
+import datetime
|
|
|
+import numpy as np
|
|
|
+from PIL import Image
|
|
|
+from io import BytesIO
|
|
|
+from ppadb.client import Client as AdbClient
|
|
|
+
|
|
|
+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')
|
|
|
+
|
|
|
+# cursor positions
|
|
|
+fight_scroll_top = "2494 626"
|
|
|
+titan_fight = "1400 860"
|
|
|
+damage_taken = "450 850"
|
|
|
+close_details = "2175 450"
|
|
|
+close_titan_fight = "2650 570"
|
|
|
+
|
|
|
+def non_max_suppression(boxes, overlapThresh):
|
|
|
+ if len(boxes) == 0:
|
|
|
+ return []
|
|
|
+
|
|
|
+ # Convert to float
|
|
|
+ boxes = np.array(boxes, dtype="float")
|
|
|
+
|
|
|
+ # 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]
|
|
|
+
|
|
|
+ # 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)
|
|
|
+
|
|
|
+ # 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 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])))
|
|
|
+
|
|
|
+ # 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()
|
|
|
+
|
|
|
+ # 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)
|
|
|
+
|
|
|
+ # 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}")
|
|
|
+
|
|
|
+ # 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()
|
|
|
+
|
|
|
+ timestamp = datetime.datetime.now().strftime("%Y%m%d_%H%M%S")
|
|
|
+ filename = f"fights/{timestamp}.png"
|
|
|
+
|
|
|
+ # Save the screenshot to a file
|
|
|
+ with open(filename, "wb") as fp:
|
|
|
+ fp.write(result)
|
|
|
+
|
|
|
+ time.sleep(0.5)
|
|
|
+
|
|
|
+def wait_for_screen_change():
|
|
|
+ # Usage example
|
|
|
+ prev_screenshot = device.screencap()
|
|
|
+
|
|
|
+ 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)
|
|
|
+
|
|
|
+def swipe(start, end):
|
|
|
+ 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]}")
|
|
|
+
|
|
|
+def is_end_of_log(template):
|
|
|
+ templates = find_templates(template)
|
|
|
+ result = len(templates) > 0
|
|
|
+ if result:
|
|
|
+ print(templates)
|
|
|
+ print("reached end of guild war log!")
|
|
|
+
|
|
|
+ return result
|
|
|
+
|
|
|
+def find_templates(template_image):
|
|
|
+ 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)
|
|
|
+
|
|
|
+ w, h = template_image.shape[:-1]
|
|
|
+
|
|
|
+ # 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
|
|
|
+
|
|
|
+ # 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]
|
|
|
+
|
|
|
+ # Apply non-maximum suppression to remove overlaps
|
|
|
+ rectangles = non_max_suppression(rectangles, 0.3)
|
|
|
+
|
|
|
+ # 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)
|
|
|
+
|
|
|
+ # Append the coordinate pair to the list
|
|
|
+ coordinates.append((centerX, centerY))
|
|
|
+
|
|
|
+ return coordinates
|
|
|
+
|
|
|
+def find_max_y_pair(coordinates):
|
|
|
+ # find the coordinate pair with the maximum y value
|
|
|
+ result = max(coordinates, key=lambda x: x[1])
|
|
|
+
|
|
|
+ return f"{result[0]} {result[1]}"
|
|
|
+
|
|
|
+def take_fight_screenshots():
|
|
|
+ save_screenshot()
|
|
|
+ tap(damage_taken)
|
|
|
+ save_screenshot()
|
|
|
+ tap_button(close_fight)
|
|
|
+
|
|
|
+def process_war_log():
|
|
|
+ buttons = find_templates(fight_button)
|
|
|
+
|
|
|
+ # 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)
|
|
|
+
|
|
|
+ find_max_y_pair(buttons)
|
|
|
+ swipe(find_max_y_pair(buttons), fight_scroll_top)
|
|
|
+
|
|
|
+# start
|
|
|
+while True:
|
|
|
+ process_war_log();
|
|
|
+
|
|
|
+ if is_end_of_log(end_of_log):
|
|
|
+ break;
|