Untitled

 avatar
unknown
ruby
10 months ago
6.0 kB
15
Indexable
class UpdateMatchPerformanceJob
  include Sidekiq::Job
  include MatchesHelper
  include PlayersHelper
  include ActionView::Helpers::AssetUrlHelper

  sidekiq_options retry: 0

  def perform(match_id)
    titles = {
      minions: "Farmer",
      damage_dealt_to_structures: "Devastator",
      damage_dealt_to_objectives: "Hunter",
      damage_taken_to_death: "Guardian",
      damage_dealt_to_death: "Elusive",
      damage_dealt_to_taken: "Dominator",
      assists: "Altruist",
      hero_damage: "Annihilator",
      kda_score: "Assassin",
      wards: "Sentinel"
    }

    match_data = MatchPlayerDatum.where(match_id: match_id)

    match_data.each do |match_player_data|
      performance_data = calculate_performance(match_player_data.match, match_player_data, avgStats(match_player_data.match.game_mode, match_player_data))
      match_player_data.update(performance_score: performance_data.values.sum)
    end

    MatchPlayerDatum.teams.each do |team|
      team_player_data = match_data.where(team: team)
      team_data = team_player_data.map { |p| calculate_performance(p.match, p, avgStats(p.match.game_mode, p)).map { |pp| [p, *pp] } }.flatten(1)

      team_data.reject! { |data|
        (data.second == :kda_score && (data.first.kills < 5 || data.first.deaths > (data.first.kills / 2))) ||
        (data.second == :minions && (data.first.support? || data.first.match.game_mode == "brawl")) ||
        (data.second == :wards && data.first.match.game_mode == "brawl") ||
        (data.second == :damage_dealt_to_structures && data.first.match.game_mode == "brawl") ||
        (data.second == :hero_damage && data.first.kills + data.first.assists <= data.first.deaths) ||
        (data.second == :damage_dealt_to_taken && (data.first.total_damage_dealt_to_heroes + 1.0) / (data.first.total_damage_taken_from_heroes + 1.0) < 1.25)
      }

      team_data.sort_by(&:last).reverse.uniq(&:first).each { |x| x.first.update(performance_title: titles[x.second]) }
    end

    transmit_match_to_channels(Match.find_by(id: match_id))
  end

  def transmit_match_to_channels(match)
    data = prepare_api([match])
    match.player_data.each do |player_data|
      LiveMatchApiChannel.transmit_matches(player_data.player_id, data)
    end
  end

  def avgStats(game_mode, match_player_data)
    avg_role_stats = JSON.parse(GameStatistics.get(:role_ps_stats))
    avg_hero_stats = JSON.parse(GameStatistics.get(:hero_ps_stats))

    role = match_player_data.role.to_s
    hero_id = match_player_data.hero_id.to_s
    hero_stats = avg_hero_stats.dig(game_mode, hero_id, role)
    role_stats = avg_role_stats.dig(game_mode, role)

    hero_stats_match_count = hero_stats&.dig(9)&.to_i

    if hero_stats_match_count && hero_stats_match_count >= 100
      return hero_stats
    elsif role_stats
      return role_stats
    end

    return nil
  end

  def weights(game_mode)
    case game_mode
    when "pvp", "custom", "ranked", "TEAM_VS_TEAM_RUSH", "TEAM_VS_TEAM_LEGACY"
      {
        minions_weight: 10,
        damage_dealt_to_structures_weight: 10,
        damage_dealt_to_objectives_weight: 10,
        damage_taken_to_death_weight: 10,
        damage_dealt_to_death_weight: 10,
        damage_dealt_to_taken_weight: 10,
        assists_weight: 10,
        hero_damage_weight: 10,
        kda_weight: 10,
        wards_weight: 10,
      }
    when "brawl"
      return {
        minions_weight: 0,
        damage_dealt_to_structures_weight: 0,
        damage_dealt_to_objectives_weight: 14.285,
        damage_taken_to_death_weight: 14.285,
        damage_dealt_to_death_weight: 14.285,
        damage_dealt_to_taken_weight: 14.285,
        assists_weight: 14.285,
        hero_damage_weight: 14.285,
        kda_weight: 14.285,
        wards_weight: 0,
      }
    end
  end

  def calculate_performance(match, data, avg_stats)
    return stats = {
      minions: 10,
      damage_dealt_to_structures: 10,
      damage_dealt_to_objectives: 10,
      damage_taken_to_death: 10,
      damage_dealt_to_death: 10,
      damage_dealt_to_taken: 10,
      assists: 10,
      hero_damage: 10,
      kda_score: 10,
      wards: 10
    } if avg_stats.nil?

    avg_match_length = avg_stats[10] || 1

    average = {
      minions: avg_stats[0] || 1,
      damage_dealt_to_structures: avg_stats[1] || 1,
      damage_dealt_to_objectives: avg_stats[2] || 1,
      damage_taken_to_death: avg_stats[3] || 1,
      damage_dealt_to_death: avg_stats[4] || 1,
      damage_dealt_to_taken: avg_stats[5] || 1,
      assists: avg_stats[6] || 1,
      hero_damage: avg_stats[7] || 1,
      kda: avg_stats[8] || 1,
      wards: avg_stats[9] || 1,
    }

    weights = weights(match.game_mode)

    kda = ((data.kills + (data.assists * 0.5)) / (data.deaths + 1.0))
    kda_score = Math.log(kda + 1.0)

    stats = {
      minions: data.minions_killed,
      damage_dealt_to_structures: data.total_damage_dealt_to_structures + 1.0,
      damage_dealt_to_objectives: data.total_damage_dealt_to_objectives + 1.0,
      damage_taken_to_death: ((data.total_damage_taken_from_heroes + data.total_damage_mitigated) / (data.deaths + 1.0)),
      damage_dealt_to_death: (data.total_damage_dealt_to_heroes / (data.deaths + 1.0)),
      damage_dealt_to_taken: (data.total_damage_dealt_to_heroes / (data.total_damage_taken_from_heroes + 1.0)),
      assists: data.assists,
      hero_damage: data.total_damage_dealt_to_heroes,
      kda_score: kda_score,
      wards: data.wards_placed + data.wards_destroyed
    }

    return stats.zip(average, weights).map { |(key, value), (_, avg), (_, weight)| [key, (value / match.game_duration.to_f) / (avg.to_f / avg_match_length.to_f) * weight] }.to_h
  end

  def update_all_match_performance
    Match.in_batches(of: 10000).each_record do |match|
      UpdateMatchPerformanceJob.perform_async(match.id)
    end
  end
end
Editor is loading...
Leave a Comment