Audit RDR2 (#31)

* remove graphics presets

* remove unused assets

* pep8 lint

* update readme

* lint

* add resolution func

* implement get resolution stub for rdr2
This commit is contained in:
Derek Hirotsu
2023-09-19 09:56:16 -07:00
committed by GitHub
parent 67a786f9fd
commit 995469aae0
12 changed files with 76 additions and 198 deletions

View File

@@ -4,7 +4,7 @@ import re
import winreg import winreg
import logging import logging
def get_resolution() -> tuple[int]: def get_resolution() -> tuple[int]:
"""Gets resolution width and height from local xml file created by game.""" """Gets resolution width and height from local xml file created by game."""
username = os.getlogin() username = os.getlogin()
config_path = f"C:\\Users\\{username}\\Documents\\My Games\\F1 22\\hardwaresettings" config_path = f"C:\\Users\\{username}\\Documents\\My Games\\F1 22\\hardwaresettings"

View File

@@ -1,45 +1,15 @@
# Red Dead Redemption 2 # Red Dead Redemption 2
This script navigates through in-game menus to the built in benchmark and runs it with the current settings.
## Prerequisites ## Prerequisites
- Python 3.10+ - Python 3.10+
- Red Dead Redemp installed. - Red Dead Redemption 2 installed via Steam.
## Setup ## Output
1. Follow the setup instructions for the framework. If you have done so, all required python dependencies *should* be installed.
2. Install Red Dead Redemption 2 from steam.
1. Location does not matter, this harness uses steam to launch the game.
## Configuration
Below is an example use of this harness as a test in a benchmark configuration.
```yaml
...
...
tests:
- name: reddeadredemption2
executable: "reddeadredemption2.py"
process_name: "RDR2.exe"
output_dir:
- 'harness/reddeadredemption2/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.
__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
## Common Issues
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

Binary file not shown.

Before

Width:  |  Height:  |  Size: 370 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 345 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 550 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 415 B

View File

@@ -2,8 +2,4 @@ friendly_name: "Red Dead Redemption 2"
executable: "reddeadredemption2.py" executable: "reddeadredemption2.py"
process_name: "RDR2.exe" process_name: "RDR2.exe"
hidden: 0 hidden: 0
output_dir: "run" output_dir: "run"
options:
- name: preset
type: select
values: [current]

View File

@@ -1,103 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<rage__fwuiSystemSettingsCollection>
<version value="37" />
<configSource>kSettingsConfig_Auto</configSource>
<graphics>
<tessellation>kSettingLevel_High</tessellation>
<shadowQuality>kSettingLevel_Ultra</shadowQuality>
<farShadowQuality>kSettingLevel_High</farShadowQuality>
<reflectionQuality>kSettingLevel_Low</reflectionQuality>
<mirrorQuality>kSettingLevel_Ultra</mirrorQuality>
<ssao>kSettingLevel_Ultra</ssao>
<textureQuality>kSettingLevel_Ultra</textureQuality>
<particleQuality>kSettingLevel_Medium</particleQuality>
<waterQuality>kSettingLevel_High</waterQuality>
<volumetricsQuality>kSettingLevel_Ultra</volumetricsQuality>
<lightingQuality>kSettingLevel_Ultra</lightingQuality>
<ambientLightingQuality>kSettingLevel_Ultra</ambientLightingQuality>
<anisotropicFiltering value="4" />
<dlssIndex value="0" />
<dlssQuality value="5" />
<taa>kSettingLevel_High</taa>
<fxaaEnabled value="false" />
<msaa value="0" />
<graphicsQualityPreset value="0.500000" />
<hdr value="true" />
<hdrIntensity value="100" />
<hdrPeakBrightness value="1000" />
<hdrFilmicMode value="true" />
<gamma value="15" />
<hdrSettingsMigrated value="true" />
</graphics>
<advancedGraphics>
<API>kSettingAPI_Vulkan</API>
<locked value="true" />
<asyncComputeEnabled value="false" />
<transferQueuesEnabled value="true" />
<shadowSoftShadows>kSettingLevel_Ultra</shadowSoftShadows>
<motionBlur value="true" />
<motionBlurLimit value="16.000000" />
<particleLightingQuality>kSettingLevel_Medium</particleLightingQuality>
<waterReflectionSSR value="true" />
<waterRefractionQuality>kSettingLevel_High</waterRefractionQuality>
<waterReflectionQuality>kSettingLevel_High</waterReflectionQuality>
<waterSimulationQuality value="3" />
<waterLightingQuality>kSettingLevel_Ultra</waterLightingQuality>
<furDisplayQuality>kSettingLevel_Medium</furDisplayQuality>
<maxTexUpgradesPerFrame value="5" />
<shadowGrassShadows>kSettingLevel_High</shadowGrassShadows>
<shadowParticleShadows value="true" />
<shadowLongShadows value="true" />
<directionalShadowsAlpha value="false" />
<worldHeightShadowQuality value="0.660000" />
<directionalScreenSpaceShadowQuality value="0.660000" />
<ambientMaskVolumesHighPrecision value="false" />
<scatteringVolumeQuality>kSettingLevel_Ultra</scatteringVolumeQuality>
<volumetricsRaymarchQuality>kSettingLevel_Ultra</volumetricsRaymarchQuality>
<volumetricsLightingQuality>kSettingLevel_Ultra</volumetricsLightingQuality>
<volumetricsRaymarchResolutionUnclamped value="false" />
<terrainShadowQuality>kSettingLevel_High</terrainShadowQuality>
<damageModelsDisabled value="false" />
<decalQuality>kSettingLevel_High</decalQuality>
<ssaoFullScreenEnabled value="false" />
<ssaoType value="0" />
<ssdoSampleCount value="4" />
<ssdoUseDualRadii value="false" />
<ssdoResolution>kSettingLevel_Low</ssdoResolution>
<ssdoTAABlendEnabled value="true" />
<ssroSampleCount value="2" />
<snowGlints value="true" />
<POMQuality>kSettingLevel_Ultra</POMQuality>
<probeRelightEveryFrame value="false" />
<scalingMode>kSettingScale_Mode1o1</scalingMode>
<reflectionMSAA value="0" />
<lodScale value="1.000000" />
<grassLod value="3.000000" />
<pedLodBias value="0.000000" />
<vehicleLodBias value="0.000000" />
<sharpenIntensity value="1.000000" />
<treeQuality>kSettingLevel_Medium</treeQuality>
<deepsurfaceQuality>kSettingLevel_High</deepsurfaceQuality>
<treeTessellationEnabled value="false" />
</advancedGraphics>
<video>
<adapterIndex value="0" />
<outputIndex value="0" />
<resolutionIndex value="16" />
<screenWidth value="2560" />
<screenHeight value="1440" />
<resolutionIndexWindowed value="16" />
<screenWidthWindowed value="2560" />
<screenHeightWindowed value="1440" />
<refreshRateIndex value="6" />
<refreshRateNumerator value="165" />
<refreshRateDenominator value="1" />
<windowed value="0" />
<vSync value="0" />
<tripleBuffered value="true" />
<pauseOnFocusLoss value="false" />
<constrainMousePointer value="false" />
</video>
<videoCardDescription>NVIDIA NVIDIA GeForce RTX 3080 Ti</videoCardDescription>
</rage__fwuiSystemSettingsCollection>

View File

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

View File

@@ -1,3 +1,35 @@
# stub """Utility functions supporting RDR2 test script."""
def get_resolution(config_path: str) -> tuple[int]: import getpass
return 0, 0 import pathlib
import re
def get_resolution() -> tuple[int]:
"""Gets resolution width and height from local xml file created by game."""
# C:\Users\User\Documents\Rockstar Games\Red Dead Redemption 2\Settings\system.xml"
path = pathlib.Path(
"C:/Users/", getpass.getuser(),
"Documents", "Rockstar Games", "Red Dead Redemption 2", "Settings",
"system.xml"
)
width = "0"
height = "0"
screen_width = re.compile(r"<screenWidth value=\"(\d+)\" />")
screen_height = re.compile(r"<screenHeight value=\"(\d+)\" />")
try:
with open(path, encoding="utf-8") as file:
lines = file.readlines()
for line in lines:
width_match = screen_width.search(line)
height_match = screen_height.search(line)
if width_match is not None:
width = width_match.group(1)
if height_match is not None:
height = height_match.group(1)
except OSError:
width = "0"
height = "0"
return (width, height)

View File

@@ -1,49 +1,58 @@
"""Red Dead Redemption 2 test script"""
import logging import logging
import os import os
import pydirectinput as user
import time import time
from subprocess import Popen from subprocess import Popen
import sys import sys
import pydirectinput as user
from red_dead_redemption_2_utils import get_resolution from red_dead_redemption_2_utils import get_resolution
sys.path.insert(1, os.path.join(sys.path[0], '..')) sys.path.insert(1, os.path.join(sys.path[0], '..'))
from harness_utils.logging import * #pylint: disable=wrong-import-position
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.process import terminate_processes
from harness_utils.steam import get_run_game_id_command, DEFAULT_EXECUTABLE_PATH as STEAM_PATH from harness_utils.steam import get_run_game_id_command, DEFAULT_EXECUTABLE_PATH as STEAM_PATH
#pylint: enable=wrong-import-position
STEAM_GAME_ID = 1174180 STEAM_GAME_ID = 1174180
PROCESS_NAME = "RDR2" PROCESS_NAME = "RDR2"
SCRIPT_DIRECTORY = os.path.dirname(os.path.realpath(__file__)) SCRIPT_DIRECTORY = os.path.dirname(os.path.realpath(__file__))
LOG_DIRECTORY = os.path.join(SCRIPT_DIRECTORY, "run") LOG_DIRECTORY = os.path.join(SCRIPT_DIRECTORY, "run")
config_path = os.path.join(os.environ["HOMEPATH"], "Documents" ,"Rockstar Games", "Red Dead Redemption 2", "Settings", "system.xml") config_path = os.path.join(
os.environ["HOMEPATH"], "Documents" ,"Rockstar Games",
"Red Dead Redemption 2", "Settings", "system.xml"
)
def start_game(): def start_game():
"""Starts the game via steam command"""
steam_run_arg = get_run_game_id_command(STEAM_GAME_ID) 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)
return Popen([STEAM_PATH, steam_run_arg]) return Popen([STEAM_PATH, steam_run_arg])
def run_benchmark(): def run_benchmark():
## """Starts the benchmark"""
# Wait for game to load to main menu # Wait for game to load to main menu
## setup_start_time = time.time()
t1 = time.time()
start_game() start_game()
time.sleep(65) time.sleep(65)
##
# Press Z to enter settings # Press Z to enter settings
##
user.press("z") user.press("z")
time.sleep(3) time.sleep(3)
##
# Enter graphics menu # Enter graphics menu
##
## ensure we are starting from the top left of the screen ## ensure we are starting from the top left of the screen
user.press("up") user.press("up")
user.press("up") user.press("up")
@@ -54,31 +63,26 @@ def run_benchmark():
user.press("enter") user.press("enter")
time.sleep(3) time.sleep(3)
##
# Run benchmark by holding X for 2 seconds # Run benchmark by holding X for 2 seconds
##
user.keyDown('x') user.keyDown('x')
time.sleep(1.5) time.sleep(1.5)
user.keyUp("x") user.keyUp("x")
##
# Press enter to confirm benchmark # Press enter to confirm benchmark
## elapsed_setup_time = round(time.time() - setup_start_time, 2)
t2 = time.time() logging.info("Setup took %f seconds", elapsed_setup_time)
logging.info(f"Harness setup took {round((t2 - t1), 2)} seconds")
user.press("enter") user.press("enter")
start_time = time.time() test_start_time = time.time()
##
# Wait for the benchmark to complete # Wait for the benchmark to complete
##
time.sleep(315) # 5 min, 15 seconds. time.sleep(315) # 5 min, 15 seconds.
end_time = time.time() test_end_time = time.time()
logging.info(f"Benchark took {round((end_time - start_time), 2)} seconds") elapsed_test_time = round(test_end_time - test_start_time, 2)
logging.info("Benchmark took %f seconds", elapsed_test_time)
# Exit # Exit
terminate_processes(PROCESS_NAME) terminate_processes(PROCESS_NAME)
return start_time, end_time return test_start_time, test_end_time
setup_log_directory(LOG_DIRECTORY) setup_log_directory(LOG_DIRECTORY)
@@ -95,16 +99,16 @@ logging.getLogger('').addHandler(console)
try: try:
start_time, end_time = run_benchmark() start_time, end_time = run_benchmark()
width, height = get_resolution(config_path) width, height = get_resolution(config_path)
result = { report = {
"resolution": format_resolution(width, height), "resolution": format_resolution(width, height),
"graphics_preset": "current",
"start_time": seconds_to_milliseconds(start_time), "start_time": seconds_to_milliseconds(start_time),
"end_time": seconds_to_milliseconds(end_time) "end_time": seconds_to_milliseconds(end_time)
} }
write_report_json(LOG_DIRECTORY, "report.json", result) write_report_json(LOG_DIRECTORY, "report.json", report)
#pylint: disable=broad-exception-caught
except Exception as e: except Exception as e:
logging.error("Something went wrong running the benchmark!") logging.error("Something went wrong running the benchmark!")
logging.exception(e) logging.exception(e)
terminate_processes(PROCESS_NAME) terminate_processes(PROCESS_NAME)
exit(1) sys.exit(1)