Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added a command that modifies the saved replay #25

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -112,4 +112,5 @@ credentials.json

# League
league/
settings.json
settings.json
/autoleagueplay/bots/
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would not recommend using the autoleagueplay folder as your working directory for league play (I am assuming that is why you had to add this). That will get annoying since ALP creates a lot of files. Either use league/ which is already ignored or a totally different folder.

2 changes: 1 addition & 1 deletion autoleagueplay/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
autoleagueplay --version

Options:
--replays=R What to do with the replays of the match. Valid values are 'ignore', 'save', and 'calculated_gg'. [default: calculated_gg]
--replays=R What to do with the replays of the match. Valid values are 'ignore', 'save', 'anonym' and 'calculated_gg'. [default: calculated_gg]
--teamsize=T How many players per team. [default: 1]
--ignore-missing Allow the script to run even though not all bots are in the bot directory.
--autoshutdown=S Shutdown the system S seconds after autoleague ends, usefull for VMs. [default: 0]
Expand Down
3 changes: 3 additions & 0 deletions autoleagueplay/match_exercise.py
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ def on_tick(self, tick: TrainingTickPacket) -> Optional[Grade]:
time.sleep(1) # Give time for replay_monitor to register replay and for RL to load main menu
if self.replay_monitor.replay_id or self.replay_monitor.replay_preference == ReplayPreference.IGNORE_REPLAY:
self.replay_monitor.stop_monitoring()
self.replay_monitor.anonymize_replay()
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The ReplayMonitor does not have this function, anonymize_replay(). There is a similarly named function replays.py file though. You also try to make this call in line 92 and 97.

return Pass()

# Check if game is over and replay recorded
Expand All @@ -88,10 +89,12 @@ def on_tick(self, tick: TrainingTickPacket) -> Optional[Grade]:
self.match_result = fetch_match_score(tick.game_tick_packet)
if self.replay_monitor.replay_id or self.replay_monitor.replay_preference == ReplayPreference.IGNORE_REPLAY:
self.replay_monitor.stop_monitoring()
self.replay_monitor.anonymize_replay()
return Pass()
seconds_since_game_end = game_info.seconds_elapsed - self.last_match_time
if seconds_since_game_end > 15:
self.replay_monitor.stop_monitoring()
self.replay_monitor.anonymize_replay()
return FailDueToNoReplay()
else:
if game_info.is_round_active and not game_info.is_match_ended:
Expand Down
2 changes: 2 additions & 0 deletions autoleagueplay/paths.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,13 +44,15 @@ def __init__(self, working_dir: Path):
self.overlay_interface = working_dir / 'current_match.json'
self.leaderboard = working_dir / 'leaderboard.png'
self.leaderboard_clip = working_dir / 'leaderboard.mp4'
self.replays = working_dir / 'replays'
self._ensure_directory_structure()

def _ensure_directory_structure(self):
self.ladder.touch(exist_ok=True)
self.match_results.mkdir(exist_ok=True)
self.versioned_results.mkdir(exist_ok=True)
self.bots.mkdir(exist_ok=True)
self.replays.mkdir(exist_ok=True)

def get_match_result(self, division_index: int, blue: str, orange: str) -> Path:
match_name = f'{Ladder.DIVISION_NAMES[division_index].lower()}_{blue}_vs_{orange}.json'
Expand Down
65 changes: 62 additions & 3 deletions autoleagueplay/replays.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,24 +2,71 @@
from enum import Enum
from pathlib import Path
from typing import Dict, Any
import os
import RattletrapPython.rattletrap as rat
import json

import requests
from rlbottraining.history.metric import Metric
from autoleagueplay.paths import WorkingDir
from watchdog.events import LoggingEventHandler
from watchdog.observers import Observer


class ReplayPreference(Enum):
SAVE = 'save' # save to the default replays directory
CALCULATED_GG = 'calculated_gg' # save locally and upload to https://calculated.gg/
IGNORE_REPLAY = 'ignore'
ANONYMIZE_REPLAY = 'anonym'


def upload_to_calculated_gg(replay_path: Path):
with open(replay_path, 'rb') as f:
response = requests.post('https://calculated.gg/api/upload', files={'replays': f})
print(f'upload response to {replay_path.name}: {response}')

def anonymize_replay(replay_path: Path, working_dir: WorkingDir):
replay_name = str(os.path.basename(str(replay_path)).split('.')[0])
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You already have the Path object, so you can just do

Suggested change
replay_name = str(os.path.basename(str(replay_path)).split('.')[0])
replay_name = replay_path.stem

