0
0
mirror of https://github.com/ok-oldking/ok-wuthering-waves.git synced 2025-06-03 09:25:19 +00:00

优化有时会提前跳出战斗的问题

This commit is contained in:
firedcto@gmail.com 2024-09-24 17:46:44 +08:00
parent c63210f119
commit 4bcb995306
4 changed files with 199 additions and 188 deletions

View File

@ -1,10 +1,6 @@
import time
import cv2
import numpy as np
from enum import IntEnum, StrEnum
from ok.color.Color import color_range_to_bound
from ok.config.Config import Config
from ok.logging.Logger import get_logger
from src import text_white_color
@ -357,63 +353,11 @@ class BaseChar:
return time.time() - self.last_echo > self.echo_cd
def is_con_full(self):
return self.get_current_con() == 1
return self.task.is_con_full()
def get_current_con(self):
box = self.task.box_of_screen_scaled(3840, 2160, 1422, 1939, to_x=1566, to_y=2076, name='con_full',
hcenter=True)
box.confidence = 0
max_area = 0
percent = 0
max_is_full = False
color_index = -1
target_index = self.config.get('_ring_color_index', -1)
cropped = box.crop_frame(self.task.frame)
for i in range(len(con_colors)):
if target_index != -1 and i != target_index:
continue
color_range = con_colors[i]
area, is_full = self.count_rings(cropped, color_range,
1500 / 3840 / 2160 * self.task.screen_width * self.task.screen_height)
# self.logger.debug(f'is_con_full test color_range {color_range} {area, is_full}')
if is_full:
max_is_full = is_full
color_index = i
if area > max_area:
max_area = int(area)
if max_is_full:
self.logger.info(
f'is_con_full found a full ring {self.config.get("_full_ring_area", 0)} -> {max_area} {color_index}')
self.config['_full_ring_area'] = max_area
self.config['_ring_color_index'] = color_index
self.logger.info(
f'is_con_full2 found a full ring {self.config.get("_full_ring_area", 0)} -> {max_area} {color_index}')
if self.config.get('_full_ring_area', 0) > 0:
percent = max_area / self.config['_full_ring_area']
if not max_is_full and percent >= 1:
self.logger.warning(
f'is_con_full not full but percent greater than 1, set to 0.99, {percent} {max_is_full}')
# self.task.screenshot(
# f'is_con_full not full but percent greater than 1, set to 0.99, {percent} {max_is_full}',
# cropped)
percent = 0.99
if percent > 1:
self.logger.error(f'is_con_full percent greater than 1, set to 1, {percent} {max_is_full}')
self.task.screenshot(f'is_con_full percent greater than 1, set to 1, {percent} {max_is_full}', cropped)
percent = 1
# self.logger.info(
# f'is_con_full {self} {percent} {max_area}/{self.config.get("_full_ring_area", 0)} {color_index} ')
# if self.task.debug:
# self.task.screenshot(
# f'is_con_full {self} {percent} {max_area}/{self.config.get("_full_ring_area", 0)} {color_index} ',
# cropped)
box.confidence = percent
self.current_con = percent
self.task.draw_boxes(f'is_con_full_{self}', box)
if percent > 1:
percent = 1
return percent
self.current_con = self.task.get_current_con()
return self.current_con
def is_forte_full(self):
box = self.task.box_of_screen_scaled(3840, 2160, 2251, 1993, 2311, 2016, name='forte_full', hcenter=True)
@ -443,17 +387,6 @@ class BaseChar:
return False
else:
return self.is_available(snap, 'liberation')
# else:
# mark_to_check = char_lib_check_marks[self.index]
# box = self.task.get_box_by_name(mark_to_check)
# box = box.copy(x_offset=-box.width, y_offset=-box.height, width_offset=box.width * 2,
# height_offset=box.height * 2)
# for match in char_lib_check_marks:
# mark = self.task.find_one(match, box=box, canny_lower=10, canny_higher=80, threshold=0.8)
# if mark is not None:
# self.logger.debug(f'{self.__repr__()} liberation ready by checking mark {mark}')
# self.liberation_available_mark = True
# return True
def __str__(self):
return self.__repr__()
@ -495,77 +428,6 @@ class BaseChar:
def flying(self):
return self.current_resonance() == 0
def count_rings(self, image, color_range, min_area):
# Define the color range
lower_bound, upper_bound = color_range_to_bound(color_range)
image_with_contours = image.copy()
# Create a binary mask
mask = cv2.inRange(image, lower_bound, upper_bound)
# Find connected components
num_labels, labels, stats, centroids = cv2.connectedComponentsWithStats(mask, connectivity=8)
colors = [
(0, 255, 0), # Green
(0, 0, 255), # Red
(255, 0, 0), # Blue
(0, 255, 255), # Yellow
(255, 0, 255), # Magenta
(255, 255, 0) # Cyan
]
# Function to check if a component forms a ring
def is_full_ring(component_mask):
# Find contours
contours, _ = cv2.findContours(component_mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
if len(contours) != 1:
return False
contour = contours[0]
# Check if the contour is closed by checking if the start and end points are the same
# if cv2.arcLength(contour, True) > 0:
# return True
# Approximate the contour with polygons.
epsilon = 0.05 * cv2.arcLength(contour, True)
approx = cv2.approxPolyDP(contour, epsilon, True)
# Check if the polygon is closed (has no gaps) and has a reasonable number of vertices for a ring.
if not cv2.isContourConvex(approx) or len(approx) < 4:
return False
# All conditions met, likely a close ring.
return True
# Iterate over each component
ring_count = 0
is_full = False
the_area = 0
for label in range(1, num_labels):
x, y, width, height, area = stats[label, :5]
bounding_box_area = width * height
component_mask = (labels == label).astype(np.uint8) * 255
contours, _ = cv2.findContours(component_mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
color = colors[label % len(colors)]
cv2.drawContours(image_with_contours, contours, -1, color, 2)
if bounding_box_area >= min_area:
# Select a color from the list based on the label index
if is_full_ring(component_mask):
is_full = True
the_area = area
ring_count += 1
# if self.task.debug:
# Save or display the image with contours
# cv2.imwrite(f'test\\test_{self}_{is_full}_{the_area}_{lower_bound}.jpg', image_with_contours)
if ring_count > 1:
is_full = False
the_area = 0
self.logger.warning(f'is_con_full found multiple rings {ring_count}')
return the_area, is_full
forte_white_color = {
'r': (244, 255), # Red range
@ -578,36 +440,3 @@ dot_color = {
'g': (195, 255), # Green range
'b': (195, 255) # Blue range
}
con_colors = [
{
'r': (205, 235),
'g': (190, 222), # for yellow spectro
'b': (90, 130)
},
{
'r': (150, 190), # Red range
'g': (95, 140), # Green range for purple electric
'b': (210, 249) # Blue range
},
{
'r': (200, 230), # Red range
'g': (100, 130), # Green range for red fire
'b': (75, 105) # Blue range
},
{
'r': (60, 95), # Red range
'g': (150, 180), # Green range for blue ice
'b': (210, 245) # Blue range
},
{
'r': (70, 110), # Red range
'g': (215, 250), # Green range for green wind
'b': (155, 190) # Blue range
},
{
'r': (190, 220), # Red range
'g': (65, 105), # Green range for havoc
'b': (145, 175) # Blue range
}
]

View File

@ -44,16 +44,15 @@ class CombatCheck:
if is_pure_black(self.frame):
logger.error('getting a pure black frame for unknown reason, reset_to_false return true')
return True
if recheck and time.time() - self.last_out_of_combat_time > 2.1:
if recheck:
logger.info('out of combat start double check')
if self.debug:
self.screenshot('out of combat start double check')
self.last_out_of_combat_time = time.time()
return True
else:
self.out_of_combat_reason = reason
self.do_reset_to_false()
return False
if self.wait_until(self.check_health_bar, time_out=1.2, wait_until_before_delay=0):
return True
self.out_of_combat_reason = reason
self.do_reset_to_false()
return False
def do_reset_to_false(self):
self._in_combat = False
@ -102,6 +101,8 @@ class CombatCheck:
if self.boss_lv_box is not None:
current = self.boss_lv_box.crop_frame(self.frame)
else:
self.boss_lv_template = None
self.boss_lv_box = None
current = None
max_val = 0
if current is not None:
@ -160,22 +161,21 @@ class CombatCheck:
if now - self.last_combat_check > self.combat_check_interval:
self.last_combat_check = now
if check_team and not self.in_team()[0]:
logger.info('not in team break out of combat')
return self.reset_to_false(recheck=False, reason="not in team")
if self.check_count_down():
return True
if self.boss_lv_template is not None:
if self.wait_until(self.check_boss, time_out=2, wait_until_before_delay=0):
if self.check_boss():
return True
else:
return self.reset_to_false(recheck=False, reason="boss disappear")
if self.check_health_bar():
return True
if self.ocr_lv_text():
return True
if self.target_enemy():
return True
logger.error('target_enemy failed, break out of combat')
return self.reset_to_false(reason='target enemy failed')
logger.error('target_enemy failed, try recheck break out of combat')
return self.reset_to_false(recheck=True, reason='target enemy failed')
else:
return True
else:

View File

@ -1,10 +1,12 @@
import math
import time
import cv2
import numpy as np
import win32api
import re
from ok.color.Color import get_connected_area_by_color
from ok.color.Color import get_connected_area_by_color, color_range_to_bound
from ok.config.ConfigOption import ConfigOption
from ok.feature.FindFeature import FindFeature
from ok.logging.Logger import get_logger
@ -347,6 +349,63 @@ class BaseCombatTask(BaseWWTask, FindFeature, OCR, CombatCheck):
def get_resonance_percentage(self):
return self.calculate_color_percentage(white_color, self.get_box_by_name('box_resonance'))
def is_con_full(self):
return self.get_current_con() == 1
def get_current_con(self):
box = self.box_of_screen_scaled(3840, 2160, 1422, 1939, to_x=1566, to_y=2076, name='con_full',
hcenter=True)
box.confidence = 0
max_area = 0
percent = 0
max_is_full = False
color_index = -1
target_index = self.config.get('_ring_color_index', -1)
cropped = box.crop_frame(self.frame)
for i in range(len(con_colors)):
if target_index != -1 and i != target_index:
continue
color_range = con_colors[i]
area, is_full = self.count_rings(cropped, color_range,
1500 / 3840 / 2160 * self.screen_width * self.screen_height)
# self.logger.debug(f'is_con_full test color_range {color_range} {area, is_full}')
if is_full:
max_is_full = is_full
color_index = i
if area > max_area:
max_area = int(area)
if max_is_full:
self.logger.info(
f'is_con_full found a full ring {self.config.get("_full_ring_area", 0)} -> {max_area} {color_index}')
self.config['_full_ring_area'] = max_area
self.config['_ring_color_index'] = color_index
self.logger.info(
f'is_con_full2 found a full ring {self.config.get("_full_ring_area", 0)} -> {max_area} {color_index}')
if self.config.get('_full_ring_area', 0) > 0:
percent = max_area / self.config['_full_ring_area']
if not max_is_full and percent >= 1:
self.logger.warning(
f'is_con_full not full but percent greater than 1, set to 0.99, {percent} {max_is_full}')
# self.task.screenshot(
# f'is_con_full not full but percent greater than 1, set to 0.99, {percent} {max_is_full}',
# cropped)
percent = 0.99
if percent > 1:
self.logger.error(f'is_con_full percent greater than 1, set to 1, {percent} {max_is_full}')
percent = 1
# self.logger.info(
# f'is_con_full {self} {percent} {max_area}/{self.config.get("_full_ring_area", 0)} {color_index} ')
# if self.task.debug:
# self.task.screenshot(
# f'is_con_full {self} {percent} {max_area}/{self.config.get("_full_ring_area", 0)} {color_index} ',
# cropped)
box.confidence = percent
self.draw_boxes(f'is_con_full_{self}', box)
if percent > 1:
percent = 1
return percent
def in_team(self):
start = time.time()
c1 = self.find_one('char_1_text',
@ -370,6 +429,8 @@ class BaseCombatTask(BaseWWTask, FindFeature, OCR, CombatCheck):
else:
return False, -1, exist_count + 1
# Function to check if a component forms a ring
def mouse_reset(self):
# logger.debug("mouse_reset")
try:
@ -392,9 +453,112 @@ class BaseCombatTask(BaseWWTask, FindFeature, OCR, CombatCheck):
except Exception as e:
logger.error('mouse_reset exception', e)
def count_rings(self, image, color_range, min_area):
# Define the color range
lower_bound, upper_bound = color_range_to_bound(color_range)
image_with_contours = image.copy()
# Create a binary mask
mask = cv2.inRange(image, lower_bound, upper_bound)
# Find connected components
num_labels, labels, stats, centroids = cv2.connectedComponentsWithStats(mask, connectivity=8)
colors = [
(0, 255, 0), # Green
(0, 0, 255), # Red
(255, 0, 0), # Blue
(0, 255, 255), # Yellow
(255, 0, 255), # Magenta
(255, 255, 0) # Cyan
]
# Function to check if a component forms a ring
def is_full_ring(component_mask):
# Find contours
contours, _ = cv2.findContours(component_mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
if len(contours) != 1:
return False
contour = contours[0]
# Check if the contour is closed by checking if the start and end points are the same
# if cv2.arcLength(contour, True) > 0:
# return True
# Approximate the contour with polygons.
epsilon = 0.05 * cv2.arcLength(contour, True)
approx = cv2.approxPolyDP(contour, epsilon, True)
# Check if the polygon is closed (has no gaps) and has a reasonable number of vertices for a ring.
if not cv2.isContourConvex(approx) or len(approx) < 4:
return False
# All conditions met, likely a close ring.
return True
# Iterate over each component
ring_count = 0
is_full = False
the_area = 0
for label in range(1, num_labels):
x, y, width, height, area = stats[label, :5]
bounding_box_area = width * height
component_mask = (labels == label).astype(np.uint8) * 255
contours, _ = cv2.findContours(component_mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
color = colors[label % len(colors)]
cv2.drawContours(image_with_contours, contours, -1, color, 2)
if bounding_box_area >= min_area:
# Select a color from the list based on the label index
if is_full_ring(component_mask):
is_full = True
the_area = area
ring_count += 1
# Save or display the image with contours
# cv2.imwrite(f'test\\test_{self}_{is_full}_{the_area}_{lower_bound}.jpg', image_with_contours)
if ring_count > 1:
is_full = False
the_area = 0
self.logger.warning(f'is_con_full found multiple rings {ring_count}')
return the_area, is_full
white_color = {
'r': (253, 255), # Red range
'g': (253, 255), # Green range
'b': (253, 255) # Blue range
}
con_colors = [
{
'r': (205, 235),
'g': (190, 222), # for yellow spectro
'b': (90, 130)
},
{
'r': (150, 190), # Red range
'g': (95, 140), # Green range for purple electric
'b': (210, 249) # Blue range
},
{
'r': (200, 230), # Red range
'g': (100, 130), # Green range for red fire
'b': (75, 105) # Blue range
},
{
'r': (60, 95), # Red range
'g': (150, 180), # Green range for blue ice
'b': (210, 245) # Blue range
},
{
'r': (70, 110), # Red range
'g': (215, 250), # Green range for green wind
'b': (155, 190) # Blue range
},
{
'r': (190, 220), # Red range
'g': (65, 105), # Green range for havoc
'b': (145, 175) # Blue range
}
]

View File

@ -35,13 +35,31 @@ class IllusiveRealmTask(BaseCombatTask):
self.click()
else:
if self.available('liberation'):
self.send_key(self.get_liberation_key())
self.send_key_and_wait_animation(self.get_liberation_key())
elif self.available('echo'):
self.send_key(self.get_echo_key())
elif self.available('resonance'):
self.send_key(self.get_resonance_key())
self.last_is_click = not self.last_is_click
def send_key_and_wait_animation(self, key, total_wait=10, animation_wait=5):
start = time.time()
animation_start = 0
while time.time() - start < total_wait and (
animation_start == 0 or time.time() - animation_start < animation_wait):
if self.in_realm() or self.in_team()[0]:
if animation_start > 0:
self.in_liberation = False
return
else:
self.send_key(key, interval=0.2)
else:
if animation_start == 0:
animation_start = time.time()
self.in_liberation = True
self.next_frame()
logger.info(f'send_key_and_wait_animation timed out {key}')
def run(self):
while True:
start = time.time()