private static string GetTypeFromSpell(string name, string type)
        {
            string key = Helpers.CreateRecordKey(type, name);

            if (string.IsNullOrEmpty(key) || !SpellTypeCache.TryGetValue(key, out string result))
            {
                result = type;
                if (!string.IsNullOrEmpty(key))
                {
                    string    spellName = DataManager.Instance.AbbreviateSpellName(name);
                    SpellData data      = DataManager.Instance.GetSpellByAbbrv(spellName);
                    if (data != null)
                    {
                        switch (data.Proc)
                        {
                        case 1:
                            result = Labels.PROC;
                            break;

                        case 2:
                            result = Labels.BANE;
                            break;
                        }
                    }
                }

                SpellTypeCache[key] = result;
            }
            return(result);
        }
示例#2
0
        private static void AddPlayerTime(Fight fight, DamageRecord record, string player, double time)
        {
            var isInitialTanking = fight.DamageBlocks.Count == 0;
            var segments         = isInitialTanking ? fight.InitialTankSegments : fight.DamageSegments;
            var subSegments      = isInitialTanking ? fight.InitialTankSubSegments : fight.DamageSubSegments;

            StatsUtil.UpdateTimeSegments(segments, subSegments, Helpers.CreateRecordKey(record.Type, record.SubType), player, time);
        }
示例#3
0
        internal static PlayerSubStats CreatePlayerSubStats(Dictionary <string, PlayerSubStats> individualStats, string subType, string type)
        {
            var            key   = Helpers.CreateRecordKey(type, subType);
            PlayerSubStats stats = null;

            lock (individualStats)
            {
                if (!individualStats.ContainsKey(key))
                {
                    stats = CreatePlayerSubStats(subType, type);
                    individualStats[key] = stats;
                }
                else
                {
                    stats = individualStats[key];
                }
            }

            return(stats);
        }
示例#4
0
        private static string GetTypeFromSpell(string name, string type)
        {
            string key = Helpers.CreateRecordKey(type, name);

            if (string.IsNullOrEmpty(key) || !SpellTypeCache.TryGetValue(key, out string result))
            {
                if (!string.IsNullOrEmpty(key))
                {
                    string    spellName = DataManager.Instance.AbbreviateSpellName(name);
                    SpellData data      = DataManager.Instance.GetSpellByAbbrv(spellName);
                    result = (data != null && data.IsProc) ? Labels.PROC : type;
                    SpellTypeCache[key] = result;
                }
                else
                {
                    result = type;
                }
            }

            return(result);
        }
        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);
                    }
                }
            }
        }
        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);
                }
            }
        }
        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);
                }
            }
        }