mirror of
https://github.com/LTTLabsOSS/markbench-tests.git
synced 2026-01-08 05:33:52 -05:00
263 lines
8.6 KiB
Python
263 lines
8.6 KiB
Python
"""Misc utility functions"""
|
|
from argparse import ArgumentParser
|
|
import logging
|
|
import os
|
|
from pathlib import Path
|
|
from zipfile import ZipFile
|
|
import time
|
|
import pydirectinput as user
|
|
import pyautogui as gui
|
|
import requests
|
|
import vgamepad as vg
|
|
import json
|
|
import re
|
|
import sys
|
|
|
|
user.FAILSAFE = False
|
|
|
|
class LTTGamePad360(vg.VX360Gamepad):
|
|
"""
|
|
Class extension for the virtual game pad library
|
|
|
|
Many of the in built functions for this library are super useful but a bit unwieldy to use.
|
|
This class extension provides some useful functions to make your code look a little cleaner when
|
|
implemented in our harnesses.
|
|
"""
|
|
|
|
def single_press(self, button=vg.XUSB_BUTTON.XUSB_GAMEPAD_DPAD_DOWN, pause=0.1):
|
|
"""
|
|
Custom function to perform a single press of a specified gamepad button
|
|
|
|
button --> must be a XUSB_BUTTON class, defaults to dpad down
|
|
|
|
Button Options:
|
|
XUSB_GAMEPAD_DPAD_UP
|
|
XUSB_GAMEPAD_DPAD_DOWN
|
|
XUSB_GAMEPAD_DPAD_LEFT
|
|
XUSB_GAMEPAD_DPAD_RIGHT
|
|
XUSB_GAMEPAD_START
|
|
XUSB_GAMEPAD_BACK
|
|
XUSB_GAMEPAD_LEFT_THUMB
|
|
XUSB_GAMEPAD_RIGHT_THUMB
|
|
XUSB_GAMEPAD_LEFT_SHOULDER
|
|
XUSB_GAMEPAD_RIGHT_SHOULDER
|
|
XUSB_GAMEPAD_GUIDE
|
|
XUSB_GAMEPAD_A
|
|
XUSB_GAMEPAD_B
|
|
XUSB_GAMEPAD_X
|
|
XUSB_GAMEPAD_Y
|
|
|
|
pause --> the delay between pressing and releasing the button, defaults to 0.1 if not specified
|
|
"""
|
|
|
|
self.press_button(button=button)
|
|
self.update()
|
|
time.sleep(pause)
|
|
self.release_button(button=button)
|
|
self.update()
|
|
|
|
def press_n_times(self, button: vg.XUSB_BUTTON, n: int, pause: float):
|
|
"""
|
|
Sometimes we need to press a certain gamepad button multiple times in a row, this loop does that for you
|
|
"""
|
|
for _ in range(n):
|
|
self.single_press(button)
|
|
time.sleep(pause)
|
|
|
|
|
|
class LTTGamePadDS4(vg.VDS4Gamepad):
|
|
"""
|
|
Class extension for the virtual game pad library
|
|
|
|
Many of the in built functions for this library are super useful but a bit unwieldy to use.
|
|
This class extension provides some useful functions to make your code look a little cleaner when
|
|
implemented in our harnesses.
|
|
"""
|
|
|
|
def single_button_press(self, button=vg.DS4_BUTTONS.DS4_BUTTON_CROSS, fastpause=0.05):
|
|
"""
|
|
Custom function to perform a single press of a specified gamepad digital button
|
|
|
|
button --> must be a DS4_BUTTONS class, defaults to cross
|
|
|
|
Button Options:
|
|
DS4_BUTTON_THUMB_RIGHT
|
|
DS4_BUTTON_THUMB_LEFT
|
|
DS4_BUTTON_OPTIONS
|
|
DS4_BUTTON_SHARE
|
|
DS4_BUTTON_TRIGGER_RIGHT
|
|
DS4_BUTTON_TRIGGER_LEFT
|
|
DS4_BUTTON_SHOULDER_RIGHT
|
|
DS4_BUTTON_SHOULDER_LEFT
|
|
DS4_BUTTON_TRIANGLE
|
|
DS4_BUTTON_CIRCLE
|
|
DS4_BUTTON_CROSS
|
|
DS4_BUTTON_SQUARE
|
|
|
|
pause --> the delay between pressing and releasing the button, defaults to 0.05 if not specified
|
|
"""
|
|
|
|
self.press_button(button=button)
|
|
self.update()
|
|
time.sleep(fastpause)
|
|
self.release_button(button=button)
|
|
self.update()
|
|
|
|
def button_press_n_times(self, button: vg.DS4_BUTTONS, n: int, pause: float):
|
|
"""
|
|
Sometimes we need to press a certain gamepad button multiple times in a row, this loop does that for you
|
|
"""
|
|
for _ in range(n):
|
|
self.single_button_press(button)
|
|
time.sleep(pause)
|
|
|
|
def single_dpad_press(self, direction=vg.DS4_DPAD_DIRECTIONS.DS4_BUTTON_DPAD_SOUTH, pause=0.1):
|
|
"""
|
|
Custom function to perform a single press of a specified gamepad button
|
|
|
|
button --> must be a DS4_DPAD_DIRECTIONS class, defaults to dpad south
|
|
|
|
DPAD Options:
|
|
DS4_BUTTON_DPAD_NONE
|
|
DS4_BUTTON_DPAD_NORTHWEST
|
|
DS4_BUTTON_DPAD_WEST
|
|
DS4_BUTTON_DPAD_SOUTHWEST
|
|
DS4_BUTTON_DPAD_SOUTH
|
|
DS4_BUTTON_DPAD_SOUTHEAST
|
|
DS4_BUTTON_DPAD_EAST
|
|
DS4_BUTTON_DPAD_NORTHEAST
|
|
DS4_BUTTON_DPAD_NORTH
|
|
|
|
pause --> the delay between pressing and releasing the button, defaults to 0.1 if not specified
|
|
"""
|
|
|
|
self.directional_pad(direction=direction)
|
|
self.update()
|
|
time.sleep(pause)
|
|
self.reset()
|
|
self.update()
|
|
|
|
def dpad_press_n_times(self, direction: vg.DS4_DPAD_DIRECTIONS, n: int, pause: float):
|
|
"""
|
|
Sometimes we need to press a certain dpad direction multiple times in a row, this loop does that for you
|
|
"""
|
|
for _ in range(n):
|
|
self.single_dpad_press(direction)
|
|
time.sleep(pause)
|
|
|
|
|
|
def clickme(x: int, y: int):
|
|
"""Pyautogui's click function sucks, this should do the trick"""
|
|
gui.moveTo(x, y)
|
|
time.sleep(0.2)
|
|
gui.mouseDown()
|
|
time.sleep(0.2)
|
|
gui.mouseUp()
|
|
|
|
|
|
def mouse_scroll_n_times(n: int, scroll_amount: int, pause: float):
|
|
"""
|
|
Pyautogui's mouse scroll function often fails to actually scroll in game menus, this functions solves that problem
|
|
|
|
n --> the number of times you want to scroll, should be a positive integer
|
|
scroll_amount --> positive is scroll up, negative is scroll down
|
|
pause --> the amount of time to pause betwee subsequent scrolls
|
|
"""
|
|
for _ in range(n):
|
|
gui.vscroll(scroll_amount)
|
|
time.sleep(pause)
|
|
|
|
|
|
def int_time() -> int:
|
|
"""Returns the current time in seconds since epoch as an integer"""
|
|
return int(time.time())
|
|
|
|
|
|
def press_n_times(key: str, n: int, pause: float = 0.5):
|
|
"""A helper function press the same button multiple times"""
|
|
for _ in range(n):
|
|
user.press(key)
|
|
time.sleep(pause)
|
|
|
|
|
|
def remove_files(paths: list[str]) -> None:
|
|
"""Removes files specified by provided list of file paths.
|
|
Does nothing for a path that does not exist.
|
|
"""
|
|
for path in paths:
|
|
try:
|
|
os.remove(path)
|
|
logging.info("Removed file: %s", path)
|
|
except FileNotFoundError:
|
|
logging.info("File already removed: %s", path)
|
|
|
|
|
|
def download_file(download_url: str, destination: Path) -> None:
|
|
"""Downloads file from given url to destination"""
|
|
response = requests.get(download_url, allow_redirects=True, timeout=120)
|
|
with open(destination, 'wb') as f:
|
|
f.write(response.content)
|
|
|
|
|
|
def extract_archive(zip_file: Path, destination_dir: Path) -> None:
|
|
"""Extract all contents of an archive"""
|
|
with ZipFile(zip_file, 'r') as zip_object:
|
|
zip_object.extractall(path=destination_dir)
|
|
|
|
|
|
def extract_file_from_archive(zip_file: Path, member_path: str, destination_dir: Path) -> None:
|
|
"""Extract a single file memeber from an archive"""
|
|
with ZipFile(zip_file, 'r') as zip_object:
|
|
zip_object.extract(member_path, path=destination_dir)
|
|
|
|
|
|
def find_eg_game_version(gamefoldername: str) -> str:
|
|
"""Find the version of the specific game (e.g., AlanWake2) from the launcher installed data."""
|
|
installerdat = r"C:\ProgramData\Epic\UnrealEngineLauncher\LauncherInstalled.dat"
|
|
|
|
try:
|
|
# Open the file and read its entire content
|
|
with open(installerdat, encoding="utf-8") as file:
|
|
file_content = file.read()
|
|
|
|
# Check if the "InstallationList" section is in the content
|
|
installation_list_match = re.search(r'"InstallationList":\s*(\[[^\]]*\])', file_content)
|
|
if not installation_list_match:
|
|
print("No InstallationList found.")
|
|
return None
|
|
|
|
# Extract the InstallationList part from the file
|
|
installation_list_json = installation_list_match.group(1)
|
|
|
|
# Load the installation list as JSON
|
|
installation_list = json.loads(installation_list_json)
|
|
|
|
# Loop through each item in the installation list
|
|
for game in installation_list:
|
|
# Check if the game's InstallLocation contains the target string (AlanWake2)
|
|
if gamefoldername in game.get("InstallLocation", ""):
|
|
# Return the AppVersion for this game
|
|
return game.get("AppVersion", None)
|
|
|
|
except Exception as e:
|
|
print(f"Error: {e}")
|
|
|
|
return None
|
|
|
|
|
|
def find_word(keras_service, word, msg, timeout=30, interval=1):
|
|
"""Function to call Keras service to find a word in the screen"""
|
|
if keras_service.wait_for_word(word=word, timeout=timeout, interval=interval) is None:
|
|
logging.error(msg)
|
|
sys.exit(1)
|
|
|
|
|
|
def keras_args():
|
|
"""helper function to get args for keras"""
|
|
parser = ArgumentParser()
|
|
parser.add_argument("--kerasHost", dest="keras_host",
|
|
help="Host for Keras OCR service", required=True)
|
|
parser.add_argument("--kerasPort", dest="keras_port",
|
|
help="Port for Keras OCR service", required=True)
|
|
return parser.parse_args()
|