public PlayerStatsFormatter(PlayerInfo playerInfo, TeraData teraData, FormatHelpers formatHelpers) { var placeHolders = new List<KeyValuePair<string, object>>(); placeHolders.Add(new KeyValuePair<string, object>("FullName", playerInfo.FullName)); placeHolders.Add(new KeyValuePair<string, object>("Name", playerInfo.Name)); placeHolders.Add(new KeyValuePair<string, object>("Class", playerInfo.Class)); placeHolders.Add(new KeyValuePair<string, object>("Crits", playerInfo.Dealt.Crits)); placeHolders.Add(new KeyValuePair<string, object>("Hits", playerInfo.Dealt.Hits)); placeHolders.Add(new KeyValuePair<string, object>("DamagePercent", formatHelpers.FormatPercent(playerInfo.Dealt.DamageFraction) ?? "NaN")); placeHolders.Add(new KeyValuePair<string, object>("CritPercent", formatHelpers.FormatPercent((double)playerInfo.Dealt.Crits / playerInfo.Dealt.Hits) ?? "NaN")); placeHolders.Add(new KeyValuePair<string, object>("Damage", formatHelpers.FormatValue(playerInfo.Dealt.Damage))); placeHolders.Add(new KeyValuePair<string, object>("DamageReceived", formatHelpers.FormatValue(playerInfo.Received.Damage))); placeHolders.Add(new KeyValuePair<string, object>("DPS", $"{formatHelpers.FormatValue(SettingsHelper.Instance.Settings.ShowPersonalDps ? playerInfo.Dealt.PersonalDps : playerInfo.Dealt.Dps)}/s")); var lastTick = playerInfo.Tracker.LastAttack?.Ticks ?? 0; var firstTick = playerInfo.Tracker.FirstAttack?.Ticks ?? 0; var slayingstr = ""; var death = ""; var deathDur = ""; if (lastTick > firstTick && firstTick > 0) { var buffs = playerInfo.Tracker.Abnormals.Get(playerInfo.Player); AbnormalityDuration slaying; buffs.Times.TryGetValue(teraData.HotDotDatabase.Get(8888889), out slaying); double slayingperc = (double) (slaying?.Duration(firstTick, lastTick) ?? 0)/(lastTick - firstTick); slayingstr = formatHelpers.FormatPercent(slayingperc); death = buffs.Death.Count(firstTick, lastTick).ToString(); deathDur = formatHelpers.FormatTimeSpan(TimeSpan.FromTicks(buffs.Death.Duration(firstTick, lastTick))); } placeHolders.Add(new KeyValuePair<string, object>("Death", death)); placeHolders.Add(new KeyValuePair<string, object>("DeathDuration", deathDur)); placeHolders.Add(new KeyValuePair<string, object>("Slaying", slayingstr)); Placeholders = placeHolders.ToDictionary(x => x.Key, y => y.Value); FormatProvider = formatHelpers.CultureInfo; }
private void HandleNewConnection(Server server) { Text = string.Format("Damage Meter connected to {0}", server.Name); _server = server; _teraData = _basicTeraData.DataForRegion(server.Region); _entityTracker = new EntityTracker(_teraData.NpcDatabase); _playerTracker = new PlayerTracker(_entityTracker); _damageTracker = new DamageTracker(); _messageFactory = new MessageFactory(_teraData.OpCodeNamer); Logger.Log(Text); }
private void HandleNewConnection(Server server) { Server = server; _teraData = BasicTeraData.DataForRegion(server.Region); _entityTracker = new EntityTracker(); _playerTracker = new PlayerTracker(_entityTracker); _messageFactory = new MessageFactory(_teraData.OpCodeNamer); Reset(null); DamageTracker = DamageTracker ?? new DamageTracker(); Logger.Info($"Connected to server {server.Name}."); }
private void HandleMessageReceived(Message obj) { var message = _messageFactory.Create(obj); if (DamageTracker.IsArchived) { var npcOccupier = message as SNpcOccupierInfo; if (npcOccupier != null) { Entity ent = _entityTracker.GetOrPlaceholder(npcOccupier.NPC); if (ent is NpcEntity) { var npce = ent as NpcEntity; if (npce.Info.Boss && npcOccupier.Target != EntityId.Empty) { CasualMessenger.Instance.ResetPlayerStats(true); //Stop viewing saved encounter on boss aggro } } return; } } _entityTracker?.Update(message); var skillResultMessage = message as EachSkillResultServerMessage; if (skillResultMessage != null) { if (skillResultMessage.IsValid(DamageTracker)) { var skillResult = new SkillResult(skillResultMessage, _entityTracker, _playerTracker, _teraData.SkillDatabase, null, _abnormalityTracker); CheckUpdate(skillResult); } return; } _playerTracker?.UpdateParty(message); _abnormalityTracker?.Update(message); var despawnNpc = message as SDespawnNpc; if (despawnNpc != null) { Entity ent = _entityTracker.GetOrPlaceholder(despawnNpc.Npc); if (ent is NpcEntity) { var npce = ent as NpcEntity; if (npce.Info.Boss && despawnNpc.Dead && !DamageTracker.IsArchived) { //no need to do something if we didn't count any skill against this boss if (DamageTracker.StatsByUser.SelectMany(x => x.SkillLog).Any(x => x.Target == npce)) { DamageTracker.PrimaryTarget = npce; //Name encounter with the last dead boss DamageTracker.IsPrimaryTargetDead = despawnNpc.Dead; //determine type ExportType exportType = ExportType.None; if (SettingsHelper.Instance.Settings.ExcelExport) exportType = exportType | ExportType.Excel; if (SettingsHelper.Instance.Settings.SiteExport) exportType = exportType | ExportType.Upload; if (exportType != ExportType.None) DataExporter.ToTeraDpsApi(exportType, DamageTracker, _teraData); if (AutosaveEncounters) ResetDamageTracker(new ResetPlayerStatsMessage { ShouldSaveCurrent = true }); } } } return; } var sLogin = message as LoginServerMessage; if (sLogin != null) { if (_needInit) { Server = BasicTeraData.Servers.GetServer(sLogin.ServerId, Server); _messageFactory.Version = Server.Region; Logger.Info($"Logged in to server {Server.Name}."); _teraData = BasicTeraData.DataForRegion(Server.Region); _entityTracker = new EntityTracker(_teraData.NpcDatabase); _playerTracker = new PlayerTracker(_entityTracker, BasicTeraData.Servers); _abnormalityTracker = new AbnormalityTracker(_entityTracker, _playerTracker, _teraData.HotDotDatabase, _abnormalityStorage, CheckUpdate); _entityTracker.Update(message); _needInit = false; } _abnormalityStorage.EndAll(message.Time.Ticks); _abnormalityTracker = new AbnormalityTracker(_entityTracker, _playerTracker, _teraData.HotDotDatabase, _abnormalityStorage, CheckUpdate); return; } var cVersion = message as C_CHECK_VERSION; if (cVersion != null) { var opCodeNamer = new OpCodeNamer(Path.Combine(BasicTeraData.ResourceDirectory, $"opcodes/{cVersion.Versions[0]}.txt")); _messageFactory = new MessageFactory(opCodeNamer, Server.Region); return; } }
private void HandleNewConnection(Server server) { Text = $"Damage Meter connected to {server.Name}"; _server = server; _teraData = BasicTeraData.DataForRegion(server.Region); _entityRegistry = new EntityTracker(); _playerTracker = new PlayerTracker(_entityRegistry); _damageTracker = new DamageTracker(_entityRegistry, _playerTracker, _teraData.SkillDatabase); _messageFactory = new MessageFactory(_teraData.OpCodeNamer); }
void _teraSniffer_NewConnection(Server server) { InvokeAction(() => { var header = new LogHeader { Region = server.Region }; _logWriter = new PacketLogWriter(string.Format("{0}.TeraLog", DateTime.Now.ToString("yyyy-MM-dd HH-mm-ss", CultureInfo.InvariantCulture)), header); ConnectionList.Items.Clear(); ConnectionList.Items.Add(string.Format("New connection to {0}started...", server.Name)); _teraData = _basicTeraData.DataForRegion(server.Region); }); }
public static void ExcelSave(ExportType exportType, EncounterBase data, TeraData teraData) { if ((exportType & (ExportType.Excel | ExportType.ExcelTemp)) == 0) return; lock (Savelock) //can't save 2 excel files at one time { NpcInfo boss = teraData.NpcDatabase.GetOrPlaceholder(ushort.Parse(data.areaId), uint.Parse(data.bossId)); var dir = Path.Combine( exportType.HasFlag(ExportType.Excel)//if regular export, save in documents, otherwise temp ? SettingsHelper.Instance.GetDocumentsPath() : SettingsHelper.Instance.GetTempFolderPath(), $"exports/{boss.Area.Replace(":", "-")}"); Directory.CreateDirectory(dir); var fname = Path.Combine(dir, $"{boss.Name.Replace(":", "-")} {DateTimeTools.UnixTimeStampToDateTime(data.encounterUnixEpoch).ToString("yyyy-MM-dd HH-mm-ss", CultureInfo.InvariantCulture)}.xlsx"); FileInfo file = new FileInfo(fname); if (!file.Exists) { using (ExcelPackage package = new ExcelPackage(file)) { ExcelWorksheet ws = package.Workbook.Worksheets.Add("Boss"); var linkStyle = package.Workbook.Styles.CreateNamedStyle("HyperLink"); //This one is language dependent linkStyle.Style.Font.UnderLine = true; linkStyle.Style.Font.Color.SetColor(Color.Blue); ws.DefaultRowHeight = 30; ws.Cells.Style.Font.Size = 14; ws.Cells.Style.Font.Name = "Arial"; ws.Cells[1, 1].Value = $"{boss.Area}: {boss.Name} {TimeSpan.FromSeconds(double.Parse(data.fightDuration)).ToString(@"mm\:ss")}"; ws.Cells[1, 1, 1, 6].Merge = true; ws.Cells[1, 1, 1, 8].Style.Font.Bold = true; ws.Cells[1, 7].Value = long.Parse(data.partyDps); ws.Cells[1, 7].Style.Numberformat.Format = @"#,#00,\k\/\s"; ws.Cells[2, 1].Value = "Ic"; ws.Cells[2, 1].Style.Font.Color.SetColor(Color.Transparent); ws.Cells[2, 2].Value = "Name"; ws.Cells[2, 3].Value = "Deaths"; ws.Cells[2, 4].Value = "Death time"; ws.Cells[2, 5].Value = "Damage %"; ws.Cells[2, 6].Value = "Crit %"; ws.Cells[2, 7].Value = "DPS"; ws.Cells[2, 8].Value = "Damage"; int i = 2; foreach (var user in data.members.OrderByDescending(x => long.Parse(x.playerTotalDamage))) { i++; ws.Cells[i, 1].Value = i - 2; AddImage(ws, i, 1, Invert( new Bitmap( SettingsHelper.Instance.GetImage( (PlayerClass) Enum.Parse(typeof (PlayerClass), user.playerClass))))); ws.Cells[i, 2].Value = $"{user.playerServer}: {user.playerName}"; ws.Cells[i, 2].Hyperlink = CreateUserSheet(package.Workbook, user, teraData); ws.Cells[i, 3].Value = long.Parse(user.playerDeaths); ws.Cells[i, 4].Value = long.Parse(user.playerDeathDuration); ws.Cells[i, 4].Style.Numberformat.Format = @"0\s"; ws.Cells[i, 5].Value = double.Parse(user.playerTotalDamagePercentage)/100; ws.Cells[i, 5].Style.Numberformat.Format = "0.0%"; ws.Cells[i, 6].Value = double.Parse(user.playerAverageCritRate)/100; ws.Cells[i, 6].Style.Numberformat.Format = "0.0%"; ws.Cells[i, 7].Value = long.Parse(user.playerDps); ws.Cells[i, 7].Style.Numberformat.Format = @"#,#0,\k\/\s"; ws.Cells[i, 8].Value = long.Parse(user.playerTotalDamage); ws.Cells[i, 8].Style.Numberformat.Format = @"#,#0,\k"; } ws.Cells[1, 8].Formula = $"SUM(H3:H{i})"; ws.Cells[1, 8].Style.Numberformat.Format = @"#,#0,\k"; var border = ws.Cells[1, 1, i, 8].Style.Border; border.Bottom.Style = border.Top.Style = border.Left.Style = border.Right.Style = ExcelBorderStyle.Thick; ws.Cells[2, 1, i, 8].AutoFilter = true; int j = i + 3; ws.Cells[j, 1].Value = "Ic"; ws.Cells[j, 1].Style.Font.Color.SetColor(Color.Transparent); ws.Cells[j, 2].Value = "Debuff name"; ws.Cells[j, 2, j, 7].Merge = true; ws.Cells[j, 8].Value = "%"; ws.Cells[j, 2, j, 8].Style.Font.Bold = true; foreach (var buf in data.debuffUptime) { j++; var hotdot = teraData.HotDotDatabase.Get(int.Parse(buf.Key)); ws.Cells[j, 1].Value = j - i - 3; AddImage(ws, j, 1, BTD.Icons.GetBitmap(hotdot.IconName)); ws.Cells[j, 2].Value = hotdot.Name; if (!string.IsNullOrEmpty(hotdot.Tooltip)) ws.Cells[j, 2].AddComment("" + hotdot.Tooltip, "info"); ws.Cells[j, 2, j, 7].Merge = true; ws.Cells[j, 8].Value = double.Parse(buf.Value)/100; ws.Cells[j, 8].Style.Numberformat.Format = "0%"; } border = ws.Cells[i + 3, 1, j, 8].Style.Border; border.Bottom.Style = border.Top.Style = border.Left.Style = border.Right.Style = ExcelBorderStyle.Thick; ws.Column(1).Width = 5.6; ws.Column(2).AutoFit(); ws.Column(3).AutoFit(); ws.Column(4).AutoFit(); ws.Column(5).AutoFit(); ws.Column(6).AutoFit(); ws.Column(7).AutoFit(); ws.Column(8).Width = 17; ws.Column(2).Width = GetTrueColumnWidth(ws.Column(2).Width); ws.Column(3).Width = GetTrueColumnWidth(ws.Column(3).Width); ws.Column(4).Width = GetTrueColumnWidth(ws.Column(4).Width); ws.Column(5).Width = GetTrueColumnWidth(ws.Column(5).Width); ws.Column(6).Width = GetTrueColumnWidth(ws.Column(6).Width); ws.Column(7).Width = GetTrueColumnWidth(ws.Column(7).Width); ws.Cells[1, 1, j, 8].Style.VerticalAlignment = ExcelVerticalAlignment.Center; ws.Cells[1, 1, j, 8].Style.HorizontalAlignment = ExcelHorizontalAlignment.Center; ws.PrinterSettings.FitToPage = true; package.Workbook.Properties.Title = boss.Name; package.Workbook.Properties.Author = "CasualMeter"; package.Workbook.Properties.Company = "github.com/lunyx github.com/Gl0 github.com/neowutran"; package.Save(); } } if (exportType == ExportType.ExcelTemp && File.Exists(fname)) Process.Start(fname); } }
private static ExcelHyperLink CreateUserSheet(ExcelWorkbook wb, Members user, TeraData teraData) { ExcelWorksheet ws = wb.Worksheets.Add($"{user.playerServer}_{user.playerName}"); var rgc = new RaceGenderClass("Common", "Common", user.playerClass); ws.DefaultRowHeight = 30; ws.Cells.Style.Font.Size = 14; ws.Cells.Style.Font.Name = "Arial"; AddImage(ws, 1, 1, Invert(new Bitmap(SettingsHelper.Instance.GetImage((PlayerClass)Enum.Parse(typeof(PlayerClass), user.playerClass))))); ws.Cells[1, 2].Value = $"{user.playerServer}: {user.playerName}"; ws.Cells[1, 2, 1, 10].Merge = true; ws.Cells[1, 2, 1, 10].Style.Font.Bold = true; ws.Cells[2, 2].Value = "Skill"; ws.Cells[2, 3].Value = "Damage %"; ws.Cells[2, 4].Value = "Damage"; ws.Cells[2, 5].Value = "Crit %"; ws.Cells[2, 6].Value = "Hits"; ws.Cells[2, 7].Value = "Max Crit"; ws.Cells[2, 8].Value = "Min Crit"; ws.Cells[2, 9].Value = "Avg Crit"; ws.Cells[2, 10].Value = "Avg White"; int i = 2; foreach (var stat in user.skillLog.OrderByDescending(x => long.Parse(x.skillTotalDamage))) { i++; var skill = teraData.SkillDatabase.GetOrNull(rgc, int.Parse(stat.skillId)); if (skill == null) { ws.Cells[i, 1].Value = i-2; ws.Cells[i, 2].Value = "Some pet skill"; } else { ws.Cells[i, 1].Value = i - 2; AddImage(ws, i, 1, BTD.Icons.GetBitmap(skill.IconName)); ws.Cells[i, 2].Value = skill.Name; } ws.Cells[i, 3].Value = double.Parse(stat.skillDamagePercent) / 100; ws.Cells[i, 3].Style.Numberformat.Format = "0.0%"; ws.Cells[i, 4].Value = long.Parse(stat.skillTotalDamage); ws.Cells[i, 4].Style.Numberformat.Format = @"#,#0,\k"; ws.Cells[i, 5].Value = double.Parse(stat.skillCritRate) / 100; ws.Cells[i, 5].Style.Numberformat.Format = "0.0%"; ws.Cells[i, 6].Value = long.Parse(stat.skillHits); ws.Cells[i, 7].Value = long.Parse(stat.skillHighestCrit); ws.Cells[i, 7].Style.Numberformat.Format = @"#,#0,\k"; ws.Cells[i, 8].Value = long.Parse(stat.skillLowestCrit); ws.Cells[i, 8].Style.Numberformat.Format = @"#,#0,\k"; ws.Cells[i, 9].Value = long.Parse(stat.skillAverageCrit); ws.Cells[i, 9].Style.Numberformat.Format = @"#,#0,\k"; ws.Cells[i, 10].Value = long.Parse(stat.skillAverageWhite); ws.Cells[i, 10].Style.Numberformat.Format = @"#,#0,\k"; } var border = ws.Cells[1, 1, i, 10].Style.Border; border.Bottom.Style = border.Top.Style = border.Left.Style = border.Right.Style = ExcelBorderStyle.Thick; ws.Cells[2, 1, i, 10].AutoFilter = true; int j = i + 3; ws.Cells[j, 2].Value = "Buff name"; ws.Cells[j, 2, j, 9].Merge = true; ws.Cells[j, 10].Value = "%"; ws.Cells[j, 2, j, 10].Style.Font.Bold = true; foreach (var buf in user.buffUptime) { j++; var hotdot = teraData.HotDotDatabase.Get(int.Parse(buf.Key)); ws.Cells[j, 1].Value = j - i - 3; AddImage(ws, j, 1, BTD.Icons.GetBitmap(hotdot.IconName)); ws.Cells[j, 2].Value = hotdot.Name; if (!string.IsNullOrEmpty(hotdot.Tooltip)) ws.Cells[j, 2].AddComment("" + hotdot.Tooltip, "info"); ws.Cells[j, 2, j, 9].Merge = true; ws.Cells[j, 10].Value = double.Parse(buf.Value) / 100; ws.Cells[j, 10].Style.Numberformat.Format = "0%"; if (!string.IsNullOrEmpty(hotdot.ItemName)) ws.Cells[j, 10].AddComment("" + hotdot.ItemName, "info"); } border = ws.Cells[i + 3, 1, j, 10].Style.Border; border.Bottom.Style = border.Top.Style = border.Left.Style = border.Right.Style = ExcelBorderStyle.Thick; ws.Column(1).Width = 5.6; ws.Column(2).AutoFit(); ws.Column(3).AutoFit(); ws.Column(4).AutoFit(); ws.Column(5).AutoFit(); ws.Column(6).AutoFit(); ws.Column(7).AutoFit(); ws.Column(8).AutoFit(); ws.Column(9).AutoFit(); ws.Column(10).AutoFit(); ws.Column(2).Width = GetTrueColumnWidth(ws.Column(2).Width); ws.Column(3).Width = GetTrueColumnWidth(ws.Column(3).Width); ws.Column(4).Width = GetTrueColumnWidth(ws.Column(4).Width); ws.Column(5).Width = GetTrueColumnWidth(ws.Column(5).Width); ws.Column(6).Width = GetTrueColumnWidth(ws.Column(6).Width); ws.Column(7).Width = GetTrueColumnWidth(ws.Column(7).Width); ws.Column(8).Width = GetTrueColumnWidth(ws.Column(8).Width); ws.Column(9).Width = GetTrueColumnWidth(ws.Column(9).Width); ws.Column(10).Width = GetTrueColumnWidth(ws.Column(10).Width); ws.Cells[1, 1, j, 10].Style.VerticalAlignment = ExcelVerticalAlignment.Center; ws.Cells[1, 1, j, 10].Style.HorizontalAlignment = ExcelHorizontalAlignment.Center; ws.PrinterSettings.FitToPage = true; return new ExcelHyperLink($"'{user.playerServer}_{user.playerName}'!A1", $"{user.playerServer}: {user.playerName}"); }
public static void ToTeraDpsApi(ExportType exportType, DamageTracker damageTracker, TeraData teraData) { if (exportType == ExportType.None) return; //if we want to upload, primary target must be dead if (exportType.HasFlag(ExportType.Upload) && !damageTracker.IsPrimaryTargetDead) return; var exportToExcel = (exportType & (ExportType.Excel | ExportType.ExcelTemp)) != 0; //if we're not exporting to excel and credentials aren't fully entered, return //if (!exportToExcel // && (string.IsNullOrEmpty(SettingsHelper.Instance.Settings.TeraDpsToken) // || string.IsNullOrEmpty(SettingsHelper.Instance.Settings.TeraDpsUser))) // return; //ignore if not a boss var entity = damageTracker.PrimaryTarget; if (!(entity?.Info.Boss ?? false)) return; var abnormals = damageTracker.Abnormals; bool timedEncounter = false; //Nightmare desolarus if (entity.Info.HuntingZoneId == 759 && entity.Info.TemplateId == 1003) { timedEncounter = true; } var firstHit = damageTracker.StatsByUser.SelectMany(x => x.SkillLog).Where(x => x.Target == entity).Min(x => x.Time as DateTime?) ?? new DateTime(0); var lastHit = damageTracker.StatsByUser.SelectMany(x => x.SkillLog).Where(x => x.Target == entity).Max(x => x.Time as DateTime?) ?? new DateTime(0); var firstTick = firstHit.Ticks; var lastTick = lastHit.Ticks; var interval = lastTick - firstTick; var seconds = interval/TimeSpan.TicksPerSecond; if (seconds == 0) return; long totaldamage; if (timedEncounter) totaldamage = damageTracker.StatsByUser.SelectMany(x => x.SkillLog) .Where(x => x.Time >= firstHit && x.Time <= lastHit) .Sum(x => x.Damage); else totaldamage = damageTracker.StatsByUser.SelectMany(x => x.SkillLog) .Where(x => x.Target == entity) .Sum(x => x.Damage); var partyDps = TimeSpan.TicksPerSecond * totaldamage / interval; var teradpsData = new EncounterBase { encounterUnixEpoch = DateTimeTools.DateTimeToUnixTimestamp(damageTracker.LastAttack?.ToUniversalTime() ?? DateTime.UtcNow), areaId = entity.Info.HuntingZoneId + "", bossId = entity.Info.TemplateId + "", fightDuration = seconds + "", partyDps = partyDps + "" }; foreach (var debuff in abnormals.Get(entity).OrderByDescending(x=>x.Value.Duration(firstTick, lastTick))) { long percentage = debuff.Value.Duration(firstTick, lastTick) * 100 / interval; if(percentage == 0) { continue; } teradpsData.debuffUptime.Add(new KeyValuePair<string, string>( debuff.Key.Id+"", percentage+"" )); } foreach (var user in damageTracker.StatsByUser.OrderByDescending(x=>x.Dealt.Damage)) { var filteredSkillog = timedEncounter ? user.SkillLog.Where(x => x.Time >= firstHit && x.Time <= lastHit).ToList() : user.SkillLog.Where(x => x.Target == entity).ToList(); long damage=filteredSkillog.Sum(x => x.Damage); if (damage <= 0) continue; var teradpsUser = new Members(); teradpsUser.playerTotalDamage = damage + ""; var buffs = abnormals.Get(user.Player); teradpsUser.playerClass = user.Class.ToString(); teradpsUser.playerName = user.Name; teradpsUser.playerServer = SettingsHelper.Instance.BasicTeraData.Servers.GetServerName(user.Player.ServerId); teradpsUser.playerAverageCritRate = Math.Round(100 * (double)filteredSkillog.Count(x => x.IsCritical && x.Damage > 0) / filteredSkillog.Count(x => x.Damage > 0)) + ""; teradpsUser.healCrit = user.Player.IsHealer ? Math.Round(100 * (double)filteredSkillog.Count(x => x.IsCritical && x.Heal > 0) / filteredSkillog.Count(x => x.Heal > 0)) + "" : null; teradpsUser.playerDps = TimeSpan.TicksPerSecond * damage / interval + ""; teradpsUser.playerTotalDamagePercentage = damage * 100 / totaldamage + ""; var death = buffs.Death; teradpsUser.playerDeaths = death.Count(firstTick, lastTick) + ""; teradpsUser.playerDeathDuration = death.Duration(firstTick, lastTick)/TimeSpan.TicksPerSecond + ""; var aggro = buffs.Aggro(entity); teradpsUser.aggro = 100 * aggro.Duration(firstTick, lastTick) / interval + ""; foreach (var buff in buffs.Times.OrderByDescending(x => x.Value.Duration(firstTick, lastTick))) { long percentage = (buff.Value.Duration(firstTick, lastTick) * 100 / interval); if (percentage == 0) { continue; } teradpsUser.buffUptime.Add(new KeyValuePair<string, string>( buff.Key.Id + "", percentage + "" )); } var aggregated = new List<AggregatedSkillResult>(); var collection = new List<SkillResult>(); foreach (var skill in filteredSkillog) { collection.Add(skill); if (aggregated.All(asr => !skill.IsSameSkillAs(asr))) aggregated.Add(new AggregatedSkillResult(skill.SkillShortName, skill.IsHeal, AggregationType.Name, CollectionHelper.Instance.CreateSyncedCollection(collection))); } foreach (var skill in aggregated.OrderByDescending(x=>x.Damage)) { var skillLog = new SkillLog(); var skilldamage = skill.Damage; if (skilldamage == 0) continue; skillLog.skillAverageCrit = skill.AverageCrit + ""; skillLog.skillAverageWhite = skill.AverageWhite + ""; skillLog.skillCritRate = Math.Round(skill.CritRate * 100) + ""; skillLog.skillDamagePercent = Math.Round(skill.DamagePercent * 100) + ""; skillLog.skillHighestCrit = skill.HighestCrit + ""; skillLog.skillHits = skill.Hits + ""; skillLog.skillId = teraData.SkillDatabase.GetSkillByPetName(skill.NpcInfo?.Name,user.Player.RaceGenderClass)?.Id.ToString() ?? skill.SkillId.ToString(); skillLog.skillLowestCrit = skill.LowestCrit + ""; skillLog.skillTotalDamage = skilldamage + ""; teradpsUser.skillLog.Add(skillLog); } teradpsData.members.Add(teradpsUser); } //export to excel if specified if (exportToExcel) Task.Run(() => ExcelExport.ExcelSave(exportType, teradpsData, teraData)); //return if we don't need to upload if (!exportType.HasFlag(ExportType.Upload)) return; /* Validation, without that, the server cpu will be burning \o */ var areaId = int.Parse(teradpsData.areaId); if ( //areaId != 886 && //areaId != 467 && //areaId != 767 && //areaId != 768 && //areaId != 468 && areaId != 770 && areaId != 769 && areaId != 916 && areaId != 969 && areaId != 970 && areaId != 950 ) { return; } //if (int.Parse(teradpsData.partyDps) < 2000000 && areaId != 468) //{ // return; //} try { using (var client = new HttpClient()) { client.Timeout = TimeSpan.FromSeconds(40); var response = client.GetAsync("http://moongourd.com/shared/servertime"); var timediff = (response.Result.Headers.Date.Value.UtcDateTime.Ticks - DateTime.UtcNow.Ticks) / TimeSpan.TicksPerSecond; teradpsData.encounterUnixEpoch += timediff; } } catch (Exception e) { Debug.WriteLine("Get server time error"); return; } var json = JsonConvert.SerializeObject(teradpsData, new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore }); Task.Run(() => Send(entity, json, 3)); }