예제 #1
0
        internal void BuildTotalStats(GenerateStatsOptions options)
        {
            lock (HealingGroups)
            {
                try
                {
                    FireNewStatsEvent(options);
                    Reset();

                    Selected = options.Npcs;
                    Title    = options.Name;

                    Selected.ForEach(fight => RaidTotals.Ranges.Add(new TimeSegment(fight.BeginTankingTime, fight.LastTankingTime)));

                    if (RaidTotals.Ranges.TimeSegments.Count > 0)
                    {
                        // calculate totals first since it can modify the ranges
                        RaidTotals.TotalSeconds = RaidTotals.Ranges.GetTotal();

                        RaidTotals.Ranges.TimeSegments.ForEach(segment =>
                        {
                            var updatedHeals = new List <ActionBlock>();
                            var healedByHealerTimeSegments = new Dictionary <string, Dictionary <string, TimeSegment> >();
                            var healedBySpellTimeSegments  = new Dictionary <string, Dictionary <string, TimeSegment> >();
                            var healerHealedTimeSegments   = new Dictionary <string, Dictionary <string, TimeSegment> >();
                            var healerSpellTimeSegments    = new Dictionary <string, Dictionary <string, TimeSegment> >();
                            DataManager.Instance.GetHealsDuring(segment.BeginTime, segment.EndTime).ForEach(heal =>
                            {
                                var updatedHeal = new ActionBlock()
                                {
                                    BeginTime = heal.BeginTime
                                };
                                foreach (var record in heal.Actions.Cast <HealRecord>())
                                {
                                    if (PlayerManager.Instance.IsPossiblePlayerName(record.Healed) || PlayerManager.Instance.IsPetOrPlayer(record.Healed))
                                    {
                                        bool valid = true;
                                        SpellData spellData;
                                        if (record.SubType != null && (spellData = DataManager.Instance.GetSpellByName(record.SubType)) != null)
                                        {
                                            if (spellData.Target == (byte)SpellTarget.TARGETAE || spellData.Target == (byte)SpellTarget.NEARBYPLAYERSAE ||
                                                spellData.Target == (byte)SpellTarget.TARGETRINGAE)
                                            {
                                                valid = MainWindow.IsAoEHealingEnabled;
                                            }
                                        }

                                        if (valid)
                                        {
                                            updatedHeal.Actions.Add(record);
                                            // store substats and substats2 which is based on the player that was healed
                                            var key = Helpers.CreateRecordKey(record.Type, record.SubType);
                                            StatsUtil.UpdateTimeSegments(null, healedByHealerTimeSegments, record.Healer, record.Healed, heal.BeginTime);
                                            StatsUtil.UpdateTimeSegments(null, healedBySpellTimeSegments, key, record.Healed, heal.BeginTime);
                                            StatsUtil.UpdateTimeSegments(null, healerHealedTimeSegments, record.Healed, record.Healer, heal.BeginTime);
                                            StatsUtil.UpdateTimeSegments(null, healerSpellTimeSegments, key, record.Healer, heal.BeginTime);
                                        }
                                    }
                                }

                                if (updatedHeal.Actions.Count > 0)
                                {
                                    updatedHeals.Add(updatedHeal);
                                }
                            });

                            Parallel.ForEach(healedByHealerTimeSegments, kv => StatsUtil.AddSubTimeEntry(HealedByHealerTimeRanges, kv));
                            Parallel.ForEach(healedBySpellTimeSegments, kv => StatsUtil.AddSubTimeEntry(HealedBySpellTimeRanges, kv));
                            Parallel.ForEach(healerHealedTimeSegments, kv => StatsUtil.AddSubTimeEntry(HealerHealedTimeRanges, kv));
                            Parallel.ForEach(healerSpellTimeSegments, kv => StatsUtil.AddSubTimeEntry(HealerSpellTimeRanges, kv));

                            if (updatedHeals.Count > 0)
                            {
                                HealingGroups.Add(updatedHeals);
                            }
                        });

                        ComputeHealingStats(options);
                    }
                    else if (Selected == null || Selected.Count == 0)
                    {
                        FireNoDataEvent(options, "NONPC");
                    }
                    else
                    {
                        FireNoDataEvent(options, "NODATA");
                    }
                }
#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);
                    }
                }
            }
        }
예제 #2
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;

                    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);
                }
            }
        }
예제 #3
0
        private static DamageRecord ParsePointsOf(string[] data, bool isNonMelee, int forIndex, int byIndex, int hitIndex, StringBuilder builder, List <string> nameList)
        {
            DamageRecord record   = null;
            uint         damage   = StatsUtil.ParseUInt(data[forIndex + 1]);
            string       type     = null;
            string       subType  = null;
            string       attacker = null;

            if (byIndex > 1)
            {
                // possible spell
                subType = ReadStringToPeriod(data, byIndex, builder);
            }

            // before hit
            nameList.Clear();
            for (int i = hitIndex - 1; i >= 0; i--)
            {
                if (data[hitIndex].EndsWith(".", StringComparison.Ordinal))
                {
                    break;
                }
                else
                {
                    nameList.Insert(0, data[i]);
                }
            }

            if (nameList.Count > 0)
            {
                attacker = string.Join(" ", nameList);
            }

            if (!isNonMelee)
            {
                subType = GetTypeFromHit(data[hitIndex], out bool additional);
                if (subType != null)
                {
                    type = Labels.MELEE;

                    if (additional)
                    {
                        hitIndex++; // multi-word hit value
                    }
                }
            }

            if (!string.IsNullOrEmpty(subType) && isNonMelee)
            {
                type = GetTypeFromSpell(subType, Labels.DD);
            }


            string defender = string.Join(" ", data, hitIndex + 1, forIndex - hitIndex - 1);

            // check for pets
            HasOwner(attacker, out string attackerOwner);
            HasOwner(defender, out string defenderOwner);

            // some new special cases
            if (!string.IsNullOrEmpty(subType) && subType.StartsWith("Elemental Conversion", StringComparison.Ordinal))
            {
                PlayerManager.Instance.AddVerifiedPet(defender);
            }
            else if (!string.IsNullOrEmpty(attacker) && !string.IsNullOrEmpty(defender))
            {
                record = BuildRecord(attacker, defender, damage, attackerOwner, defenderOwner, subType, type);
            }

            return(record);
        }
예제 #4
0
        private void ComputeHealingStats(GenerateStatsOptions options)
        {
            lock (HealingGroups)
            {
                if (RaidTotals != null)
                {
                    CombinedStats combined = null;
                    Dictionary <string, PlayerStats> individualStats = new Dictionary <string, PlayerStats>();

                    // always start over
                    RaidTotals.Total = 0;

                    try
                    {
                        FireChartEvent(options, "UPDATE");

                        if (options.RequestSummaryData)
                        {
                            HealingGroups.ForEach(group =>
                            {
                                group.ForEach(block =>
                                {
                                    block.Actions.ForEach(action =>
                                    {
                                        if (action is HealRecord record)
                                        {
                                            RaidTotals.Total += record.Total;
                                            PlayerStats stats = StatsUtil.CreatePlayerStats(individualStats, record.Healer);
                                            StatsUtil.UpdateStats(stats, record);

                                            var spellStatName         = record.SubType ?? Labels.SELFHEAL;
                                            PlayerSubStats spellStats = StatsUtil.CreatePlayerSubStats(stats.SubStats, spellStatName, record.Type);
                                            StatsUtil.UpdateStats(spellStats, record);

                                            var healedStatName         = record.Healed;
                                            PlayerSubStats healedStats = StatsUtil.CreatePlayerSubStats(stats.SubStats2, healedStatName, record.Type);
                                            StatsUtil.UpdateStats(healedStats, record);
                                        }
                                    });
                                });
                            });

                            RaidTotals.DPS = (long)Math.Round(RaidTotals.Total / RaidTotals.TotalSeconds, 2);
                            Parallel.ForEach(individualStats.Values, stats => UpdateStats(stats, HealerSpellTimeRanges, HealerHealedTimeRanges));

                            combined = new CombinedStats
                            {
                                RaidStats   = RaidTotals,
                                TargetTitle = (Selected.Count > 1 ? "Combined (" + Selected.Count + "): " : "") + Title,
                                TimeTitle   = string.Format(CultureInfo.CurrentCulture, StatsUtil.TIME_FORMAT, RaidTotals.TotalSeconds),
                                TotalTitle  = string.Format(CultureInfo.CurrentCulture, StatsUtil.TOTAL_FORMAT, StatsUtil.FormatTotals(RaidTotals.Total), " Heals ", StatsUtil.FormatTotals(RaidTotals.DPS))
                            };

                            combined.StatsList.AddRange(individualStats.Values.AsParallel().OrderByDescending(item => item.Total));
                            combined.FullTitle  = StatsUtil.FormatTitle(combined.TargetTitle, combined.TimeTitle, combined.TotalTitle);
                            combined.ShortTitle = StatsUtil.FormatTitle(combined.TargetTitle, combined.TimeTitle, "");

                            for (int i = 0; i < combined.StatsList.Count; i++)
                            {
                                combined.StatsList[i].Rank = Convert.ToUInt16(i + 1);
                                combined.UniqueClasses[combined.StatsList[i].ClassName] = 1;
                            }
                        }
                    }
#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);
                        }
                    }

                    if (options.RequestSummaryData)
                    {
                        // generating new stats
                        var genEvent = new StatsGenerationEvent()
                        {
                            Type          = Labels.HEALPARSE,
                            State         = "COMPLETED",
                            CombinedStats = combined
                        };

                        genEvent.Groups.AddRange(HealingGroups);
                        EventsGenerationStatus?.Invoke(this, genEvent);
                    }
                }
            }
        }
예제 #5
0
        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));
                    }
                });
            }
        }
예제 #6
0
        internal void BuildTotalStats(GenerateStatsOptions options)
        {
            lock (DamageGroupIds)
            {
                try
                {
                    FireNewStatsEvent(options);
                    Reset();

                    Selected = options.Npcs;
                    Title    = options.Name;
                    var damageBlocks = new List <ActionBlock>();

                    Selected.ForEach(fight =>
                    {
                        damageBlocks.AddRange(fight.DamageBlocks);

                        if (fight.GroupId > -1)
                        {
                            DamageGroupIds[fight.GroupId] = 1;
                        }

                        RaidTotals.Ranges.Add(new TimeSegment(fight.BeginDamageTime, fight.LastDamageTime));
                        StatsUtil.UpdateRaidTimeRanges(fight, PlayerTimeRanges, PlayerSubTimeRanges);
                    });

                    damageBlocks.Sort((a, b) => a.BeginTime.CompareTo(b.BeginTime));

                    if (damageBlocks.Count > 0)
                    {
                        RaidTotals.TotalSeconds = RaidTotals.Ranges.GetTotal();
                        RaidTotals.MaxTime      = RaidTotals.TotalSeconds;

                        int    rangeIndex = 0;
                        double lastTime   = 0;
                        var    newBlock   = new List <ActionBlock>();
                        damageBlocks.ForEach(block =>
                        {
                            if (RaidTotals.Ranges.TimeSegments.Count > rangeIndex && block.BeginTime > RaidTotals.Ranges.TimeSegments[rangeIndex].EndTime)
                            {
                                rangeIndex++;

                                if (newBlock.Count > 0)
                                {
                                    DamageGroups.Add(newBlock);
                                }

                                newBlock = new List <ActionBlock>();
                            }

                            if (lastTime != block.BeginTime)
                            {
                                var copy = new ActionBlock();
                                copy.Actions.AddRange(block.Actions);
                                copy.BeginTime = block.BeginTime;
                                newBlock.Add(copy);
                            }
                            else
                            {
                                newBlock.Last().Actions.AddRange(block.Actions);
                            }

                            // update pet mapping
                            block.Actions.ForEach(action => UpdatePetMapping(action as DamageRecord));
                            lastTime = block.BeginTime;
                        });

                        DamageGroups.Add(newBlock);
                        RaidTotals.Ranges.TimeSegments.ForEach(segment => DataManager.Instance.GetResistsDuring(segment.BeginTime, segment.EndTime).ForEach(block => Resists.AddRange(block.Actions)));
                        ComputeDamageStats(options);
                    }
                    else if (Selected == null || Selected.Count == 0)
                    {
                        FireNoDataEvent(options, "NONPC");
                    }
                    else
                    {
                        FireNoDataEvent(options, "NODATA");
                    }
                }
#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);
                    }
                }
            }
        }
