Remove ACV (#14)
* remove pyproject.toml * remove presets * remove preset args * remove deprecated template tests * Remove deprecated features related to configuring settings * pep8 lint * remove ac valhalla
@@ -1,83 +0,0 @@
|
||||
[Language]
|
||||
Client=en-US
|
||||
Text=en-US
|
||||
Sound=en-US
|
||||
Subtitles=en-US
|
||||
[Graphics]
|
||||
AdapterVendorID=4318
|
||||
AdapterDeviceID=7812
|
||||
MonitorDesc=
|
||||
DisplayIndex=0
|
||||
WindowPosX=0
|
||||
WindowPosY=0
|
||||
FullscreenWidth=2560
|
||||
FullscreenHeight=1440
|
||||
WindowedWidth=2560
|
||||
WindowedHeight=1440
|
||||
WindowMaximised=0
|
||||
RefreshRate=60
|
||||
WindowMode=3
|
||||
VSyncMode=0
|
||||
MaxFPS=30
|
||||
IsFpsLimitEnabled=0
|
||||
PixelDensity=1.00000
|
||||
LastUsedFullscreenMode=0
|
||||
KeepStandardAspect=0
|
||||
HDREnabled=0
|
||||
Freesync2Enabled=0
|
||||
UpsampleType=0
|
||||
FSRQuality=0
|
||||
AdaptiveQuality=0
|
||||
Antialiasing=2
|
||||
Bloom=1
|
||||
Character=2
|
||||
CharacterTexture=2
|
||||
Cloud=2
|
||||
Clutter=3
|
||||
CrowdDensity=0
|
||||
Culling=0
|
||||
DOF=2
|
||||
Environment=3
|
||||
Fog=2
|
||||
Lighting=0
|
||||
MotionBlur=1
|
||||
Rain=2
|
||||
Reflection=1
|
||||
Shadow=3
|
||||
SSAO=2
|
||||
Terrain=0
|
||||
Tessellation=3
|
||||
Texture=2
|
||||
TextureFiltering=2
|
||||
Water=2
|
||||
[Startup]
|
||||
StickyKeys=2
|
||||
ToggleKeys=2
|
||||
FilterKeys=2
|
||||
[LightingDevices]
|
||||
Config=[{"id":"MSI MysticLight SDK","enabled":true,"config":{"ip":"localhost","port":1462,"ambientPort":14621,"authToken":""}}]
|
||||
Enabled=0
|
||||
[VoiceInput]
|
||||
InputMode=1
|
||||
[Options]
|
||||
TobiiEnabled=1
|
||||
TobiiExtendedViewEnabled=1
|
||||
TobiiAimAtGazeEnabled=1
|
||||
TobiiMarkAtGazeEnabled=1
|
||||
TobiiInteractAtGazeEnabled=1
|
||||
TobiiLockTargetAtGazeEnabled=1
|
||||
TobiiDynamicLightAdaptationEnabled=1
|
||||
TobiiSunEffectsEnabled=1
|
||||
TobiiHeadTrackingAutoResetEnabled=1
|
||||
TobiiExtendedViewSensitivity=50
|
||||
TobiiExtendedViewResponsiveness=50
|
||||
TobiiEyeVsHeadTrackingRatio=80
|
||||
Controller Feedback=4294967295
|
||||
WideAspectStretchedHUDMode=1
|
||||
KeyboardHighlightingMode=dynamic
|
||||
FOVScale=1.00000
|
||||
AutoFOV=0
|
||||
LockCursorToTheWindow=0
|
||||
AlwaysShowCursor=0
|
||||
[Input]
|
||||
InputSourcesSelectorMode=1
|
||||
@@ -1,70 +0,0 @@
|
||||
# Assassins Creed Valhalla
|
||||
|
||||
## TODO's
|
||||
- Iteration within the same game process.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- Python 3.10+
|
||||
- Assassins Creed Valhalla installed
|
||||
|
||||
## Setup
|
||||
|
||||
1. Follow the setup instructions for the framework. If you have done so, all required python dependencies *should* be installed.
|
||||
2. Install Assassins Creed Valhalla from Ubisoft.
|
||||
1. Location should be default C:\ path
|
||||
|
||||
## Configuration
|
||||
|
||||
Below is an example use of this harness as a test in a benchmark configuration.
|
||||
|
||||
```yaml
|
||||
...
|
||||
...
|
||||
tests:
|
||||
- name: acvalhalla
|
||||
executable: "acvalhalla.py"
|
||||
output_dir:
|
||||
- 'harness/acvalhalla/run'
|
||||
args:
|
||||
- "--preset medium"
|
||||
- "--resolution 1080,1920"
|
||||
```
|
||||
|
||||
__name__ : _(required)_ name of the test. This much match the name of a directory in the harness folder so the framework
|
||||
can find the executable and any supplementary files.
|
||||
|
||||
__executable__ : _(required)_ the entry point to the test harness. In this case a python script.
|
||||
|
||||
__process_name__ : _(required)_ The process name that should be the target for FPS recording (ex: PresentMon).
|
||||
|
||||
__output_dir__: _(optional)_ Directory containing files to aggregate copies of after a successful test run. If a directory path is
|
||||
given, the contents are copied.
|
||||
|
||||
__args__ : _(optional)_ list of arguments to be appended to the command to execute. All the arguments will be passed to
|
||||
the executable when invoked by the framework.
|
||||
|
||||
### Arguments
|
||||
|flag|required|what?|notes
|
||||
|--|--|--|--|
|
||||
|--preset|No|Graphics preset to load for test|See the `presets` folder to determine options. If none provided, the current settings will be used|
|
||||
|--resolution|No|Display settings to load for test|If none provided, current display settings will be used|
|
||||
|--template_set|No|Template set of images to use. Thesse are what are used to find buttons on the screen|If not provided 1080 set is default|
|
||||
|
||||
#### Presets
|
||||
This harness requires a single argument for the option `preset`. This is the graphics presets that are found in the game. They are represented in YAML in the folder **presets**. To select one you take the prefix of the name of the file, and the harness will find the corresponding INI file.
|
||||
|
||||
For example if I pass in the argument `--preset medium` to the harness. The harness will load the settings in `presets/medium.ini`. You can also create and supply a custom preset if you wish.
|
||||
|
||||
#### Resolution
|
||||
Resolution is expected to be passed in as `<height>,<width>`.
|
||||
|
||||
#### Template Set
|
||||
This harness uses OpenCV template matching to click on buttons through the menu. Sometimes the template matching can be finicky and not find images. Trying out different template sets can sometimes alleviate this issue. Or adding a template set for a specific display and test bench combination.
|
||||
|
||||
You can see what options there are in `images` folder. Each set is in a labelled folder.
|
||||
|
||||
> Yes, finding buttons on the screen via features or text search would be better, but this is one of the first harnesses, and brute forcing was easiest option.. cut me some slack.
|
||||
|
||||
## Common Issues
|
||||
|
||||
@@ -1,125 +0,0 @@
|
||||
import json
|
||||
from subprocess import Popen
|
||||
|
||||
import psutil
|
||||
import os, stat
|
||||
from arg_utils import read_args
|
||||
from config_utils import ASS_CREED_FOLDER, CONFIG_FILENAME, load_preset, mydocumentspath, read_current_resolution, save_current_config
|
||||
from cv2_utils import *
|
||||
|
||||
DEFAULT_INSTALLATION_PATH = "C:/Program Files (x86)/Ubisoft/Ubisoft Game Launcher/games/Assassin's Creed Valhalla"
|
||||
EXECUTABLE = "ACValhalla.exe"
|
||||
|
||||
def delete_vids():
|
||||
"""
|
||||
Speed up the intro screen by deleting or renaming in /video folder:
|
||||
ANVIL_Logo.webm
|
||||
PC_AMD_Ryzen.webm
|
||||
UbisoftLogo.webm
|
||||
"""
|
||||
vid1 = os.path.join(DEFAULT_INSTALLATION_PATH, "videos", "ANVIL_Logo.webm")
|
||||
vid2 = os.path.join(DEFAULT_INSTALLATION_PATH, "videos", "PC_AMD_Ryzen.webm")
|
||||
vid3 = os.path.join(DEFAULT_INSTALLATION_PATH, "videos", "UbisoftLogo.webm")
|
||||
vids = [vid1, vid2, vid3]
|
||||
for vid in vids:
|
||||
try:
|
||||
os.remove(vid)
|
||||
except:
|
||||
pass
|
||||
|
||||
|
||||
def start_game():
|
||||
cmd = DEFAULT_INSTALLATION_PATH + '\\' + EXECUTABLE
|
||||
logging.info(cmd)
|
||||
return Popen(cmd)
|
||||
|
||||
|
||||
def run_benchmark():
|
||||
game_process = start_game()
|
||||
t1 = time.time()
|
||||
|
||||
###
|
||||
# Wait for the intro screen to reach the "Press Any Key" title screen
|
||||
###
|
||||
time.sleep(60)
|
||||
# wait_for_image_on_screen('press_any')
|
||||
user.press('enter')
|
||||
time.sleep(20)
|
||||
|
||||
###
|
||||
# Mercifully the benchmark button is right on the main screen, so push it!
|
||||
###
|
||||
wait_and_click('benchmark', "run benchmark")
|
||||
user.press('enter') # help it along if the click didn't work
|
||||
time.sleep(2) # massage the menu loading
|
||||
wait_and_click('benchmark_confirmation', "confirm benchmark")
|
||||
time.sleep(1)
|
||||
user.press('space')
|
||||
|
||||
t2 = time.time()
|
||||
logging.info(f"Setup took {round((t2 - t1), 2)} seconds")
|
||||
global START_TIME
|
||||
START_TIME = time.time()
|
||||
|
||||
time.sleep(100) # sleep during benchmark, takes 90 + 10 grace seconds.
|
||||
|
||||
# look for the results header
|
||||
logging.info("Test should be complete, looking for results page")
|
||||
wait_for_image_on_screen('results_header', DEFAULT_MATCH_THRESHOLD, interval=2, timeout=60)
|
||||
gui.screenshot(os.path.join(log_dir, "results.png"))
|
||||
global END_TIME
|
||||
END_TIME = time.time()
|
||||
logging.info(f"Benchark took {round((END_TIME - START_TIME), 2)} seconds")
|
||||
|
||||
###
|
||||
# Exit
|
||||
###
|
||||
for proc in psutil.process_iter():
|
||||
if "ACValhalla" in proc.name():
|
||||
proc.terminate()
|
||||
|
||||
|
||||
script_dir = os.path.dirname(os.path.realpath(__file__))
|
||||
log_dir = os.path.join(script_dir, "run")
|
||||
if not os.path.isdir(log_dir):
|
||||
os.mkdir(log_dir)
|
||||
|
||||
logging_format = '%(asctime)s %(levelname)-s %(message)s'
|
||||
logging.basicConfig(filename=f'{log_dir}/harness.log',
|
||||
format=logging_format,
|
||||
datefmt='%m-%d %H:%M',
|
||||
level=logging.DEBUG)
|
||||
console = logging.StreamHandler()
|
||||
formatter = logging.Formatter(logging_format)
|
||||
console.setFormatter(formatter)
|
||||
logging.getLogger('').addHandler(console)
|
||||
|
||||
args = read_args()
|
||||
|
||||
try:
|
||||
mydocuments = mydocumentspath()
|
||||
cfg = os.path.join(mydocuments, ASS_CREED_FOLDER, CONFIG_FILENAME)
|
||||
delete_vids()
|
||||
save_current_config(log_dir)
|
||||
run_benchmark()
|
||||
|
||||
height, width = read_current_resolution()
|
||||
result = {
|
||||
"resolution": f"{width}x{height}",
|
||||
"start_time": round((START_TIME * 1000)), # seconds * 1000 = millis
|
||||
"end_time": round((END_TIME * 1000))
|
||||
}
|
||||
|
||||
f = open(os.path.join(log_dir, "report.json"), "w")
|
||||
f.write(json.dumps(result))
|
||||
f.close()
|
||||
except Exception as e:
|
||||
os.chmod(cfg, stat.S_IWRITE)
|
||||
logging.error("Something went wrong running the benchmark!")
|
||||
logging.exception(e)
|
||||
for proc in psutil.process_iter():
|
||||
if "ACValhalla" in proc.name():
|
||||
proc.terminate()
|
||||
exit(1)
|
||||
finally:
|
||||
os.chmod(cfg, stat.S_IWRITE)
|
||||
@@ -1,9 +0,0 @@
|
||||
from argparse import ArgumentParser
|
||||
|
||||
|
||||
def read_args():
|
||||
parser = ArgumentParser()
|
||||
parser.add_argument("-p", "--preset", dest="preset",
|
||||
help="graphics preset", metavar="preset", required=False)
|
||||
args = parser.parse_args()
|
||||
return args
|
||||
@@ -1,108 +0,0 @@
|
||||
import os
|
||||
import re
|
||||
import shutil
|
||||
import tempfile
|
||||
import winreg
|
||||
import logging
|
||||
|
||||
HEIGHT_PATTERN = r"FullscreenHeight=(\d*)"
|
||||
WIDTH_PATTERN = r"FullscreenWidth=(\d*)"
|
||||
vendorid_pattern = r"AdapterVendorID=(\w+)"
|
||||
deviceid_pattern = r"AdapterDeviceID=(\w+)"
|
||||
ASS_CREED_FOLDER = "Assassin's Creed Valhalla"
|
||||
CONFIG_FILENAME = "ACValhalla.ini"
|
||||
|
||||
|
||||
def sed_inplace(filename, pattern, repl):
|
||||
'''
|
||||
Perform of in-place `sed` substitution: e.g.,
|
||||
`sed -i -e 's/'${pattern}'/'${repl}' "${filename}"`.
|
||||
See https://stackoverflow.com/a/31499114
|
||||
'''
|
||||
pattern_compiled = re.compile(pattern)
|
||||
|
||||
with tempfile.NamedTemporaryFile(mode='w', delete=False) as tmp_file:
|
||||
with open(filename) as src_file:
|
||||
for line in src_file:
|
||||
tmp_file.write(pattern_compiled.sub(repl, line))
|
||||
|
||||
shutil.copystat(filename, tmp_file.name)
|
||||
shutil.move(tmp_file.name, filename)
|
||||
|
||||
|
||||
def set_resolution(path, height, width):
|
||||
sed_inplace(path, HEIGHT_PATTERN, f"FullscreenHeight={height}")
|
||||
sed_inplace(path, WIDTH_PATTERN, f"FullscreenWidth={width}")
|
||||
|
||||
|
||||
def mydocumentspath():
|
||||
SHELL_FOLDER_KEY = r'SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders'
|
||||
try:
|
||||
root_handle = winreg.ConnectRegistry(None, winreg.HKEY_CURRENT_USER)
|
||||
shell_folders_handle = winreg.OpenKeyEx(root_handle, SHELL_FOLDER_KEY)
|
||||
personal_path_key = winreg.QueryValueEx(shell_folders_handle, 'Personal')
|
||||
return personal_path_key[0]
|
||||
finally:
|
||||
root_handle.Close()
|
||||
|
||||
|
||||
def load_preset(name, height, width):
|
||||
mydocuments = mydocumentspath()
|
||||
script_dir = os.path.dirname(os.path.realpath(__file__))
|
||||
preset_path = os.path.join(script_dir, "presets", f'{name}.ini')
|
||||
dest = os.path.join(mydocuments, ASS_CREED_FOLDER, CONFIG_FILENAME)
|
||||
vendorid, deviceid = read_device_ids()
|
||||
logging.info(f"vendorid: {vendorid} deviceid: {deviceid}")
|
||||
logging.info(f"Copying config {preset_path} to {dest}")
|
||||
shutil.copy2(preset_path, dest)
|
||||
set_resolution(dest, height, width)
|
||||
sed_inplace(dest, vendorid_pattern, f"AdapterVendorID={vendorid}")
|
||||
sed_inplace(dest, deviceid_pattern, f"AdapterDeviceID={deviceid}")
|
||||
|
||||
|
||||
def save_current_config(dest):
|
||||
mydocuments = mydocumentspath()
|
||||
src = os.path.join(mydocuments, ASS_CREED_FOLDER, CONFIG_FILENAME)
|
||||
shutil.copy2(src, dest)
|
||||
|
||||
|
||||
def read_device_ids():
|
||||
pat1 = re.compile(vendorid_pattern)
|
||||
pat2 = re.compile(deviceid_pattern)
|
||||
mydocuments = mydocumentspath()
|
||||
src = os.path.join(mydocuments, ASS_CREED_FOLDER, CONFIG_FILENAME)
|
||||
vendorid = 0
|
||||
deviceid = 0
|
||||
with open(src) as fp:
|
||||
lines = fp.readlines()
|
||||
for line in lines:
|
||||
result = pat1.match(line)
|
||||
if result is not None:
|
||||
vendorid = result.group(1)
|
||||
result2 = pat2.match(line)
|
||||
if result2 is not None:
|
||||
deviceid = result2.group(1)
|
||||
if int(vendorid) > 0 and int(deviceid) > 0:
|
||||
break
|
||||
return (vendorid, deviceid)
|
||||
|
||||
|
||||
def read_current_resolution():
|
||||
mydocuments = mydocumentspath()
|
||||
src = os.path.join(mydocuments, ASS_CREED_FOLDER, CONFIG_FILENAME)
|
||||
hpattern = re.compile(HEIGHT_PATTERN)
|
||||
wpattern = re.compile(WIDTH_PATTERN)
|
||||
h = w = 0
|
||||
with open(src) as fp:
|
||||
lines = fp.readlines()
|
||||
for line in lines:
|
||||
result = hpattern.match(line)
|
||||
if result is not None:
|
||||
h = result.group(1)
|
||||
|
||||
result2 = wpattern.match(line)
|
||||
if result2 is not None:
|
||||
w = result2.group(1)
|
||||
if int(h) > 0 and int(w) > 0:
|
||||
break
|
||||
return (h, w)
|
||||
@@ -1,189 +0,0 @@
|
||||
import logging
|
||||
import os
|
||||
import time
|
||||
from enum import Enum
|
||||
|
||||
import cv2
|
||||
import imutils
|
||||
import numpy as np
|
||||
import pyautogui as gui
|
||||
import pydirectinput as user
|
||||
|
||||
DEFAULT_MATCH_THRESHOLD = 0.8
|
||||
DEFAULT_INTERVAL = 2 # seconds
|
||||
DEFAULT_TIMEOUT = 60 # seconds
|
||||
|
||||
# path relative to script
|
||||
script_dir = os.path.dirname(os.path.realpath(__file__))
|
||||
images_dir = os.path.join(script_dir, "images")
|
||||
dir16x9 = os.path.join(images_dir, "16x9")
|
||||
dir16x10 = os.path.join(images_dir, "16x10")
|
||||
|
||||
templates = {
|
||||
"press_any": {
|
||||
"16x10": cv2.imread(os.path.join(dir16x10, "ass_logo.png"), cv2.IMREAD_UNCHANGED),
|
||||
"16x9": cv2.imread(os.path.join(dir16x9, "ass_logo.png"), cv2.IMREAD_UNCHANGED)
|
||||
},
|
||||
"benchmark": {
|
||||
"16x10": cv2.imread(os.path.join(dir16x10, "benchmark.png"), cv2.IMREAD_UNCHANGED),
|
||||
"16x9": cv2.imread(os.path.join(dir16x9, "bench_1080.png"), cv2.IMREAD_UNCHANGED)
|
||||
},
|
||||
"benchmark_confirmation": {
|
||||
"16x10": cv2.imread(os.path.join(dir16x10, "confirm_benchmark.png"), cv2.IMREAD_UNCHANGED),
|
||||
"16x9": cv2.imread(os.path.join(dir16x9, "bench_yes_1080.png"), cv2.IMREAD_UNCHANGED)
|
||||
},
|
||||
"results_header": {
|
||||
"16x10": cv2.imread(os.path.join(dir16x10, "results.png"), cv2.IMREAD_UNCHANGED),
|
||||
"16x9": cv2.imread(os.path.join(dir16x9, "results2_1080.png"), cv2.IMREAD_UNCHANGED)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
def get_template(name, set="16x9"):
|
||||
return templates[name][set]
|
||||
|
||||
|
||||
class ClickType(Enum):
|
||||
SINGLE = 0 # uses .click()
|
||||
DOUBLE = 1 # uses .doubleclick()
|
||||
HARD = 2 # uses mouse.down() and mouse.up()
|
||||
|
||||
|
||||
def get_middle_of_rect(top_left_corner, height, width):
|
||||
x = top_left_corner[0] + (width / 2)
|
||||
y = top_left_corner[1] + (height / 2)
|
||||
return int(x), int(y) # round to avoid fractional pixels
|
||||
|
||||
|
||||
def click(top_left_corner, img):
|
||||
click_loc = get_middle_of_rect(top_left_corner, img.shape[0], img.shape[1])
|
||||
logging.info(f"Clicking {click_loc}")
|
||||
user.click(click_loc[0], click_loc[1])
|
||||
|
||||
|
||||
def double_click(top_left_corner, img):
|
||||
click_loc = get_middle_of_rect(top_left_corner, img.shape[0], img.shape[1])
|
||||
logging.info(f"Double clicking {click_loc}")
|
||||
user.doubleClick(click_loc[0], click_loc[1])
|
||||
|
||||
|
||||
def hard_click(top_left_corner, img):
|
||||
click_loc = get_middle_of_rect(top_left_corner, img.shape[0], img.shape[1])
|
||||
user.moveTo(click_loc[0], click_loc[1])
|
||||
user.mouseDown()
|
||||
user.mouseUp()
|
||||
|
||||
|
||||
def wait_and_click(template_name, name, click_type: ClickType = ClickType.SINGLE, timeout=DEFAULT_TIMEOUT):
|
||||
logging.info(f"Waiting to find and click on {name}")
|
||||
img, img_loc = wait_for_image_on_screen(template_name, timeout=timeout)
|
||||
if click_type == ClickType.SINGLE:
|
||||
click(img_loc, img)
|
||||
elif click_type == ClickType.DOUBLE:
|
||||
double_click(img_loc, img)
|
||||
elif click_type == ClickType.HARD:
|
||||
hard_click(img_loc, img)
|
||||
else:
|
||||
raise ValueError("Unknown click type")
|
||||
|
||||
|
||||
class ImageNotFoundTimeout(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class ImageNotFound(Exception):
|
||||
pass
|
||||
|
||||
|
||||
def gcd(a, b):
|
||||
return a if b == 0 else gcd(b, a % b)
|
||||
|
||||
|
||||
def aspect_ratio(w, h):
|
||||
denom = int(gcd(w, h))
|
||||
x = int(w / denom)
|
||||
y = int(h / denom)
|
||||
if x == 8 and y == 5:
|
||||
return "16x10"
|
||||
elif x == 16 and y == 9:
|
||||
return "16x9"
|
||||
|
||||
|
||||
def locate_on_screen(template_name, threshold=DEFAULT_MATCH_THRESHOLD, debug=1):
|
||||
screen = gui.screenshot()
|
||||
screen = np.array(
|
||||
screen) # pyautogui is using Pillow which is giving a format that must be adapted to work with opencv.
|
||||
screen = cv2.cvtColor(screen, cv2.COLOR_RGB2BGR)
|
||||
(h, w) = screen.shape[:2]
|
||||
r = aspect_ratio(w, h)
|
||||
needle = get_template(template_name, r)
|
||||
return needle, locate_in_image(needle, screen, threshold=DEFAULT_MATCH_THRESHOLD, debug=0)
|
||||
|
||||
|
||||
# This approach was largely inspired by the article
|
||||
# https://pyimagesearch.com/2015/01/26/multi-scale-template-matching-using-python-opencv/
|
||||
def locate_in_image(needle, haystack, threshold=DEFAULT_MATCH_THRESHOLD, debug=0):
|
||||
(tH, tW) = needle.shape[:2]
|
||||
|
||||
if debug:
|
||||
cv2.imshow("Looking For", needle)
|
||||
cv2.waitKey(0)
|
||||
|
||||
for scale in np.linspace(0.2, 1.0, 20)[::-1]:
|
||||
# resize the image according to the scale, and keep track
|
||||
# of the ratio of the resizing
|
||||
resized = imutils.resize(haystack, width=int(haystack.shape[1] * scale), inter=cv2.INTER_NEAREST)
|
||||
r = haystack.shape[1] / float(resized.shape[1])
|
||||
|
||||
# if the resized image is smaller than the template, then break
|
||||
# from the loop
|
||||
if resized.shape[0] < tH or resized.shape[1] < tW:
|
||||
break
|
||||
|
||||
result = cv2.matchTemplate(resized, needle, cv2.TM_CCOEFF_NORMED)
|
||||
(_, maxVal, _, maxLoc) = cv2.minMaxLoc(result)
|
||||
|
||||
if debug:
|
||||
# draw a bounding box around the detected region
|
||||
# clone = np.dstack([edged, edged, edged])
|
||||
cv2.rectangle(resized, (maxLoc[0], maxLoc[1]),
|
||||
(maxLoc[0] + tW, maxLoc[1] + tH), (0, 0, 255), 2)
|
||||
cv2.imshow("Searching", resized)
|
||||
cv2.waitKey(0)
|
||||
|
||||
if maxVal >= threshold:
|
||||
found = (maxVal, maxLoc, r)
|
||||
|
||||
# unpack the bookkeeping variable and compute the (x, y) coordinates
|
||||
# of the bounding box based on the resized ratio
|
||||
(_, maxLoc, r) = found
|
||||
(startX, startY) = (int(maxLoc[0] * r), int(maxLoc[1] * r))
|
||||
(endX, endY) = (int((maxLoc[0] + tW) * r), int((maxLoc[1] + tH) * r))
|
||||
|
||||
if debug:
|
||||
# draw a bounding box around the detected result and display the image
|
||||
cv2.rectangle(haystack, (startX, startY), (endX, endY), (0, 0, 255), 2)
|
||||
cv2.imshow("Found", haystack)
|
||||
cv2.waitKey(0)
|
||||
|
||||
return startX, startY
|
||||
raise ImageNotFound("Image not found on screen")
|
||||
|
||||
|
||||
def wait_for_image_on_screen(template_name, match_threshold=DEFAULT_MATCH_THRESHOLD, interval=DEFAULT_INTERVAL,
|
||||
timeout=DEFAULT_TIMEOUT):
|
||||
"""Function that will wait for an image to appear on screen. This function will check every
|
||||
interval for a match that meets is greater than the match threshold. The function will raise
|
||||
an error if the image is not found within the timeout given. Will return the location
|
||||
of the image if found"""
|
||||
t0 = time.time()
|
||||
t1 = t0
|
||||
while not t1 - t0 > timeout:
|
||||
try:
|
||||
img, loc = locate_on_screen(template_name, match_threshold)
|
||||
return img, loc
|
||||
except ImageNotFound:
|
||||
pass
|
||||
time.sleep(interval)
|
||||
t1 = time.time()
|
||||
raise ImageNotFoundTimeout("Could not find image on screen within timeout")
|
||||
|
Before Width: | Height: | Size: 14 KiB |
|
Before Width: | Height: | Size: 2.5 KiB |
|
Before Width: | Height: | Size: 985 B |
|
Before Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 23 KiB |
|
Before Width: | Height: | Size: 1.6 KiB |
|
Before Width: | Height: | Size: 871 B |
|
Before Width: | Height: | Size: 1.3 KiB |
|
Before Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 1.2 KiB |
|
Before Width: | Height: | Size: 2.4 KiB |
|
Before Width: | Height: | Size: 7.8 KiB |
|
Before Width: | Height: | Size: 2.4 MiB |
|
Before Width: | Height: | Size: 3.8 MiB |
|
Before Width: | Height: | Size: 5.7 MiB |
@@ -1,11 +0,0 @@
|
||||
friendly_name: "Assassins Creed Valhalla"
|
||||
executable: "acvalhalla.py"
|
||||
process_name: "ACValhalla.exe"
|
||||
output_dir: "run"
|
||||
options:
|
||||
- name: preset
|
||||
type: select
|
||||
# removing preset options in favor of manual process for now
|
||||
# values: [current, lowest, medium, high, veryhigh, ultrahigh]
|
||||
values: [current]
|
||||
tooltip: Don't forget to set the game settings!
|
||||
@@ -1,68 +0,0 @@
|
||||
[Language]
|
||||
Client=en-US
|
||||
Text=en-US
|
||||
Sound=en-US
|
||||
Subtitles=en-US
|
||||
[Graphics]
|
||||
AdapterVendorID=4318
|
||||
AdapterDeviceID=8712
|
||||
MonitorDesc=
|
||||
DisplayIndex=0
|
||||
WindowPosX=0
|
||||
WindowPosY=0
|
||||
FullscreenWidth=1920
|
||||
FullscreenHeight=1080
|
||||
WindowedWidth=1920
|
||||
WindowedHeight=1080
|
||||
WindowMaximised=0
|
||||
RefreshRate=0
|
||||
WindowMode=3
|
||||
VSyncMode=0
|
||||
MaxFPS=30
|
||||
IsFpsLimitEnabled=0
|
||||
PixelDensity=1.00000
|
||||
LastUsedFullscreenMode=1
|
||||
KeepStandardAspect=0
|
||||
HDREnabled=0
|
||||
Freesync2Enabled=0
|
||||
UpsampleType=0
|
||||
FSRQuality=0
|
||||
AdaptiveQuality=0
|
||||
Antialiasing=2
|
||||
Bloom=1
|
||||
Character=2
|
||||
CharacterTexture=2
|
||||
Cloud=1
|
||||
Clutter=2
|
||||
CrowdDensity=0
|
||||
Culling=0
|
||||
DOF=2
|
||||
Environment=2
|
||||
Fog=2
|
||||
Lighting=0
|
||||
MotionBlur=1
|
||||
Rain=2
|
||||
Reflection=1
|
||||
Shadow=2
|
||||
SSAO=2
|
||||
Terrain=0
|
||||
Tessellation=2
|
||||
Texture=2
|
||||
TextureFiltering=2
|
||||
Water=2
|
||||
[LightingDevices]
|
||||
Config=[{"id":"MSI MysticLight SDK","enabled":true,"config":{"ip":"localhost","port":1462,"ambientPort":14621,"authToken":""}}]
|
||||
Enabled=0
|
||||
[VoiceInput]
|
||||
InputMode=1
|
||||
[Input]
|
||||
InputSourcesSelectorMode=1
|
||||
[Options]
|
||||
Controller Feedback=4294967295
|
||||
WideAspectStretchedHUDMode=1
|
||||
KeyboardHighlightingMode=dynamic
|
||||
FOVScale=1.00000
|
||||
AutoFOV=0
|
||||
LockCursorToTheWindow=0
|
||||
AlwaysShowCursor=0
|
||||
[Startup]
|
||||
@@ -1,68 +0,0 @@
|
||||
[Language]
|
||||
Client=en-US
|
||||
Text=en-US
|
||||
Sound=en-US
|
||||
Subtitles=en-US
|
||||
[Graphics]
|
||||
AdapterVendorID=4318
|
||||
AdapterDeviceID=8712
|
||||
MonitorDesc=
|
||||
DisplayIndex=0
|
||||
WindowPosX=0
|
||||
WindowPosY=0
|
||||
FullscreenWidth=1920
|
||||
FullscreenHeight=1080
|
||||
WindowedWidth=1920
|
||||
WindowedHeight=1080
|
||||
WindowMaximised=0
|
||||
RefreshRate=0
|
||||
WindowMode=3
|
||||
VSyncMode=0
|
||||
MaxFPS=30
|
||||
IsFpsLimitEnabled=0
|
||||
PixelDensity=1.00000
|
||||
LastUsedFullscreenMode=1
|
||||
KeepStandardAspect=0
|
||||
HDREnabled=0
|
||||
Freesync2Enabled=0
|
||||
UpsampleType=0
|
||||
FSRQuality=0
|
||||
AdaptiveQuality=0
|
||||
Antialiasing=0
|
||||
Bloom=1
|
||||
Character=2
|
||||
CharacterTexture=0
|
||||
Cloud=0
|
||||
Clutter=0
|
||||
CrowdDensity=0
|
||||
Culling=0
|
||||
DOF=0
|
||||
Environment=0
|
||||
Fog=2
|
||||
Lighting=0
|
||||
MotionBlur=0
|
||||
Rain=2
|
||||
Reflection=0
|
||||
Shadow=0
|
||||
SSAO=2
|
||||
Terrain=0
|
||||
Tessellation=0
|
||||
Texture=0
|
||||
TextureFiltering=2
|
||||
Water=0
|
||||
[LightingDevices]
|
||||
Config=[{"id":"MSI MysticLight SDK","enabled":true,"config":{"ip":"localhost","port":1462,"ambientPort":14621,"authToken":""}}]
|
||||
Enabled=0
|
||||
[VoiceInput]
|
||||
InputMode=1
|
||||
[Input]
|
||||
InputSourcesSelectorMode=1
|
||||
[Options]
|
||||
Controller Feedback=4294967295
|
||||
WideAspectStretchedHUDMode=1
|
||||
KeyboardHighlightingMode=dynamic
|
||||
FOVScale=1.00000
|
||||
AutoFOV=0
|
||||
LockCursorToTheWindow=0
|
||||
AlwaysShowCursor=0
|
||||
[Startup]
|
||||
@@ -1,68 +0,0 @@
|
||||
[Language]
|
||||
Client=en-US
|
||||
Text=en-US
|
||||
Sound=en-US
|
||||
Subtitles=en-US
|
||||
[Graphics]
|
||||
AdapterVendorID=4318
|
||||
AdapterDeviceID=8712
|
||||
MonitorDesc=
|
||||
DisplayIndex=0
|
||||
WindowPosX=0
|
||||
WindowPosY=0
|
||||
FullscreenWidth=1920
|
||||
FullscreenHeight=1080
|
||||
WindowedWidth=1920
|
||||
WindowedHeight=1080
|
||||
WindowMaximised=0
|
||||
RefreshRate=0
|
||||
WindowMode=3
|
||||
VSyncMode=0
|
||||
MaxFPS=30
|
||||
IsFpsLimitEnabled=0
|
||||
PixelDensity=1.00000
|
||||
LastUsedFullscreenMode=1
|
||||
KeepStandardAspect=0
|
||||
HDREnabled=0
|
||||
Freesync2Enabled=0
|
||||
UpsampleType=0
|
||||
FSRQuality=0
|
||||
AdaptiveQuality=0
|
||||
Antialiasing=1
|
||||
Bloom=1
|
||||
Character=2
|
||||
CharacterTexture=1
|
||||
Cloud=0
|
||||
Clutter=1
|
||||
CrowdDensity=0
|
||||
Culling=0
|
||||
DOF=1
|
||||
Environment=1
|
||||
Fog=2
|
||||
Lighting=0
|
||||
MotionBlur=1
|
||||
Rain=2
|
||||
Reflection=0
|
||||
Shadow=1
|
||||
SSAO=2
|
||||
Terrain=0
|
||||
Tessellation=1
|
||||
Texture=1
|
||||
TextureFiltering=2
|
||||
Water=1
|
||||
[LightingDevices]
|
||||
Config=[{"id":"MSI MysticLight SDK","enabled":true,"config":{"ip":"localhost","port":1462,"ambientPort":14621,"authToken":""}}]
|
||||
Enabled=0
|
||||
[VoiceInput]
|
||||
InputMode=1
|
||||
[Input]
|
||||
InputSourcesSelectorMode=1
|
||||
[Options]
|
||||
Controller Feedback=4294967295
|
||||
WideAspectStretchedHUDMode=1
|
||||
KeyboardHighlightingMode=dynamic
|
||||
FOVScale=1.00000
|
||||
AutoFOV=0
|
||||
LockCursorToTheWindow=0
|
||||
AlwaysShowCursor=0
|
||||
[Startup]
|
||||
@@ -1,68 +0,0 @@
|
||||
[Language]
|
||||
Client=en-US
|
||||
Text=en-US
|
||||
Sound=en-US
|
||||
Subtitles=en-US
|
||||
[Graphics]
|
||||
AdapterVendorID=4318
|
||||
AdapterDeviceID=8712
|
||||
MonitorDesc=
|
||||
DisplayIndex=0
|
||||
WindowPosX=0
|
||||
WindowPosY=0
|
||||
FullscreenWidth=1920
|
||||
FullscreenHeight=1080
|
||||
WindowedWidth=1920
|
||||
WindowedHeight=1080
|
||||
WindowMaximised=0
|
||||
RefreshRate=0
|
||||
WindowMode=3
|
||||
VSyncMode=0
|
||||
MaxFPS=30
|
||||
IsFpsLimitEnabled=0
|
||||
PixelDensity=1.00000
|
||||
LastUsedFullscreenMode=1
|
||||
KeepStandardAspect=0
|
||||
HDREnabled=0
|
||||
Freesync2Enabled=0
|
||||
UpsampleType=0
|
||||
FSRQuality=0
|
||||
AdaptiveQuality=0
|
||||
Antialiasing=2
|
||||
Bloom=1
|
||||
Character=2
|
||||
CharacterTexture=2
|
||||
Cloud=3
|
||||
Clutter=3
|
||||
CrowdDensity=0
|
||||
Culling=0
|
||||
DOF=2
|
||||
Environment=4
|
||||
Fog=2
|
||||
Lighting=0
|
||||
MotionBlur=1
|
||||
Rain=2
|
||||
Reflection=1
|
||||
Shadow=4
|
||||
SSAO=2
|
||||
Terrain=0
|
||||
Tessellation=3
|
||||
Texture=2
|
||||
TextureFiltering=2
|
||||
Water=2
|
||||
[LightingDevices]
|
||||
Config=[{"id":"MSI MysticLight SDK","enabled":true,"config":{"ip":"localhost","port":1462,"ambientPort":14621,"authToken":""}}]
|
||||
Enabled=0
|
||||
[VoiceInput]
|
||||
InputMode=1
|
||||
[Input]
|
||||
InputSourcesSelectorMode=1
|
||||
[Options]
|
||||
Controller Feedback=4294967295
|
||||
WideAspectStretchedHUDMode=1
|
||||
KeyboardHighlightingMode=dynamic
|
||||
FOVScale=1.00000
|
||||
AutoFOV=0
|
||||
LockCursorToTheWindow=0
|
||||
AlwaysShowCursor=0
|
||||
[Startup]
|
||||
@@ -1,68 +0,0 @@
|
||||
[Language]
|
||||
Client=en-US
|
||||
Text=en-US
|
||||
Sound=en-US
|
||||
Subtitles=en-US
|
||||
[Graphics]
|
||||
AdapterVendorID=4318
|
||||
AdapterDeviceID=8712
|
||||
MonitorDesc=
|
||||
DisplayIndex=0
|
||||
WindowPosX=0
|
||||
WindowPosY=0
|
||||
FullscreenWidth=1920
|
||||
FullscreenHeight=1080
|
||||
WindowedWidth=1920
|
||||
WindowedHeight=1080
|
||||
WindowMaximised=0
|
||||
RefreshRate=0
|
||||
WindowMode=3
|
||||
VSyncMode=0
|
||||
MaxFPS=30
|
||||
IsFpsLimitEnabled=0
|
||||
PixelDensity=1.00000
|
||||
LastUsedFullscreenMode=1
|
||||
KeepStandardAspect=0
|
||||
HDREnabled=0
|
||||
Freesync2Enabled=0
|
||||
UpsampleType=0
|
||||
FSRQuality=0
|
||||
AdaptiveQuality=0
|
||||
Antialiasing=2
|
||||
Bloom=1
|
||||
Character=2
|
||||
CharacterTexture=2
|
||||
Cloud=2
|
||||
Clutter=3
|
||||
CrowdDensity=0
|
||||
Culling=0
|
||||
DOF=2
|
||||
Environment=3
|
||||
Fog=2
|
||||
Lighting=0
|
||||
MotionBlur=1
|
||||
Rain=2
|
||||
Reflection=1
|
||||
Shadow=3
|
||||
SSAO=2
|
||||
Terrain=0
|
||||
Tessellation=3
|
||||
Texture=2
|
||||
TextureFiltering=2
|
||||
Water=2
|
||||
[LightingDevices]
|
||||
Config=[{"id":"MSI MysticLight SDK","enabled":true,"config":{"ip":"localhost","port":1462,"ambientPort":14621,"authToken":""}}]
|
||||
Enabled=0
|
||||
[VoiceInput]
|
||||
InputMode=1
|
||||
[Input]
|
||||
InputSourcesSelectorMode=1
|
||||
[Options]
|
||||
Controller Feedback=4294967295
|
||||
WideAspectStretchedHUDMode=1
|
||||
KeyboardHighlightingMode=dynamic
|
||||
FOVScale=1.00000
|
||||
AutoFOV=0
|
||||
LockCursorToTheWindow=0
|
||||
AlwaysShowCursor=0
|
||||
[Startup]
|
||||
@@ -1,21 +0,0 @@
|
||||
[tool.poetry]
|
||||
name = "acvalhalla-harness"
|
||||
version = "0.1.0"
|
||||
description = ""
|
||||
authors = ["Nikolas Harris <nikolas@linusmediagroup.com"]
|
||||
|
||||
[tool.poetry.dependencies]
|
||||
python = "^3.10"
|
||||
PyAutoGUI = "^0.9.53"
|
||||
PyDirectInput = "^1.0.4"
|
||||
opencv-python = "^4.5.5"
|
||||
Pillow = "^9.1.1"
|
||||
psutil = "^5.9.1"
|
||||
PyYAML = "^6.0"
|
||||
imutils = "^0.5.4"
|
||||
|
||||
[tool.poetry.dev-dependencies]
|
||||
|
||||
[build-system]
|
||||
requires = ["poetry-core>=1.0.0"]
|
||||
build-backend = "poetry.core.masonry.api"
|
||||
@@ -1,19 +0,0 @@
|
||||
import cv2
|
||||
import os
|
||||
|
||||
from cv2_utils import *
|
||||
|
||||
script_dir = os.path.dirname(os.path.realpath(__file__))
|
||||
images_dir = os.path.join(script_dir, "images")
|
||||
test_images_dir = os.path.join(images_dir, "tests")
|
||||
|
||||
test_menus = {
|
||||
"mainmenu_2k": cv2.imread(os.path.join(test_images_dir, "menu_test_2k.png"), cv2.IMREAD_UNCHANGED),
|
||||
"menu_2k": cv2.imread(os.path.join(test_images_dir, "main_menu_2k.png"), cv2.IMREAD_UNCHANGED),
|
||||
"menu_1080": cv2.imread(os.path.join(test_images_dir, "1080_mainmenu_27inch4kscreen.png"), cv2.IMREAD_UNCHANGED),
|
||||
}
|
||||
|
||||
# found = locate_in_image(get_template('press_any'), test_menus['mainmenu_2k'], debug = 0)
|
||||
# print(found)
|
||||
found = locate_in_image(get_template('benchmark'), test_menus['menu_1080'], debug=1, threshold=0.8)
|
||||
print(found)
|
||||