anonym_replay_path = working_dir.replays / str(replay_name + '.replay')
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What about remaning the replay file to something reasonable? Like "Beast from the East vs Skybot"? This means you will have to call the anonymize_play() function from the run_match() function https://github.com/RLBot/AutoLeaguePlay/blob/master/autoleagueplay/run_matches.py#L43-L48 where your other match info is available. Calling it from there actually makes a lot more sense if you ask me. You would also avoid passing the working_dir to ReplayMonitor for instance.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wanted to do that. i can even rename the in-game name, but i couldnt from replay.py
I'll work on those changes

anonym_json_path = working_dir.replays / str('replay' + '.json')
rat.parse(str(replay_path), anonym_json_path)

with open(anonym_json_path) as replay_file:
replay = json.load(replay_file)
try:
replay['header']['body']['properties']['value']['Team0Score']['value']['int'] = 0
except:
pass
try:
replay['header']['body']['properties']['value']['Team1Score']['value']['int'] = 0
except:
pass
try:
replay['header']['body']['properties']['value']['HighLights']['value']['array'] = []
except:
pass
try:
replay['header']['body']['properties']['value']['HighLights']['size'] = '0'
except:
pass
try:
replay['header']['body']['properties']['value']['Goals']['value']['array'] = []
except:
pass
try:
replay['header']['body']['properties']['value']['Goals']['size'] = '0'
except:
pass
try:
replay['content']['body']['marks'] = []
except:
pass
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just curious, does all these try-excepts has to be done individually?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

there may be a better way, but if one fails, i want it to keep going to the next ( for example, if team 0 doesn't score, that field doesn't exist)

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Then this is probably fine.

with open(anonym_json_path, 'w') as replay_file:
json.dump(replay, replay_file, indent=4)

rat.generate(anonym_json_path, str(anonym_replay_path))




def parse_replay_id(replay_path: Path) -> str:
replay_id, extension = replay_path.name.split('.')
Expand All @@ -31,6 +78,7 @@ def parse_replay_id(replay_path: Path) -> str:
class ReplayMonitor(Metric):

replay_preference: ReplayPreference
working_dir: WorkingDir

replay_id: str = None
observer: Observer = None
Expand All @@ -52,10 +100,21 @@ def on_modified(set_replay_id_self, event):
replay_path = Path(event.src_path)
if replay_monitor.replay_preference == ReplayPreference.CALCULATED_GG:
upload_to_calculated_gg(replay_path)
if replay_monitor.replay_preference == ReplayPreference.ANONYMIZE_REPLAY:
anonymize_replay(replay_path, replay_monitor.working_dir)
replay_monitor.replay_id = parse_replay_id(replay_path)

def on_created(set_replay_id_self, event):
NicEastvillage marked this conversation as resolved.
Show resolved Hide resolved
if event.is_directory: return
assert event.src_path.endswith('.replay')
nonlocal replay_monitor
replay_path = Path(event.src_path)
if replay_monitor.replay_preference == ReplayPreference.CALCULATED_GG:
upload_to_calculated_gg(replay_path)
if replay_monitor.replay_preference == ReplayPreference.ANONYMIZE_REPLAY:
anonymize_replay(replay_path, replay_monitor.working_dir)
replay_monitor.replay_id = parse_replay_id(replay_path)

def on_created(self, event):
pass
def on_deleted(self, event):
pass
def on_moved(self, event):
Expand Down
14 changes: 11 additions & 3 deletions autoleagueplay/run_matches.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,13 @@
logger = get_logger('autoleagueplay')


def run_match(participant_1: str, participant_2: str, match_config, replay_preference: ReplayPreference) -> MatchResult:
def run_match(
participant_1: str,
participant_2: str,
match_config,
replay_preference: ReplayPreference,
working_dir,
) -> MatchResult:
with setup_manager_context() as setup_manager:

# Prepare the match exercise
Expand All @@ -31,8 +37,10 @@ def run_match(participant_1: str, participant_2: str, match_config, replay_prefe
match_config=match_config,
grader=MatchGrader(
mercy_rule=MercyRule(game_interface=setup_manager.game_interface),
replay_monitor=ReplayMonitor(replay_preference=replay_preference),
)
replay_monitor=ReplayMonitor(
replay_preference=replay_preference, working_dir=working_dir
),
),
)

# If any bots have signed up for early start, give them 10 seconds.
Expand Down
1 change: 1 addition & 0 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ def load_module(module_name, full_path):
'google-auth-httplib2',
'google-auth-oauthlib',
'pywinauto',
'RattletrapPython',
],
python_requires='>=3.7.0',
version=version.__version__,
Expand Down