예제 #7
0
        internal void BuildTotalStats(GenerateStatsOptions options)
        {
            lock (HealingGroups)
            {
                try
                {
                    FireNewStatsEvent(options);
                    Reset();

                    Selected = options.Npcs.OrderBy(sel => sel.Id).ToList();
                    Title    = options.Name;

                    Selected.ForEach(fight => RaidTotals.Ranges.Add(new TimeSegment(fight.BeginTankingTime, fight.LastTankingTime)));

                    if (RaidTotals.Ranges.TimeSegments.Count > 0)
                    {
                        // calculate totals first since it can modify the ranges
                        RaidTotals.TotalSeconds = RaidTotals.MaxTime = RaidTotals.Ranges.GetTotal();

                        RaidTotals.Ranges.TimeSegments.ForEach(segment =>
                        {
                            var updatedHeals = new List <ActionBlock>();
                            var healedByHealerTimeSegments = new Dictionary <string, Dictionary <string, TimeSegment> >();
                            var healedBySpellTimeSegments  = new Dictionary <string, Dictionary <string, TimeSegment> >();
                            var healerHealedTimeSegments   = new Dictionary <string, Dictionary <string, TimeSegment> >();
                            var healerSpellTimeSegments    = new Dictionary <string, Dictionary <string, TimeSegment> >();

                            double currentTime = double.NaN;
                            Dictionary <string, HashSet <string> > currentSpellCounts = new Dictionary <string, HashSet <string> >();
                            Dictionary <double, Dictionary <string, HashSet <string> > > previousSpellCounts = new Dictionary <double, Dictionary <string, HashSet <string> > >();
                            Dictionary <string, byte> ignoreRecords = new Dictionary <string, byte>();
                            List <ActionBlock> filtered             = new List <ActionBlock>();
                            DataManager.Instance.GetHealsDuring(segment.BeginTime, segment.EndTime).ForEach(heal =>
                            {
                                // copy
                                var newBlock = new ActionBlock {
                                    BeginTime = heal.BeginTime
                                };
                                filtered.Add(newBlock);

                                if (currentSpellCounts.Count > 0)
                                {
                                    previousSpellCounts[currentTime] = currentSpellCounts;
                                }

                                currentTime        = heal.BeginTime;
                                currentSpellCounts = new Dictionary <string, HashSet <string> >();

                                foreach (var timeKey in previousSpellCounts.Keys.ToList())
                                {
                                    if (previousSpellCounts.ContainsKey(timeKey))
                                    {
                                        if (currentTime != double.NaN && (currentTime - timeKey) > 7)
                                        {
                                            previousSpellCounts.Remove(timeKey);
                                        }
                                    }
                                }

                                foreach (var record in heal.Actions.Cast <HealRecord>())
                                {
                                    if (PlayerManager.Instance.IsPetOrPlayer(record.Healed) || PlayerManager.Instance.IsPossiblePlayerName(record.Healed))
                                    {
                                        // if AOEHealing is disabled then filter out AEs
                                        if (!MainWindow.IsAoEHealingEnabled)
                                        {
                                            SpellData spellData;
                                            if (record.SubType != null && (spellData = DataManager.Instance.GetHealingSpellByName(record.SubType)) != null)
                                            {
                                                if (spellData.Target == (byte)SpellTarget.TARGETAE || spellData.Target == (byte)SpellTarget.NEARBYPLAYERSAE ||
                                                    spellData.Target == (byte)SpellTarget.TARGETRINGAE || spellData.Target == (byte)SpellTarget.CASTERPBPLAYERS)
                                                {
                                                    // just skip these entirely if AOEs are turned off
                                                    continue;
                                                }
                                                else if ((spellData.Target == (byte)SpellTarget.CASTERGROUP || spellData.Target == (byte)SpellTarget.TARGETGROUP) && spellData.Mgb)
                                                {
                                                    // need to count group AEs and if more than 6 are seen we need to ignore those
                                                    // casts since they're from MGB and count as an AE
                                                    var key = record.Healer + "|" + record.SubType;
                                                    if (!currentSpellCounts.TryGetValue(key, out HashSet <string> value))
                                                    {
                                                        value = new HashSet <string>();
                                                        currentSpellCounts[key] = value;
                                                    }

                                                    value.Add(record.Healed);

                                                    HashSet <string> totals = new HashSet <string>();
                                                    List <double> temp      = new List <double>();
                                                    foreach (var timeKey in previousSpellCounts.Keys)
                                                    {
                                                        if (previousSpellCounts[timeKey].ContainsKey(key))
                                                        {
                                                            foreach (var item in previousSpellCounts[timeKey][key])
                                                            {
                                                                totals.Add(item);
                                                            }
                                                            temp.Add(timeKey);
                                                        }
                                                    }

                                                    foreach (var item in currentSpellCounts[key])
                                                    {
                                                        totals.Add(item);
                                                    }

                                                    if (totals.Count > 6)
                                                    {
                                                        ignoreRecords[heal.BeginTime + "|" + key] = 1;
                                                        temp.ForEach(timeKey =>
                                                        {
                                                            ignoreRecords[timeKey + "|" + key] = 1;
                                                        });
                                                    }
                                                }
                                            }
                                        }

                                        newBlock.Actions.Add(record);
                                    }
                                }
                            });

                            filtered.ForEach(heal =>
                            {
                                var updatedHeal = new ActionBlock()
                                {
                                    BeginTime = heal.BeginTime
                                };
                                foreach (var record in heal.Actions.Cast <HealRecord>())
                                {
                                    var ignoreKey = heal.BeginTime + "|" + record.Healer + "|" + record.SubType;
                                    if (!ignoreRecords.ContainsKey(ignoreKey))
                                    {
                                        updatedHeal.Actions.Add(record);
                                        // store substats and substats2 which is based on the player that was healed
                                        var key = Helpers.CreateRecordKey(record.Type, record.SubType);
                                        StatsUtil.UpdateTimeSegments(null, healedByHealerTimeSegments, record.Healer, record.Healed, heal.BeginTime);
                                        StatsUtil.UpdateTimeSegments(null, healedBySpellTimeSegments, key, record.Healed, heal.BeginTime);
                                        StatsUtil.UpdateTimeSegments(null, healerHealedTimeSegments, record.Healed, record.Healer, heal.BeginTime);
                                        StatsUtil.UpdateTimeSegments(null, healerSpellTimeSegments, key, record.Healer, heal.BeginTime);
                                    }
                                }

                                if (updatedHeal.Actions.Count > 0)
                                {
                                    updatedHeals.Add(updatedHeal);
                                }
                            });

                            Parallel.ForEach(healedByHealerTimeSegments, kv => StatsUtil.AddSubTimeEntry(HealedByHealerTimeRanges, kv));
                            Parallel.ForEach(healedBySpellTimeSegments, kv => StatsUtil.AddSubTimeEntry(HealedBySpellTimeRanges, kv));
                            Parallel.ForEach(healerHealedTimeSegments, kv => StatsUtil.AddSubTimeEntry(HealerHealedTimeRanges, kv));
                            Parallel.ForEach(healerSpellTimeSegments, kv => StatsUtil.AddSubTimeEntry(HealerSpellTimeRanges, kv));

                            if (updatedHeals.Count > 0)
                            {
                                HealingGroups.Add(updatedHeals);
                            }
                        });

                        ComputeHealingStats(options);
                    }
                    else if (Selected == null || Selected.Count == 0)
                    {
                        FireNoDataEvent(options, "NONPC");
                    }
                    else
                    {
                        FireNoDataEvent(options, "NODATA");
                    }
                }
                catch (Exception ex)
                {
                    LOG.Error(ex);
                }
            }
        }
예제 #8
0
        internal void BuildTotalStats(GenerateStatsOptions options)
        {
            lock (HealingGroups)
            {
                Selected = options.Npcs;
                Title    = options.Name;

                try
                {
                    FireNewStatsEvent(options);

                    RaidTotals = StatsUtil.CreatePlayerStats(Labels.RAID);
                    HealingGroups.Clear();

                    Selected.ForEach(npc => StatsUtil.UpdateTimeDiffs(RaidTotals, npc, HEAL_OFFSET));
                    RaidTotals.TotalSeconds = RaidTotals.TimeDiffs.Sum();

                    if (RaidTotals.BeginTimes.Count > 0 && RaidTotals.BeginTimes.Count == RaidTotals.LastTimes.Count)
                    {
                        for (int i = 0; i < RaidTotals.BeginTimes.Count; i++)
                        {
                            var updatedHeals = new List <ActionBlock>();
                            var heals        = DataManager.Instance.GetHealsDuring(RaidTotals.BeginTimes[i], RaidTotals.LastTimes[i]);
                            heals.ForEach(heal =>
                            {
                                var updatedHeal = new ActionBlock()
                                {
                                    BeginTime = heal.BeginTime
                                };
                                updatedHeal.Actions.AddRange(heal.Actions.Where(item => item is HealRecord record && IsValidHeal(record)));

                                if (updatedHeal.Actions.Count > 0)
                                {
                                    updatedHeals.Add(updatedHeal);
                                }
                            });

                            if (updatedHeals.Count > 0)
                            {
                                HealingGroups.Add(updatedHeals);
                            }
                        }

                        ComputeHealingStats(options);
                    }
                    else if (Selected == null || Selected.Count == 0)
                    {
                        FireNoDataEvent(options, "NONPC");
                    }
                    else
                    {
                        FireNoDataEvent(options, "NODATA");
                    }
                }
                catch (ArgumentNullException ne)
                {
                    LOG.Error(ne);
                }
                catch (NullReferenceException nr)
                {
                    LOG.Error(nr);
                }
                catch (ArgumentOutOfRangeException aor)
                {
                    LOG.Error(aor);
                }
                catch (ArgumentException ae)
                {
                    LOG.Error(ae);
                }
                catch (OutOfMemoryException oem)
                {
                    LOG.Error(oem);
                }
            }
        }
예제 #9
0
        public static void Process(LineData lineData)
        {
            try
            {
                string[] split = lineData.Action.Split(' ');

                if (split != null && split.Length > 2)
                {
                    // [Sun Mar 01 22:20:36 2020] A shaded torch has been awakened by Drogbaa.
                    // [Sun Mar 01 22:34:58 2020] You have entered The Eastern Wastes.
                    // [Sun Mar 01 20:35:55 2020] The master looter, Qulas, looted 32426 platinum from the corpse.
                    // [Sun Mar 01 23:51:02 2020] You receive 129 platinum, 2 gold and 1 copper as your split (with a lucky bonus).
                    // [Sun Feb 02 22:43:51 2020] You receive 28 platinum, 7 gold, 2 silver and 5 copper as your split.
                    // [Sun Feb 02 23:31:23 2020] You receive 57 platinum as your split.
                    // [Fri Feb 07 22:01:20 2020] --Kizant has looted a Lesser Engraved Velium Rune from Velden Dragonbane's corpse.--
                    // [Sat Feb 08 01:20:26 2020] --Proximoe has looted a Velium Infused Spider Silk from a restless devourer's corpse.--
                    // [Sat Feb 08 21:21:36 2020] --You have looted a Cold-Forged Cudgel from Queen Dracnia's corpse.--

                    string looter          = null;
                    int    awakenedIndex   = -1;
                    int    lootedIndex     = -1;
                    int    masterLootIndex = -1;
                    int    receiveIndex    = -1;
                    bool   handled         = false;

                    for (int i = 0; i < split.Length && !handled; i++)
                    {
                        if (i == 0 && split[0].StartsWith("--"))
                        {
                            looter = split[0] == "--You" ? ConfigUtil.PlayerName : split[0].TrimStart('-');
                        }
                        else
                        {
                            switch (split[i])
                            {
                            case "awakened":
                                awakenedIndex = i;
                                break;

                            case "looted":
                                lootedIndex = i;
                                break;

                            case "looter,":
                                masterLootIndex = (i == 2 && split[1] == "master" && split[0] == "The") ? masterLootIndex = i + 1 : -1;
                                break;

                            case "receive":
                                receiveIndex = (i == 1 && split[0] == "You") ? i : -1;
                                break;

                            case "by":
                                if (awakenedIndex > -1 && awakenedIndex == (i - 1) && split.Length > 5 && split[i - 2] == "been" && split[i - 3] == "has")
                                {
                                    string awakened = string.Join(" ", split, 0, i - 3);
                                    string breaker  = string.Join(" ", split, i + 1, split.Length - i - 1).TrimEnd('.');
                                    DataManager.Instance.AddMiscRecord(new MezBreakRecord()
                                    {
                                        Breaker = breaker, Awakened = awakened
                                    }, DateUtil.ParseLogDate(lineData.Line));
                                    handled = true;
                                }
                                break;

                            case "entered":
                                if (i == 2 && split[1] == "have" && split[0] == "You" && split.Length > 2)
                                {
                                    string zone = string.Join(" ", split, 3, split.Length - 3).TrimEnd('.');
                                    DataManager.Instance.AddMiscRecord(new ZoneRecord()
                                    {
                                        Zone = zone
                                    }, DateUtil.ParseLogDate(lineData.Line));
                                    handled = true;
                                }
                                break;

                            case "from":
                                if (masterLootIndex > -1 && lootedIndex > masterLootIndex && split.Length > lootedIndex + 1 && split.Length > 3)
                                {
                                    string name = split[3].TrimEnd(',');
                                    if (ParseCurrency(split, lootedIndex + 1, i, out string item, out uint count))
                                    {
                                        PlayerManager.Instance.AddVerifiedPlayer(name);
                                        LootRecord record = new LootRecord()
                                        {
                                            Item = item, Player = name, Quantity = count, IsCurrency = true
                                        };
                                        DataManager.Instance.AddLootRecord(record, DateUtil.ParseLogDate(lineData.Line));
                                        handled = true;
                                    }
                                }
                                else if (!string.IsNullOrEmpty(looter) && lootedIndex == 2 && split.Length > 4)
                                {
                                    // covers "a" or "an"
                                    uint   count = split[3][0] == 'a' ? 1 : StatsUtil.ParseUInt(split[3]);
                                    string item  = string.Join(" ", split, 4, i - 4);
                                    string npc   = string.Join(" ", split, i + 1, split.Length - i - 1).TrimEnd(LootedFromTrim).Replace("'s corpse", "");

                                    if (count > 0 && count != ushort.MaxValue)
                                    {
                                        PlayerManager.Instance.AddVerifiedPlayer(looter);
                                        LootRecord record = new LootRecord()
                                        {
                                            Item = item, Player = looter, Quantity = count, IsCurrency = false, Npc = npc
                                        };
                                        DataManager.Instance.AddLootRecord(record, DateUtil.ParseLogDate(lineData.Line));
                                        handled = true;
                                    }
                                }
                                break;

                            case "split":
                                if (receiveIndex > -1 && split[i - 1] == "your" && split[i - 2] == "as")
                                {
                                    if (ParseCurrency(split, 2, i - 2, out string item, out uint count))
                                    {
                                        LootRecord record = new LootRecord()
                                        {
                                            Item = item, Player = ConfigUtil.PlayerName, Quantity = count, IsCurrency = true
                                        };
                                        DataManager.Instance.AddLootRecord(record, DateUtil.ParseLogDate(lineData.Line));
                                        handled = true;
                                    }
                                }
                                break;
                            }
                        }
                    }
                }
            }
            catch (ArgumentNullException ne)
            {
                LOG.Error(ne);
            }
            catch (NullReferenceException nr)
            {
                LOG.Error(nr);
            }
            catch (ArgumentOutOfRangeException aor)
            {
                LOG.Error(aor);
            }
            catch (ArgumentException ae)
            {
                LOG.Error(ae);
            }
        }
