Example #1
0
        private void NpcDamageManager_EventsPlayerAttackProcessed(object sender, DamageProcessedEvent e)
        {
            lock (StatsLock)
            {
                var activeFights = DataManager.Instance.GetActiveFights();

                // reset if stats if first time or first new damage is received
                if (Stats == null || (activeFights.Count == 1 && activeFights[0].DamageBlocks.Count == 1 &&
                                      activeFights[0].DamageBlocks[0].Actions.Count == 1 && CurrentDamageSelectionMode == 0))
                {
                    Stats = new OverlayDamageStats {
                        BeginTime = e.BeginTime, RaidStats = new PlayerStats()
                    };
                }

                Stats.ActiveFights = activeFights;
                var timeout = CurrentDamageSelectionMode == 0 ? DataManager.FIGHTTIMEOUT : CurrentDamageSelectionMode;
                DamageStatsManager.Instance.ComputeOverlayDamageStats(e.Record, e.BeginTime, timeout, Stats);

                if (UpdateTimer != null && !UpdateTimer.IsEnabled)
                {
                    UpdateTimer.Start();
                }
            }
        }
 private void NpcDamageManager_EventsPlayerAttackProcessed(object sender, DamageProcessedEvent e)
 {
     lock (StatsLock)
     {
         Stats = DamageStatsManager.Instance.ComputeOverlayDamageStats(e.Record, e.BeginTime, Stats);
         if (UpdateTimer != null && !UpdateTimer.IsEnabled)
         {
             UpdateTimer.Start();
         }
     }
 }
        internal void ComputeOverlayDamageStats(DamageRecord record, double beginTime, int timeout, OverlayDamageStats overlayStats = null)
        {
            try
            {
                // set current time
                overlayStats.LastTime = beginTime;

                if (record != null && (record.Type != Labels.BANE || MainWindow.IsBaneDamageEnabled))
                {
                    overlayStats.RaidStats.Total += record.Total;

                    var raidTimeRange = new TimeRange();
                    overlayStats.InactiveFights.ForEach(fight => raidTimeRange.Add(new TimeSegment(Math.Max(fight.BeginDamageTime, overlayStats.BeginTime), fight.LastDamageTime)));
                    overlayStats.ActiveFights.ForEach(fight => raidTimeRange.Add(new TimeSegment(Math.Max(fight.BeginDamageTime, overlayStats.BeginTime), fight.LastDamageTime)));
                    overlayStats.RaidStats.TotalSeconds = Math.Max(raidTimeRange.GetTotal(), overlayStats.RaidStats.TotalSeconds);

                    // update pets
                    UpdatePetMapping(record);

                    bool isPet         = PetToPlayer.TryGetValue(record.Attacker, out string player);
                    bool needAggregate = isPet || (!isPet && PlayerPets.ContainsKey(record.Attacker) && overlayStats.TopLevelStats.ContainsKey(record.Attacker + " +Pets"));

                    if (!needAggregate)
                    {
                        // not a pet
                        PlayerStats stats = StatsUtil.CreatePlayerStats(overlayStats.IndividualStats, record.Attacker);
                        overlayStats.TopLevelStats[record.Attacker] = stats;
                        StatsUtil.UpdateStats(stats, record);
                        stats.LastTime = beginTime;
                    }
                    else
                    {
                        string origName      = player ?? record.Attacker;
                        string aggregateName = origName + " +Pets";

                        PlayerStats aggregatePlayerStats;
                        aggregatePlayerStats = StatsUtil.CreatePlayerStats(overlayStats.IndividualStats, aggregateName, origName);
                        overlayStats.TopLevelStats[aggregateName] = aggregatePlayerStats;

                        if (overlayStats.TopLevelStats.ContainsKey(origName))
                        {
                            var origPlayer = overlayStats.TopLevelStats[origName];
                            StatsUtil.MergeStats(aggregatePlayerStats, origPlayer);
                            overlayStats.TopLevelStats.Remove(origName);
                            overlayStats.IndividualStats.Remove(origName);
                        }

                        if (record.Attacker != origName && overlayStats.TopLevelStats.ContainsKey(record.Attacker))
                        {
                            var origPet = overlayStats.TopLevelStats[record.Attacker];
                            StatsUtil.MergeStats(aggregatePlayerStats, origPet);
                            overlayStats.TopLevelStats.Remove(record.Attacker);
                            overlayStats.IndividualStats.Remove(record.Attacker);
                        }

                        StatsUtil.UpdateStats(aggregatePlayerStats, record);
                        aggregatePlayerStats.LastTime = beginTime;
                    }

                    overlayStats.RaidStats.DPS = (long)Math.Round(overlayStats.RaidStats.Total / overlayStats.RaidStats.TotalSeconds, 2);

                    var list  = overlayStats.TopLevelStats.Values.OrderByDescending(item => item.Total).ToList();
                    int found = list.FindIndex(stats => stats.Name.StartsWith(ConfigUtil.PlayerName, StringComparison.Ordinal));
                    var you   = found > -1 ? list[found] : null;

                    int renumber;
                    if (found > 4)
                    {
                        you.Rank = Convert.ToUInt16(found + 1);
                        overlayStats.StatsList.Clear();
                        overlayStats.StatsList.AddRange(list.Where(stats => (stats != null && stats == you) || beginTime - stats.LastTime <= timeout).Take(4));
                        overlayStats.StatsList.Add(you);
                        renumber = overlayStats.StatsList.Count - 1;
                    }
                    else
                    {
                        overlayStats.StatsList.Clear();
                        overlayStats.StatsList.AddRange(list.Where(stats => (stats != null && stats == you) || beginTime - stats.LastTime <= timeout).Take(5));
                        renumber = overlayStats.StatsList.Count;
                    }

                    for (int i = 0; i < overlayStats.StatsList.Count; i++)
                    {
                        if (i < renumber)
                        {
                            overlayStats.StatsList[i].Rank = Convert.ToUInt16(i + 1);
                        }

                        // only update time if damage changed
                        if (overlayStats.StatsList[i].LastTime == beginTime && overlayStats.StatsList[i].CalcTime != beginTime)
                        {
                            var timeRange = new TimeRange();
                            if (PlayerPets.TryGetValue(overlayStats.StatsList[i].OrigName, out ConcurrentDictionary <string, byte> mapping))
                            {
                                mapping.Keys.ToList().ForEach(key =>
                                {
                                    AddSegments(timeRange, overlayStats.InactiveFights, key, overlayStats.BeginTime);
                                    AddSegments(timeRange, overlayStats.ActiveFights, key, overlayStats.BeginTime);
                                });
                            }

                            AddSegments(timeRange, overlayStats.InactiveFights, overlayStats.StatsList[i].OrigName, overlayStats.BeginTime);
                            AddSegments(timeRange, overlayStats.ActiveFights, overlayStats.StatsList[i].OrigName, overlayStats.BeginTime);
                            overlayStats.StatsList[i].TotalSeconds = Math.Max(timeRange.GetTotal(), overlayStats.StatsList[i].TotalSeconds);
                            overlayStats.StatsList[i].CalcTime     = beginTime;
                        }

                        StatsUtil.UpdateCalculations(overlayStats.StatsList[i], overlayStats.RaidStats);
                    }

                    var count = overlayStats.InactiveFights.Count + overlayStats.ActiveFights.Count;
                    overlayStats.TargetTitle = (count > 1 ? "C(" + count + "): " : "") + record.Defender;
                    overlayStats.TimeTitle   = string.Format(CultureInfo.CurrentCulture, StatsUtil.TIME_FORMAT, overlayStats.RaidStats.TotalSeconds);
                    overlayStats.TotalTitle  = string.Format(CultureInfo.CurrentCulture, StatsUtil.TOTAL_FORMAT, StatsUtil.FormatTotals(overlayStats.RaidStats.Total),
                                                             " Damage ", StatsUtil.FormatTotals(overlayStats.RaidStats.DPS));
                }
            }
#pragma warning disable CA1031 // Do not catch general exception types
            catch (Exception ex)
#pragma warning restore CA1031 // Do not catch general exception types
            {
                if (ex is ArgumentNullException || ex is NullReferenceException || ex is ArgumentOutOfRangeException || ex is ArgumentException || ex is OutOfMemoryException)
                {
                    LOG.Error(ex);
                }
            }

            void AddSegments(TimeRange range, List <Fight> fights, string key, double start)
            {
                fights.ForEach(fight =>
                {
                    if (fight.DamageSegments.TryGetValue(key, out TimeSegment segment) && segment.EndTime >= start)
                    {
                        range.Add(new TimeSegment(Math.Max(segment.BeginTime, start), segment.EndTime));
                    }
                });
            }
        }
