public static void Uninitialize() { try { if (_thread != null) { _stopThread = true; for (int i = 0; i < 10; i++) { if (_thread.ThreadState == System.Threading.ThreadState.Stopped) { break; } System.Threading.Thread.Sleep(50); Application.DoEvents(); } if (_thread.ThreadState != System.Threading.ThreadState.Stopped) { _thread.Abort(); } _thread = null; } } catch (Exception ex) { BNS_ACT_Plugin.LogParserMessage("Error [BNS_Log.Uninitialize] " + ex.ToString().Replace(Environment.NewLine, " ")); } }
public static void Initialize() { _stopThread = false; try { _thread = new Thread(new ThreadStart(Scan)); string folderName = Path.Combine(Advanced_Combat_Tracker.ActGlobals.oFormActMain.AppDataFolder.FullName, @"BNSLogs\"); if (!Directory.Exists(folderName)) { Directory.CreateDirectory(folderName); } _logFileName = Path.Combine(folderName, "combatlog_" + DateTime.Now.ToString("yyyy-MM-dd") + ".log"); File.AppendAllText(_logFileName, null); // update filename in ACT Advanced_Combat_Tracker.ActGlobals.oFormActMain.LogFilePath = _logFileName; Advanced_Combat_Tracker.ActGlobals.oFormActMain.OpenLog(false, false); // GetCurrentZone flag means it will scan for the zone regex in the log file. _thread.Start(); } catch (Exception ex) { BNS_ACT_Plugin.LogParserMessage("Error [BNS_Log.Initialize] " + ex.ToString().Replace(Environment.NewLine, " ")); _stopThread = true; } }
public static DateTime ParseLogDateTime(string message) { DateTime ret = DateTime.MinValue; if (_ACT == null) { throw new ApplicationException("ACT Wrapper not initialized."); } try { if (message == null) { return(ret); } if (message.IndexOf('|') > 0) { if (!DateTime.TryParse(message.Substring(0, message.IndexOf('|')), out ret)) { return(DateTime.MinValue); } } else if (message.IndexOf(' ') > 5) { if (!DateTime.TryParse(message.Substring(0, message.IndexOf(' ')), out ret)) { return(DateTime.MinValue); } } } catch (Exception ex) { BNS_ACT_Plugin.LogParserMessage("Error [ParseLogDateTime] " + ex.ToString().Replace(Environment.NewLine, " ")); } return(ret); }
public static void BeforeLogLineRead(bool isImport, Advanced_Combat_Tracker.LogLineEventArgs logInfo) { string logLine = logInfo.logLine; if (_ACT == null) { throw new ApplicationException("ACT Wrapper not initialized."); } try { // parse datetime DateTime timestamp = ParseLogDateTime(logLine); int chatLogType = 0; if (logLine.IndexOf('|') > 5) { logLine = logLine.Substring(logLine.IndexOf('|') + 1); if (logLine.IndexOf('|') > 0) { chatLogType = Convert.ToInt32(logLine.Substring(0, logLine.IndexOf('|')), 16); logLine = logLine.Substring(logLine.IndexOf('|') + 1); } } else if (logLine.IndexOf(' ') > 5) { logLine = logLine.Substring(logLine.IndexOf(' ')); } // reformat logline logInfo.logLine = "[" + timestamp.ToString("HH:mm:ss.fff") + "] " + logLine; // timestamp = DateTime.ParseExact(logLine.Substring(1, logLine.IndexOf(']') - 1), "HH:mm:ss.fff", System.Globalization.CultureInfo.InvariantCulture); // Exclude certain chat codes if (chatLogType == 0x0c) // 0x0c = NPC talking, not parsed. { return; } Match m; m = regex_yourdamage.Match(logLine); if (m.Success) { string actor = "You"; string target = m.Groups["target"].Success ? DecodeString(m.Groups["target"].Value) : ""; string damage = (m.Groups["damage"].Value ?? "").Replace(",", ""); string hpdrain = (m.Groups["HPDrain"].Value ?? "").Replace(",", ""); if (_ACT.SetEncounter(timestamp, actor, target)) { _ACT.AddCombatAction( (int)Advanced_Combat_Tracker.SwingTypeEnum.NonMelee, m.Groups["critical"].Value == "critically hit", "", actor, DecodeString(m.Groups["skill"].Value), new Advanced_Combat_Tracker.Dnum(int.Parse(damage)), timestamp, _ACT.GlobalTimeSorter, target, ""); if (m.Groups["HPDrain"].Success) { _ACT.AddCombatAction( (int)Advanced_Combat_Tracker.SwingTypeEnum.Healing, false, "Drain", actor, DecodeString(m.Groups["skill"].Value), new Advanced_Combat_Tracker.Dnum(int.Parse(hpdrain)), timestamp, _ACT.GlobalTimeSorter, actor, ""); } } return; } m = regex_incomingdamage1.Match(logLine); if (!m.Success) { m = regex_incomingdamage2.Match(logLine); } if (!m.Success) { m = regex_incomingdamage3.Match(logLine); } if (m.Success) { string target = m.Groups["target"].Success ? DecodeString(m.Groups["target"].Value) : ""; string actor = m.Groups["actor"].Success ? DecodeString(m.Groups["actor"].Value) : ""; string skill = m.Groups["skill"].Success ? DecodeString(m.Groups["skill"].Value) : ""; string damage = (m.Groups["damage"].Value ?? "").Replace(",", ""); string hpdrain = (m.Groups["HPDrain"].Value ?? "").Replace(",", ""); // if skillname is blank, the skillname and actor may be transposed if (string.IsNullOrWhiteSpace(skill)) { if (!string.IsNullOrWhiteSpace(actor)) { // "Received 1373 damage from Rising Blaze's ." skill = actor; } } if (string.IsNullOrWhiteSpace(target)) { target = "You"; } if (string.IsNullOrWhiteSpace(actor)) { actor = "You"; } // todo: in the future, if damage is missing, still parse the buff portion if (!m.Groups["damage"].Success) { return; } if (_ACT.SetEncounter(timestamp, actor, target)) { _ACT.AddCombatAction( (int)Advanced_Combat_Tracker.SwingTypeEnum.NonMelee, m.Groups["critical"].Value == "Critical", "", actor, skill, new Advanced_Combat_Tracker.Dnum(int.Parse(damage)), timestamp, _ACT.GlobalTimeSorter, target, ""); if (m.Groups["HPDrain"].Success) { _ACT.AddCombatAction( (int)Advanced_Combat_Tracker.SwingTypeEnum.Healing, false, "Drain", actor, skill, new Advanced_Combat_Tracker.Dnum(int.Parse(hpdrain)), timestamp, _ACT.GlobalTimeSorter, actor, ""); } } return; } m = regex_heal.Match(logLine); if (m.Success) { string target = m.Groups["target"].Success ? DecodeString(m.Groups["target"].Value) : ""; if (string.IsNullOrWhiteSpace(target)) { target = "You"; } string actor = "Unknown"; // do not process if there is no HP amount. if (!m.Groups["HPAmount"].Success) { return; } string hpamount = (m.Groups["HPAmount"].Value ?? "").Replace(",", ""); if (_ACT.SetEncounter(timestamp, actor, target)) { _ACT.AddCombatAction( (int)Advanced_Combat_Tracker.SwingTypeEnum.Healing, false, "", actor, DecodeString(m.Groups["skill"].Value), new Advanced_Combat_Tracker.Dnum(int.Parse(hpamount)), timestamp, _ACT.GlobalTimeSorter, target, ""); } return; } m = regex_debuff2.Match(logLine); if (m.Success) { // todo: add debuff support return; } m = regex_debuff.Match(logLine); if (m.Success) { // todo: add debuff support return; } m = regex_buff.Match(logLine); if (m.Success) { // todo: add buff support return; } m = regex_evade.Match(logLine); if (m.Success) { // todo: add evade support return; } m = regex_defeat.Match(logLine); if (m.Success) { string target = m.Groups["target"].Success ? DecodeString(m.Groups["target"].Value) : ""; string actor = m.Groups["actor"].Success ? DecodeString(m.Groups["actor"].Value) : ""; if (string.IsNullOrWhiteSpace(actor)) { actor = "Unknown"; } if (_ACT.SetEncounter(timestamp, actor, target)) { _ACT.AddCombatAction( (int)Advanced_Combat_Tracker.SwingTypeEnum.NonMelee, false, "", actor, DecodeString(m.Groups["skill"].Value), Advanced_Combat_Tracker.Dnum.Death, timestamp, _ACT.GlobalTimeSorter, target, ""); } return; } } catch (Exception ex) { string exception = ex.ToString().Replace(Environment.NewLine, " "); if (ex.InnerException != null) { exception += " " + ex.InnerException.ToString().Replace(Environment.NewLine, " "); } BNS_ACT_Plugin.LogParserMessage("Error [LogParse.BeforeLogLineRead] " + exception + " " + logInfo.logLine); } // For debugging if (!string.IsNullOrWhiteSpace(logLine)) { BNS_ACT_Plugin.LogParserMessage("Unhandled Line: " + logInfo.logLine); } }
private static void Scan() { Process process = null; IntPtr baseAddress = IntPtr.Zero; IntPtr chatlogPointer = IntPtr.Zero; DateTime lastPointerUpdate = DateTime.MinValue; int lastLine = -1; while (!_stopThread) { System.Threading.Thread.Sleep(10); try { // update process and pointer every 10 seconds if (process == null || DateTime.Now.Subtract(lastPointerUpdate).TotalSeconds > 10.0) { Process[] processList = Process.GetProcessesByName("Client"); if (processList != null && processList.Length > 0) { process = processList[0]; try { _is64Bit = NativeMethods.Is64Bit(process); } catch (Win32Exception ex) { BNS_ACT_Plugin.LogParserMessage("Error [BNS_Log.Scan] failed to detect client CPU architecture: " + ex.ToString().Replace(Environment.NewLine, " ")); } } else { continue; } // todo: validate process // cache base address if it is missing if (baseAddress == IntPtr.Zero) { baseAddress = process.MainModule.BaseAddress; } // cache chatlog pointer tree chatlogPointer = ReadIntPtr(process.Handle, IntPtr.Add(baseAddress, chatlogOffset)); chatlogPointer = ReadIntPtr(process.Handle, IntPtr.Add(chatlogPointer, clientPtrSize * 0x14)); chatlogPointer = ReadIntPtr(process.Handle, IntPtr.Add(chatlogPointer, clientPtrSize * 0x34 + 0x488)); chatlogPointer = ReadIntPtr(process.Handle, IntPtr.Add(chatlogPointer, clientPtrSize * 0x1)); lastPointerUpdate = DateTime.Now; } if (process == null || baseAddress == IntPtr.Zero || chatlogPointer == IntPtr.Zero) { continue; } // read in the # of lines int lineCount = (int)ReadUInt32(process.Handle, IntPtr.Add(chatlogPointer, clientPtrSize * 0xE10 + 0x6720)); if (lineCount > 300) { throw new ApplicationException("line count too high: [" + lineCount.ToString() + "]."); } if (lineCount == lastLine) { continue; } // first scan - do not parse past data since we do not have timestamps if (lastLine == -1) { lastLine = lineCount; continue; } // check for wrap-around if (lineCount < lastLine) { lineCount += lastLine; } // assume average line length is 50 characters, preallocate stringbuilder StringBuilder buffer = new StringBuilder(50 * (lineCount - lastLine)); for (int i = lastLine + 1; i <= lineCount; i++) { // pointer to 'chat log line' structure which has std::string at offset 0x0 IntPtr linePointer = IntPtr.Add(chatlogPointer, (clientPtrSize * 0xC + 0x58) * (i % 300)); string chatLine = ReadStlString(process.Handle, linePointer); // offset 0x74 is chat code uint chatCode = ReadUInt32(process.Handle, IntPtr.Add(linePointer, clientPtrSize * 0xC + 0x44)); //for (int j = 0; j < 0x80; j+=4) //buffer.Append(BitConverter.ToUInt32(header, j).ToString("X8") + "|"); buffer.Append(DateTime.Now.ToString("HH:mm:ss.fff", System.Globalization.CultureInfo.InvariantCulture) + "|"); buffer.Append(chatCode.ToString("X2") + "|"); buffer.AppendLine(chatLine); } File.AppendAllText(_logFileName, buffer.ToString()); lastLine = lineCount % 300; } catch (Exception ex) { File.AppendAllText(_logFileName, DateTime.Now.ToString("HH:mm:ss.fff", System.Globalization.CultureInfo.InvariantCulture) + "|Error [BNS_Log.Scan] " + ex.ToString().Replace(Environment.NewLine, " ")); // do not exit scan thread, but pause so that the errors dont pile up. System.Threading.Thread.Sleep(1000); } } }