예제 #10
0
        private void HandleDamageProcessed(object sender, DamageProcessedEvent processed)
        {
            if (LastFightProcessTime != processed.BeginTime)
            {
                DataManager.Instance.CheckExpireFights(processed.BeginTime);
                ValidCombo.Clear();

                if (processed.BeginTime - LastFightProcessTime > RECENTSPELLTIME)
                {
                    RecentSpellCache.Clear();
                }
            }

            // cache recent player spells to help determine who the caster was
            var isAttackerPlayer = PlayerManager.Instance.IsPetOrPlayer(processed.Record.Attacker) || processed.Record.Attacker == Labels.RS;

            if (isAttackerPlayer && (processed.Record.Type == Labels.DD || processed.Record.Type == Labels.DOT || processed.Record.Type == Labels.PROC))
            {
                RecentSpellCache[processed.Record.SubType] = true;
            }

            string comboKey = processed.Record.Attacker + "=" + processed.Record.Defender;

            if (ValidCombo.TryGetValue(comboKey, out bool defender) || IsValidAttack(processed.Record, isAttackerPlayer, out defender))
            {
                ValidCombo[comboKey] = defender;
                bool   isNonTankingFight = false;
                string origTimeString    = processed.OrigTimeString.Substring(4, 15);

                // fix for unknown spells having a good name to work from
                if (processed.Record.AttackerIsSpell && defender)
                {
                    processed.Record.Attacker = Labels.UNK;
                }

                Fight fight = Get(processed.Record, processed.BeginTime, origTimeString, defender);

                if (defender)
                {
                    Helpers.AddAction(fight.DamageBlocks, processed.Record, processed.BeginTime);
                    AddPlayerTime(fight, processed.Record, processed.Record.Attacker, processed.BeginTime);
                    fight.BeginDamageTime = double.IsNaN(fight.BeginDamageTime) ? processed.BeginTime : fight.BeginDamageTime;
                    fight.LastDamageTime  = processed.BeginTime;

                    if (StatsUtil.IsHitType(processed.Record.Type))
                    {
                        fight.DamageHits++;
                        fight.Total      += processed.Record.Total;
                        isNonTankingFight = fight.DamageHits == 1;

                        var attacker = processed.Record.AttackerOwner ?? processed.Record.Attacker;
                        if (fight.PlayerTotals.TryGetValue(attacker, out FightTotalDamage total))
                        {
                            total.Damage         += (processed.Record.Type == Labels.BANE) ? 0 : processed.Record.Total;
                            total.DamageWithBane += processed.Record.Total;
                            total.Name            = processed.Record.Attacker;
                            total.PetOwner        = total.PetOwner ?? processed.Record.AttackerOwner;
                            total.UpdateTime      = processed.BeginTime;
                        }
                        else
                        {
                            fight.PlayerTotals[attacker] = new FightTotalDamage
                            {
                                Damage         = (processed.Record.Type == Labels.BANE) ? 0 : processed.Record.Total,
                                DamageWithBane = processed.Record.Total,
                                Name           = processed.Record.Attacker,
                                PetOwner       = processed.Record.AttackerOwner,
                                UpdateTime     = processed.BeginTime,
                                BeginTime      = processed.BeginTime
                            };
                        }

                        SpellDamageStats stats = null;
                        var spellKey           = processed.Record.Attacker + "++" + processed.Record.SubType;
                        if (processed.Record.Type == Labels.DD)
                        {
                            if (!fight.DDDamage.TryGetValue(spellKey, out stats))
                            {
                                stats = new SpellDamageStats {
                                    Caster = processed.Record.Attacker, Spell = processed.Record.SubType
                                };
                                fight.DDDamage[spellKey] = stats;
                            }
                        }
                        else if (processed.Record.Type == Labels.DOT)
                        {
                            if (!fight.DoTDamage.TryGetValue(spellKey, out stats))
                            {
                                stats = new SpellDamageStats {
                                    Caster = processed.Record.Attacker, Spell = processed.Record.SubType
                                };
                                fight.DoTDamage[spellKey] = stats;
                            }
                        }

                        if (stats != null)
                        {
                            stats.Count += 1;
                            stats.Max    = Math.Max(processed.Record.Total, stats.Max);
                            stats.Total += processed.Record.Total;
                        }

                        // only a pet can 'hit' with a Flurry since players only crush/slash/punch/pierce with main hand weapons
                        if (processed.Record.AttackerOwner == null && processed.Record.Type == Labels.MELEE && processed.Record.SubType == "Hits" &&
                            LineModifiersParser.IsFlurry(processed.Record.ModifiersMask))
                        {
                            PlayerManager.Instance.AddVerifiedPet(processed.Record.Attacker);
                        }
                    }
                }
                else
                {
                    Helpers.AddAction(fight.TankingBlocks, processed.Record, processed.BeginTime);
                    AddPlayerTime(fight, processed.Record, processed.Record.Defender, processed.BeginTime);
                    fight.BeginTankingTime = double.IsNaN(fight.BeginTankingTime) ? processed.BeginTime : fight.BeginTankingTime;
                    fight.LastTankingTime  = processed.BeginTime;

                    if (StatsUtil.IsHitType(processed.Record.Type))
                    {
                        fight.TankHits++;
                    }
                }

                fight.LastTime       = processed.BeginTime;
                LastFightProcessTime = processed.BeginTime;

                var ttl = fight.LastTime - fight.BeginTime + 1;
                fight.TooltipText = string.Format(CultureInfo.CurrentCulture, "#Hits To Players: {0}, #Hits From Players: {1}, Time Alive: {2}s", fight.TankHits, fight.DamageHits, ttl);

                DataManager.Instance.UpdateIfNewFightMap(fight.CorrectMapKey, fight, isNonTankingFight);
            }
        }