Example #4
0
        private void UpdateTimerTick(object sender, EventArgs e)
        {
            lock (StatsLock)
            {
                try
                {
                    Topmost = true; // possible workaround

                    // people wanted shorter delays for damage updates but I don't want the indicator to change constantly
                    // so this limits it to 1/2 the current time value
                    ProcessDirection = !ProcessDirection;

                    var timeout = CurrentDamageSelectionMode == 0 ? DataManager.FIGHTTIMEOUT : CurrentDamageSelectionMode;
                    if (Stats == null || (DateTime.Now - DateTime.MinValue.AddSeconds(Stats.LastTime)).TotalSeconds > timeout)
                    {
                        windowBrush.Opacity = 0.0;
                        ButtonPopup.IsOpen  = false;
                        SetVisible(false);
                        Height   = 0;
                        Stats    = null;
                        PrevList = null;
                        UpdateTimer.Stop();
                    }
                    else if (Active && Stats != null)
                    {
                        var list = Stats.StatsList.Take(MAX_ROWS).ToList();
                        if (list.Count > 0)
                        {
                            TitleBlock.Text       = Stats.TargetTitle;
                            TitleDamageBlock.Text = string.Format(CultureInfo.CurrentCulture, "{0} [{1}s @{2}]",
                                                                  StatsUtil.FormatTotals(Stats.RaidStats.Total), Stats.RaidStats.TotalSeconds, StatsUtil.FormatTotals(Stats.RaidStats.DPS));

                            long total        = 0;
                            int  goodRowCount = 0;
                            long me           = 0;
                            var  topList      = new Dictionary <int, long>();
                            for (int i = 0; i < MAX_ROWS; i++)
                            {
                                if (list.Count > i)
                                {
                                    if (ProcessDirection)
                                    {
                                        DamageRateList[i].Opacity = 0.0;
                                    }

                                    if (i == 0)
                                    {
                                        total = list[i].Total;
                                        RectangleList[i].Width = Width;
                                    }
                                    else
                                    {
                                        RectangleList[i].Visibility = Visibility.Hidden; // maybe it calculates width better
                                        RectangleList[i].Width      = Convert.ToDouble(list[i].Total) / total * Width;
                                    }

                                    string playerName = ConfigUtil.PlayerName;
                                    var    isMe       = !string.IsNullOrEmpty(playerName) && list[i].Name.StartsWith(playerName, StringComparison.OrdinalIgnoreCase) &&
                                                        (playerName.Length >= list[i].Name.Length || list[i].Name[playerName.Length] == ' ');

                                    string updateText;
                                    if (IsHideOverlayOtherPlayersEnabled && !isMe)
                                    {
                                        updateText = string.Format(CultureInfo.CurrentCulture, "{0}. Hidden Player", list[i].Rank);
                                    }
                                    else
                                    {
                                        updateText = string.Format(CultureInfo.CurrentCulture, "{0}. {1}", list[i].Rank, list[i].Name);
                                    }

                                    if (IsShowOverlayCritRateEnabled)
                                    {
                                        List <string> critMods = new List <string>();

                                        if (isMe && PlayerManager.Instance.IsDoTClass(list[i].ClassName) && DataManager.Instance.MyDoTCritRateMod is uint doTCritRate && doTCritRate > 0)
                                        {
                                            critMods.Add(string.Format(CultureInfo.CurrentCulture, "DoT CR +{0}", doTCritRate));
                                        }

                                        if (isMe && DataManager.Instance.MyNukeCritRateMod is uint nukeCritRate && nukeCritRate > 0)
                                        {
                                            critMods.Add(string.Format(CultureInfo.CurrentCulture, "Nuke CR +{0}", nukeCritRate));
                                        }

                                        if (critMods.Count > 0)
                                        {
                                            updateText = string.Format(CultureInfo.CurrentCulture, "{0} [{1}]", updateText, string.Join(", ", critMods));
                                        }
                                    }

                                    NameBlockList[i].Text = updateText;

                                    if (i <= 4 && !isMe && list[i].Total > 0)
                                    {
                                        topList[i] = list[i].Total;
                                    }
                                    else if (isMe)
                                    {
                                        me = list[i].Total;
                                    }

                                    var damage = StatsUtil.FormatTotals(list[i].Total) + " [" + list[i].TotalSeconds.ToString(CultureInfo.CurrentCulture) + "s @" + StatsUtil.FormatTotals(list[i].DPS) + "]";
                                    DamageBlockList[i].Text = damage;
                                    goodRowCount++;
                                }
                            }

                            if (ProcessDirection)
                            {
                                if (me > 0 && topList.Count > 0)
                                {
                                    var updatedList = new Dictionary <int, double>();
                                    foreach (int i in topList.Keys)
                                    {
                                        if (i != me)
                                        {
                                            var diff = topList[i] / (double)me;
                                            updatedList[i] = diff;
                                            if (PrevList != null && PrevList.ContainsKey(i))
                                            {
                                                if (PrevList[i] > diff)
                                                {
                                                    DamageRateList[i].Icon       = FontAwesomeIcon.LongArrowDown;
                                                    DamageRateList[i].Foreground = DOWNBRUSH;
                                                    DamageRateList[i].Opacity    = DATA_OPACITY;
                                                }
                                                else if (PrevList[i] < diff)
                                                {
                                                    DamageRateList[i].Icon       = FontAwesomeIcon.LongArrowUp;
                                                    DamageRateList[i].Foreground = UPBRUSH;
                                                    DamageRateList[i].Opacity    = DATA_OPACITY;
                                                }
                                            }
                                        }
                                    }

                                    PrevList = updatedList;
                                }
                                else
                                {
                                    PrevList = null;
                                }
                            }

                            var requested = (goodRowCount + 1) * CalculatedRowHeight;
                            if (ActualHeight != requested)
                            {
                                Height = requested;
                            }

                            if (overlayCanvas.Visibility != Visibility.Visible)
                            {
                                overlayCanvas.Visibility    = Visibility.Hidden;
                                TitleRectangle.Visibility   = Visibility.Hidden;
                                TitlePanel.Visibility       = Visibility.Hidden;
                                TitleDamagePanel.Visibility = Visibility.Hidden;
                                TitleRectangle.Height       = CalculatedRowHeight;
                                TitleDamagePanel.Height     = CalculatedRowHeight;
                                TitlePanel.Height           = CalculatedRowHeight;
                                overlayCanvas.Visibility    = Visibility.Visible;
                                TitleRectangle.Visibility   = Visibility.Visible;
                                TitlePanel.Visibility       = Visibility.Visible;
                                TitleDamagePanel.Visibility = Visibility.Visible;
                                windowBrush.Opacity         = OPACITY;
                                ButtonPopup.IsOpen          = true;
                            }

                            for (int i = 0; i < MAX_ROWS; i++)
                            {
                                SetRowVisible(i < goodRowCount, i);
                            }
                        }
                    }
                }
                catch (Exception ex)
                {
                    LOG.Error("Overlay Error", ex);
                }
            }
        }
        internal OverlayDamageStats ComputeOverlayDamageStats(DamageRecord record, double beginTime, OverlayDamageStats overlayStats = null)
        {
            if (overlayStats == null)
            {
                overlayStats = new OverlayDamageStats
                {
                    RaidStats = new PlayerStats()
                };

                overlayStats.RaidStats.BeginTime = beginTime;
            }
            else
            {
                overlayStats.RaidStats = overlayStats.RaidStats;
            }

            if (overlayStats.UniqueNpcs.Count == 0 || (beginTime - overlayStats.RaidStats.LastTime > DataManager.FIGHT_TIMEOUT))
            {
                overlayStats.RaidStats.Total     = 0;
                overlayStats.RaidStats.BeginTime = beginTime;
                overlayStats.UniqueNpcs.Clear();
                overlayStats.TopLevelStats.Clear();
                overlayStats.AggregateStats.Clear();
                overlayStats.IndividualStats.Clear();
            }

            overlayStats.RaidStats.LastTime     = beginTime;
            overlayStats.RaidStats.TotalSeconds = overlayStats.RaidStats.LastTime - overlayStats.RaidStats.BeginTime + 1;

            if (record != null && (record.Type != Labels.BANE || MainWindow.IsBaneDamageEnabled))
            {
                overlayStats.UniqueNpcs[record.Defender] = 1;
                overlayStats.RaidStats.Total            += record.Total;

                // see if there's a pet mapping, check this first
                string pname = PlayerManager.Instance.GetPlayerFromPet(record.Attacker);
                if (pname != null || !string.IsNullOrEmpty(pname = record.AttackerOwner))
                {
                    PlayerHasPet[pname]          = 1;
                    PetToPlayer[record.Attacker] = pname;
                }

                bool isPet         = PetToPlayer.TryGetValue(record.Attacker, out string player);
                bool needAggregate = isPet || (!isPet && PlayerHasPet.ContainsKey(record.Attacker) && overlayStats.TopLevelStats.ContainsKey(record.Attacker + " +Pets"));

                if (!needAggregate || player == Labels.UNASSIGNED)
                {
                    // not a pet
                    PlayerStats stats = StatsUtil.CreatePlayerStats(overlayStats.IndividualStats, record.Attacker);
                    StatsUtil.UpdateStats(stats, record, beginTime);
                    overlayStats.TopLevelStats[record.Attacker] = stats;
                    stats.TotalSeconds = stats.LastTime - stats.BeginTime + 1;
                }
                else
                {
                    string origName      = player ?? record.Attacker;
                    string aggregateName = origName + " +Pets";

                    PlayerStats aggregatePlayerStats;
                    aggregatePlayerStats = StatsUtil.CreatePlayerStats(overlayStats.IndividualStats, aggregateName, origName);
                    overlayStats.TopLevelStats[aggregateName] = aggregatePlayerStats;

                    if (overlayStats.TopLevelStats.ContainsKey(origName))
                    {
                        var origPlayer = overlayStats.TopLevelStats[origName];
                        StatsUtil.MergeStats(aggregatePlayerStats, origPlayer);
                        overlayStats.TopLevelStats.Remove(origName);
                        overlayStats.IndividualStats.Remove(origName);
                    }

                    if (record.Attacker != origName && overlayStats.TopLevelStats.ContainsKey(record.Attacker))
                    {
                        var origPet = overlayStats.TopLevelStats[record.Attacker];
                        StatsUtil.MergeStats(aggregatePlayerStats, origPet);
                        overlayStats.TopLevelStats.Remove(record.Attacker);
                        overlayStats.IndividualStats.Remove(record.Attacker);
                    }

                    StatsUtil.UpdateStats(aggregatePlayerStats, record, beginTime);
                    aggregatePlayerStats.TotalSeconds = aggregatePlayerStats.LastTime - aggregatePlayerStats.BeginTime + 1;
                }

                overlayStats.RaidStats.DPS = (long)Math.Round(overlayStats.RaidStats.Total / overlayStats.RaidStats.TotalSeconds, 2);

                var list  = overlayStats.TopLevelStats.Values.OrderByDescending(item => item.Total).ToList();
                int found = list.FindIndex(stats => stats.Name.StartsWith(ConfigUtil.PlayerName, StringComparison.Ordinal));

                int renumber;
                if (found > 4)
                {
                    var you = list[found];
                    you.Rank = Convert.ToUInt16(found + 1);
                    overlayStats.StatsList.Clear();
                    overlayStats.StatsList.AddRange(list.Take(4));
                    overlayStats.StatsList.Add(you);
                    renumber = overlayStats.StatsList.Count - 1;
                }
                else
                {
                    overlayStats.StatsList.Clear();
                    overlayStats.StatsList.AddRange(list.Take(5));
                    renumber = overlayStats.StatsList.Count;
                }

                for (int i = 0; i < renumber; i++)
                {
                    overlayStats.StatsList[i].Rank = Convert.ToUInt16(i + 1);
                }

                // only calculate the top few
                Parallel.ForEach(overlayStats.StatsList, top => StatsUtil.UpdateCalculations(top, overlayStats.RaidStats));
                overlayStats.TargetTitle = (overlayStats.UniqueNpcs.Count > 1 ? "Combined (" + overlayStats.UniqueNpcs.Count + "): " : "") + record.Defender;
                overlayStats.TimeTitle   = string.Format(CultureInfo.CurrentCulture, StatsUtil.TIME_FORMAT, overlayStats.RaidStats.TotalSeconds);
                overlayStats.TotalTitle  = string.Format(CultureInfo.CurrentCulture, StatsUtil.TOTAL_FORMAT, StatsUtil.FormatTotals(overlayStats.RaidStats.Total), " Damage ", StatsUtil.FormatTotals(overlayStats.RaidStats.DPS));
            }

            return(overlayStats);
        }
        private void UpdateTimerTick(object sender, EventArgs e)
        {
            lock (StatsLock)
            {
                try
                {
                    Topmost = true; // possible workaround

                    // people wanted shorter delays for damage updates but I don't want the indicator to change constantly
                    // so this limits it to 1/2 the current time value
                    ProcessDirection = !ProcessDirection;

                    if (Stats == null || (DateTime.Now - DateTime.MinValue.AddSeconds(Stats.RaidStats.LastTime)).TotalSeconds > DataManager.FIGHT_TIMEOUT)
                    {
                        windowBrush.Opacity = 0.0;
                        ButtonPopup.IsOpen  = false;
                        SetVisible(false);
                        this.Height = 0;
                        Stats       = null;
                        PrevList    = null;
                        UpdateTimer.Stop();
                    }
                    else if (Active && Stats != null && Stats.RaidStats.LastTime > LastUpdate)
                    {
                        var list = Stats.StatsList.Take(MAX_ROWS).ToList();
                        if (list.Count > 0)
                        {
                            TitleBlock.Text       = Stats.TargetTitle;
                            TitleDamageBlock.Text = StatsUtil.FormatTotals(Stats.RaidStats.Total) + " [" + Stats.RaidStats.TotalSeconds + "s @" +
                                                    StatsUtil.FormatTotals(Stats.RaidStats.DPS) + "]";

                            long total        = 0;
                            int  goodRowCount = 0;
                            long me           = 0;
                            var  topList      = new Dictionary <int, long>();
                            for (int i = 0; i < MAX_ROWS; i++)
                            {
                                if (list.Count > i)
                                {
                                    if (ProcessDirection)
                                    {
                                        DamageRateList[i].Opacity = 0.0;
                                    }

                                    if (i == 0)
                                    {
                                        total = list[i].Total;
                                        RectangleList[i].Width = this.Width;
                                    }
                                    else
                                    {
                                        RectangleList[i].Visibility = Visibility.Hidden; // maybe it calculates width better
                                        RectangleList[i].Width      = Convert.ToDouble(list[i].Total) / total * this.Width;
                                    }

                                    string playerName = ConfigUtil.PlayerName;
                                    var    isMe       = !string.IsNullOrEmpty(playerName) && list[i].Name.StartsWith(playerName, StringComparison.OrdinalIgnoreCase) &&
                                                        (playerName.Length >= list[i].Name.Length || list[i].Name[playerName.Length] == ' ');
                                    if (MainWindow.IsHideOverlayOtherPlayersEnabled && !isMe)
                                    {
                                        NameBlockList[i].Text = list[i].Rank + ". " + "Hidden Player";
                                    }
                                    else
                                    {
                                        NameBlockList[i].Text = list[i].Rank + ". " + list[i].Name;
                                    }

                                    if (i <= 3 && !isMe && list[i].Total > 0)
                                    {
                                        topList[i] = list[i].Total;
                                    }
                                    else if (isMe)
                                    {
                                        me = list[i].Total;
                                    }

                                    var damage = StatsUtil.FormatTotals(list[i].Total) + " [" + list[i].TotalSeconds + "s @" + StatsUtil.FormatTotals(list[i].DPS) + "]";
                                    DamageBlockList[i].Text = damage;
                                    goodRowCount++;
                                }
                            }

                            if (ProcessDirection)
                            {
                                if (me > 0 && topList.Count > 0)
                                {
                                    var updatedList = new Dictionary <int, double>();
                                    foreach (int i in topList.Keys)
                                    {
                                        if (i != me)
                                        {
                                            var diff = topList[i] / (double)me;
                                            updatedList[i] = diff;
                                            if (PrevList != null && PrevList.ContainsKey(i))
                                            {
                                                if (PrevList[i] > diff)
                                                {
                                                    DamageRateList[i].Icon       = FontAwesomeIcon.LongArrowDown;
                                                    DamageRateList[i].Foreground = DOWN_BRUSH;
                                                    DamageRateList[i].Opacity    = DATA_OPACITY;
                                                }
                                                else if (PrevList[i] < diff)
                                                {
                                                    DamageRateList[i].Icon       = FontAwesomeIcon.LongArrowUp;
                                                    DamageRateList[i].Foreground = UP_BRUSH;
                                                    DamageRateList[i].Opacity    = DATA_OPACITY;
                                                }
                                            }
                                        }
                                    }

                                    PrevList = updatedList;
                                }
                                else
                                {
                                    PrevList = null;
                                }
                            }

                            var requested = (goodRowCount + 1) * CalculatedRowHeight;
                            if (this.ActualHeight != requested)
                            {
                                this.Height = requested;
                            }

                            if (overlayCanvas.Visibility != Visibility.Visible)
                            {
                                overlayCanvas.Visibility    = Visibility.Hidden;
                                TitlePanel.Visibility       = Visibility.Hidden;
                                TitleRectangle.Visibility   = Visibility.Hidden;
                                TitleBlock.Visibility       = Visibility.Hidden;
                                TitleDamageBlock.Visibility = Visibility.Hidden;
                                TitlePanel.Height           = CalculatedRowHeight;
                                TitleRectangle.Height       = CalculatedRowHeight;
                                TitleDamageBlock.Height     = CalculatedRowHeight;
                                TitleBlock.Height           = CalculatedRowHeight;
                                overlayCanvas.Visibility    = Visibility.Visible;
                                TitlePanel.Visibility       = Visibility.Visible;
                                TitleRectangle.Visibility   = Visibility.Visible;
                                TitleBlock.Visibility       = Visibility.Visible;
                                TitleDamageBlock.Visibility = Visibility.Visible;
                                windowBrush.Opacity         = OPACITY;
                                ButtonPopup.IsOpen          = true;
                            }

                            for (int i = 0; i < MAX_ROWS; i++)
                            {
                                SetRowVisible(i < goodRowCount, i);
                            }
                        }
                    }
                }
#pragma warning disable CA1031 // Do not catch general exception types
                catch (Exception ex)
#pragma warning restore CA1031 // Do not catch general exception types
                {
                    LOG.Error("Overlay Error", ex);
                }
            }
        }