def set_seat_frequency(self, frequency): FREQUENCY_TIMEOUT = 10 time_now = monotonic() time_expires = time_now + FREQUENCY_TIMEOUT self.set_message_direct( __("!!! Frequency changing to {0} in <10s !!!").format(frequency)) gevent.sleep(10) self.set_seat_frequency_direct(frequency) self.set_message_direct(__(""))
def getClusterStatusInfo(self): nowTime = monotonic() payload = [] for slave in self.slaves: upTimeSecs = int(round( nowTime - slave.firstContactTime)) if slave.lastContactTime > 0 else 0 downTimeSecs = int(round(slave.secsSinceDisconnect) ) if slave.lastContactTime <= 0 else 0 totalUpSecs = slave.totalUpTimeSecs + upTimeSecs totalDownSecs = slave.totalDownTimeSecs + downTimeSecs payload.append( {'address': slave.address, \ 'modeIndicator': ('M' if slave.isMirrorMode else 'S'), \ 'minLatencyMs': slave.latencyAveragerObj.minVal, \ 'avgLatencyMs': slave.latencyAveragerObj.getIntAvgVal(), \ 'maxLatencyMs': slave.latencyAveragerObj.maxVal, \ 'lastLatencyMs': slave.latencyAveragerObj.lastVal, \ 'numDisconnects': slave.numDisconnects, \ 'numContacts': slave.numContacts, \ 'timeDiffMs': slave.timeDiffMedianMs, \ 'upTimeSecs': upTimeSecs, \ 'downTimeSecs': downTimeSecs, \ 'availability': round((100.0*totalUpSecs/(totalUpSecs+totalDownSecs) \ if totalUpSecs+totalDownSecs > 0 else 0), 1), \ 'last_contact': int(nowTime-slave.lastContactTime) if slave.lastContactTime >= 0 else \ (__("connection lost") if slave.numDisconnects > 0 else __("never connected")) }) return {'slaves': payload}
def do_heat_set(self, arg): self.logger.info("VRx Signaling Heat Set") try: heat_id = arg["heat_id"] except KeyError: self.logger.error( "Unable to send callsigns. heat_id not found in event.") return for heatseat in Database.HeatNode.query.filter_by( heat_id=heat_id).all(): heatseat_index = heatseat.seat_index if heatseat_index < self.num_seats: # TODO this may break with non-contiguous nodes if heatseat.pilot_id != Database.PILOT_ID_NONE: pilot = Database.Pilot.query.get(heatseat.pilot_id) self.set_message_direct(heatseat_index, pilot.callsign) else: self.set_message_direct(heatseat_index, __("-None-"))
def do_heat_set(self, arg): self.logger.info("VRx Signaling Heat Set") try: heat_id = arg["heat_id"] except KeyError: self.logger.error( "Unable to send callsigns. heat_id not found in event.") return try: RACE = arg["race"] except KeyError: self.logger.error( "Unable to send callsigns. RACE not found in event") return for heatnode in Database.HeatNode.query.filter_by( heat_id=heat_id).all(): if heatnode.node_index < self.num_nodes: if heatnode.pilot_id != Database.PILOT_ID_NONE: pilot = Database.Pilot.query.get(heatnode.pilot_id) self.set_message_direct(heatnode.node_index, pilot.callsign) else: self.set_message_direct(heatnode.node_index, __("-None-"))
def set_seat_frequency(self, seat_number, frequency): fmsg = __("Frequency Change: ") + str(frequency) seat = self._seats[seat_number] seat.set_seat_frequency(frequency)
def do_lap_recorded(self, args): ''' *** TODO: Formatting for hardware (OSD length, etc.) ''' RESULTS_TIMEOUT = 5 # maximum time to wait for results to generate LAP_HEADER = Options.get('osd_lapHeader') POS_HEADER = Options.get('osd_positionHeader') if 'node_index' in args: seat_index = args['node_index'] else: self.logger.warning('Failed to send results: Seat not specified') return False # wait for results to generate time_now = monotonic() timeout = time_now + RESULTS_TIMEOUT while self.RACE.cacheStatus != Results.CacheStatus.VALID and time_now < timeout: time_now = monotonic() gevent.sleep() if self.RACE.cacheStatus == Results.CacheStatus.VALID: ''' Get relevant results ''' results = self.RACE.results # select correct results # *** leaderboard = results[results['meta']['primary_leaderboard']] win_condition = self.RACE.format.win_condition if win_condition == WinCondition.FASTEST_3_CONSECUTIVE: leaderboard = results['by_consecutives'] elif win_condition == WinCondition.FASTEST_LAP: leaderboard = results['by_fastest_lap'] else: # WinCondition.MOST_LAPS # WinCondition.FIRST_TO_LAP_X # WinCondition.NONE leaderboard = results['by_race_time'] # get this seat's results for index, result in enumerate(leaderboard): if result['node'] == seat_index: #TODO issue408 rank_index = index break # check for best lap is_best_lap = False if result['fastest_lap_raw'] == result['last_lap_raw']: is_best_lap = True # get the next faster results next_rank_split = None next_rank_split_result = None if result['position'] > 1: next_rank_split_result = leaderboard[rank_index - 1] if next_rank_split_result['total_time_raw']: if win_condition == WinCondition.FASTEST_3_CONSECUTIVE: if next_rank_split_result['consecutives_raw']: next_rank_split = result[ 'consecutives_raw'] - next_rank_split_result[ 'consecutives_raw'] elif win_condition == WinCondition.FASTEST_LAP: if next_rank_split_result['fastest_lap_raw']: next_rank_split = result[ 'last_lap_raw'] - next_rank_split_result[ 'fastest_lap_raw'] else: # WinCondition.MOST_LAPS # WinCondition.FIRST_TO_LAP_X next_rank_split = result[ 'total_time_raw'] - next_rank_split_result[ 'total_time_raw'] next_rank_split_fastest = '' else: # check split to self next_rank_split_result = leaderboard[rank_index] if win_condition == WinCondition.FASTEST_3_CONSECUTIVE or win_condition == WinCondition.FASTEST_LAP: if next_rank_split_result['fastest_lap_raw']: if result['last_lap_raw'] > next_rank_split_result[ 'fastest_lap_raw']: next_rank_split = result[ 'last_lap_raw'] - next_rank_split_result[ 'fastest_lap_raw'] # get the next slower results prev_rank_split = None prev_rank_split_result = None if rank_index + 1 in leaderboard: prev_rank_split_result = leaderboard[rank_index - 1] if prev_rank_split_result['total_time_raw']: if win_condition == WinCondition.FASTEST_3_CONSECUTIVE: if prev_rank_split_result['consecutives_raw']: prev_rank_split = result[ 'consecutives_raw'] - prev_rank_split_result[ 'consecutives_raw'] prev_rank_split_fastest = prev_rank_split elif win_condition == WinCondition.FASTEST_LAP: if prev_rank_split_result['fastest_lap_raw']: prev_rank_split = result[ 'last_lap_raw'] - prev_rank_split_result[ 'fastest_lap_raw'] prev_rank_split_fastest = result[ 'fastest_lap_raw'] - prev_rank_split_result[ 'fastest_lap_raw'] else: # WinCondition.MOST_LAPS # WinCondition.FIRST_TO_LAP_X prev_rank_split = result[ 'total_time_raw'] - prev_rank_split_result[ 'total_time_raw'] prev_rank_split_fastest = '' # get the fastest result first_rank_split = None first_rank_split_result = None if result['position'] > 2: first_rank_split_result = leaderboard[0] if next_rank_split_result['total_time_raw']: if win_condition == WinCondition.FASTEST_3_CONSECUTIVE: if first_rank_split_result['consecutives_raw']: first_rank_split = result[ 'consecutives_raw'] - first_rank_split_result[ 'consecutives_raw'] elif win_condition == WinCondition.FASTEST_LAP: if first_rank_split_result['fastest_lap_raw']: first_rank_split = result[ 'last_lap_raw'] - first_rank_split_result[ 'fastest_lap_raw'] else: # WinCondition.MOST_LAPS # WinCondition.FIRST_TO_LAP_X first_rank_split = result[ 'total_time_raw'] - first_rank_split_result[ 'total_time_raw'] ''' Set up output objects ''' osd = { 'position_prefix': POS_HEADER, 'position': str(result['position']), 'callsign': result['callsign'], 'lap_prefix': LAP_HEADER, 'lap_number': '', 'last_lap_time': '', 'total_time': result['total_time'], 'total_time_laps': result['total_time_laps'], 'consecutives': result['consecutives'], 'is_best_lap': is_best_lap, } if result['laps']: osd['lap_number'] = str(result['laps']) osd['last_lap_time'] = result['last_lap'] else: osd['lap_prefix'] = '' osd['lap_number'] = __('HS') osd['last_lap_time'] = result['total_time'] osd['is_best_lap'] = False if next_rank_split: osd_next_split = { 'position_prefix': POS_HEADER, 'position': str(next_rank_split_result['position']), 'callsign': next_rank_split_result['callsign'], 'split_time': RHUtils.time_format(next_rank_split), } osd_next_rank = { 'position_prefix': POS_HEADER, 'position': str(next_rank_split_result['position']), 'callsign': next_rank_split_result['callsign'], 'lap_prefix': LAP_HEADER, 'lap_number': '', 'last_lap_time': '', 'total_time': result['total_time'], } if next_rank_split_result['laps']: osd_next_rank['lap_number'] = str( next_rank_split_result['laps']) osd_next_rank['last_lap_time'] = next_rank_split_result[ 'last_lap'] else: osd_next_rank['lap_prefix'] = '' osd_next_rank['lap_number'] = __('HS') osd_next_rank['last_lap_time'] = next_rank_split_result[ 'total_time'] if first_rank_split: osd_first_split = { 'position_prefix': POS_HEADER, 'position': str(first_rank_split_result['position']), 'callsign': first_rank_split_result['callsign'], 'split_time': RHUtils.time_format(first_rank_split), } ''' Format and send messages ''' # "Pos-Callsign L[n]|0:00:00" message = osd['position_prefix'] + osd['position'] + '-' + osd[ 'callsign'][:10] + ' ' + osd['lap_prefix'] + osd[ 'lap_number'] + '|' + osd['last_lap_time'] if win_condition == WinCondition.FASTEST_3_CONSECUTIVE: # "Pos-Callsign L[n]|0:00:00 | #/0:00.000" (current | best consecutives) if result['laps'] >= 3: message += ' | 3/' + osd['consecutives'] elif result['laps'] == 2: message += ' | 2/' + osd['total_time_laps'] elif win_condition == WinCondition.FASTEST_LAP: if next_rank_split: # pilot in 2nd or lower # "Pos-Callsign L[n]|0:00:00 / +0:00.000 Callsign" message += ' / +' + osd_next_split[ 'split_time'] + ' ' + osd_next_split['callsign'][:10] elif osd['is_best_lap']: # pilot in 1st and is best lap # "Pos:Callsign L[n]:0:00:00 / Best" message += ' / ' + __('Best Lap') else: # WinCondition.MOST_LAPS # WinCondition.FIRST_TO_LAP_X # WinCondition.NONE # "Pos-Callsign L[n]|0:00:00 / +0:00.000 Callsign" if next_rank_split: message += ' / +' + osd_next_split[ 'split_time'] + ' ' + osd_next_split['callsign'][:10] # send message to crosser seat_dest = seat_index self.set_message_direct(seat_dest, message) self.logger.debug('msg n{1}: {0}'.format(message, seat_dest)) # show split when next pilot crosses if next_rank_split: if win_condition == WinCondition.FASTEST_3_CONSECUTIVE or win_condition == WinCondition.FASTEST_LAP: # don't update pass else: # WinCondition.MOST_LAPS # WinCondition.FIRST_TO_LAP_X # WinCondition.NONE # update pilot ahead with split-behind # "Pos-Callsign L[n]|0:00:00" message = osd_next_rank['position_prefix'] + osd_next_rank[ 'position'] + '-' + osd_next_rank[ 'callsign'][:10] + ' ' + osd_next_rank[ 'lap_prefix'] + osd_next_rank[ 'lap_number'] + '|' + osd_next_rank[ 'last_lap_time'] # "Pos-Callsign L[n]|0:00:00 / -0:00.000 Callsign" message += ' / -' + osd_next_split[ 'split_time'] + ' ' + osd['callsign'][:10] seat_dest = leaderboard[rank_index - 1]['node'] self.set_message_direct(seat_dest, message) self.logger.debug('msg n{1}: {0}'.format( message, seat_dest)) else: self.logger.warning( 'Failed to send results: Results not available') return False
def do_race_stop(self, arg): self.logger.info("VRx Signaling Race Stop") self.set_message_direct(VRxALL, __("Race Stopped. Land Now."))
def do_race_finish(self, arg): self.logger.info("VRx Signaling Race Finish") self.set_message_direct(VRxALL, __("Finish"))
def do_race_start(self, arg): self.logger.info("VRx Signaling Race Start") self.set_message_direct(VRxALL, __("Go"))
def do_race_stage(self, arg): self.logger.info("VRx Signaling Race Stage") self.set_message_direct(VRxALL, __("Ready"))
def calc_leaderboard(DB, **params): ''' Generates leaderboards ''' USE_CURRENT = False USE_ROUND = None USE_HEAT = None USE_CLASS = None if ('current_race' in params): USE_CURRENT = True if ('class_id' in params): USE_CLASS = params['class_id'] elif ('round_id' in params and 'heat_id' in params): USE_ROUND = params['round_id'] USE_HEAT = params['heat_id'] elif ('heat_id' in params): USE_ROUND = None USE_HEAT = params['heat_id'] # Get profile (current), frequencies (current), race query (saved), and race format (all) if USE_CURRENT: profile = params['current_profile'] profile_freqs = json.loads(profile.frequencies) RACE = params['current_race'] race_format = RACE.format else: if USE_CLASS: race_query = Database.SavedRaceMeta.query.filter_by(class_id=USE_CLASS) if race_query.count() >= 1: current_format = Database.RaceClass.query.get(USE_CLASS).format_id else: current_format = None elif USE_HEAT: if USE_ROUND: race_query = Database.SavedRaceMeta.query.filter_by(heat_id=USE_HEAT, round_id=USE_ROUND) current_format = race_query.first().format_id else: race_query = Database.SavedRaceMeta.query.filter_by(heat_id=USE_HEAT) if race_query.count() >= 1: heat_class = race_query.first().class_id if heat_class: current_format = Database.RaceClass.query.get(heat_class).format_id else: current_format = None else: current_format = None else: race_query = Database.SavedRaceMeta.query current_format = None selected_races = race_query.all() racelist = [r.id for r in selected_races] if current_format: race_format = Database.RaceFormat.query.get(current_format) else: race_format = None gevent.sleep() # Get the pilot ids for all relevant races # Add pilot callsigns # Add pilot team names # Get total laps for each pilot # Get hole shot laps pilot_ids = [] callsigns = [] nodes = [] team_names = [] max_laps = [] current_laps = [] holeshots = [] for pilot in Database.Pilot.query.filter(Database.Pilot.id != Database.PILOT_ID_NONE): gevent.sleep() if USE_CURRENT: laps = [] for node_index in RACE.node_pilots: if RACE.node_pilots[node_index] == pilot.id and node_index < RACE.num_nodes: laps = RACE.get_active_laps()[node_index] break if laps: max_lap = len(laps) - 1 else: max_lap = 0 current_heat = Database.HeatNode.query.filter_by(heat_id=RACE.current_heat, pilot_id=pilot.id).first() if current_heat and profile_freqs["f"][current_heat.node_index] != RHUtils.FREQUENCY_ID_NONE: pilot_ids.append(pilot.id) callsigns.append(pilot.callsign) nodes.append(current_heat.node_index) team_names.append(pilot.team) max_laps.append(max_lap) current_laps.append(laps) else: # find hole shots holeshot_laps = [] pilotnode = None for race in racelist: pilotraces = Database.SavedPilotRace.query \ .filter(Database.SavedPilotRace.pilot_id == pilot.id, \ Database.SavedPilotRace.race_id == race \ ).all() if len(pilotraces): pilotnode = pilotraces[-1].node_index for pilotrace in pilotraces: gevent.sleep() holeshot_lap = Database.SavedRaceLap.query \ .filter(Database.SavedRaceLap.pilotrace_id == pilotrace.id, \ Database.SavedRaceLap.deleted != 1, \ ).order_by(Database.SavedRaceLap.lap_time_stamp).first() if holeshot_lap: holeshot_laps.append(holeshot_lap.id) # get total laps stat_query = DB.session.query(DB.func.count(Database.SavedRaceLap.id)) \ .filter(Database.SavedRaceLap.pilot_id == pilot.id, \ Database.SavedRaceLap.deleted != 1, \ Database.SavedRaceLap.race_id.in_(racelist), \ ~Database.SavedRaceLap.id.in_(holeshot_laps)) max_lap = stat_query.scalar() if max_lap > 0: pilot_ids.append(pilot.id) callsigns.append(pilot.callsign) team_names.append(pilot.team) max_laps.append(max_lap) holeshots.append(holeshot_laps) nodes.append(pilotnode) total_time = [] total_time_laps = [] last_lap = [] average_lap = [] fastest_lap = [] consecutives = [] fastest_lap_source = [] consecutives_source = [] for i, pilot in enumerate(pilot_ids): gevent.sleep() # Get the total race time for each pilot if USE_CURRENT: race_total = 0 laps_total = 0 for lap in current_laps[i]: race_total += lap['lap_time'] if lap > 0: laps_total += lap['lap_time'] total_time.append(race_total) total_time_laps.append(laps_total) else: stat_query = DB.session.query(DB.func.sum(Database.SavedRaceLap.lap_time)) \ .filter(Database.SavedRaceLap.pilot_id == pilot, \ Database.SavedRaceLap.deleted != 1, \ Database.SavedRaceLap.race_id.in_(racelist)) if stat_query.scalar(): total_time.append(stat_query.scalar()) else: total_time.append(0) stat_query = DB.session.query(DB.func.sum(Database.SavedRaceLap.lap_time)) \ .filter(Database.SavedRaceLap.pilot_id == pilot, \ Database.SavedRaceLap.deleted != 1, \ Database.SavedRaceLap.race_id.in_(racelist), \ ~Database.SavedRaceLap.id.in_(holeshots[i])) if stat_query.scalar(): total_time_laps.append(stat_query.scalar()) else: total_time_laps.append(0) gevent.sleep() # Get the last lap for each pilot (current race only) if max_laps[i] is 0: last_lap.append(None) # Add zero if no laps completed else: if USE_CURRENT: last_lap.append(current_laps[i][-1]['lap_time']) else: last_lap.append(None) gevent.sleep() # Get the average lap time for each pilot if max_laps[i] is 0: average_lap.append(0) # Add zero if no laps completed else: if USE_CURRENT: avg_lap = (current_laps[i][-1]['lap_time_stamp'] - current_laps[i][0]['lap_time_stamp']) / (len(current_laps[i]) - 1) ''' timed_laps = filter(lambda x : x['lap_number'] > 0, current_laps[i]) lap_total = 0 for lap in timed_laps: lap_total += lap['lap_time'] avg_lap = lap_total / len(timed_laps) ''' else: stat_query = DB.session.query(DB.func.avg(Database.SavedRaceLap.lap_time)) \ .filter(Database.SavedRaceLap.pilot_id == pilot, \ Database.SavedRaceLap.deleted != 1, \ Database.SavedRaceLap.race_id.in_(racelist), \ ~Database.SavedRaceLap.id.in_(holeshots[i])) avg_lap = stat_query.scalar() average_lap.append(avg_lap) gevent.sleep() # Get the fastest lap time for each pilot if max_laps[i] is 0: fastest_lap.append(0) # Add zero if no laps completed fastest_lap_source.append(None) else: if USE_CURRENT: timed_laps = filter(lambda x : x['lap_number'] > 0, current_laps[i]) fast_lap = sorted(timed_laps, key=lambda val : val['lap_time'])[0]['lap_time'] fastest_lap_source.append(None) else: stat_query = DB.session.query(DB.func.min(Database.SavedRaceLap.lap_time).label('time'), Database.SavedRaceLap.race_id) \ .filter(Database.SavedRaceLap.pilot_id == pilot, \ Database.SavedRaceLap.deleted != 1, \ Database.SavedRaceLap.race_id.in_(racelist), \ ~Database.SavedRaceLap.id.in_(holeshots[i])).one() fast_lap = stat_query.time if USE_HEAT: fastest_lap_source.append(None) else: source_query = Database.SavedRaceMeta.query.get(stat_query.race_id) fast_lap_round = source_query.round_id fast_lap_heat = source_query.heat_id fast_lap_heatnote = Database.Heat.query.get(fast_lap_heat).note if fast_lap_heatnote: source_text = fast_lap_heatnote + ' / ' + __('Round') + ' ' + str(fast_lap_round) else: source_text = __('Heat') + ' ' + str(fast_lap_heat) + ' / ' + __('Round') + ' ' + str(fast_lap_round) fastest_lap_source.append(source_text) fastest_lap.append(fast_lap) gevent.sleep() # find best consecutive 3 laps if max_laps[i] < 3: consecutives.append(None) consecutives_source.append(None) else: all_consecutives = [] if USE_CURRENT: thisrace = current_laps[i][1:] for j in range(len(thisrace) - 2): gevent.sleep() all_consecutives.append({ 'time': thisrace[j]['lap_time'] + thisrace[j+1]['lap_time'] + thisrace[j+2]['lap_time'], 'race_id': None, }) else: for race_id in racelist: gevent.sleep() thisrace = DB.session.query(Database.SavedRaceLap.lap_time) \ .filter(Database.SavedRaceLap.pilot_id == pilot, \ Database.SavedRaceLap.race_id == race_id, \ Database.SavedRaceLap.deleted != 1, \ ~Database.SavedRaceLap.id.in_(holeshots[i]) \ ).all() if len(thisrace) >= 3: for j in range(len(thisrace) - 2): gevent.sleep() all_consecutives.append({ 'time': thisrace[j].lap_time + thisrace[j+1].lap_time + thisrace[j+2].lap_time, 'race_id': race_id }) # Sort consecutives all_consecutives.sort(key = lambda x: (x['time'] is None, x['time'])) # Get lowest not-none value (if any) if all_consecutives: consecutives.append(all_consecutives[0]['time']) if USE_CURRENT: consecutives_source.append(None) else: source_query = Database.SavedRaceMeta.query.get(all_consecutives[0]['race_id']) if source_query: fast_lap_round = source_query.round_id fast_lap_heat = source_query.heat_id fast_lap_heatnote = Database.Heat.query.get(fast_lap_heat).note if fast_lap_heatnote: source_text = fast_lap_heatnote + ' / ' + __('Round') + ' ' + str(fast_lap_round) else: source_text = __('Heat') + ' ' + str(fast_lap_heat) + ' / ' + __('Round') + ' ' + str(fast_lap_round) consecutives_source.append(source_text) else: consecutives_source.append(None) else: consecutives.append(None) consecutives_source.append(None) gevent.sleep() # Combine for sorting leaderboard = zip(callsigns, max_laps, total_time, average_lap, fastest_lap, team_names, consecutives, fastest_lap_source, consecutives_source, last_lap, pilot_ids, nodes, total_time_laps) # Reverse sort max_laps x[1], then sort on total time x[2] leaderboard_by_race_time = sorted(leaderboard, key = lambda x: (-x[1], x[2] if x[2] > 0 else float('inf'))) leaderboard_total_data = [] last_rank = '-' last_rank_laps = 0 last_rank_time = RHUtils.time_format(0) for i, row in enumerate(leaderboard_by_race_time, start=1): pos = i total_time = RHUtils.time_format(row[2]) if last_rank_laps == row[1] and last_rank_time == total_time: pos = last_rank last_rank = pos last_rank_laps = row[1] last_rank_time = total_time leaderboard_total_data.append({ 'position': pos, 'callsign': row[0], 'laps': row[1], 'behind': (leaderboard_by_race_time[0][1] - row[1]), 'total_time': RHUtils.time_format(row[2]), 'total_time_raw': row[2], 'total_time_laps': RHUtils.time_format(row[12]), 'total_time_laps_raw': row[12], 'average_lap': RHUtils.time_format(row[3]), 'fastest_lap': RHUtils.time_format(row[4]), 'fastest_lap_raw': row[4], 'team_name': row[5], 'consecutives': RHUtils.time_format(row[6]), 'consecutives_raw': row[6], 'fastest_lap_source': row[7], 'consecutives_source': row[8], 'last_lap': RHUtils.time_format(row[9]), 'last_lap_raw': row[9], 'pilot_id': row[10], 'node': row[11], }) gevent.sleep() # Sort fastest_laps x[4] leaderboard_by_fastest_lap = sorted(leaderboard, key = lambda x: (x[4] if x[4] > 0 else float('inf'))) leaderboard_fast_lap_data = [] last_rank = '-' last_rank_lap = 0 for i, row in enumerate(leaderboard_by_fastest_lap, start=1): pos = i fast_lap = RHUtils.time_format(row[4]) if last_rank_lap == fast_lap: pos = last_rank last_rank = pos last_rank_laps = fast_lap leaderboard_fast_lap_data.append({ 'position': pos, 'callsign': row[0], 'laps': row[1], 'total_time': RHUtils.time_format(row[2]), 'total_time_raw': row[2], 'total_time_laps': RHUtils.time_format(row[12]), 'total_time_laps_raw': row[12], 'average_lap': RHUtils.time_format(row[3]), 'fastest_lap': RHUtils.time_format(row[4]), 'fastest_lap_raw': row[4], 'team_name': row[5], 'consecutives': RHUtils.time_format(row[6]), 'consecutives_raw': row[6], 'fastest_lap_source': row[7], 'consecutives_source': row[8], 'last_lap': RHUtils.time_format(row[9]), 'last_lap_raw': row[9], 'pilot_id': row[10], 'node': row[11], }) gevent.sleep() # Sort consecutives x[6] leaderboard_by_consecutives = sorted(leaderboard, key = lambda x: (x[6] if x[6] > 0 else float('inf'))) leaderboard_consecutives_data = [] last_rank = '-' last_rank_consecutive = 0 for i, row in enumerate(leaderboard_by_consecutives, start=1): pos = i fast_consecutive = RHUtils.time_format(row[4]) if last_rank_consecutive == fast_consecutive: pos = last_rank last_rank = pos last_rank_consecutive = fast_consecutive leaderboard_consecutives_data.append({ 'position': i, 'callsign': row[0], 'laps': row[1], 'total_time': RHUtils.time_format(row[2]), 'total_time_raw': row[2], 'total_time_laps': RHUtils.time_format(row[12]), 'total_time_laps_raw': row[12], 'average_lap': RHUtils.time_format(row[3]), 'fastest_lap': RHUtils.time_format(row[4]), 'fastest_lap_raw': row[4], 'team_name': row[5], 'consecutives': RHUtils.time_format(row[6]), 'consecutives_raw': row[6], 'fastest_lap_source': row[7], 'consecutives_source': row[8], 'last_lap': RHUtils.time_format(row[9]), 'last_lap_raw': row[9], 'pilot_id': row[10], 'node': row[11], }) leaderboard_output = { 'by_race_time': leaderboard_total_data, 'by_fastest_lap': leaderboard_fast_lap_data, 'by_consecutives': leaderboard_consecutives_data } if race_format: if race_format.win_condition == WinCondition.FASTEST_3_CONSECUTIVE: primary_leaderboard = 'by_consecutives' elif race_format.win_condition == WinCondition.FASTEST_LAP: primary_leaderboard = 'by_fastest_lap' else: # WinCondition.NONE # WinCondition.MOST_LAPS # WinCondition.FIRST_TO_LAP_X primary_leaderboard = 'by_race_time' leaderboard_output['meta'] = { 'primary_leaderboard': primary_leaderboard, 'win_condition': race_format.win_condition, 'team_racing_mode': race_format.team_racing_mode, } else: leaderboard_output['meta'] = { 'primary_leaderboard': 'by_race_time', 'win_condition': WinCondition.NONE, 'team_racing_mode': False } return leaderboard_output
def set_node_frequency(self, node_number, frequency): fmsg = __("Frequency Change: ") + str(frequency) node = self._nodes[node_number] node.set_node_frequency(frequency)