mirror of
https://github.com/bnowakow/GT7-Scripts.git
synced 2025-12-17 09:37:05 +00:00
Merge pull request #4 from IlIllII/patch-1
Patch 1 - added a python script
This commit is contained in:
39
python_scripts/README.md
Normal file
39
python_scripts/README.md
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
# race_in_circles
|
||||||
|
|
||||||
|
The `race_in_circles.py` script allows you to automate racing circular tracks using pyautogui and PS Remote Play. NOTE: The track MUST be circular. I think the script should work on any platform.
|
||||||
|
|
||||||
|
## Instructions
|
||||||
|
|
||||||
|
All you need to do is open PS Remote Play and then navigate to the race start screen for the track you want to automate. This is the screen with `Start`, `Settings`, and `Exit` buttons. Make sure that the remote play window is in the middle of your primary monitor because the script clicks the center of the screen to get the winow's focus.
|
||||||
|
|
||||||
|
Next, open a terminal with administrator privileges (I had to use administrator privileges, but you might not have to). Navigate to the directory containing this script and run it:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
py race_in_circles.py
|
||||||
|
```
|
||||||
|
|
||||||
|
Voila! You are now racing in circles.
|
||||||
|
|
||||||
|
By default this will race around a circular track with left turns for 200 seconds before navigating through the menus to restart the race. You can change the behavior by passing some command line arguments.
|
||||||
|
|
||||||
|
- To change the side of the track you hug, you can pass the flag `--direction=DIRECTION`. By default you hug the `right` rail. You can also simply pass `-left` or `-l` or `-right` or `-r`.
|
||||||
|
- You can change the duration with `--duration=DURATION`, where `DURATION` is the number of seconds that the race takes. You can also simply pass a number, like `200`. To get a sense for how long the race takes, start the script with a long duration, say `1000` seconds, and see how long it takes to navigate the course and then restart the script using the new duration (you should add some padding to account for collisions, maybe +10 seconds to be safe).
|
||||||
|
|
||||||
|
The following command will automate a 120 second race where you hug the left hand rail of the course:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
py race_in_circles.py --direction=left --duration=120
|
||||||
|
```
|
||||||
|
|
||||||
|
Another command that does the same thing:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
py race_in_circles.py -left 120
|
||||||
|
```
|
||||||
|
|
||||||
|
## Notes
|
||||||
|
|
||||||
|
Right now the script simply navigates through the menus for standard races and runs a race based on timing, meaning if you spin out or something the timing will likely be off.
|
||||||
|
|
||||||
|
If you want to automate a different event, say a championship series, you can edit the script with new menu navigation commands. These are self explanatory in the script.
|
||||||
|
|
||||||
137
python_scripts/race_in_circles.py
Normal file
137
python_scripts/race_in_circles.py
Normal file
@@ -0,0 +1,137 @@
|
|||||||
|
import sys
|
||||||
|
import time
|
||||||
|
import random
|
||||||
|
import pyautogui
|
||||||
|
|
||||||
|
# Default parameters - these can be overridden with command
|
||||||
|
# line arguments. See end of script for details.
|
||||||
|
RACE_DURATION = 200
|
||||||
|
DIRECTION = "right"
|
||||||
|
SILENCE = False
|
||||||
|
|
||||||
|
|
||||||
|
def press(key: str) -> None:
|
||||||
|
"""Press a key.
|
||||||
|
|
||||||
|
Using vanilla `pyautogui.press()` will not register the keystroke
|
||||||
|
because GT requires you hold a keypress for a small duration."""
|
||||||
|
with pyautogui.hold(key):
|
||||||
|
time.sleep(0.2)
|
||||||
|
|
||||||
|
|
||||||
|
def hold(key: str, duration: float) -> None:
|
||||||
|
"""Hold a key for some duration."""
|
||||||
|
|
||||||
|
with pyautogui.hold(key):
|
||||||
|
time.sleep(duration)
|
||||||
|
|
||||||
|
|
||||||
|
def ride_rail(direction: str) -> None:
|
||||||
|
"""
|
||||||
|
This will drive a car around any convex hull while hugging
|
||||||
|
the `direction` rail. If you pass `left`, your car will hug
|
||||||
|
the left rail, thus allowing you to go around righthand turns.
|
||||||
|
"""
|
||||||
|
|
||||||
|
race_start = time.time()
|
||||||
|
with pyautogui.hold("up"):
|
||||||
|
while time.time() - race_start < RACE_DURATION:
|
||||||
|
hold(direction, (random.randrange(200) / 1000))
|
||||||
|
time.sleep((random.randrange(100) / 100))
|
||||||
|
|
||||||
|
|
||||||
|
def race(direction: str) -> None:
|
||||||
|
"""`direction` is the rail to hug, not the direction to turn!"""
|
||||||
|
|
||||||
|
ride_rail(direction)
|
||||||
|
|
||||||
|
|
||||||
|
def end_race() -> None:
|
||||||
|
"""Navigate through post-race menus and replay."""
|
||||||
|
|
||||||
|
commands = [
|
||||||
|
"enter",
|
||||||
|
"enter",
|
||||||
|
"enter",
|
||||||
|
"enter",
|
||||||
|
"enter",
|
||||||
|
"enter",
|
||||||
|
"enter",
|
||||||
|
"right",
|
||||||
|
"enter",
|
||||||
|
"down",
|
||||||
|
"down",
|
||||||
|
"down",
|
||||||
|
"left",
|
||||||
|
"left",
|
||||||
|
"enter",
|
||||||
|
]
|
||||||
|
for command in commands:
|
||||||
|
press(command)
|
||||||
|
time.sleep((random.randrange(500) / 1000) + 2)
|
||||||
|
|
||||||
|
|
||||||
|
def start_race(first: bool) -> None:
|
||||||
|
"""Initiate race from the start race menu."""
|
||||||
|
if first:
|
||||||
|
# Click center of screen to focus remote play window.
|
||||||
|
# You can reposition and resize remote play window, just
|
||||||
|
# make sure you update where you click. I don't know how to
|
||||||
|
# use pyautogui in headless mode.
|
||||||
|
width, height = pyautogui.size()
|
||||||
|
center = width / 2, height / 2
|
||||||
|
pyautogui.moveTo(center)
|
||||||
|
pyautogui.click()
|
||||||
|
time.sleep(1)
|
||||||
|
|
||||||
|
# This is the button sequence you press when the 'replay'
|
||||||
|
# button IS NOT visible on the race start screen.
|
||||||
|
press("down")
|
||||||
|
press("down")
|
||||||
|
press("down")
|
||||||
|
press("left")
|
||||||
|
press("enter")
|
||||||
|
else:
|
||||||
|
# This is the button sequence you press when the 'replay'
|
||||||
|
# button IS visible on the race start screen.
|
||||||
|
press("down")
|
||||||
|
press("down")
|
||||||
|
press("down")
|
||||||
|
press("left")
|
||||||
|
press("left")
|
||||||
|
press("enter")
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
|
||||||
|
args = sys.argv
|
||||||
|
for arg in args[1:]:
|
||||||
|
if "=" in arg:
|
||||||
|
flag, value = arg.split("=")
|
||||||
|
if flag == "--direction":
|
||||||
|
DIRECTION = value
|
||||||
|
if flag == "--duration" and value.isdigit():
|
||||||
|
RACE_DURATION = int(value)
|
||||||
|
else:
|
||||||
|
if arg == "-left" or arg == "-l":
|
||||||
|
DIRECTION = "left"
|
||||||
|
if arg == "-right" or arg == "-r":
|
||||||
|
DIRECTION = "right"
|
||||||
|
if arg == "-silence":
|
||||||
|
SILENCE = True
|
||||||
|
if arg.isdigit():
|
||||||
|
RACE_DURATION = int(value)
|
||||||
|
|
||||||
|
first = True
|
||||||
|
while True:
|
||||||
|
start = time.time()
|
||||||
|
start_race(first)
|
||||||
|
first = False
|
||||||
|
race(DIRECTION)
|
||||||
|
end_race()
|
||||||
|
end = time.time()
|
||||||
|
duration = end - start
|
||||||
|
print(duration, flush=True)
|
||||||
|
|
||||||
|
if not SILENCE:
|
||||||
|
print(f"{(((60*60) / duration)):.2f} races/hour", flush=True)
|
||||||
Reference in New Issue
Block a user