예제 #11
0
        public static void Process(LineData lineData)
        {
            bool handled = false;

            try
            {
                string[] split = lineData.Action.Split(' ');

                if (split != null && split.Length >= 2)
                {
                    int stop = split.Length - 1;
                    if (!string.IsNullOrEmpty(split[stop]) && split[stop][split[stop].Length - 1] == ')')
                    {
                        for (int i = stop; i >= 0 && stop > 2; i--)
                        {
                            if (!string.IsNullOrEmpty(split[i]) && split[i][0] == '(')
                            {
                                stop = i - 1;
                                break;
                            }
                        }
                    }

                    // see if it's a died message right away
                    if (split.Length > 1 && stop >= 1 && split[stop] == "died.")
                    {
                        var test = string.Join(" ", split, 0, stop);
                        if (!string.IsNullOrEmpty(test))
                        {
                            UpdateSlain(test, "", lineData);
                            handled = true;
                        }
                    }

                    if (!handled)
                    {
                        int    byIndex = -1, forIndex = -1, pointsOfIndex = -1, endDamage = -1, byDamage = -1, extraIndex = -1;
                        int    fromDamage = -1, hasIndex = -1, haveIndex = -1, hitType = -1, hitTypeAdd = -1, slainIndex = -1;
                        int    takenIndex = -1, tryIndex = -1, yourIndex = -1, isIndex = -1, dsIndex = -1, butIndex = -1;
                        int    missType = -1, nonMeleeIndex = -1;
                        string subType = null;

                        bool found = false;
                        for (int i = 0; i <= stop && !found; i++)
                        {
                            if (!string.IsNullOrEmpty(split[i]))
                            {
                                switch (split[i])
                                {
                                case "healed":
                                    found = true; // short circuit
                                    break;

                                case "but":
                                    butIndex = i;
                                    break;

                                case "is":
                                case "was":
                                    isIndex = i;
                                    break;

                                case "has":
                                    hasIndex = i;
                                    break;

                                case "have":
                                    haveIndex = i;
                                    break;

                                case "by":
                                    byIndex = i;

                                    if (slainIndex > -1)
                                    {
                                        found = true; // short circut
                                    }
                                    else if (i > 4 && split[i - 1] == "damage")
                                    {
                                        byDamage = i - 1;
                                    }
                                    break;

                                case "from":
                                    if (i > 3 && split[i - 1] == "damage")
                                    {
                                        fromDamage = i - 1;
                                        if (pointsOfIndex > -1 && extraIndex > -1)
                                        {
                                            found = true; // short circut
                                        }
                                        else if (stop > (i + 1) && split[i + 1] == "your")
                                        {
                                            yourIndex = i + 1;
                                        }
                                    }
                                    break;

                                case "damage.":
                                    if (i == stop)
                                    {
                                        endDamage = i;
                                    }
                                    break;

                                case "non-melee":
                                    nonMeleeIndex = i;
                                    if (i > 9 && stop == (i + 1) && split[i + 1] == "damage." && pointsOfIndex == (i - 2) && forIndex == (i - 4))
                                    {
                                        dsIndex = i - 5;
                                        found   = true; // short circut
                                    }
                                    break;

                                case "point":
                                case "points":
                                    if (stop >= (i + 1) && split[i + 1] == "of")
                                    {
                                        pointsOfIndex = i;
                                        if (i > 2 && split[i - 2] == "for")
                                        {
                                            forIndex = i - 2;
                                        }
                                    }
                                    break;

                                case "blocks!":
                                    missType = (stop == i && butIndex > -1 && i > tryIndex) ? 0 : missType;
                                    break;

                                case "shield!":
                                case "staff!":
                                    missType = (i > 5 && stop == i && butIndex > -1 && i > tryIndex && split[i - 2] == "with" &&
                                                split[i - 3].StartsWith("block", StringComparison.OrdinalIgnoreCase)) ? 0 : missType;
                                    break;

                                case "dodge!":
                                case "dodges!":
                                    missType = (stop == i && butIndex > -1 && i > tryIndex) ? 1 : missType;
                                    break;

                                case "miss!":
                                case "misses!":
                                    missType = (stop == i && butIndex > -1 && i > tryIndex) ? 2 : missType;
                                    break;

                                case "parries!":
                                    missType = (stop == i && butIndex > -1 && i > tryIndex) ? 3 : missType;
                                    break;

                                case "INVULNERABLE!":
                                    missType = (stop == i && butIndex > -1 && i > tryIndex) ? 4 : missType;
                                    break;

                                case "slain":
                                    slainIndex = i;
                                    break;

                                case "taken":
                                    if (i > 1 && (hasIndex == (i - 1) || haveIndex == (i - 1)))
                                    {
                                        takenIndex = i - 1;

                                        if (stop > (i + 2) && split[i + 1] == "an" && split[i + 2] == "extra")
                                        {
                                            extraIndex = i + 2;
                                        }
                                    }
                                    break;

                                // Old (EQEMU) crit and crippling blow handling
                                case "hit!":
                                    if (stop == i && split.Length > 4 && split[i - 1] == "critical" && split[i - 3] == "scores")
                                    {
                                        LastCrit = new OldCritData {
                                            Attacker = split[0], LineData = lineData
                                        };
                                    }
                                    break;

                                case "Crippling":
                                    if (stop == (i + 1) && split.Length > 4 && split[i + 1].StartsWith("Blow!") && split[i - 2] == "lands")
                                    {
                                        LastCrit = new OldCritData {
                                            Attacker = split[0], LineData = lineData
                                        };
                                    }
                                    break;

                                default:
                                    if (slainIndex == -1 && i > 0 && string.IsNullOrEmpty(subType) && HitMap.TryGetValue(split[i], out subType))
                                    {
                                        hitType = i;
                                        if (i < stop && HitAdditionalMap.ContainsKey(split[i]))
                                        {
                                            hitTypeAdd = i + i;
                                        }

                                        if (i > 2 && split[i - 1] == "to" && (split[i - 2] == "tries" || split[i - 2] == "try"))
                                        {
                                            tryIndex = i - 2;
                                        }
                                    }
                                    break;
                                }
                            }
                        }

                        // [Sun Apr 18 19:36:39 2021] Tantor is pierced by Tolzol's thorns for 6718 points of non-melee damage.
                        // [Mon Apr 19 22:02:52 2021] Honvar is tormented by Reisil's frost for 7809 points of non-melee damage.
                        // [Sun Apr 25 13:47:12 2021] Test One Hundred Three is burned by YOUR flames for 5224 points of non-melee damage.
                        // [Sun Apr 18 14:16:13 2021] A failed reclaimer is pierced by YOUR thorns for 193 points of non-melee damage.
                        if (dsIndex > -1 && pointsOfIndex > dsIndex && isIndex > -1 && isIndex < dsIndex && byIndex > isIndex)
                        {
                            string attacker = string.Join(" ", split, byIndex + 1, dsIndex - byIndex - 1);
                            if (!string.IsNullOrEmpty(attacker))
                            {
                                var valid = attacker == "YOUR";
                                if (!valid && attacker.EndsWith("'s", StringComparison.OrdinalIgnoreCase))
                                {
                                    attacker = attacker.Substring(0, attacker.Length - 2);
                                    valid    = true;
                                }

                                if (valid)
                                {
                                    string defender = string.Join(" ", split, 0, isIndex);
                                    uint   damage   = StatsUtil.ParseUInt(split[pointsOfIndex - 1]);
                                    handled = CreateDamageRecord(lineData, split, stop, attacker, defender, damage, Labels.DS, Labels.DS);
                                }
                            }
                        }
                        // [Mon May 10 22:18:46 2021] A dendridic shard was chilled to the bone for 410 points of non-melee damage.
                        else if (dsIndex > -1 && pointsOfIndex > dsIndex && isIndex > -1 && isIndex < dsIndex && byIndex == -1)
                        {
                            string defender = string.Join(" ", split, 0, isIndex);
                            uint   damage   = StatsUtil.ParseUInt(split[pointsOfIndex - 1]);
                            handled = CreateDamageRecord(lineData, split, stop, Labels.RS, defender, damage, Labels.DS, Labels.DS);
                        }
                        // [Tue Mar 26 22:43:47 2019] a wave sentinel has taken an extra 6250000 points of non-melee damage from Kazint's Greater Fetter spell.
                        else if (extraIndex > -1 && pointsOfIndex == (extraIndex + 2) && fromDamage == (pointsOfIndex + 3) && split[stop] == "spell.")
                        {
                            if (split[fromDamage + 2].EndsWith("'s", StringComparison.OrdinalIgnoreCase))
                            {
                                string      attacker  = split[fromDamage + 2].Substring(0, split[fromDamage + 2].Length - 2);
                                string      defender  = string.Join(" ", split, 0, takenIndex);
                                uint        damage    = StatsUtil.ParseUInt(split[extraIndex + 1]);
                                string      spell     = string.Join(" ", split, fromDamage + 3, stop - fromDamage - 3);
                                var         spellData = DataManager.Instance.GetDamagingSpellByName(spell);
                                SpellResist resist    = spellData != null ? spellData.Resist : SpellResist.UNDEFINED;
                                handled = CreateDamageRecord(lineData, split, stop, attacker, defender, damage, Labels.BANE, spell, resist);
                            }
                        }
                        // [Sun Apr 18 21:26:15 2021] Astralx crushes Sontalak for 126225 points of damage. (Strikethrough Critical)
                        // [Sun Apr 18 20:20:32 2021] Susarrak the Crusader claws Villette for 27699 points of damage. (Strikethrough Wild Rampage)
                        else if (!string.IsNullOrEmpty(subType) && endDamage > -1 && pointsOfIndex == (endDamage - 2) && forIndex > -1 && hitType < forIndex)
                        {
                            int    hitTypeMod = hitTypeAdd > 0 ? 1 : 0;
                            string attacker   = string.Join(" ", split, 0, hitType);
                            string defender   = string.Join(" ", split, hitType + hitTypeMod + 1, forIndex - hitType - hitTypeMod - 1);
                            subType = TextFormatUtils.ToUpper(subType);
                            uint damage = StatsUtil.ParseUInt(split[pointsOfIndex - 1]);
                            handled = CreateDamageRecord(lineData, split, stop, attacker, defender, damage, Labels.MELEE, subType);
                        }
                        // [Sun Apr 18 20:24:56 2021] Sonozen hit Jortreva the Crusader for 38948 points of fire damage by Burst of Flames. (Lucky Critical Twincast)
                        else if (byDamage > 3 && pointsOfIndex == (byDamage - 3) && byIndex == (byDamage + 1) && forIndex > -1 &&
                                 subType == "hits" && hitType < forIndex && split[stop].Length > 0 && split[stop][split[stop].Length - 1] == '.')
                        {
                            string spell = string.Join(" ", split, byIndex + 1, stop - byIndex);
                            if (!string.IsNullOrEmpty(spell) && spell[spell.Length - 1] == '.')
                            {
                                spell = spell.Substring(0, spell.Length - 1);
                                string      attacker = string.Join(" ", split, 0, hitType);
                                string      defender = string.Join(" ", split, hitType + 1, forIndex - hitType - 1);
                                string      type     = GetTypeFromSpell(spell, Labels.DD);
                                uint        damage   = StatsUtil.ParseUInt(split[pointsOfIndex - 1]);
                                SpellResist resist   = SpellResist.UNDEFINED;
                                SpellResistMap.TryGetValue(split[byDamage - 1], out resist);

                                // extra way to check for pets
                                if (spell.StartsWith("Elemental Conversion", StringComparison.Ordinal))
                                {
                                    PlayerManager.Instance.AddVerifiedPet(defender);
                                }

                                handled = CreateDamageRecord(lineData, split, stop, attacker, defender, damage, type, spell, resist);
                            }
                        }
                        // [Sun Apr 18 20:32:39 2021] Dovhesi has taken 173674 damage from Curse of the Shrine by Grendish the Crusader.
                        // [Sun Apr 18 20:32:42 2021] Grendish the Crusader has taken 1003231 damage from Pyre of Klraggek Rk. III by Atvar. (Lucky Critical)
                        // [Thu Mar 18 18:48:10 2021] You have taken 4852 damage from Nectar of Misery by Commander Gartik.
                        // [Thu Mar 18 01:05:46 2021] A gnoll has taken 108790 damage from your Mind Coil Rk. II.
                        // Old (eqemu) [Sat Jan 15 21:09:10 2022] Pixtt Invi Mal has taken 189 damage from Goanna by Tuyen`s Chant of Fire.
                        else if (fromDamage > 3 && takenIndex == (fromDamage - 3) && (byIndex > fromDamage || yourIndex > fromDamage))
                        {
                            string attacker = null;
                            string spell    = null;
                            if (byIndex > -1)
                            {
                                attacker = string.Join(" ", split, byIndex + 1, stop - byIndex);
                                attacker = (!string.IsNullOrEmpty(attacker) && attacker[attacker.Length - 1] == '.') ? attacker.Substring(0, attacker.Length - 1) : null;
                                spell    = string.Join(" ", split, fromDamage + 2, byIndex - fromDamage - 2);
                            }
                            else if (yourIndex > -1)
                            {
                                attacker = split[yourIndex];
                                spell    = string.Join(" ", split, yourIndex + 1, stop - yourIndex);
                                spell    = (!string.IsNullOrEmpty(spell) && spell[spell.Length - 1] == '.') ? spell.Substring(0, spell.Length - 1) : Labels.DOT;
                            }

                            if (!string.IsNullOrEmpty(attacker) && !string.IsNullOrEmpty(spell))
                            {
                                string    type;
                                SpellData spellData = DataManager.Instance.GetDamagingSpellByName(spell);

                                // Old (eqemu) if attacker is actually a spell then swap attacker and spell
                                // Spells dont change on eqemu servers so this should always be a spell even with old spell data
                                if (spellData == null && DataManager.Instance.IsOldSpell(attacker))
                                {
                                    // check that we can't find a spell where the player name is
                                    var temp = attacker;
                                    attacker = spell;
                                    spell    = temp;
                                    type     = Labels.DOT;
                                }
                                else
                                {
                                    type = GetTypeFromSpell(spell, Labels.DOT);
                                }

                                string      defender = string.Join(" ", split, 0, takenIndex);
                                uint        damage   = StatsUtil.ParseUInt(split[fromDamage - 1]);
                                SpellResist resist   = spellData != null ? spellData.Resist : SpellResist.UNDEFINED;
                                handled = CreateDamageRecord(lineData, split, stop, attacker, defender, damage, type, spell, resist);
                            }
                        }
                        // [Mon Apr 26 21:07:21 2021] Lawlstryke has taken 216717 damage by Wisp Explosion.
                        else if (byDamage > -1 && takenIndex == (byDamage - 3))
                        {
                            string defender = string.Join(" ", split, 0, takenIndex);
                            uint   damage   = StatsUtil.ParseUInt(split[byDamage - 1]);
                            string spell    = string.Join(" ", split, byDamage + 2, stop - byDamage - 1);
                            if (!string.IsNullOrEmpty(spell) && spell[spell.Length - 1] == '.')
                            {
                                spell = spell.Substring(0, spell.Length - 1);
                            }

                            SpellResist resist = SpellResist.UNDEFINED;
                            if (DataManager.Instance.GetDamagingSpellByName(spell) is SpellData spellData && spellData != null)
                            {
                                resist = spellData.Resist;
                            }

                            handled = CreateDamageRecord(lineData, split, stop, "", defender, damage, Labels.DOT, spell, resist, true);
                        }
                        // Old (eqemu direct damage) [Sat Jan 15 21:08:54 2022] Jaun hit Pixtt Invi Mal for 150 points of non-melee damage.
                        else if (hitType > -1 && forIndex > -1 && forIndex < pointsOfIndex && nonMeleeIndex > pointsOfIndex)
                        {
                            int    hitTypeMod = hitTypeAdd > 0 ? 1 : 0;
                            string attacker   = string.Join(" ", split, 0, hitType);
                            string defender   = string.Join(" ", split, hitType + hitTypeMod + 1, forIndex - hitType - hitTypeMod - 1);
                            uint   damage     = StatsUtil.ParseUInt(split[pointsOfIndex - 1]);
                            handled = CreateDamageRecord(lineData, split, stop, attacker, defender, damage, Labels.DD, Labels.DD);
                        }
                        // [Mon Aug 05 02:05:12 2019] An enchanted Syldon stalker tries to crush YOU, but misses! (Strikethrough)
                        // [Sat Aug 03 00:20:57 2019] You try to crush a Kar`Zok soldier, but miss! (Riposte Strikethrough)
                        // [Sat Apr 24 01:08:49 2021] Test One Hundred Three tries to punch Kazint, but misses!
                        // [Sat Apr 24 01:08:49 2021] Test One Hundred Three tries to punch Kazint, but Kazint dodges!
                        // [Sat Apr 24 01:10:17 2021] Test One Hundred Three tries to punch YOU, but YOU dodge!
                        // [Sat Apr 24 01:10:17 2021] Kazint tries to crush Test One Hundred Three, but Test One Hundred Three dodges!
                        // [Sun Apr 18 19:45:21 2021] You try to crush a primal guardian, but a primal guardian parries!
                        // [Mon May 31 20:29:49 2021] A bloodthirsty gnawer tries to bite Vandil, but Vandil parries!
                        // [Sun Apr 25 22:56:22 2021] Romance tries to bash Vulak`Aerr, but Vulak`Aerr parries!
                        // [Sun Jul 28 20:12:46 2019] Drogbaa tries to slash Whirlrender Scout, but misses! (Strikethrough)
                        // [Tue Mar 30 16:43:54 2021] You try to crush a desert madman, but a desert madman blocks!
                        // [Mon Apr 26 22:40:10 2021] An ancient warden tries to hit Reisil, but Reisil blocks with his shield!
                        // [Sun Mar 21 00:11:31 2021] A carrion bat tries to bite YOU, but YOU block with your shield!
                        // [Mon Apr 26 14:51:01 2021] A windchill sprite tries to smash YOU, but YOU block with your staff!
                        // [Mon May 10 22:18:46 2021] Tolzol tries to crush Dendritic Golem, but Dendritic Golem is INVULNERABLE!
                        else if (tryIndex > -1 && butIndex > tryIndex && missType > -1)
                        {
                            string label = null;
                            switch (missType)
                            {
                            case 0:
                                label = Labels.BLOCK;
                                break;

                            case 1:
                                label = Labels.DODGE;
                                break;

                            case 2:
                                label = Labels.MISS;
                                break;

                            case 3:
                                label = Labels.PARRY;
                                break;

                            case 4:
                                label = Labels.INVULNERABLE;
                                break;
                            }

                            if (!string.IsNullOrEmpty(label))
                            {
                                int    hitTypeMod = hitTypeAdd > 0 ? 1 : 0;
                                string defender   = string.Join(" ", split, hitType + hitTypeMod + 1, butIndex - hitType - hitTypeMod - 1);
                                if (!string.IsNullOrEmpty(defender) && defender[defender.Length - 1] == ',')
                                {
                                    defender = defender.Substring(0, defender.Length - 1);
                                    string attacker = string.Join(" ", split, 0, tryIndex);
                                    subType = TextFormatUtils.ToUpper(subType);
                                    handled = CreateDamageRecord(lineData, split, stop, attacker, defender, 0, label, subType);
                                }
                            }
                        }
                        // [Sun Apr 18 21:26:20 2021] Strangle`s pet has been slain by Kzerk!
                        else if (slainIndex > -1 && byIndex == (slainIndex + 1) && hasIndex > 0 && stop > (slainIndex + 1) && split[hasIndex + 1] == "been")
                        {
                            string killer = string.Join(" ", split, byIndex + 1, stop - byIndex);
                            killer = killer.Length > 1 && killer[killer.Length - 1] == '!' ? killer.Substring(0, killer.Length - 1) : killer;
                            string slain = string.Join(" ", split, 0, hasIndex);
                            handled = UpdateSlain(slain, killer, lineData);
                            HasOwner(slain, out string t1);
                            HasOwner(killer, out string t2);
                        }
                        // [Mon Apr 19 02:22:09 2021] You have been slain by an armed flyer!
                        else if (stop > 4 && slainIndex == 3 && byIndex == 4 && split[0] == "You" && split[1] == "have" && split[2] == "been")
                        {
                            string killer = string.Join(" ", split, 5, stop - 4);
                            killer = killer.Length > 1 && killer[killer.Length - 1] == '!' ? killer.Substring(0, killer.Length - 1) : killer;
                            string slain = ConfigUtil.PlayerName;
                            handled = UpdateSlain(slain, killer, lineData);
                        }
                        // [Mon Apr 19 02:22:09 2021] You have slain a failed bodyguard!
                        else if (slainIndex == 2 && split[0] == "You" && split[1] == "have")
                        {
                            string killer = ConfigUtil.PlayerName;
                            string slain  = string.Join(" ", split, 3, stop - 2);
                            slain   = slain.Length > 1 && slain[slain.Length - 1] == '!' ? slain.Substring(0, slain.Length - 1) : slain;
                            handled = UpdateSlain(slain, killer, lineData);
                        }
                    }
                }
            }
            catch (Exception e)
            {
                LOG.Error(e);
            }

            DebugUtil.UnregisterLine(lineData.LineNumber, handled);
        }
예제 #12
0
        internal void BuildTotalStats(GenerateStatsOptions options)
        {
            lock (TankingGroups)
            {
                Selected = options.Npcs;
                Title    = options.Name;

                try
                {
                    FireNewStatsEvent(options);

                    RaidTotals = StatsUtil.CreatePlayerStats(Labels.RAID);
                    TankingGroups.Clear();

                    var damageBlocks = new List <ActionBlock>();
                    Selected.ForEach(fight =>
                    {
                        StatsUtil.UpdateTimeDiffs(RaidTotals, fight);
                        damageBlocks.AddRange(fight.TankingBlocks);
                    });

                    damageBlocks.Sort((a, b) => a.BeginTime.CompareTo(b.BeginTime));

                    if (damageBlocks.Count > 0)
                    {
                        RaidTotals.TotalSeconds = RaidTotals.TimeDiffs.Sum();

                        var newBlock  = new List <ActionBlock>();
                        var timeIndex = 0;

                        damageBlocks.ForEach(block =>
                        {
                            if (block.BeginTime > RaidTotals.LastTimes[timeIndex])
                            {
                                timeIndex++;

                                if (newBlock.Count > 0)
                                {
                                    TankingGroups.Add(newBlock);
                                }

                                newBlock = new List <ActionBlock>();
                            }

                            newBlock.Add(block);
                        });

                        TankingGroups.Add(newBlock);
                        ComputeTankingStats(options);
                    }
                    else if (Selected == null || Selected.Count == 0)
                    {
                        FireNoDataEvent(options, "NONPC");
                    }
                    else
                    {
                        FireNoDataEvent(options, "NODATA");
                    }
                }
                catch (ArgumentNullException ne)
                {
                    LOG.Error(ne);
                }
                catch (NullReferenceException nr)
                {
                    LOG.Error(nr);
                }
                catch (ArgumentOutOfRangeException aor)
                {
                    LOG.Error(aor);
                }
                catch (ArgumentException ae)
                {
                    LOG.Error(ae);
                }
                catch (OutOfMemoryException oem)
                {
                    LOG.Error(oem);
                }
            }
        }
예제 #13
0
 private static void UpdateSubStats(PlayerSubStats subStats, DamageRecord record, double beginTime)
 {
     StatsUtil.UpdateStats(subStats, record, beginTime);
 }
