def match_start(self, payload: typing.Dict[str, typing.Any], user: DiscordUser): """ We will scaffold a basic match into the database and give it a status of 'initial'. This status changes when the replay parser successfully runs in which case the status will change to 'final'. We will have a background cron job that will destroy any match that is 'initial' when it has elapsed 4 hours from its creation time to account for "abandoned" matches. Parameters ---------- payload user Returns ------- """ log.debug('In match start') game_id = str(payload['game_id']) observers = payload['observers'] players = payload['players'] match, match_created = TempMatch.objects.get_or_create(id=game_id, defaults={ 'status': 'initial', }) for o in observers: if o['handle'] == '': continue log.debug(f'creating {o}') obs = utils.fetch_or_create_profile(o['handle']) match.observers.add(obs) match.save() for p in players: profile = utils.fetch_or_create_profile(p['handle']) TempRoster.objects.get_or_create(match=match, sc2_profile=profile, defaults={ 'team_number': p['team'], 'position_number': p['slot'], 'color': p['color'], }) # Look for current connected clients for user in profile.discord_users.all(): heartbeat = user.client_heartbeat now = datetime.now(timezone.utc) if now - heartbeat < timedelta(minutes=10): match.clients.add(user) print('done!') new_match.send(sender=self.__class__, instance=match)
def _update(self, pb: PlayerBank): profile_cache = {} profile = utils.fetch_or_create_profile(pb.id, profile_cache) for mode in pb.modes: print(f'updating self for mode {mode}') obj = pb.modes[mode] Leaderboard.objects.get_or_create(profile=profile, mode=mode, defaults={ 'wins': int(obj.get('wins', 0)), 'games': int(obj.get('games', 0)), 'losses': int(obj.get('losses', 0)), 'elo': float(obj.get('elo', 0)), }) # Update records where the 'time' field is greater than last update. mode = pb.last_game.get('mode') if mode is None: return time = int(pb.last_game.get('time'), 0) players = pb.last_game.get('players', {}) for id, stats in players.items(): profile = utils.fetch_or_create_profile(id, profile_cache) print(f'getting ready to update {mode} for {profile.name}') wins = int(stats.get('wins', 0)) games = int(stats.get('games', 0)) losses = int(stats.get('losses', 0)) elo = float(stats.get('elo', 0)) lb, created = Leaderboard.objects.get_or_create(profile=profile, mode=mode, defaults={ 'wins': wins, 'games': games, 'losses': losses, 'elo': elo }) if created: continue # updated_iso = lb.updated.timestamp() # Can't use time. Epoch is not UTC based. if lb.games > games: continue lb.wins = wins lb.losses = losses lb.games = games lb.elo = elo lb.save()
def import_leaderboards(cache=None): cache = cache if cache is not None else {} for l in leaderboards: toon = fetch_or_create_profile(l.get('player_handle'), cache) print(f'Importing {toon.name}') wins = l.get('wins', 0) games = l.get('games', 0) losses = games - wins models.Leaderboard.objects.update_or_create( profile=toon, mode='2v2v2v2', defaults={ 'created': l.get('created'), 'wins': wins, 'games': games, 'losses': losses, 'elo': l.get('elo'), } )
def import_matches(match_set=matches): cache = {} handle_map = {h['id']:h['handle'] for h in handles} arcade_map = models.Game.objects.all().first() guild = import_guild() game = import_game() for m in match_set: try: guild, season, league = None, None, None print(f"Importing Match{m.get('id')}") related_rosters = [r for r in rosters if r['match_id'] == m['id']] related_events = [me for me in match_events if me['match_id'] == m['id']] season = None league = None if m['league_id'] is not None: league = get_league(m['league_id']) if m['season_id'] is not None and league is not None: season = get_season(m['season_id'], league) if m['game_id'] is None: # No game Id. This match will never be able to get imported. # Make a very long fake one. m['game_id'] = ''.join(str(random.randint(0, 9)) for _ in range(30)) print(f"Using Game ID {m['game_id']}") match, created = models.Match.objects.get_or_create( id=m['game_id'], defaults={ 'created': m['created'], 'guild': guild, 'arcade_map': arcade_map, 'league': league, 'season': season, 'legacy': True, 'ranked': True, } ) team_map = {0: {'players': []}, 1: {'players': []}, 2: {'players': []}, 3: {'players': []}} for r in related_rosters: roster_handle_string = None roster_handle_string = handle_map[r['handle_id']] #for h in handles: # if h['id'] == r['handle_id']: # roster_handle_string = h['handle'] print(f"Importing Roster Match {match.id}") print(f"Handle {roster_handle_string}") handle = fetch_or_create_profile(roster_handle_string, cache) team_map[r['team_number']]['players'].append(handle) team_map[r['team_number']]['position'] = get_team_position(r['position_number']) lane = get_lane(r['position_number'], related_rosters) if lane is not None: lane = get_profile(lane, handle_map, cache) roster, _ = models.Roster.objects.get_or_create( match=match, sc2_profile=handle, team_number=r['team_number'], position_number=r['position_number'], defaults={ 'created': r['created'], 'color': r['color'], 'lane': lane, } ) for me in [r for r in related_events]: # Need to get the original handle profile string handle_string = None opposing_handle_string = None for h in handles: if h['id'] == me['opposing_handle_id']: opposing_handle_string = h['handle'] if h['id'] == me['handle_id']: handle_string = h['handle'] sc2handle, opposing_handle = None, None if handle_string is not None: sc2handle = fetch_or_create_profile(handle_string, cache) if opposing_handle_string is not None: opposing_handle = fetch_or_create_profile(opposing_handle_string, cache) print(f"Importing Match {match.id} Event {me['key']}") if me['key'] == 'WIN': models.MatchWinner.objects.update_or_create( match=match, profile=sc2handle ) update_team_outcome(team_map, sc2handle, 'win') elif me['key'] == 'LOSS': models.MatchLoser.objects.update_or_create( match=match, profile=sc2handle, defaults={ 'killer': None, 'left_game': False, 'game_time': me.get('game_time', 0) or 0, 'victim_number': 0, } ) update_team_outcome(team_map, sc2handle, 'loss') elif me['key'] == 'DRAW': match.draw = True match.save() update_team_outcome(team_map, sc2handle, 'draw') else: game_event_name, created = models.GameEventName.objects.get_or_create( id=me['key'], defaults={'title': f"New Game Event {me['key']}"} ) obj, _ = models.GameEvent.objects.get_or_create( key=game_event_name, match=match, profile=sc2handle, opposing_profile=opposing_handle, game_time=me['game_time'], defaults= { 'value': me['value'], 'description': me['description'], 'total_score': 0, 'minerals_on_hand': 0, } ) print(obj.key) updated_rosters = models.Roster.objects.filter(match=match) for team_num, team_details in team_map.items(): team_obj = get_or_create_team(team_details['players']) print(f"Mapping {team_details}") print(team_obj) match_team, created = models.MatchTeam.objects.get_or_create( match=match, team=team_obj, defaults={ 'position': team_details.get('position', -1), 'outcome': team_details.get('outcome', "unknown"), } ) for ros in updated_rosters: if ros.sc2_profile in team_details['players']: ros.team = match_team ros.save() except models.SC2Profile.DoesNotExist: continue return cache
def get_profile(handle, handle_map, cache={}) -> typing.Optional[models.SC2Profile]: handle_string = handle_map[handle['handle_id']] return fetch_or_create_profile(handle_string, cache)