Audit ttw (#22)

* remove pyproject

* delete presets

* Remove template tests

* pep8 lint cv2 utils

* pep8 lint
This commit is contained in:
Derek Hirotsu
2023-09-18 11:34:28 -07:00
committed by GitHub
parent 8431e79ddf
commit d109efe428
18 changed files with 138 additions and 780 deletions

5
.gitignore vendored
View File

@@ -1,9 +1,4 @@
.vscode/*
!.vscode/settings.json
!.vscode/tasks.json
!.vscode/launch.json
!.vscode/extensions.json
!.vscode/*.code-snippets
# Local History for Visual Studio Code
.history/

View File

@@ -1,3 +1,4 @@
"""DEPRECATED: Utility functions using Open CV"""
from enum import Enum
import logging
import time
@@ -13,36 +14,42 @@ DEFAULT_TIMEOUT = 60 # seconds
templates = {}
class ImageNotFoundTimeout(Exception):
pass
"""Raised when image not found after timeout"""
class ImageNotFound(Exception):
pass
"""Raised when image is not found"""
def get_template(name, set="16x9"):
return templates[name][set]
def get_template(name, aspect="16x9"):
"""Get template image of given aspect ratio"""
return templates[name][aspect]
def gcd(a, b):
def gcd(a, b) -> int:
"""Recursively finds the greatest common divisor of two numbers"""
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)
def aspect_ratio(width, height) -> str:
"""Calculates an aspect ratio given a width and height"""
denom = int(gcd(width, height))
x = int(width / denom)
y = int(height / denom)
if x == 8 and y == 5:
return "16x10"
elif x == 16 and y == 9:
if x == 16 and y == 9:
return "16x9"
return f"{x}x{y}"
# 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]
"""Tries to find an image template within another image"""
(template_height, template_width) = needle.shape[:2]
if debug:
cv2.imshow("Looking For", needle)
@@ -51,125 +58,112 @@ def locate_in_image(needle, haystack, threshold=DEFAULT_MATCH_THRESHOLD, debug=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])
resized = imutils.resize(
haystack, width=int(haystack.shape[1] * scale), inter=cv2.INTER_NEAREST)
ratio = 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:
if resized.shape[0] < template_height or resized.shape[1] < template_width:
break
result = cv2.matchTemplate(resized, needle, cv2.TM_CCOEFF_NORMED)
(_, maxVal, _, maxLoc) = cv2.minMaxLoc(result)
(_, max_val, _, max_loc) = cv2.minMaxLoc(
cv2.matchTemplate(resized, needle, cv2.TM_CCOEFF_NORMED))
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.rectangle(resized, (max_loc[0], max_loc[1]),
(max_loc[0] + template_width, max_loc[1] + template_height), (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 max_val >= threshold:
# compute the (x, y) coordinates of the bounding box based on the resized ratio
(start_x, start_y) = (int(max_loc[0] * ratio), int(max_loc[1] * ratio))
(end_x, end_y) = (
int((max_loc[0] + template_width) * ratio),
int((max_loc[1] + template_height) * ratio)
)
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.rectangle(
haystack, (start_x, start_y), (end_x, end_y), (0, 0, 255), 2)
cv2.imshow("Found", haystack)
cv2.waitKey(0)
return startX, startY
return start_x, start_y
raise ImageNotFound("Image not found on screen")
def locate_on_screen(template_name, threshold=DEFAULT_MATCH_THRESHOLD, debug=0):
"""Tries to find an image template on the screen"""
screen = gui.screenshot()
# pyautogui is using Pillow which is giving a format that must be adapted to work with opencv.
screen = np.array(screen)
screen = np.array(screen)
screen = cv2.cvtColor(screen, cv2.COLOR_RGB2BGR)
(h, w) = screen.shape[:2]
r = aspect_ratio(w, h)
needle = get_template(template_name, r)
(height, width) = screen.shape[:2]
ratio = aspect_ratio(width, height)
needle = get_template(template_name, ratio)
return needle, locate_in_image(needle, screen, threshold, debug)
def wait_for_image_on_screen(template_name, match_threshold=DEFAULT_MATCH_THRESHOLD, interval=DEFAULT_INTERVAL,
timeout=DEFAULT_TIMEOUT):
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:
of the image if found
"""
start_time = time.time()
current_time = start_time
while not current_time - start_time > timeout:
try:
img, loc = locate_on_screen(template_name, match_threshold)
return img, loc
except ImageNotFound:
pass
time.sleep(interval)
t1 = time.time()
current_time = time.time()
raise ImageNotFoundTimeout("Could not find image on screen within timeout")
class ClickType(Enum):
"""Enumerates different types of clicks"""
SINGLE = 0 # uses .click()
DOUBLE = 1 # uses .doubleclick()
HARD = 2 # uses mouse.down() and mouse.up()
AUTO_GUI = 3 # uses pyautogui instead of pydirectinput
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 get_middle_of_rect(top_left_corner, height, width) -> tuple[int]:
"""Given x, y coordinates of top left corner of a rectangle and its
width and height, calculate the coordinates of the center
"""
center_x = top_left_corner[0] + (width / 2)
center_y = top_left_corner[1] + (height / 2)
return int(center_x), int(center_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])
print(f"Hard click loc {click_loc}")
user.moveTo(click_loc[0], click_loc[1])
user.mouseDown()
user.mouseUp()
def autogui_click(top_left_corner, img):
click_loc = get_middle_of_rect(top_left_corner, img.shape[0], img.shape[1])
logging.info(f"Using AutoGui Clicking {click_loc}")
user.moveTo(click_loc[0], click_loc[1])
gui.click()
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}")
def wait_and_click(
template_name, name, click_type: ClickType = ClickType.SINGLE, timeout=DEFAULT_TIMEOUT):
"""Wait to find an given image on screen and then click it"""
logging.info("Waiting to find and click on %s", name)
img, img_loc = wait_for_image_on_screen(template_name, timeout=timeout)
click_loc = get_middle_of_rect(img_loc, img.shape[0], img.shape[1])
logging.info("Click coordinates %s", (click_loc,))
if click_type == ClickType.SINGLE:
click(img_loc, img)
user.click(click_loc[0], click_loc[1])
elif click_type == ClickType.DOUBLE:
double_click(img_loc, img)
user.doubleClick(click_loc[0], click_loc[1])
elif click_type == ClickType.HARD:
hard_click(img_loc, img)
user.moveTo(click_loc[0], click_loc[1])
user.mouseDown()
user.mouseUp()
elif click_type == ClickType.AUTO_GUI:
autogui_click(img_loc, img)
user.moveTo(click_loc[0], click_loc[1])
gui.click()
else:
raise ValueError("Unknown click type")
raise ValueError("Unknown click type")

View File

@@ -1,5 +1,7 @@
# Tiny Tina's Wonderland
This script navigates through in-game menus to the built in benchmark and runs it with the current settings.
## Prerequisites
- Python 3.10+
@@ -11,30 +13,13 @@
2. Install Tiny Tina's Wonderland from Epic Launcher.
1. Location **does** matter, the harness has to be aware of install location.
## Configuration
## Output
Below is an example use of this harness as a test in a benchmark configuration.
report.json
- `resolution`: string representing the resolution the test was run at, formatted as "[width]x[heigt]", e.x. `1920x1080`
- `start_time`: number representing a timestamp of the test's start time in milliseconds
- `end_time`: number representing a timestamp of the test's end time in milliseconds
```yaml
...
...
tests:
- name: tinytinaswonderland
executable: "tinytinaswonderland.py"
process_name: "Wonderlands.exe"
output_dir: "run"
```
__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.
## Common Issues
## Known Issues
1. "Login to Microsoft" modal pops up
- This game will not let you pass into the menu if you are not signed into Xbox. If you run this game at least once before running you can login then, or pre-login before running the harness.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.0 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.6 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.8 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.8 MiB

View File

@@ -1,12 +1,5 @@
friendly_name: "Tiny Tina's Wonderlands"
executable: "tinytinaswonderland.py"
process_name: "Wonderlands.exe"
# default recording delay to reduce capturing menus during setup, this should be revisited every test bench as loading times may be different
recording_delay: 75
output_dir: "run"
options:
- name: preset
type: select
# disabling presets in favor of manually setting for now
# values: [verylow,low,medium,high,ultra,badass]
values: [current]
output_dir: "run"

View File

@@ -1,100 +0,0 @@
[ScalabilityGroups]
sg.ResolutionQuality=100.000000
sg.ViewDistanceQuality=3
sg.AntiAliasingQuality=3
sg.ShadowQuality=3
sg.PostProcessQuality=3
sg.TextureQuality=3
sg.EffectsQuality=3
sg.FoliageQuality=3
[/Script/OakGame.OakGameUserSettings]
ResolutionScale=Scale_100
FrameRateLimitMode=Unlimited
CustomFrameRateLimit=144
bEnableCameraMotionBlur=True
bEnablePerObjectMotionBlur=True
bEnableCAS=True
GraphicsQualityMode=Badass
RecommendedGraphicsQualityMode=High
TextureStreamingQuality=Ultra
MaterialQuality=Ultra
AntiAliasingModeIndex=2
AnisotropicFilteringMode=SixteenX
ShadowQualityMode=Ultra
PerformanceStatsLevel=0
EnvironmentTextureDetailMode=Deprecated
DrawDistanceMode=Ultra
EnvironmentDetailMode=Ultra
TerrainMode=Ultra
FoliageMode=Ultra
VolumetricFogType=Ultra
ScreenSpaceReflectionsMode=Ultra
CharacterTextureDetailMode=Deprecated
CharacterDetailMode=Ultra
AmbientOcclusionQualityMode=Ultra
AMD_FSR2_Preset=Off
AMD_FSR2_Sharpness_Preset=0.000000
EdgeDetectionTexelOffset=-1.000000
BenchmarkDataOutputMode=DetailedCSV
UISafeFrameScaling=1.000000
HDRBrightness=400.000000
Brightness=50.000000
BlackLevel=0.000000
HdrUIBrightness=4.000000
LastBenchmarkDateTime=
LastBenchmarkDataOutputPath=
LastBenchmarkAvgFPS=0.000000
LastBenchmarkAvgFrameTime=0.000000
LastBenchmarkAvgCPU=0.000000
LastBenchmarkAvgGPU=0.000000
LastBenchmarkLoadTimeSeconds=0.000000
AnalyticsTag=
TextureStreamingViewBoostScale=0.000000
TextureStreamingViewBoostScaleOverride=-1.000000
TextureStreamingAdaptiveBoostScale=0.750000
TextureStreamingAdaptiveBoostScaleOverride=-1.000000
TextureStreamingPoolSizeMB=3000
TextureStreamingPoolSizeMBOverride=-1
bHasPerformedDirectXBetaUpgrade=False
bUseVSync=False
bUseDynamicResolution=False
ResolutionSizeX=1920
ResolutionSizeY=1080
LastUserConfirmedResolutionSizeX=2560
LastUserConfirmedResolutionSizeY=1440
WindowPosX=-1
WindowPosY=-1
FullscreenMode=0
LastConfirmedFullscreenMode=2
PreferredFullscreenMode=1
Version=8
AudioQualityLevel=0
FrameRateLimit=0.000000
DesiredScreenWidth=1280
DesiredScreenHeight=720
LastUserConfirmedDesiredScreenWidth=1280
LastUserConfirmedDesiredScreenHeight=720
LastRecommendedScreenWidth=-1.000000
LastRecommendedScreenHeight=-1.000000
PreferredMonitor=SAM7176
PreferredMonitorDeviceName=
bPrimaryIsPreferredMonitor=True
LastCPUBenchmarkResult=1.000000
LastGPUBenchmarkResult=1.000000
LastGPUBenchmarkMultiplier=1.000000
LastBenchmarkResultCPUName=
LastBenchmarkResultGPUName=
bUseHDRDisplayOutput=False
HDRDisplayOutputNits=1000
bUsePerformanceMode=False
PreferredGraphicsAPI=DX12
PreferredRefreshRate=0
[/Script/Engine.GameUserSettings]
bUseDesiredScreenHeight=False
[ShaderPipelineCache.CacheFile]
LastOpened=

View File

@@ -1,100 +0,0 @@
[ScalabilityGroups]
sg.ResolutionQuality=100.000000
sg.ViewDistanceQuality=3
sg.AntiAliasingQuality=3
sg.ShadowQuality=2
sg.PostProcessQuality=3
sg.TextureQuality=2
sg.EffectsQuality=3
sg.FoliageQuality=2
[/Script/OakGame.OakGameUserSettings]
ResolutionScale=Scale_100
FrameRateLimitMode=Unlimited
CustomFrameRateLimit=144
bEnableCameraMotionBlur=False
bEnablePerObjectMotionBlur=False
bEnableCAS=True
GraphicsQualityMode=High
RecommendedGraphicsQualityMode=High
TextureStreamingQuality=High
MaterialQuality=High
AntiAliasingModeIndex=2
AnisotropicFilteringMode=EightX
ShadowQualityMode=High
PerformanceStatsLevel=0
EnvironmentTextureDetailMode=Deprecated
DrawDistanceMode=High
EnvironmentDetailMode=High
TerrainMode=High
FoliageMode=High
VolumetricFogType=High
ScreenSpaceReflectionsMode=High
CharacterTextureDetailMode=Deprecated
CharacterDetailMode=High
AmbientOcclusionQualityMode=High
AMD_FSR2_Preset=Off
AMD_FSR2_Sharpness_Preset=0.000000
EdgeDetectionTexelOffset=-1.000000
BenchmarkDataOutputMode=DetailedCSV
UISafeFrameScaling=1.000000
HDRBrightness=400.000000
Brightness=50.000000
BlackLevel=0.000000
HdrUIBrightness=4.000000
LastBenchmarkDateTime=
LastBenchmarkDataOutputPath=
LastBenchmarkAvgFPS=0.000000
LastBenchmarkAvgFrameTime=0.000000
LastBenchmarkAvgCPU=0.000000
LastBenchmarkAvgGPU=0.000000
LastBenchmarkLoadTimeSeconds=0.000000
AnalyticsTag=
TextureStreamingViewBoostScale=0.000000
TextureStreamingViewBoostScaleOverride=-1.000000
TextureStreamingAdaptiveBoostScale=0.500000
TextureStreamingAdaptiveBoostScaleOverride=-1.000000
TextureStreamingPoolSizeMB=2000
TextureStreamingPoolSizeMBOverride=-1
bHasPerformedDirectXBetaUpgrade=False
bUseVSync=False
bUseDynamicResolution=False
ResolutionSizeX=1920
ResolutionSizeY=1080
LastUserConfirmedResolutionSizeX=2560
LastUserConfirmedResolutionSizeY=1440
WindowPosX=-1
WindowPosY=-1
FullscreenMode=0
LastConfirmedFullscreenMode=2
PreferredFullscreenMode=1
Version=8
AudioQualityLevel=0
FrameRateLimit=0.000000
DesiredScreenWidth=1280
DesiredScreenHeight=720
LastUserConfirmedDesiredScreenWidth=1280
LastUserConfirmedDesiredScreenHeight=720
LastRecommendedScreenWidth=-1.000000
LastRecommendedScreenHeight=-1.000000
PreferredMonitor=SAM7176
PreferredMonitorDeviceName=
bPrimaryIsPreferredMonitor=True
LastCPUBenchmarkResult=1.000000
LastGPUBenchmarkResult=1.000000
LastGPUBenchmarkMultiplier=1.000000
LastBenchmarkResultCPUName=
LastBenchmarkResultGPUName=
bUseHDRDisplayOutput=False
HDRDisplayOutputNits=1000
bUsePerformanceMode=False
PreferredGraphicsAPI=DX12
PreferredRefreshRate=0
[/Script/Engine.GameUserSettings]
bUseDesiredScreenHeight=False
[ShaderPipelineCache.CacheFile]
LastOpened=

View File

@@ -1,100 +0,0 @@
[ScalabilityGroups]
sg.ResolutionQuality=100.000000
sg.ViewDistanceQuality=3
sg.AntiAliasingQuality=3
sg.ShadowQuality=1
sg.PostProcessQuality=3
sg.TextureQuality=1
sg.EffectsQuality=3
sg.FoliageQuality=0
[/Script/OakGame.OakGameUserSettings]
ResolutionScale=Scale_100
FrameRateLimitMode=Unlimited
CustomFrameRateLimit=144
bEnableCameraMotionBlur=False
bEnablePerObjectMotionBlur=False
bEnableCAS=False
GraphicsQualityMode=Low
RecommendedGraphicsQualityMode=High
TextureStreamingQuality=Medium
MaterialQuality=Medium
AntiAliasingModeIndex=1
AnisotropicFilteringMode=TwoX
ShadowQualityMode=Medium
PerformanceStatsLevel=0
EnvironmentTextureDetailMode=Deprecated
DrawDistanceMode=Low
EnvironmentDetailMode=Low
TerrainMode=Medium
FoliageMode=Low
VolumetricFogType=Low
ScreenSpaceReflectionsMode=Off
CharacterTextureDetailMode=Deprecated
CharacterDetailMode=Low
AmbientOcclusionQualityMode=Low
AMD_FSR2_Preset=Off
AMD_FSR2_Sharpness_Preset=0.000000
EdgeDetectionTexelOffset=-1.000000
BenchmarkDataOutputMode=DetailedCSV
UISafeFrameScaling=1.000000
HDRBrightness=400.000000
Brightness=50.000000
BlackLevel=0.000000
HdrUIBrightness=4.000000
LastBenchmarkDateTime=
LastBenchmarkDataOutputPath=
LastBenchmarkAvgFPS=0.000000
LastBenchmarkAvgFrameTime=0.000000
LastBenchmarkAvgCPU=0.000000
LastBenchmarkAvgGPU=0.000000
LastBenchmarkLoadTimeSeconds=0.000000
AnalyticsTag=
TextureStreamingViewBoostScale=0.000000
TextureStreamingViewBoostScaleOverride=-1.000000
TextureStreamingAdaptiveBoostScale=0.250000
TextureStreamingAdaptiveBoostScaleOverride=-1.000000
TextureStreamingPoolSizeMB=1200
TextureStreamingPoolSizeMBOverride=-1
bHasPerformedDirectXBetaUpgrade=False
bUseVSync=False
bUseDynamicResolution=False
ResolutionSizeX=1920
ResolutionSizeY=1080
LastUserConfirmedResolutionSizeX=2560
LastUserConfirmedResolutionSizeY=1440
WindowPosX=-1
WindowPosY=-1
FullscreenMode=0
LastConfirmedFullscreenMode=2
PreferredFullscreenMode=1
Version=8
AudioQualityLevel=0
FrameRateLimit=0.000000
DesiredScreenWidth=1280
DesiredScreenHeight=720
LastUserConfirmedDesiredScreenWidth=1280
LastUserConfirmedDesiredScreenHeight=720
LastRecommendedScreenWidth=-1.000000
LastRecommendedScreenHeight=-1.000000
PreferredMonitor=SAM7176
PreferredMonitorDeviceName=
bPrimaryIsPreferredMonitor=True
LastCPUBenchmarkResult=1.000000
LastGPUBenchmarkResult=1.000000
LastGPUBenchmarkMultiplier=1.000000
LastBenchmarkResultCPUName=
LastBenchmarkResultGPUName=
bUseHDRDisplayOutput=False
HDRDisplayOutputNits=1000
bUsePerformanceMode=False
PreferredGraphicsAPI=DX12
PreferredRefreshRate=0
[/Script/Engine.GameUserSettings]
bUseDesiredScreenHeight=False
[ShaderPipelineCache.CacheFile]
LastOpened=

View File

@@ -1,100 +0,0 @@
[ScalabilityGroups]
sg.ResolutionQuality=100.000000
sg.ViewDistanceQuality=3
sg.AntiAliasingQuality=3
sg.ShadowQuality=1
sg.PostProcessQuality=3
sg.TextureQuality=2
sg.EffectsQuality=3
sg.FoliageQuality=1
[/Script/OakGame.OakGameUserSettings]
ResolutionScale=Scale_100
FrameRateLimitMode=Unlimited
CustomFrameRateLimit=144
bEnableCameraMotionBlur=False
bEnablePerObjectMotionBlur=False
bEnableCAS=False
GraphicsQualityMode=Medium
RecommendedGraphicsQualityMode=High
TextureStreamingQuality=High
MaterialQuality=High
AntiAliasingModeIndex=1
AnisotropicFilteringMode=FourX
ShadowQualityMode=Medium
PerformanceStatsLevel=0
EnvironmentTextureDetailMode=Deprecated
DrawDistanceMode=Medium
EnvironmentDetailMode=Medium
TerrainMode=Medium
FoliageMode=Medium
VolumetricFogType=Medium
ScreenSpaceReflectionsMode=Medium
CharacterTextureDetailMode=Deprecated
CharacterDetailMode=Medium
AmbientOcclusionQualityMode=Medium
AMD_FSR2_Preset=Off
AMD_FSR2_Sharpness_Preset=0.000000
EdgeDetectionTexelOffset=-1.000000
BenchmarkDataOutputMode=DetailedCSV
UISafeFrameScaling=1.000000
HDRBrightness=400.000000
Brightness=50.000000
BlackLevel=0.000000
HdrUIBrightness=4.000000
LastBenchmarkDateTime=
LastBenchmarkDataOutputPath=
LastBenchmarkAvgFPS=0.000000
LastBenchmarkAvgFrameTime=0.000000
LastBenchmarkAvgCPU=0.000000
LastBenchmarkAvgGPU=0.000000
LastBenchmarkLoadTimeSeconds=0.000000
AnalyticsTag=
TextureStreamingViewBoostScale=0.000000
TextureStreamingViewBoostScaleOverride=-1.000000
TextureStreamingAdaptiveBoostScale=0.500000
TextureStreamingAdaptiveBoostScaleOverride=-1.000000
TextureStreamingPoolSizeMB=2000
TextureStreamingPoolSizeMBOverride=-1
bHasPerformedDirectXBetaUpgrade=False
bUseVSync=False
bUseDynamicResolution=False
ResolutionSizeX=1920
ResolutionSizeY=1080
LastUserConfirmedResolutionSizeX=2560
LastUserConfirmedResolutionSizeY=1440
WindowPosX=-1
WindowPosY=-1
FullscreenMode=0
LastConfirmedFullscreenMode=2
PreferredFullscreenMode=1
Version=8
AudioQualityLevel=0
FrameRateLimit=0.000000
DesiredScreenWidth=1280
DesiredScreenHeight=720
LastUserConfirmedDesiredScreenWidth=1280
LastUserConfirmedDesiredScreenHeight=720
LastRecommendedScreenWidth=-1.000000
LastRecommendedScreenHeight=-1.000000
PreferredMonitor=SAM7176
PreferredMonitorDeviceName=
bPrimaryIsPreferredMonitor=True
LastCPUBenchmarkResult=1.000000
LastGPUBenchmarkResult=1.000000
LastGPUBenchmarkMultiplier=1.000000
LastBenchmarkResultCPUName=
LastBenchmarkResultGPUName=
bUseHDRDisplayOutput=False
HDRDisplayOutputNits=1000
bUsePerformanceMode=False
PreferredGraphicsAPI=DX12
PreferredRefreshRate=0
[/Script/Engine.GameUserSettings]
bUseDesiredScreenHeight=False
[ShaderPipelineCache.CacheFile]
LastOpened=

View File

@@ -1,100 +0,0 @@
[ScalabilityGroups]
sg.ResolutionQuality=100.000000
sg.ViewDistanceQuality=3
sg.AntiAliasingQuality=3
sg.ShadowQuality=3
sg.PostProcessQuality=3
sg.TextureQuality=3
sg.EffectsQuality=3
sg.FoliageQuality=3
[/Script/OakGame.OakGameUserSettings]
ResolutionScale=Scale_100
FrameRateLimitMode=Unlimited
CustomFrameRateLimit=144
bEnableCameraMotionBlur=True
bEnablePerObjectMotionBlur=True
bEnableCAS=True
GraphicsQualityMode=Ultra
RecommendedGraphicsQualityMode=High
TextureStreamingQuality=Ultra
MaterialQuality=Ultra
AntiAliasingModeIndex=2
AnisotropicFilteringMode=SixteenX
ShadowQualityMode=Ultra
PerformanceStatsLevel=0
EnvironmentTextureDetailMode=Deprecated
DrawDistanceMode=Ultra
EnvironmentDetailMode=Ultra
TerrainMode=Ultra
FoliageMode=Ultra
VolumetricFogType=High
ScreenSpaceReflectionsMode=High
CharacterTextureDetailMode=Deprecated
CharacterDetailMode=Ultra
AmbientOcclusionQualityMode=Ultra
AMD_FSR2_Preset=Off
AMD_FSR2_Sharpness_Preset=0.000000
EdgeDetectionTexelOffset=-1.000000
BenchmarkDataOutputMode=DetailedCSV
UISafeFrameScaling=1.000000
HDRBrightness=400.000000
Brightness=50.000000
BlackLevel=0.000000
HdrUIBrightness=4.000000
LastBenchmarkDateTime=
LastBenchmarkDataOutputPath=
LastBenchmarkAvgFPS=0.000000
LastBenchmarkAvgFrameTime=0.000000
LastBenchmarkAvgCPU=0.000000
LastBenchmarkAvgGPU=0.000000
LastBenchmarkLoadTimeSeconds=0.000000
AnalyticsTag=
TextureStreamingViewBoostScale=0.000000
TextureStreamingViewBoostScaleOverride=-1.000000
TextureStreamingAdaptiveBoostScale=0.750000
TextureStreamingAdaptiveBoostScaleOverride=-1.000000
TextureStreamingPoolSizeMB=3000
TextureStreamingPoolSizeMBOverride=-1
bHasPerformedDirectXBetaUpgrade=False
bUseVSync=False
bUseDynamicResolution=False
ResolutionSizeX=1920
ResolutionSizeY=1080
LastUserConfirmedResolutionSizeX=2560
LastUserConfirmedResolutionSizeY=1440
WindowPosX=-1
WindowPosY=-1
FullscreenMode=0
LastConfirmedFullscreenMode=2
PreferredFullscreenMode=1
Version=8
AudioQualityLevel=0
FrameRateLimit=0.000000
DesiredScreenWidth=1280
DesiredScreenHeight=720
LastUserConfirmedDesiredScreenWidth=1280
LastUserConfirmedDesiredScreenHeight=720
LastRecommendedScreenWidth=-1.000000
LastRecommendedScreenHeight=-1.000000
PreferredMonitor=SAM7176
PreferredMonitorDeviceName=
bPrimaryIsPreferredMonitor=True
LastCPUBenchmarkResult=1.000000
LastGPUBenchmarkResult=1.000000
LastGPUBenchmarkMultiplier=1.000000
LastBenchmarkResultCPUName=
LastBenchmarkResultGPUName=
bUseHDRDisplayOutput=False
HDRDisplayOutputNits=1000
bUsePerformanceMode=False
PreferredGraphicsAPI=DX12
PreferredRefreshRate=0
[/Script/Engine.GameUserSettings]
bUseDesiredScreenHeight=False
[ShaderPipelineCache.CacheFile]
LastOpened=

View File

@@ -1,100 +0,0 @@
[ScalabilityGroups]
sg.ResolutionQuality=100.000000
sg.ViewDistanceQuality=3
sg.AntiAliasingQuality=3
sg.ShadowQuality=0
sg.PostProcessQuality=3
sg.TextureQuality=0
sg.EffectsQuality=3
sg.FoliageQuality=0
[/Script/OakGame.OakGameUserSettings]
ResolutionScale=Scale_100
FrameRateLimitMode=Unlimited
CustomFrameRateLimit=144
bEnableCameraMotionBlur=False
bEnablePerObjectMotionBlur=False
bEnableCAS=False
GraphicsQualityMode=VeryLow
RecommendedGraphicsQualityMode=High
TextureStreamingQuality=Low
MaterialQuality=Low
AntiAliasingModeIndex=0
AnisotropicFilteringMode=Trilinear
ShadowQualityMode=Low
PerformanceStatsLevel=0
EnvironmentTextureDetailMode=Deprecated
DrawDistanceMode=Low
EnvironmentDetailMode=Low
TerrainMode=Low
FoliageMode=Low
VolumetricFogType=Low
ScreenSpaceReflectionsMode=Off
CharacterTextureDetailMode=Deprecated
CharacterDetailMode=Low
AmbientOcclusionQualityMode=Off
AMD_FSR2_Preset=Off
AMD_FSR2_Sharpness_Preset=0.000000
EdgeDetectionTexelOffset=-1.000000
BenchmarkDataOutputMode=DetailedCSV
UISafeFrameScaling=1.000000
HDRBrightness=400.000000
Brightness=50.000000
BlackLevel=0.000000
HdrUIBrightness=4.000000
LastBenchmarkDateTime=
LastBenchmarkDataOutputPath=
LastBenchmarkAvgFPS=0.000000
LastBenchmarkAvgFrameTime=0.000000
LastBenchmarkAvgCPU=0.000000
LastBenchmarkAvgGPU=0.000000
LastBenchmarkLoadTimeSeconds=0.000000
AnalyticsTag=
TextureStreamingViewBoostScale=0.000000
TextureStreamingViewBoostScaleOverride=-1.000000
TextureStreamingAdaptiveBoostScale=0.000000
TextureStreamingAdaptiveBoostScaleOverride=-1.000000
TextureStreamingPoolSizeMB=800
TextureStreamingPoolSizeMBOverride=-1
bHasPerformedDirectXBetaUpgrade=False
bUseVSync=False
bUseDynamicResolution=False
ResolutionSizeX=1920
ResolutionSizeY=1080
LastUserConfirmedResolutionSizeX=2560
LastUserConfirmedResolutionSizeY=1440
WindowPosX=-1
WindowPosY=-1
FullscreenMode=0
LastConfirmedFullscreenMode=2
PreferredFullscreenMode=1
Version=8
AudioQualityLevel=0
FrameRateLimit=0.000000
DesiredScreenWidth=1280
DesiredScreenHeight=720
LastUserConfirmedDesiredScreenWidth=1280
LastUserConfirmedDesiredScreenHeight=720
LastRecommendedScreenWidth=-1.000000
LastRecommendedScreenHeight=-1.000000
PreferredMonitor=SAM7176
PreferredMonitorDeviceName=
bPrimaryIsPreferredMonitor=True
LastCPUBenchmarkResult=1.000000
LastGPUBenchmarkResult=1.000000
LastGPUBenchmarkMultiplier=1.000000
LastBenchmarkResultCPUName=
LastBenchmarkResultGPUName=
bUseHDRDisplayOutput=False
HDRDisplayOutputNits=1000
bUsePerformanceMode=False
PreferredGraphicsAPI=DX12
PreferredRefreshRate=0
[/Script/Engine.GameUserSettings]
bUseDesiredScreenHeight=False
[ShaderPipelineCache.CacheFile]
LastOpened=

View File

@@ -1,21 +0,0 @@
[tool.poetry]
name = "tinytinaswonderland"
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"

View File

@@ -1,15 +0,0 @@
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": cv2.imread(os.path.join(test_images_dir, "main_menu_2k.png"), cv2.IMREAD_UNCHANGED),
"settings_menu": cv2.imread(os.path.join(test_images_dir, "settings_menu_2k.png"), cv2.IMREAD_UNCHANGED),
"benchmark_menu": cv2.imread(os.path.join(test_images_dir, "benchmark_menu_2k.png"), cv2.IMREAD_UNCHANGED),
"1080menu": cv2.imread(os.path.join(test_images_dir, "menu_1080p_27inch.png"), cv2.IMREAD_UNCHANGED)
}
found = locate_in_image(get_template('options'), test_menus['1080menu'], threshold=0.8, debug=1)
print(found)

View File

@@ -1,15 +1,25 @@
"""Tiny Tina's Wonderland test script"""
import logging
import time
import os
from subprocess import Popen
import sys
import os
import time
from utils import read_resolution, try_install_paths, get_local_drives, templates
sys.path.insert(1, os.path.join(sys.path[0], '..'))
#pylint: disable=wrong-import-position
import deprecated.cv2_utils
from harness_utils.logging import *
from harness_utils.logging import (
format_resolution,
seconds_to_milliseconds,
setup_log_directory,
write_report_json,
DEFAULT_LOGGING_FORMAT,
DEFAULT_DATE_FORMAT,
)
from harness_utils.process import terminate_processes
from harness_utils.steam import get_run_game_id_command, DEFAULT_EXECUTABLE_PATH as steam_path
#pylint: disable=wrong-import-position
SCRIPT_DIRECTORY = os.path.dirname(os.path.realpath(__file__))
LOG_DIRECTORY = os.path.join(SCRIPT_DIRECTORY, "run")
@@ -18,41 +28,45 @@ EXECUTABLE = "Wonderlands.exe"
def start_game() -> any:
"""Start the game process"""
game_process = None
try:
exec_path = try_install_paths(get_local_drives())
game_process = Popen(exec_path)
except ValueError:
logging.info("Could not find executable, trying a steam launch")
pass
if game_process is None:
steam_run_arg = get_run_game_id_command(STEAM_GAME_ID)
logging.info(steam_path + " " + steam_run_arg)
logging.info("%s %s", steam_path, steam_run_arg)
game_process = Popen([steam_path, steam_run_arg])
def run_benchmark():
"""Start the benchmark"""
start_game()
t1 = time.time()
setup_start_time = time.time()
# wait for menu to load
time.sleep(30)
deprecated.cv2_utils.wait_and_click("options", "options menu", deprecated.cv2_utils.ClickType.HARD)
deprecated.cv2_utils.wait_and_click("benchmark", "benchmark menu", deprecated.cv2_utils.ClickType.HARD)
deprecated.cv2_utils.wait_and_click("start", "start benchmark", deprecated.cv2_utils.ClickType.HARD)
t2 = time.time()
logging.info(f"Harness setup took {round((t2 - t1), 2)} seconds")
deprecated.cv2_utils.wait_and_click(
"options", "options menu", deprecated.cv2_utils.ClickType.HARD)
deprecated.cv2_utils.wait_and_click(
"benchmark", "benchmark menu", deprecated.cv2_utils.ClickType.HARD)
deprecated.cv2_utils.wait_and_click(
"start", "start benchmark", deprecated.cv2_utils.ClickType.HARD)
elapsed_setup_time = round(time.time() - setup_start_time, 2)
logging.info("Setup took %f seconds", elapsed_setup_time)
start_time = time.time()
test_start_time = time.time()
time.sleep(124)
deprecated.cv2_utils.wait_for_image_on_screen("options", 0.8, 2, 60)
end_time = time.time()
logging.info(f"Benchark took {round((end_time - start_time), 2)} seconds")
test_end_time = time.time()
elapsed_test_time = round(test_end_time - test_start_time, 2)
logging.info("Benchmark took %f seconds", elapsed_test_time)
terminate_processes("Wonderlands")
return start_time, end_time
@@ -74,14 +88,14 @@ try:
height, width = read_resolution()
result = {
"resolution": format_resolution(width, height),
"graphics_preset": "current",
"start_time": seconds_to_milliseconds(start_time),
"end_time": seconds_to_milliseconds(end_time)
}
write_report_json(LOG_DIRECTORY, "report.json", result)
#pylint: disable=broad-exception-caught
except Exception as e:
logging.error("Something went wrong running the benchmark!")
logging.exception(e)
terminate_processes("Wonderlands")
exit(1)
sys.exit(1)

View File

@@ -1,19 +1,21 @@
import win32api
import win32file
import winreg
"""Utility functions for Tiny Tina's Wonderland test script"""
import os
import logging
import re
import winreg
import win32api
import win32file
import cv2
EXECUTABLE = "Wonderlands.exe"
def get_documents_path() -> str:
SHELL_FOLDER_KEY = r'SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders'
"""Use registry to find documents path"""
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)
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:
@@ -38,13 +40,20 @@ def get_local_drives() -> list[str]:
for letter in drive_list:
if win32file.GetDriveType(letter) == win32file.DRIVE_FIXED:
list_local_drives.append(letter)
return list_local_drives
return list_local_drives
def try_install_paths(drives) -> str:
"""Look for executable in common install paths"""
for drive_letter in drives:
try_me = f"{drive_letter}Program Files\\Epic Games\\TinyTinasWonderlands\\OakGame\\Binaries\\Win64\\{EXECUTABLE}"
try_me2 = f"{drive_letter}Epic Games\\TinyTinasWonderlands\\OakGame\\Binaries\\Win64\\{EXECUTABLE}"
try_me = (
f"{drive_letter}Program Files\\Epic Games\\TinyTinasWonderlands"
f"\\OakGame\\Binaries\\Win64\\{EXECUTABLE}"
)
try_me2 = (
f"{drive_letter}Epic Games\\TinyTinasWonderlands"
f"\\OakGame\\Binaries\\Win64\\{EXECUTABLE}"
)
if valid_filepath(try_me):
return try_me
if valid_filepath(try_me2):
@@ -53,12 +62,16 @@ def try_install_paths(drives) -> str:
def read_resolution() -> tuple[int]:
dest = f"{get_documents_path()}\\My Games\\Tiny Tina's Wonderlands\\Saved\\Config\\WindowsNoEditor\\GameUserSettings.ini"
"""Read resolution from local ini file"""
dest = (
f"{get_documents_path()}\\My Games\\Tiny Tina's Wonderlands"
"\\Saved\\Config\\WindowsNoEditor\\GameUserSettings.ini"
)
hpattern = re.compile(r"ResolutionSizeY=(\d*)")
wpattern = re.compile(r"ResolutionSizeX=(\d*)")
h = w = 0
with open(dest) as fp:
lines = fp.readlines()
with open(dest, encoding="utf-8") as file:
lines = file.readlines()
for line in lines:
result = hpattern.match(line)
if result is not None:
@@ -69,7 +82,7 @@ def read_resolution() -> tuple[int]:
w = result2.group(1)
if int(h) > 0 and int(w) > 0:
break
logging.info(f"Current resolution is {h}x{w}")
logging.info("Current resolution is %dx%d", h, w)
return (h, w)