예제 #14
0
        internal void PopulateHealing(CombinedStats combined)
        {
            lock (HealingGroups)
            {
                List <PlayerStats> playerStats = combined.StatsList;
                Dictionary <string, PlayerStats> individualStats = new Dictionary <string, PlayerStats>();
                Dictionary <string, long>        totals          = new Dictionary <string, long>();

                HealingGroups.ForEach(group =>
                {
                    // keep track of time range as well as the players that have been updated
                    Dictionary <string, PlayerSubStats> allStats = new Dictionary <string, PlayerSubStats>();

                    group.ForEach(block =>
                    {
                        block.Actions.ForEach(action =>
                        {
                            if (action is HealRecord record)
                            {
                                PlayerStats stats = StatsUtil.CreatePlayerStats(individualStats, record.Healed);
                                StatsUtil.UpdateStats(stats, record, block.BeginTime);
                                allStats[record.Healed] = stats;

                                PlayerSubStats subStats = StatsUtil.CreatePlayerSubStats(stats.SubStats, record.Healer, record.Type);
                                StatsUtil.UpdateStats(subStats, record, block.BeginTime);
                                allStats[record.Healer + "-" + record.Healed] = subStats;

                                var spellStatName         = record.SubType ?? Labels.SELFHEAL;
                                PlayerSubStats spellStats = StatsUtil.CreatePlayerSubStats(stats.SubStats2, spellStatName, record.Type);
                                StatsUtil.UpdateStats(spellStats, record, block.BeginTime);
                                allStats[stats.Name + "=" + spellStatName] = spellStats;

                                long value = 0;
                                if (totals.ContainsKey(record.Healed))
                                {
                                    value = totals[record.Healed];
                                }

                                totals[record.Healed] = record.Total + value;
                            }
                        });
                    });

                    foreach (var stats in allStats.Values)
                    {
                        stats.TotalSeconds += stats.LastTime - stats.BeginTime + 1;
                        stats.BeginTime     = double.NaN;
                    }
                });


                Parallel.ForEach(playerStats, stat =>
                {
                    if (individualStats.ContainsKey(stat.Name))
                    {
                        if (totals.ContainsKey(stat.Name))
                        {
                            stat.Extra = totals[stat.Name];
                        }

                        var indStat = individualStats[stat.Name];
                        stat.SubStats2["receivedHealing"] = indStat;
                        StatsUtil.UpdateCalculations(indStat, RaidTotals);

                        indStat.SubStats.Values.ToList().ForEach(subStat => StatsUtil.UpdateCalculations(subStat, indStat));
                        indStat.SubStats2.Values.ToList().ForEach(subStat => StatsUtil.UpdateCalculations(subStat, indStat));
                    }
                });
            }
        }
예제 #15
0
        private static HealRecord HandleHealed(ProcessLine pline)
        {
            // [Sun Feb 24 21:00:58 2019] Foob's promised interposition is fulfilled Foob healed himself for 44238 hit points by Promised Interposition Heal V. (Lucky Critical)
            // [Sun Feb 24 21:01:01 2019] Rowanoak is soothed by Brell's Soothing Wave. Farzi healed Rowanoak for 524 hit points by Brell's Sacred Soothing Wave.
            // [Sun Feb 24 21:00:52 2019] Kuvani healed Tolzol over time for 11000 hit points by Spirit of the Wood XXXIV.
            // [Sun Feb 24 21:00:52 2019] Kuvani healed Foob over time for 9409 (11000) hit points by Spirit of the Wood XXXIV.
            // [Sun Feb 24 21:00:58 2019] Fllint healed Foob for 11820 hit points by Blessing of the Ancients III.
            // [Sun Feb 24 21:01:00 2019] Tolzol healed itself for 548 hit points.
            // [Sun Feb 24 21:01:01 2019] Piemastaj`s pet has been healed for 15000 hit points by Enhanced Theft of Essence Effect X.
            // [Sun Feb 24 23:30:51 2019] Piemastaj`s pet glows with holy light. Findawenye healed Piemastaj`s pet for 2823 (78079) hit points by Mending Splash Rk. III. (Critical)
            // [Mon Feb 18 21:21:12 2019] Nylenne has been healed over time for 8211 hit points by Roar of the Lion 6.
            // [Mon Feb 18 21:20:39 2019] You have been healed over time for 1063 (8211) hit points by Roar of the Lion 6.
            // [Mon Feb 18 21:17:35 2019] Snowzz healed Malkatar over time for 8211 hit points by Roar of the Lion 6.
            // [Wed Nov 06 14:19:54 2019] Your ward heals you as it breaks! You healed Niktaza for 8970 (86306) hit points by Healing Ward. (Critical)

            HealRecord record   = null;
            string     part     = pline.ActionPart;
            int        optional = pline.OptionalIndex;
            string     test     = part.Substring(0, optional);

            bool   done     = false;
            string healer   = "";
            string healed   = "";
            string spell    = null;
            string type     = Labels.HEAL;
            uint   heal     = 0;
            uint   overHeal = 0;

            int previous = test.Length >= 2 ? test.LastIndexOf(" ", test.Length - 2, StringComparison.Ordinal) : -1;

            if (previous > -1)
            {
                if (test.IndexOf("are ", previous + 1, StringComparison.Ordinal) > -1)
                {
                    done = true;
                }
                else if (previous - 1 >= 0 && (test[previous - 1] == '.' || test[previous - 1] == '!') || previous - 9 > 0 && test.IndexOf("fulfilled", previous - 9, StringComparison.Ordinal) > -1)
                {
                    healer = test.Substring(previous + 1);
                }
                else if (previous - 4 >= 0 && test.IndexOf("has been", previous - 3, StringComparison.Ordinal) > -1)
                {
                    healed = test.Substring(0, previous - 4);

                    if (part.Length > optional + 17 && part.IndexOf("over time", optional + 8, 9, StringComparison.Ordinal) > -1)
                    {
                        type = Labels.HOT;
                    }
                }
                else if (previous - 5 >= 0 && test.IndexOf("have been", previous - 4, StringComparison.Ordinal) > -1)
                {
                    healed = test.Substring(0, previous - 5);

                    if (part.Length > optional + 17 && part.IndexOf("over time", optional + 8, 9, StringComparison.Ordinal) > -1)
                    {
                        type = Labels.HOT;
                    }
                }
            }
            else
            {
                healer = test.Substring(0, optional);
            }

            if (!done)
            {
                int amountIndex = -1;
                if (healed.Length == 0)
                {
                    int afterHealed = optional + 8;
                    int forIndex    = part.IndexOf(" for ", afterHealed, StringComparison.Ordinal);

                    if (forIndex > 1)
                    {
                        if (forIndex - 9 >= 0 && part.IndexOf("over time", forIndex - 9, StringComparison.Ordinal) > -1)
                        {
                            type   = Labels.HOT;
                            healed = part.Substring(afterHealed, forIndex - afterHealed - 10);
                        }
                        else
                        {
                            healed = part.Substring(afterHealed, forIndex - afterHealed);
                        }

                        amountIndex = forIndex + 5;
                    }
                }
                else
                {
                    if (type == Labels.HEAL)
                    {
                        amountIndex = optional + 12;
                    }
                    else if (type == Labels.HOT)
                    {
                        amountIndex = optional + 22;
                    }
                }

                if (amountIndex > -1)
                {
                    int amountEnd = part.IndexOf(" ", amountIndex, StringComparison.Ordinal);
                    if (amountEnd > -1)
                    {
                        uint value = StatsUtil.ParseUInt(part.Substring(amountIndex, amountEnd - amountIndex));
                        if (value != uint.MaxValue)
                        {
                            heal = value;
                        }

                        int overEnd = -1;
                        if (part.Length > amountEnd + 1 && part[amountEnd + 1] == '(')
                        {
                            overEnd = part.IndexOf(")", amountEnd + 2, StringComparison.Ordinal);
                            if (overEnd > -1)
                            {
                                uint value2 = StatsUtil.ParseUInt(part.Substring(amountEnd + 2, overEnd - amountEnd - 2));
                                if (value2 != uint.MaxValue)
                                {
                                    overHeal = value2;
                                }
                            }
                        }

                        int rest    = overEnd > -1 ? overEnd : amountEnd;
                        int byIndex = part.IndexOf(" by ", rest, StringComparison.Ordinal);
                        if (byIndex > -1)
                        {
                            int periodIndex = part.LastIndexOf(".", StringComparison.Ordinal);
                            if (periodIndex > -1 && periodIndex - byIndex - 4 > 0)
                            {
                                spell = part.Substring(byIndex + 4, periodIndex - byIndex - 4);
                            }
                        }
                    }
                }

                if (healed.Length > 0)
                {
                    // check for pets
                    int possessive = healed.IndexOf("`s ", StringComparison.Ordinal);
                    if (possessive > -1)
                    {
                        if (PlayerManager.Instance.IsVerifiedPlayer(healed.Substring(0, possessive)))
                        {
                            PlayerManager.Instance.AddVerifiedPet(healed);
                        }

                        // dont count swarm pets
                        healer = "";
                        heal   = 0;
                    }

                    if (healer.Length > 0 && heal != 0)
                    {
                        record = new HealRecord()
                        {
                            Total         = heal,
                            OverTotal     = overHeal,
                            Healer        = string.Intern(healer),
                            Healed        = string.Intern(healed),
                            Type          = string.Intern(type),
                            ModifiersMask = -1
                        };

                        record.SubType = string.IsNullOrEmpty(spell) ? Labels.SELFHEAL : string.Intern(spell);

                        if (part[part.Length - 1] == ')')
                        {
                            // using 4 here since the shortest modifier should at least be 3 even in the future. probably.
                            int firstParen = part.LastIndexOf('(', part.Length - 4);
                            if (firstParen > -1)
                            {
                                record.ModifiersMask = LineModifiersParser.Parse(part.Substring(firstParen + 1, part.Length - 1 - firstParen - 1));
                                if (LineModifiersParser.IsTwincast(record.ModifiersMask))
                                {
                                    PlayerManager.Instance.AddVerifiedPlayer(record.Healer);
                                }
                            }
                        }
                    }
                }
            }

            return(record);
        }
예제 #16
0
        private void ComputeHealingStats(GenerateStatsOptions options)
        {
            lock (HealingGroups)
            {
                if (RaidTotals != null)
                {
                    CombinedStats combined = null;
                    Dictionary <string, PlayerStats> individualStats = new Dictionary <string, PlayerStats>();

                    // always start over
                    RaidTotals.Total = 0;

                    try
                    {
                        FireUpdateEvent(options);

                        if (options.RequestSummaryData)
                        {
                            HealingGroups.ForEach(group =>
                            {
                                // keep track of time range as well as the players that have been updated
                                Dictionary <string, PlayerSubStats> allStats = new Dictionary <string, PlayerSubStats>();

                                group.ForEach(block =>
                                {
                                    block.Actions.ForEach(action =>
                                    {
                                        if (action is HealRecord record)
                                        {
                                            RaidTotals.Total += record.Total;
                                            PlayerStats stats = StatsUtil.CreatePlayerStats(individualStats, record.Healer);

                                            StatsUtil.UpdateStats(stats, record, block.BeginTime);
                                            allStats[record.Healer] = stats;

                                            var spellStatName         = record.SubType ?? Labels.SELFHEAL;
                                            PlayerSubStats spellStats = StatsUtil.CreatePlayerSubStats(stats.SubStats, spellStatName, record.Type);
                                            StatsUtil.UpdateStats(spellStats, record, block.BeginTime);
                                            allStats[stats.Name + "=" + spellStatName] = spellStats;

                                            var healedStatName         = record.Healed;
                                            PlayerSubStats healedStats = StatsUtil.CreatePlayerSubStats(stats.SubStats2, healedStatName, record.Type);
                                            StatsUtil.UpdateStats(healedStats, record, block.BeginTime);
                                            allStats[stats.Name + "=" + healedStatName] = healedStats;
                                        }
                                    });
                                });

                                foreach (var stats in allStats.Values)
                                {
                                    stats.TotalSeconds += stats.LastTime - stats.BeginTime + 1;
                                    stats.BeginTime     = double.NaN;
                                }
                            });

                            RaidTotals.DPS = (long)Math.Round(RaidTotals.Total / RaidTotals.TotalSeconds, 2);
                            Parallel.ForEach(individualStats.Values, stats => StatsUtil.UpdateCalculations(stats, RaidTotals));

                            combined = new CombinedStats
                            {
                                RaidStats   = RaidTotals,
                                TargetTitle = (Selected.Count > 1 ? "Combined (" + Selected.Count + "): " : "") + Title,
                                TimeTitle   = string.Format(CultureInfo.CurrentCulture, StatsUtil.TIME_FORMAT, RaidTotals.TotalSeconds),
                                TotalTitle  = string.Format(CultureInfo.CurrentCulture, StatsUtil.TOTAL_FORMAT, StatsUtil.FormatTotals(RaidTotals.Total), " Heals ", StatsUtil.FormatTotals(RaidTotals.DPS))
                            };

                            combined.StatsList.AddRange(individualStats.Values.AsParallel().OrderByDescending(item => item.Total));
                            combined.FullTitle  = StatsUtil.FormatTitle(combined.TargetTitle, combined.TimeTitle, combined.TotalTitle);
                            combined.ShortTitle = StatsUtil.FormatTitle(combined.TargetTitle, combined.TimeTitle, "");

                            for (int i = 0; i < combined.StatsList.Count; i++)
                            {
                                combined.StatsList[i].Rank = Convert.ToUInt16(i + 1);
                                combined.UniqueClasses[combined.StatsList[i].ClassName] = 1;
                            }
                        }
                    }
                    catch (ArgumentNullException ane)
                    {
                        LOG.Error(ane);
                    }
                    catch (NullReferenceException nre)
                    {
                        LOG.Error(nre);
                    }
                    catch (ArgumentOutOfRangeException aro)
                    {
                        LOG.Error(aro);
                    }

                    FireCompletedEvent(options, combined, HealingGroups);
                }
            }
        }
예제 #17
0
        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);
        }
예제 #18
0
        public StatsSummary BuildSummary(string type, CombinedStats currentStats, List <PlayerStats> selected, bool showTotals, bool rankPlayers, bool _)
        {
            List <string> list = new List <string>();

            string title   = "";
            string details = "";

            if (currentStats != null && type == Labels.HEALPARSE)
            {
                if (selected?.Count > 0)
                {
                    foreach (PlayerStats stats in selected.OrderByDescending(item => item.Total))
                    {
                        string playerFormat = rankPlayers ? string.Format(CultureInfo.CurrentCulture, StatsUtil.PLAYER_RANK_FORMAT, stats.Rank, stats.Name) : string.Format(CultureInfo.CurrentCulture, StatsUtil.PLAYER_FORMAT, stats.Name);
                        string damageFormat = string.Format(CultureInfo.CurrentCulture, StatsUtil.TOTAL_ONLY_FORMAT, StatsUtil.FormatTotals(stats.Total));
                        list.Add(playerFormat + damageFormat + " ");
                    }
                }

                details = list.Count > 0 ? ", " + string.Join(" | ", list) : "";
                title   = StatsUtil.FormatTitle(currentStats.TargetTitle, currentStats.TimeTitle, showTotals ? currentStats.TotalTitle : "");
            }

            return(new StatsSummary()
            {
                Title = title, RankedPlayers = details,
            });
        }
