private static void MeasureTimes(string filename, EVTCParser parser, LogProcessor processor, GW2ApiData apiData, TextWriter outputWriter) { var stopwatch = Stopwatch.StartNew(); var log = parser.ParseLog(filename); var parsedTime = stopwatch.Elapsed; stopwatch.Restart(); var processedLog = processor.ProcessLog(log); var processedTime = stopwatch.Elapsed; stopwatch.Restart(); var analyzer = new LogAnalyzer(processedLog, apiData); var result = analyzer.GetResult(); var duration = analyzer.GetEncounterDuration(); var mode = analyzer.GetMode(); var statisticsTime = stopwatch.Elapsed; var totalTime = parsedTime + processedTime + statisticsTime; outputWriter.WriteLine( $"{filename},{parsedTime.TotalMilliseconds},{processedTime.TotalMilliseconds},{statisticsTime.TotalMilliseconds},{totalTime.TotalMilliseconds}"); outputWriter.Flush(); }
static void Main() { string filename = "example.zevtc"; var parser = new EVTCParser(); // Used to read a log file and get raw data out of it var processor = new LogProcessor(); // Used to process the raw data // The parsed log contains raw data from the EVTC file ParsedLog parsedLog = parser.ParseLog(filename); // The log after processing the raw data into structured events and agents. Log log = processor.ProcessLog(parsedLog); // At this point, we can do anything with the processed data, and use the LogAnalyzer // for easy access to most common results with caching. var analyzer = new LogAnalyzer(log); Encounter encounter = analyzer.GetEncounter(); // Encounter names are available for some languages, we use the target name if it's not. if (EncounterNames.TryGetEncounterNameForLanguage(GameLanguage.English, encounter, out string name)) { Console.WriteLine($"Encounter: {name}"); } else { Console.WriteLine($"Encounter: {log.MainTarget?.Name ?? "unknown target"}"); } Console.WriteLine($"Result: {analyzer.GetResult()}"); Console.WriteLine($"Mode: {analyzer.GetMode()}"); Console.WriteLine($"Duration: {analyzer.GetEncounterDuration()}"); // The processed log allows easy access to data about agents foreach (var player in log.Agents.OfType <Player>()) { Console.WriteLine($"{player.Name} - {player.AccountName} - {player.Profession} - {player.EliteSpecialization}"); } // Events may be accessed as well foreach (var deadEvent in log.Events.OfType <AgentDeadEvent>()) { if (deadEvent.Agent is Player player) { Console.WriteLine($"{player.Name} died at {deadEvent.Time}."); } } }
public CheckResult CheckLog(string filename) { try { var parser = new EVTCParser(); var processor = new LogProcessor(); var bytes = ReadLogFileBytes(filename); var parsedLog = parser.ParseLog(bytes); var log = processor.ProcessLog(parsedLog); var analyzer = new LogAnalyzer(log); var encounter = log.EncounterData.Encounter; var mode = analyzer.GetMode(); var result = analyzer.GetResult(); var players = analyzer.GetPlayers() .Select(p => new LogPlayer { CharacterName = p.Name, AccountName = p.AccountName, Profession = p.Profession, EliteSpecialization = p.EliteSpecialization, Subgroup = p.Subgroup }).ToList(); var duration = analyzer.GetEncounterDuration(); // This combination of builds resulted in logs that did not contain NPCs other than the main target. // There is not much of a point in checking these. // This outdated version of arcdps was commonly used for extended periods of time due to it being // the last version that had working arcdps build templates. if (log.EvtcVersion == "EVTC20191001" && (log.GameBuild ?? 0) >= 100565) { return(new CheckResult { Ignored = true, Correct = false, ProcessingFailed = false, Encounter = Result <Encounter> .UncheckedResult(encounter), Mode = Result <EncounterMode> .UncheckedResult(mode), Result = Result <EncounterResult> .UncheckedResult(result), Players = Result <List <LogPlayer> > .UncheckedResult(players), Duration = Result <TimeSpan> .UncheckedResult(duration) }); } var eiSettings = new EvtcParserSettings(false, false, true, false, false, 0); var eiParser = new EvtcParser(eiSettings, eiApiController); var eiLog = eiParser.ParseLog(new EIController(), new MemoryStream(bytes), out var eiFailureReason); if (eiLog == null) { eiFailureReason.Throw(); } var eiDuration = TimeSpan.FromMilliseconds(eiLog.FightData.FightEnd - eiLog.FightData.FightStart); var eiResult = eiLog.FightData.Success ? EncounterResult.Success : EncounterResult.Failure; var eiPlayers = eiLog.PlayerList .Where(p => p.Prof != "Sword") .Select(p => { Profession profession; if (Enum.TryParse(p.Prof, out EliteSpecialization specialization)) { profession = GameData.Characters.GetProfession(specialization); } else { specialization = EliteSpecialization.None; if (!Enum.TryParse(p.Prof, out profession)) { throw new Exception($"Unknown profession {p.Prof} found in Elite Insights data."); } } return(new LogPlayer { CharacterName = p.Character, // EI strips the leading : in account names, so we re-add it AccountName = $":{p.Account}", Profession = profession, EliteSpecialization = specialization, Subgroup = p.Group }); }).ToList(); var eiMode = eiLog.FightData.IsCM ? EncounterMode.Challenge : EncounterMode.Normal; // There is no reasonable way to compare EI and Analytics encounters var encounterResult = Result <Encounter> .UncheckedResult(encounter); var resultResult = CheckResult ? Result <EncounterResult> .CheckedResult(eiResult, result) : Result <EncounterResult> .UncheckedResult(result); var modeResult = CheckMode ? Result <EncounterMode> .CheckedResult(eiMode, mode) : Result <EncounterMode> .UncheckedResult(mode); var playerResult = CheckPlayers ? players.ToHashSet().SetEquals(eiPlayers) ? Result <List <LogPlayer> > .CorrectResult(players) : Result <List <LogPlayer> > .IncorrectResult(eiPlayers, players) : Result <List <LogPlayer> > .UncheckedResult(players); var durationResult = CheckDuration ? (eiDuration - duration) < DurationEpsilon ? Result <TimeSpan> .CorrectResult(duration) : Result <TimeSpan> .IncorrectResult(eiDuration, duration) : Result <TimeSpan> .UncheckedResult(duration); bool correct = encounterResult.Correct && resultResult.Correct && modeResult.Correct && playerResult.Correct && durationResult.Correct; return(new CheckResult { Correct = correct, ProcessingFailed = false, Encounter = encounterResult, Mode = modeResult, Result = resultResult, Players = playerResult, Duration = durationResult }); } catch (TooShortException) { return(new CheckResult { Ignored = true, Correct = false }); } catch (Exception e) { return(new CheckResult { Correct = false, ProcessingFailed = true, ProcessingException = e }); } }
public void SelectLog(string logFilename) { var statusStringBuilder = new StringBuilder(); var parser = new EVTCParser(); var processor = new LogProcessor() { IgnoreUnknownEvents = false }; // Parsing var sw = Stopwatch.StartNew(); ParsedLog parsedLog = null; try { parsedLog = parser.ParseLog(logFilename); var parseTime = sw.Elapsed; statusStringBuilder.AppendLine($"Parsed in {parseTime}"); Application.Instance.Invoke(() => { parsedAgents.Clear(); parsedAgents.AddRange(parsedLog.ParsedAgents); parsedAgents.Refresh(); parsedSkills.Clear(); parsedSkills.AddRange(parsedLog.ParsedSkills); parsedSkills.Refresh(); parsedCombatItems.Clear(); parsedCombatItems.AddRange(parsedLog.ParsedCombatItems); parsedCombatItems.Refresh(); }); } catch (Exception ex) { statusStringBuilder.AppendLine($"Parsing failed: {ex.Message}\n{ex.StackTrace}"); } // Processing Log processedLog = null; try { sw.Restart(); processedLog = processor.ProcessLog(parsedLog); var processTime = sw.Elapsed; statusStringBuilder.AppendLine($"Processed in {processTime}"); Application.Instance.Invoke(() => { eventList.Clear(); eventList.AddRange(processedLog.Events); eventListControl.Events = eventList; eventListControl.Agents = processedLog.Agents.ToArray(); agents.Clear(); agents.AddRange(new FilterCollection <Agent>(processedLog.Agents)); agents.Refresh(); agentControl.Events = processedLog.Events.ToArray(); }); } catch (Exception ex) { statusStringBuilder.AppendLine($"Processing failed: {ex.Message}\n{ex.StackTrace}"); } // Statistics Statistics stats = null; sw.Restart(); try { var analyzer = new LogAnalyzer(processedLog); stats = new Statistics(processedLog.StartTime.LocalTime, processedLog.PointOfView, analyzer.GetResult(), analyzer.GetMode(), analyzer.GetEncounter(), processedLog.EvtcVersion, analyzer.GetEncounterDuration()); var statsTime = sw.Elapsed; statusStringBuilder.AppendLine($"Statistics generated in {statsTime}"); Application.Instance.Invoke(() => { statisticsJsonControl.Object = stats; }); } catch (Exception ex) { statusStringBuilder.AppendLine($"Statistics generation failed: {ex.Message}\n{ex.StackTrace}"); } Application.Instance.Invoke(() => { statusStringBuilder.AppendLine( $"Build version: {parsedLog?.LogVersion?.BuildVersion}, revision {parsedLog?.LogVersion?.Revision}"); statusStringBuilder.AppendLine( $"Parsed: {parsedLog?.ParsedAgents?.Count} agents, {parsedLog?.ParsedSkills?.Count} skills, {parsedLog?.ParsedCombatItems?.Count} combat items."); statusStringBuilder.AppendLine( $"Processed: {processedLog?.Events?.Count} events, {processedLog?.Agents?.Count} agents."); parsedStateLabel.Text = statusStringBuilder.ToString(); }); }