static void Main(string[] args) { // load spells to give the trackers more context when processing log files // this is optional and can be skipped Console.Error.WriteLine("Loading spells..."); var spells = new SpellParser(); spells.Load("d:/games/everquest/spells_us.txt"); // generate an open event that stores the player name, server name, and file path // all trackers should receive this as their first event to signal that a new log file is being processed var open = LogOpenEvent.FromFileName("d:/games/everquest/logs/eqlog_Rumstil_erollisi.txt"); // create a CharTracker to help the FightTracker determine friends/foes var chars = new CharTracker(spells); chars.Files = new FileService(Path.GetDirectoryName(open.Path) + @"\..\"); chars.HandleEvent(open); // create a FightTracker to build fight summaries from various combat events var fights = new FightTracker(spells, chars); fights.HandleEvent(open); fights.OnFightStarted += ShowFight; fights.OnFightFinished += ShowFight; // create a log parser for converting log lines into events that can be passed to the trackers var parser = new LogParser(); parser.Player = open.Player; //parser.MinDate = DateTime.MinValue; //parser.MinDate = DateTime.Today.AddDays(-1).ToUniversalTime(); var timer = Stopwatch.StartNew(); var reader = File.OpenText(open.Path); while (true) { var line = reader.ReadLine(); if (line == null) { break; } // pass line to the parser and convert to an event // lines that cannot be parsed will be returned as nulls var e = parser.ParseLine(line); if (e == null) { continue; } // pass event to the trackers chars.HandleEvent(e); fights.HandleEvent(e); //if (e is LogRawEvent) Console.WriteLine(e); } ; fights.ForceFightTimeouts(); Console.Error.WriteLine("Parse completed in {0}", timer.Elapsed); }
/// <summary> /// Start monitoring a log file from a background task. /// </summary> private async void WatchFile(string path) { if (!File.Exists(path)) { return; } if (String.IsNullOrEmpty(LogOpenEvent.GetPlayerFromFileName(path))) { LogInfo($"Cannot open {path} because it doesn't use the standard naming convention."); return; } // cancel previous log parsing task if (cancellationSource != null) { cancellationSource.Cancel(); await Task.Delay(600); } // always disable auto uploads when opening a file to avoid accidentally uploading a lot of data chkAutoUpload.Checked = chkAutoUpload.Enabled = false; // we don't know where to find the spell_us.txt file until we open a log file // spells should be one folder down from the log folder if (!spells.IsReady) { var spellpath = Path.GetDirectoryName(path) + @"\..\spells_us.txt"; if (File.Exists(spellpath)) { LogInfo("Loading " + spellpath); spells.Load(spellpath); if (!spells.IsReady) { LogInfo("spells_us.txt could not be loaded. Class detection and buff tracking will not work properly."); } } else { LogInfo("spells_us.txt not found. Class detection and buff tracking will not work properly."); } } config.Write("filename", path); LogInfo("Loading " + path); var open = LogOpenEvent.FromFileName(path); var parser = new LogParser(); parser.Player = open.Player; // reset the trackers by creating new ones var charTracker = new CharTracker(spells); charTracker.Files = new FileService(Path.GetDirectoryName(path) + @"\..\"); charTracker.HandleEvent(open); charTracker.ImportPlayers(config.Read("chars:" + open.Server)); var fightTracker = new FightTracker(spells, charTracker); fightTracker.OnFightFinished += x => fightsQueue.Enqueue(x); fightTracker.AddTemplateFromResource(); fightTracker.HandleEvent(open); var lootTracker = new LootTracker(); lootTracker.OnLoot += x => lootQueue.Enqueue(x); lootTracker.HandleEvent(open); // reset UI lvFights.VirtualListSize = 0; fightList.Clear(); fightListSearchResults = null; toolStripStatusLabel1.Text = "-"; toolStripStatusLabel2.Text = "-"; // read roster files to assist player tracking if (!String.IsNullOrEmpty(open.Server)) { var files = new DirectoryInfo(Path.GetDirectoryName(path)).Parent .GetFiles("*_" + open.Server + "-*.txt") .Where(x => x.CreationTime > DateTime.Today.AddDays(-14)) .Take(20); var roster = RosterParser.Load(files); foreach (var who in roster) { charTracker.HandleEvent(who); } } // this handler runs in a background thread and must be threadsafe Action <string> handler = line => { var e = parser.ParseLine(line); if (e != null) { charTracker.HandleEvent(e); fightTracker.HandleEvent(e); lootTracker.HandleEvent(e); } }; // this event runs in the main app thread // https://stackoverflow.com/questions/661561/how-do-i-update-the-gui-from-another-thread/18033198#18033198 var progress = new Progress <LogReaderStatus>(p => { toolStripStatusLabel1.Text = p.Percent.ToString("P0") + " " + p.Notes; var completed = p.Percent > 0.99; chkAutoUpload.Enabled = completed; }); cancellationSource = new CancellationTokenSource(); var reader = new BackgroundLogReader(path, cancellationSource.Token, handler, progress); try { await reader.Start(); } catch (Exception ex) { LogInfo("Error: " + ex.Message); LogInfo("Last Line: " + reader.LastLine); } //LogInfo("Closing " + path); // this log message can occur after the form has been disposed if (open.Server != null) { // save a list of players so that we have better information next time we run the parser var players = charTracker.ExportPlayers(); config.Write("chars:" + open.Server, players); } //await ProcessLogFileAsync(path); }