예제 #19
0
        private void ComputeDamageStats(GenerateStatsOptions options)
        {
            lock (DamageGroups)
            {
                if (RaidTotals != null)
                {
                    CombinedStats combined = null;
                    ConcurrentDictionary <string, Dictionary <string, PlayerStats> > childrenStats = new ConcurrentDictionary <string, Dictionary <string, PlayerStats> >();
                    ConcurrentDictionary <string, PlayerStats> topLevelStats   = new ConcurrentDictionary <string, PlayerStats>();
                    ConcurrentDictionary <string, PlayerStats> aggregateStats  = new ConcurrentDictionary <string, PlayerStats>();
                    Dictionary <string, PlayerStats>           individualStats = new Dictionary <string, PlayerStats>();

                    // always start over
                    RaidTotals.Total = 0;

                    try
                    {
                        FireUpdateEvent(options);

                        if (options.RequestSummaryData)
                        {
                            DamageGroups.ForEach(group =>
                            {
                                // keep track of time range as well as the players that have been updated
                                Dictionary <string, PlayerSubStats> allStats = new Dictionary <string, PlayerSubStats>();

                                int found = -1;
                                if (MainWindow.IsIgnoreIntialPullDamageEnabled)
                                {
                                    // ignore initial low activity time
                                    double previousDps = 0;
                                    long rolling       = 0;
                                    for (int i = 0; group.Count >= 10 && i < 10; i++)
                                    {
                                        if (previousDps == 0)
                                        {
                                            rolling     = group[i].Actions.Sum(test => (test as DamageRecord).Total);
                                            previousDps = rolling / 1.0;
                                        }
                                        else
                                        {
                                            double theTime = group[i].BeginTime - group[0].BeginTime + 1;
                                            if (theTime > 12.0)
                                            {
                                                break;
                                            }

                                            rolling          += group[i].Actions.Sum(test => (test as DamageRecord).Total);
                                            double currentDps = rolling / (theTime);
                                            if (currentDps / previousDps > 1.75)
                                            {
                                                found = i - 1;
                                                break;
                                            }
                                            else
                                            {
                                                previousDps = currentDps;
                                            }
                                        }
                                    }
                                }

                                var goodGroups = found > -1 ? group.GetRange(found, group.Count - found) : group;

                                goodGroups.ForEach(block =>
                                {
                                    block.Actions.ForEach(action =>
                                    {
                                        if (action is DamageRecord record)
                                        {
                                            PlayerStats stats = StatsUtil.CreatePlayerStats(individualStats, record.Attacker);

                                            if (!MainWindow.IsBaneDamageEnabled && record.Type == Labels.BANE)
                                            {
                                                stats.BaneHits++;

                                                if (individualStats.TryGetValue(stats.OrigName + " +Pets", out PlayerStats temp))
                                                {
                                                    temp.BaneHits++;
                                                }
                                            }
                                            else
                                            {
                                                RaidTotals.Total += record.Total;
                                                StatsUtil.UpdateStats(stats, record, block.BeginTime);
                                                allStats[record.Attacker] = stats;

                                                if (!PetToPlayer.TryGetValue(record.Attacker, out string player) && !PlayerHasPet.ContainsKey(record.Attacker))
                                                {
                                                    // not a pet
                                                    topLevelStats[record.Attacker] = stats;
                                                }
                                                else
                                                {
                                                    string origName      = player ?? record.Attacker;
                                                    string aggregateName = (player == Labels.UNASSIGNED) ? origName : origName + " +Pets";

                                                    PlayerStats aggregatePlayerStats = StatsUtil.CreatePlayerStats(individualStats, aggregateName, origName);
                                                    StatsUtil.UpdateStats(aggregatePlayerStats, record, block.BeginTime);
                                                    allStats[aggregateName]      = aggregatePlayerStats;
                                                    topLevelStats[aggregateName] = aggregatePlayerStats;

                                                    if (!childrenStats.TryGetValue(aggregateName, out Dictionary <string, PlayerStats> children))
                                                    {
                                                        childrenStats[aggregateName] = new Dictionary <string, PlayerStats>();
                                                    }

                                                    childrenStats[aggregateName][stats.Name] = stats;
                                                }

                                                PlayerSubStats subStats = StatsUtil.CreatePlayerSubStats(stats.SubStats, record.SubType, record.Type);
                                                UpdateSubStats(subStats, record, block.BeginTime);
                                                allStats[stats.Name + "=" + Helpers.CreateRecordKey(record.Type, record.SubType)] = subStats;
                                            }
                                        }
                                    });
                                });

                                foreach (var stats in allStats.Values)
                                {
                                    stats.TotalSeconds += stats.LastTime - stats.BeginTime + 1;
                                    stats.BeginTime     = double.NaN;
                                }
                            });

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

                            // add up resists
                            Dictionary <string, uint> resistCounts = new Dictionary <string, uint>();

                            Resists.ForEach(resist =>
                            {
                                ResistRecord record = resist as ResistRecord;
                                Helpers.StringUIntAddHelper.Add(resistCounts, record.Spell, 1);
                            });

                            // get special field
                            var specials = StatsUtil.GetSpecials(RaidTotals);

                            Parallel.ForEach(individualStats.Values, stats =>
                            {
                                if (topLevelStats.TryGetValue(stats.Name, out PlayerStats topLevel))
                                {
                                    if (childrenStats.TryGetValue(stats.Name, out Dictionary <string, PlayerStats> children))
                                    {
                                        foreach (var child in children.Values)
                                        {
                                            StatsUtil.UpdateCalculations(child, RaidTotals, resistCounts);

                                            if (stats.Total > 0)
                                            {
                                                child.Percent = Math.Round(Convert.ToDouble(child.Total) / stats.Total * 100, 2);
                                            }

                                            if (specials.TryGetValue(child.Name, out string special1))
                                            {
                                                child.Special = special1;
                                            }
                                        }
                                    }

                                    StatsUtil.UpdateCalculations(stats, RaidTotals, resistCounts);

                                    if (specials.TryGetValue(stats.OrigName, out string special2))
                                    {
                                        stats.Special = special2;
                                    }
                                }
                            });

                            combined = new CombinedStats
                            {
                                RaidStats   = RaidTotals,
                                TargetTitle = (Selected.Count > 1 ? "Combined (" + Selected.Count + "): " : "") + Title,
                                TimeTitle   = string.Format(CultureInfo.CurrentCulture, StatsUtil.TIME_FORMAT, RaidTotals.TotalSeconds),
                                TotalTitle  = string.Format(CultureInfo.CurrentCulture, StatsUtil.TOTAL_FORMAT, StatsUtil.FormatTotals(RaidTotals.Total), " Damage ", StatsUtil.FormatTotals(RaidTotals.DPS))
                            };

                            combined.StatsList.AddRange(topLevelStats.Values.AsParallel().OrderByDescending(item => item.Total));
                            combined.FullTitle  = StatsUtil.FormatTitle(combined.TargetTitle, combined.TimeTitle, combined.TotalTitle);
                            combined.ShortTitle = StatsUtil.FormatTitle(combined.TargetTitle, combined.TimeTitle, "");

                            for (int i = 0; i < combined.StatsList.Count; i++)
                            {
                                combined.StatsList[i].Rank = Convert.ToUInt16(i + 1);
                                combined.UniqueClasses[combined.StatsList[i].ClassName] = 1;

                                if (childrenStats.TryGetValue(combined.StatsList[i].Name, out Dictionary <string, PlayerStats> children))
                                {
                                    combined.Children.Add(combined.StatsList[i].Name, children.Values.OrderByDescending(stats => stats.Total).ToList());
                                }
                            }
                        }
                    }
                    catch (ArgumentNullException anx)
                    {
                        LOG.Error(anx);
                    }
                    catch (AggregateException agx)
                    {
                        LOG.Error(agx);
                    }

                    FireCompletedEvent(options, combined, DamageGroups);
                }
            }
        }
예제 #20
0
        private void ComputeDamageStats(GenerateStatsOptions options)
        {
            lock (DamageGroupIds)
            {
                if (RaidTotals != null)
                {
                    CombinedStats combined = null;
                    ConcurrentDictionary <string, Dictionary <string, PlayerStats> > childrenStats = new ConcurrentDictionary <string, Dictionary <string, PlayerStats> >();
                    ConcurrentDictionary <string, PlayerStats> topLevelStats   = new ConcurrentDictionary <string, PlayerStats>();
                    ConcurrentDictionary <string, PlayerStats> aggregateStats  = new ConcurrentDictionary <string, PlayerStats>();
                    Dictionary <string, PlayerStats>           individualStats = new Dictionary <string, PlayerStats>();

                    // always start over
                    RaidTotals.Total = 0;
                    double stopTime = -1;

                    try
                    {
                        FireChartEvent(options, "UPDATE");

                        if (options.RequestSummaryData)
                        {
                            if (options.MaxSeconds > -1 && options.MaxSeconds <= RaidTotals.MaxTime && options.MaxSeconds != RaidTotals.TotalSeconds)
                            {
                                var filteredGroups = new List <List <ActionBlock> >();
                                AllDamageGroups.ForEach(group =>
                                {
                                    var filteredBlocks = new List <ActionBlock>();
                                    filteredGroups.Add(filteredBlocks);
                                    group.ForEach(block =>
                                    {
                                        stopTime = stopTime == -1 ? block.BeginTime + options.MaxSeconds : stopTime;
                                        if (block.BeginTime <= stopTime)
                                        {
                                            filteredBlocks.Add(block);
                                        }
                                    });
                                });

                                DamageGroups            = filteredGroups;
                                RaidTotals.TotalSeconds = options.MaxSeconds;
                            }
                            else
                            {
                                DamageGroups = AllDamageGroups;
                            }

                            DamageGroups.ForEach(group =>
                            {
                                group.ForEach(block =>
                                {
                                    block.Actions.ForEach(action =>
                                    {
                                        if (action is DamageRecord record)
                                        {
                                            PlayerStats stats = StatsUtil.CreatePlayerStats(individualStats, record.Attacker);

                                            if (!MainWindow.IsBaneDamageEnabled && record.Type == Labels.BANE)
                                            {
                                                stats.BaneHits++;

                                                if (individualStats.TryGetValue(stats.OrigName + " +Pets", out PlayerStats temp))
                                                {
                                                    temp.BaneHits++;
                                                }
                                            }
                                            else
                                            {
                                                RaidTotals.Total += record.Total;
                                                StatsUtil.UpdateStats(stats, record);

                                                if ((!PetToPlayer.TryGetValue(record.Attacker, out string player) && !PlayerPets.ContainsKey(record.Attacker)) || player == Labels.UNASSIGNED)
                                                {
                                                    topLevelStats[record.Attacker] = stats;
                                                    stats.IsTopLevel = true;
                                                }
                                                else
                                                {
                                                    string origName      = player ?? record.Attacker;
                                                    string aggregateName = origName + " +Pets";

                                                    PlayerStats aggregatePlayerStats = StatsUtil.CreatePlayerStats(individualStats, aggregateName, origName);
                                                    StatsUtil.UpdateStats(aggregatePlayerStats, record);
                                                    topLevelStats[aggregateName] = aggregatePlayerStats;

                                                    if (!childrenStats.TryGetValue(aggregateName, out Dictionary <string, PlayerStats> children))
                                                    {
                                                        childrenStats[aggregateName] = new Dictionary <string, PlayerStats>();
                                                    }


                                                    childrenStats[aggregateName][stats.Name] = stats;
                                                    stats.IsTopLevel = false;
                                                }

                                                PlayerSubStats subStats = StatsUtil.CreatePlayerSubStats(stats.SubStats, record.SubType, record.Type);

                                                uint critHits = subStats.CritHits;
                                                StatsUtil.UpdateStats(subStats, record);

                                                // dont count misses or where no damage was done
                                                if (record.Total > 0)
                                                {
                                                    Dictionary <long, int> values = subStats.CritHits > critHits ? subStats.CritFreqValues : subStats.NonCritFreqValues;
                                                    Helpers.LongIntAddHelper.Add(values, record.Total, 1);
                                                }
                                            }
                                        }
                                    });
                                });
                            });
예제 #21
0
        internal void BuildTotalStats(GenerateStatsOptions options)
        {
            lock (DamageGroups)
            {
                Selected = options.Npcs;
                Title    = options.Name;

                try
                {
                    FireNewStatsEvent(options);

                    RaidTotals = StatsUtil.CreatePlayerStats(Labels.RAID);
                    DamageGroups.Clear();
                    DamageGroupIds.Clear();
                    PlayerHasPet.Clear();
                    PetToPlayer.Clear();
                    Resists.Clear();

                    var damageBlocks = new List <ActionBlock>();
                    Selected.ForEach(fight =>
                    {
                        StatsUtil.UpdateTimeDiffs(RaidTotals, fight);
                        damageBlocks.AddRange(fight.DamageBlocks);

                        if (fight.GroupId > -1)
                        {
                            DamageGroupIds[fight.GroupId] = 1;
                        }
                    });

                    damageBlocks.Sort((a, b) => a.BeginTime.CompareTo(b.BeginTime));

                    if (damageBlocks.Count > 0)
                    {
                        RaidTotals.TotalSeconds = RaidTotals.TimeDiffs.Sum();

                        var newBlock  = new List <ActionBlock>();
                        var timeIndex = 0;

                        damageBlocks.ForEach(block =>
                        {
                            if (block.BeginTime > RaidTotals.LastTimes[timeIndex])
                            {
                                timeIndex++;

                                if (newBlock.Count > 0)
                                {
                                    DamageGroups.Add(newBlock);
                                }

                                newBlock = new List <ActionBlock>();
                            }

                            newBlock.Add(block);

                            block.Actions.ForEach(action =>
                            {
                                DamageRecord damage = action as DamageRecord;
                                // see if there's a pet mapping, check this first
                                string pname = PlayerManager.Instance.GetPlayerFromPet(damage.Attacker);
                                if (!string.IsNullOrEmpty(pname) || !string.IsNullOrEmpty(pname = damage.AttackerOwner))
                                {
                                    PlayerHasPet[pname]          = 1;
                                    PetToPlayer[damage.Attacker] = pname;
                                }
                            });
                        });

                        DamageGroups.Add(newBlock);

                        for (int i = 0; i < RaidTotals.BeginTimes.Count && i < RaidTotals.LastTimes.Count; i++)
                        {
                            var group = DataManager.Instance.GetResistsDuring(RaidTotals.BeginTimes[i], RaidTotals.LastTimes[i]);
                            group.ForEach(block => Resists.AddRange(block.Actions));
                        }

                        ComputeDamageStats(options);
                    }
                    else if (Selected == null || Selected.Count == 0)
                    {
                        FireNoDataEvent(options, "NONPC");
                    }
                    else
                    {
                        FireNoDataEvent(options, "NODATA");
                    }
                }
                catch (ArgumentNullException ne)
                {
                    LOG.Error(ne);
                }
                catch (NullReferenceException nr)
                {
                    LOG.Error(nr);
                }
                catch (ArgumentOutOfRangeException aor)
                {
                    LOG.Error(aor);
                }
                catch (ArgumentException ae)
                {
                    LOG.Error(ae);
                }
                catch (OutOfMemoryException oem)
                {
                    LOG.Error(oem);
                }
            }
        }
예제 #22
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);
                }
            }
        }
예제 #23
0
        public StatsSummary BuildSummary(string type, CombinedStats currentStats, List <PlayerStats> selected, bool showTotals, bool rankPlayers, bool showSpecial)
        {
            List <string> list = new List <string>();

            string title   = "";
            string details = "";

            if (currentStats != null && type == Labels.DAMAGEPARSE)
            {
                if (selected?.Count > 0)
                {
                    foreach (PlayerStats stats in selected.OrderByDescending(item => item.Total))
                    {
                        string playerFormat = rankPlayers ? string.Format(CultureInfo.CurrentCulture, StatsUtil.PLAYER_RANK_FORMAT, stats.Rank, stats.Name) : string.Format(CultureInfo.CurrentCulture, StatsUtil.PLAYER_FORMAT, stats.Name);
                        string damageFormat = string.Format(CultureInfo.CurrentCulture, StatsUtil.TOTAL_FORMAT, StatsUtil.FormatTotals(stats.Total), "", StatsUtil.FormatTotals(stats.DPS));
                        string timeFormat   = string.Format(CultureInfo.CurrentCulture, StatsUtil.TIME_FORMAT, stats.TotalSeconds);

                        var dps = playerFormat + damageFormat + " " + timeFormat;

                        if (showSpecial && !string.IsNullOrEmpty(stats.Special))
                        {
                            dps = string.Format(CultureInfo.CurrentCulture, StatsUtil.SPECIAL_FORMAT, dps, stats.Special);
                        }

                        list.Add(dps);
                    }
                }

                details = list.Count > 0 ? ", " + string.Join(", ", list) : "";
                title   = StatsUtil.FormatTitle(currentStats.TargetTitle, currentStats.TimeTitle, showTotals ? currentStats.TotalTitle : "");
            }

            return(new StatsSummary()
            {
                Title = title, RankedPlayers = details
            });
        }
예제 #24
0
        private void BuildGroups(PlayerStats playerStats, List <PlayerSubStats> all)
        {
            List <PlayerSubStats> list = new List <PlayerSubStats>();
            PlayerSubStats        dots = new PlayerSubStats()
            {
                Name = Labels.DOT, Type = Labels.DOT
            };
            PlayerSubStats dds = new PlayerSubStats()
            {
                Name = Labels.DD, Type = Labels.DD
            };
            PlayerSubStats procs = new PlayerSubStats()
            {
                Name = Labels.PROC, Type = Labels.PROC
            };
            PlayerSubStats resisted = new PlayerSubStats()
            {
                Name = Labels.RESIST, Type = Labels.RESIST, ResistRate = 100
            };
            List <PlayerSubStats> allDots     = new List <PlayerSubStats>();
            List <PlayerSubStats> allDds      = new List <PlayerSubStats>();
            List <PlayerSubStats> allProcs    = new List <PlayerSubStats>();
            List <PlayerSubStats> allResisted = new List <PlayerSubStats>();

            all.ForEach(sub =>
            {
                PlayerSubStats stats = null;

                switch (sub.Type)
                {
                case Labels.DOT:
                    stats = dots;
                    allDots.Add(sub);
                    break;

                case Labels.DD:
                case Labels.BANE:
                    stats = dds;
                    allDds.Add(sub);
                    break;

                case Labels.PROC:
                    stats = procs;
                    allProcs.Add(sub);
                    break;

                case Labels.RESIST:
                    stats = resisted;
                    allResisted.Add(sub);
                    break;

                default:
                    list.Add(sub);
                    break;
                }

                StatsUtil.MergeStats(stats, sub);
            });

            foreach (var stats in new PlayerSubStats[] { dots, dds, procs, resisted })
            {
                StatsUtil.CalculateRates(stats, RaidStats, playerStats);
            }

            UnGroupedDD[playerStats.Name]       = allDds;
            UnGroupedDoT[playerStats.Name]      = allDots;
            UnGroupedProcs[playerStats.Name]    = allProcs;
            UnGroupedResisted[playerStats.Name] = allResisted;
            GroupedDD[playerStats.Name]         = dds;
            GroupedDoT[playerStats.Name]        = dots;
            GroupedProcs[playerStats.Name]      = procs;
            GroupedResisted[playerStats.Name]   = resisted;
            OtherDamage[playerStats.Name]       = list;

            Dispatcher.InvokeAsync(() =>
            {
                if (allDds.Count > 0 && !groupDirectDamage.IsEnabled)
                {
                    groupDirectDamage.IsEnabled = true;
                }

                if (allProcs.Count > 0 && !groupProcs.IsEnabled)
                {
                    groupProcs.IsEnabled = true;
                }

                if (allDots.Count > 0 && !groupDoT.IsEnabled)
                {
                    groupDoT.IsEnabled = true;
                }

                if (allResisted.Count > 0 && !groupResisted.IsEnabled)
                {
                    groupResisted.IsEnabled = true;
                }
            });
        }
예제 #25
0
        public StatsSummary BuildSummary(string type, CombinedStats currentStats, List <PlayerStats> selected, bool showTotals, bool rankPlayers, bool _, bool showTime)
        {
            List <string> list = new List <string>();

            string title   = "";
            string details = "";

            if (currentStats != null)
            {
                if (type == Labels.TANKPARSE)
                {
                    if (selected?.Count > 0)
                    {
                        foreach (PlayerStats stats in selected.OrderByDescending(item => item.Total))
                        {
                            string playerFormat = rankPlayers ? string.Format(CultureInfo.CurrentCulture, StatsUtil.PLAYER_RANK_FORMAT, stats.Rank, stats.Name) : string.Format(CultureInfo.CurrentCulture, StatsUtil.PLAYER_FORMAT, stats.Name);
                            string damageFormat = string.Format(CultureInfo.CurrentCulture, StatsUtil.TOTAL_ONLY_FORMAT, StatsUtil.FormatTotals(stats.Total));
                            list.Add(playerFormat + damageFormat + " ");
                        }
                    }

                    details = list.Count > 0 ? ", " + string.Join(" | ", list) : "";
                    var timeTitle = showTime ? (" " + currentStats.TimeTitle) : "";
                    title = StatsUtil.FormatTitle(currentStats.TargetTitle, timeTitle, showTotals ? currentStats.TotalTitle : "");
                }
                else if (type == Labels.RECEIVEDHEALPARSE)
                {
                    if (selected?.Count == 1 && (selected[0] as PlayerStats).SubStats2.TryGetValue("receivedHealing", out PlayerSubStats subStats) && subStats is PlayerStats receivedHealing)
                    {
                        int  rank   = 1;
                        long totals = 0;
                        foreach (var stats in receivedHealing.SubStats.Values.OrderByDescending(stats => stats.Total).Take(10))
                        {
                            string playerFormat = rankPlayers ? string.Format(CultureInfo.CurrentCulture, StatsUtil.PLAYER_RANK_FORMAT, rank++, stats.Name) : string.Format(CultureInfo.CurrentCulture, StatsUtil.PLAYER_FORMAT, stats.Name);
                            string damageFormat = string.Format(CultureInfo.CurrentCulture, StatsUtil.TOTAL_ONLY_FORMAT, StatsUtil.FormatTotals(stats.Total));
                            list.Add(playerFormat + damageFormat + " ");
                            totals += stats.Total;
                        }

                        var    hps        = (long)Math.Round(totals / currentStats.RaidStats.TotalSeconds, 2);
                        string totalTitle = showTotals ? (selected[0].Name + " Received " + StatsUtil.FormatTotals(totals) + " Healing") : (selected[0].Name + " Received Healing");
                        details = list.Count > 0 ? ", " + string.Join(" | ", list) : "";
                        var timeTitle = showTime ? (" " + currentStats.TimeTitle) : "";
                        title = StatsUtil.FormatTitle(currentStats.TargetTitle, timeTitle, totalTitle);
                    }
                }
            }

            return(new StatsSummary()
            {
                Title = title, RankedPlayers = details,
            });
        }
예제 #26
0
        public StatsSummary BuildSummary(string type, CombinedStats currentStats, List <PlayerStats> selected, bool showTotals, bool rankPlayers, bool _, bool showTime)
        {
            List <string> list = new List <string>();

            string title   = "";
            string details = "";

            if (currentStats != null)
            {
                if (type == Labels.HEALPARSE)
                {
                    if (selected?.Count > 0)
                    {
                        foreach (PlayerStats stats in selected.OrderByDescending(item => item.Total))
                        {
                            string playerFormat = rankPlayers ? string.Format(CultureInfo.CurrentCulture, StatsUtil.PLAYER_RANK_FORMAT, stats.Rank, stats.Name) : string.Format(CultureInfo.CurrentCulture, StatsUtil.PLAYER_FORMAT, stats.Name);
                            string healsFormat  = string.Format(CultureInfo.CurrentCulture, StatsUtil.TOTAL_ONLY_FORMAT, StatsUtil.FormatTotals(stats.Total));
                            list.Add(playerFormat + healsFormat + " ");
                        }
                    }

                    details = list.Count > 0 ? ", " + string.Join(" | ", list) : "";
                    var timeTitle = showTime ? (" " + currentStats.TimeTitle) : "";
                    title = StatsUtil.FormatTitle(currentStats.TargetTitle, timeTitle, showTotals ? currentStats.TotalTitle : "");
                }
                else if (type == Labels.TOPHEALSPARSE)
                {
                    if (selected?.Count == 1 && selected[0].SubStats.Count > 0)
                    {
                        int rank = 1;
                        foreach (var stats in selected[0].SubStats.Values.OrderByDescending(stats => stats.Total).Take(10))
                        {
                            string abbrv        = DataManager.Instance.AbbreviateSpellName(stats.Name);
                            string playerFormat = rankPlayers ? string.Format(CultureInfo.CurrentCulture, StatsUtil.PLAYER_RANK_FORMAT, rank++, abbrv) : string.Format(CultureInfo.CurrentCulture, StatsUtil.PLAYER_FORMAT, abbrv);
                            string healsFormat  = string.Format(CultureInfo.CurrentCulture, StatsUtil.TOTAL_ONLY_FORMAT, StatsUtil.FormatTotals(stats.Total));
                            list.Add(playerFormat + healsFormat + " ");
                        }

                        string totalTitle = selected[0].Name + "'s Top Heals";
                        details = list.Count > 0 ? ", " + string.Join(" | ", list) : "";
                        var timeTitle = showTime ? (" " + currentStats.TimeTitle) : "";
                        title = StatsUtil.FormatTitle(currentStats.TargetTitle, timeTitle, totalTitle);
                    }
                }
            }

            return(new StatsSummary()
            {
                Title = title, RankedPlayers = details,
            });
        }
예제 #27
0
        internal void BuildTotalStats(GenerateStatsOptions options)
        {
            lock (TankingGroups)
            {
                try
                {
                    FireNewStatsEvent(options);
                    Reset();

                    Selected = options.Npcs;
                    Title    = options.Name;
                    var damageBlocks = new List <ActionBlock>();

                    Selected.ForEach(fight =>
                    {
                        damageBlocks.AddRange(fight.TankingBlocks);
                        RaidTotals.Ranges.Add(new TimeSegment(fight.BeginTankingTime, fight.LastTankingTime));
                        StatsUtil.UpdateRaidTimeRanges(fight, PlayerTimeRanges, PlayerSubTimeRanges, true);
                    });

                    damageBlocks.Sort((a, b) => a.BeginTime.CompareTo(b.BeginTime));

                    if (damageBlocks.Count > 0)
                    {
                        RaidTotals.TotalSeconds = RaidTotals.Ranges.GetTotal();

                        int rangeIndex = 0;
                        var newBlock   = new List <ActionBlock>();
                        damageBlocks.ForEach(block =>
                        {
                            if (RaidTotals.Ranges.TimeSegments.Count > rangeIndex && block.BeginTime > RaidTotals.Ranges.TimeSegments[rangeIndex].EndTime)
                            {
                                rangeIndex++;

                                if (newBlock.Count > 0)
                                {
                                    TankingGroups.Add(newBlock);
                                }

                                newBlock = new List <ActionBlock>();
                            }

                            newBlock.Add(block);
                        });

                        TankingGroups.Add(newBlock);
                        ComputeTankingStats(options);
                    }
                    else if (Selected == null || Selected.Count == 0)
                    {
                        FireNoDataEvent(options, "NONPC");
                    }
                    else
                    {
                        FireNoDataEvent(options, "NODATA");
                    }
                }
#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);
                    }
                }
            }
        }
예제 #28
0
        public static void Process(LineData lineData)
        {
            bool handled = false;

            try
            {
                string[] split = lineData.Action.Split(' ');

                if (split != null && split.Length >= 2)
                {
                    // [Sun Mar 01 22:20:36 2020] A shaded torch has been awakened by Drogbaa.
                    // [Sun Mar 01 20:35:55 2020] The master looter, Qulas, looted 32426 platinum from the corpse.
                    // [Sun Mar 01 23:51:02 2020] You receive 129 platinum, 2 gold and 1 copper as your split (with a lucky bonus).
                    // [Sun Feb 02 22:43:51 2020] You receive 28 platinum, 7 gold, 2 silver and 5 copper as your split.
                    // [Sun Feb 02 23:31:23 2020] You receive 57 platinum as your split.
                    // [Fri Feb 07 22:01:20 2020] --Kizant has looted a Lesser Engraved Velium Rune from Velden Dragonbane's corpse.--
                    // [Sat Feb 08 01:20:26 2020] --Proximoe has looted a Velium Infused Spider Silk from a restless devourer's corpse.--
                    // [Sat Feb 08 21:21:36 2020] --You have looted a Cold-Forged Cudgel from Queen Dracnia's corpse.--
                    // [Mon Apr 27 22:32:04 2020] Restless Tijoely resisted your Stormjolt Vortex Effect!
                    // [Mon Apr 27 20:51:22 2020] Kazint's Scorching Beam Rk. III spell has been reflected by a shadow reflection.
                    // [Sun Mar 28 19:42:46 2021] A Draconic Lava Chain Feet Ornament was given to Aldryn.
                    // [Mon Apr 05 19:42:24 2021] Hacket won the need roll on 1 item(s): Restless Velium Tainted Pelt with a roll of 996.

                    string looter          = null;
                    int    awakenedIndex   = -1;
                    int    lootedIndex     = -1;
                    int    masterLootIndex = -1;
                    int    receiveIndex    = -1;
                    int    resistedIndex   = -1;
                    int    isIndex         = -1;
                    int    itemsIndex      = -1;

                    for (int i = 0; i < split.Length && !handled; i++)
                    {
                        if (i == 0 && split[0].StartsWith("--", StringComparison.OrdinalIgnoreCase))
                        {
                            looter = split[0] == "--You" ? ConfigUtil.PlayerName : split[0].TrimStart('-');
                        }
                        else
                        {
                            switch (split[i])
                            {
                            case "awakened":
                                awakenedIndex = i;
                                break;

                            case "is":
                                isIndex = i;
                                break;

                            case "looted":
                                lootedIndex = i;
                                break;

                            case "resisted":
                                resistedIndex = i;
                                break;

                            case "item(s):":
                                if (split.Length > 9 && split[1] == "won" && split[4] == "roll")
                                {
                                    itemsIndex = i;
                                }
                                break;

                            case "looter,":
                                masterLootIndex = (i == 2 && split[1] == "master" && split[0] == "The") ? masterLootIndex = i + 1 : -1;
                                break;

                            case "receive":
                                receiveIndex = (i == 1 && split[0] == "You") ? i : -1;
                                break;

                            case "with":
                                if (itemsIndex > -1 && split.Length > i + 2 && split[i + 2] == "roll")
                                {
                                    looter = split[0].Equals("you", StringComparison.OrdinalIgnoreCase) ? ConfigUtil.PlayerName : split[0];
                                    string item = string.Join(" ", split, itemsIndex + 1, i - itemsIndex - 1);

                                    var currentTime = DateUtil.ParseLogDate(lineData.Line, out _);
                                    PlayerManager.Instance.AddVerifiedPlayer(looter, currentTime);

                                    LootRecord record = new LootRecord()
                                    {
                                        Item = item, Player = looter, Quantity = 0, IsCurrency = false, Npc = "Won Roll (Not Looted)"
                                    };
                                    DataManager.Instance.AddLootRecord(record, currentTime);
                                    handled = true;
                                }
                                break;

                            case "reflected":
                                if (split.Length > 6 && i >= 6 && i + 2 < split.Length && split[0].StartsWith(ConfigUtil.PlayerName, StringComparison.Ordinal) &&
                                    split[i - 1] == "been" && split[i - 2] == "has" && split[i - 3] == "spell" && split[i + 1] == "by")
                                {
                                    // var spell = string.Join(" ", split, 1, i - 4);
                                    var npc = string.Join(" ", split, i + 2, split.Length - i - 2).TrimEnd('.');
                                    DataManager.Instance.UpdateNpcSpellReflectStats(npc);
                                    handled = true;
                                }
                                break;

                            case "your":
                                if (resistedIndex > 0 && resistedIndex + 1 == i && split.Length > i + 1 && split[split.Length - 1].EndsWith("!", StringComparison.Ordinal))
                                {
                                    string npc   = string.Join(" ", split, 0, resistedIndex);
                                    string spell = string.Join(" ", split, i + 1, split.Length - i - 1).TrimEnd('!');
                                    DataManager.Instance.AddResistRecord(new ResistRecord {
                                        Defender = npc, Spell = spell
                                    }, DateUtil.ParseLogDate(lineData.Line, out _));
                                    handled = true;
                                }
                                break;

                            case "by":
                                if (awakenedIndex > -1 && awakenedIndex == (i - 1) && split.Length > 5 && split[i - 2] == "been" && split[i - 3] == "has")
                                {
                                    string awakened = string.Join(" ", split, 0, i - 3);
                                    string breaker  = string.Join(" ", split, i + 1, split.Length - i - 1).TrimEnd('.');
                                    DataManager.Instance.AddMiscRecord(new MezBreakRecord {
                                        Breaker = breaker, Awakened = awakened
                                    }, DateUtil.ParseLogDate(lineData.Line, out _));
                                    handled = true;
                                }
                                else if (isIndex > 0 && StruckByTypes.ContainsKey(split[i - 1]))
                                {
                                    // ignore common lines like: is struck by
                                    handled = true;
                                }
                                break;

                            case "from":
                                if (masterLootIndex > -1 && lootedIndex > masterLootIndex && split.Length > lootedIndex + 1 && split.Length > 3)
                                {
                                    string name = split[3].TrimEnd(',');
                                    if (ParseCurrency(split, lootedIndex + 1, i, out string item, out uint count))
                                    {
                                        var currentTime = DateUtil.ParseLogDate(lineData.Line, out _);
                                        PlayerManager.Instance.AddVerifiedPlayer(name, currentTime);
                                        LootRecord record = new LootRecord()
                                        {
                                            Item = item, Player = name, Quantity = count, IsCurrency = true
                                        };
                                        DataManager.Instance.AddLootRecord(record, currentTime);
                                        handled = true;
                                    }
                                }
                                else if (!string.IsNullOrEmpty(looter) && lootedIndex == 2 && split.Length > 4)
                                {
                                    // covers "a" or "an"
                                    uint   count = split[3][0] == 'a' ? 1 : StatsUtil.ParseUInt(split[3]);
                                    string item  = string.Join(" ", split, 4, i - 4);
                                    string npc   = string.Join(" ", split, i + 1, split.Length - i - 1).TrimEnd(LootedFromTrim).Replace("'s corpse", "");

                                    if (count > 0 && count != ushort.MaxValue)
                                    {
                                        var currentTime = DateUtil.ParseLogDate(lineData.Line, out _);
                                        PlayerManager.Instance.AddVerifiedPlayer(looter, currentTime);
                                        LootRecord record = new LootRecord()
                                        {
                                            Item = item, Player = looter, Quantity = count, IsCurrency = false, Npc = npc
                                        };
                                        DataManager.Instance.AddLootRecord(record, currentTime);
                                        handled = true;
                                    }
                                }
                                break;

                            case "given":
                                if (split[i - 1] == "was" && split.Length == (i + 3) && split[i + 1] == "to")
                                {
                                    string player = split[i + 2];
                                    if (player.Length > 3)
                                    {
                                        looter = player.Substring(0, player.Length - 1);
                                        looter = looter.Equals("you", StringComparison.OrdinalIgnoreCase) ? ConfigUtil.PlayerName : looter;

                                        var currentTime = DateUtil.ParseLogDate(lineData.Line, out _);
                                        PlayerManager.Instance.AddVerifiedPlayer(looter, currentTime);

                                        string     item   = string.Join(" ", split, 1, i - 2);
                                        LootRecord record = new LootRecord()
                                        {
                                            Item = item, Player = looter, Quantity = 0, IsCurrency = false, Npc = "Given (Not Looted)"
                                        };
                                        DataManager.Instance.AddLootRecord(record, currentTime);
                                        handled = true;
                                    }
                                }
                                break;

                            case "split.":
                            case "split":
                                if (receiveIndex > -1 && split[i - 1] == "your" && split[i - 2] == "as")
                                {
                                    if (ParseCurrency(split, 2, i - 2, out string item, out uint count))
                                    {
                                        LootRecord record = new LootRecord()
                                        {
                                            Item = item, Player = ConfigUtil.PlayerName, Quantity = count, IsCurrency = true
                                        };
                                        DataManager.Instance.AddLootRecord(record, DateUtil.ParseLogDate(lineData.Line, out _));
                                        handled = true;
                                    }
                                }
                                break;
                            }
                        }
                    }
                }
            }
            catch (ArgumentNullException ne)
            {
                LOG.Error(ne);
            }
            catch (NullReferenceException nr)
            {
                LOG.Error(nr);
            }
            catch (ArgumentOutOfRangeException aor)
            {
                LOG.Error(aor);
            }
            catch (ArgumentException ae)
            {
                LOG.Error(ae);
            }

            DebugUtil.UnregisterLine(lineData.LineNumber, handled);
        }
예제 #29
0
        internal static CombinedStats ComputeOverlayStats(int mode, int maxRows, string selectedClass)
        {
            CombinedStats combined = null;

            var   allDamage    = 0L;
            var   allTime      = new TimeRange();
            var   playerTotals = new Dictionary <string, OverlayPlayerTotal>();
            var   playerHasPet = new Dictionary <string, bool>();
            var   updateTime   = 0d;
            var   oldestTime   = 0d;
            var   fights       = DataManager.Instance.GetOverlayFights();
            Fight oldestFight  = null;
            bool  baneEnabled  = MainWindow.IsBaneDamageEnabled;

            // clear out anything pending in the queue
            DamageLineParser.CheckSlainQueue(DateUtil.ToDouble(DateTime.Now.AddSeconds(-3)));

            if (fights.Count > 0)
            {
                oldestFight = fights[0];
                foreach (var fight in fights.Where(fight => !fight.Dead || mode > 0))
                {
                    foreach (var keypair in fight.PlayerTotals)
                    {
                        var player = keypair.Key;
                        if (!string.IsNullOrEmpty(keypair.Value.PetOwner))
                        {
                            player = keypair.Value.PetOwner;
                            playerHasPet[player] = true;
                        }
                        else if (PlayerManager.Instance.GetPlayerFromPet(player) is string owner && owner != Labels.UNASSIGNED)
                        {
                            player = owner;
                            playerHasPet[player] = true;
                        }

                        allDamage += baneEnabled ? keypair.Value.DamageWithBane : keypair.Value.Damage;
                        allTime.Add(new TimeSegment(keypair.Value.BeginTime, fight.LastDamageTime));

                        if (updateTime == 0)
                        {
                            updateTime  = keypair.Value.UpdateTime;
                            oldestTime  = keypair.Value.UpdateTime;
                            oldestFight = fight;
                        }
                        else
                        {
                            updateTime = Math.Max(updateTime, keypair.Value.UpdateTime);
                            if (oldestTime > keypair.Value.UpdateTime)
                            {
                                oldestTime  = keypair.Value.UpdateTime;
                                oldestFight = fight;
                            }
                        }

                        if (playerTotals.TryGetValue(player, out OverlayPlayerTotal total))
                        {
                            total.Damage += baneEnabled ? keypair.Value.DamageWithBane : keypair.Value.Damage;
                            total.Range.Add(new TimeSegment(keypair.Value.BeginTime, keypair.Value.UpdateTime));
                            total.UpdateTime = Math.Max(total.UpdateTime, keypair.Value.UpdateTime);
                        }
                        else
                        {
                            playerTotals[player] = new OverlayPlayerTotal
                            {
                                Name       = player,
                                Damage     = baneEnabled ? keypair.Value.DamageWithBane : keypair.Value.Damage,
                                Range      = new TimeRange(new TimeSegment(keypair.Value.BeginTime, keypair.Value.UpdateTime)),
                                UpdateTime = keypair.Value.UpdateTime
                            };
                        }
                    }
                }

                var timeout      = mode == 0 ? DataManager.FIGHTTIMEOUT : mode;
                var totalSeconds = allTime.GetTotal();
                if (oldestFight != null && totalSeconds > 0 && allDamage > 0 && (DateTime.Now - DateTime.MinValue.AddSeconds(updateTime)).TotalSeconds <= timeout)
                {
                    int rank     = 1;
                    var list     = new List <PlayerStats>();
                    var totalDps = (long)Math.Round(allDamage / totalSeconds, 2);
                    int myIndex  = -1;

                    foreach (var total in playerTotals.Values.OrderByDescending(total => total.Damage))
                    {
                        var time = total.Range.GetTotal();
                        if (time > 0 && (DateTime.Now - DateTime.MinValue.AddSeconds(total.UpdateTime)).TotalSeconds <= DataManager.MAXTIMEOUT)
                        {
                            PlayerStats playerStats = new PlayerStats()
                            {
                                Name         = playerHasPet.ContainsKey(total.Name) ? total.Name + " +Pets" : total.Name,
                                Total        = total.Damage,
                                DPS          = (long)Math.Round(total.Damage / time, 2),
                                TotalSeconds = time,
                                Rank         = (ushort)rank++,
                                ClassName    = PlayerManager.Instance.GetPlayerClass(total.Name),
                                OrigName     = total.Name
                            };

                            if (playerStats.Name.StartsWith(ConfigUtil.PlayerName, StringComparison.Ordinal))
                            {
                                myIndex = list.Count;
                            }

                            if (myIndex == list.Count || selectedClass == Properties.Resources.ANY_CLASS || selectedClass == playerStats.ClassName)
                            {
                                list.Add(playerStats);
                            }
                        }
                    }

                    if (myIndex > (maxRows - 1))
                    {
                        var me = list[myIndex];
                        list = list.Take(maxRows - 1).ToList();
                        list.Add(me);
                    }
                    else
                    {
                        list = list.Take(maxRows).ToList();
                    }

                    combined = new CombinedStats();
                    combined.StatsList.AddRange(list);
                    combined.RaidStats = new PlayerStats {
                        Total = allDamage, DPS = totalDps, TotalSeconds = totalSeconds
                    };
                    combined.TargetTitle = (fights.Count > 1 ? "C(" + fights.Count + "): " : "") + oldestFight.Name;

                    // these are here to support copy/paste of the parse
                    combined.TimeTitle  = string.Format(CultureInfo.CurrentCulture, StatsUtil.TIME_FORMAT, combined.RaidStats.TotalSeconds);
                    combined.TotalTitle = string.Format(CultureInfo.CurrentCulture, StatsUtil.TOTAL_FORMAT, StatsUtil.FormatTotals(combined.RaidStats.Total),
                                                        " Damage ", StatsUtil.FormatTotals(combined.RaidStats.DPS));
                }
            }

            return(combined);
        }