/************************************************************************************/ protected override bool OnLogNarrative(ConsoleLogEventArgs NewArgs) { if (base.OnLogNarrative(NewArgs)) { return(true); } if (m_iLastChestDisarmAttempted != -1) { if (NewArgs.OriginalLine.StartsWith("You disarm the trap on") || NewArgs.OriginalLine.StartsWith("You failed to disarm the trap on") || NewArgs.OriginalLine.StartsWith("You trigger the trap on")) { if (m_NearbyChestDictionary.ContainsKey(m_iLastChestDisarmAttempted)) { m_NearbyChestDictionary[m_iLastChestDisarmAttempted] = true; } m_iLastChestDisarmAttempted = -1; Program.Log("Chest disarmed or triggered. Checking for others."); return(true); } } return(false); }
/************************************************************************************/ /// <summary> /// This is meant to get called by the parse thread. /// </summary> /// <param name="NewEvent"></param> public static void EnqueueLogEvent(ConsoleLogEventArgs NewEvent) { s_ChatEventQueue.Enqueue(NewEvent); return; }
/************************************************************************************/ public static void Run() { s_ParseThread.Start(); s_strSharedOverridesINIFilePath = Path.Combine(Program.ConfigurationFolderPath, "SharedOverrides.ini"); if (!File.Exists(s_strSharedOverridesINIFilePath)) { File.Create(s_strSharedOverridesINIFilePath).Close(); } string strPreviousSubClass = string.Empty; string strPreviousName = string.Empty; bool bFirstZoningFrame = true; bool bRunGarbageCollector = false; do { s_CurrentCycleTimestamp = DateTime.Now; /// Run this outside of the frame lock. if (bRunGarbageCollector) { Program.RunGarbageCollector(); bRunGarbageCollector = false; } Frame.Wait(true); try { /// Call the controller if we zone. During zoning, no game variables are assumed to be worth a damn. /// We go straight to a string check for now instead of the property (which uses <int> conversion) /// because the property has had a troubled past and returned buggy/invalid values. if (s_EQ2.GetMember <string>("Zoning") != "0") { if (bFirstZoningFrame) { Program.Log("Zoning..."); bFirstZoningFrame = false; ReleaseAllKeys(); s_RecentThrottledCommandCache.Clear(); if (s_Controller != null) { s_Controller.OnZoningBegin(); } bRunGarbageCollector = true; } continue; } else { if (!UpdateStaticGlobals()) { continue; } if (!bFirstZoningFrame) { Program.Log("Done zoning."); bFirstZoningFrame = true; if (s_Controller != null) { s_Controller.OnZoningComplete(); } ApplyGameSettings(); } } try { /// An amazing little thing I discovered while watching console spam. /// EQ2 will prefix your character name if you are watching a flythrough zone intro video. /// Pressing Escape kills it. if (Me.Group(0).Name.StartsWith("Flythrough_")) { Program.Log("Zone flythrough sequence detected, attempting to cancel with the Esc key..."); LavishScript.ExecuteCommand("press esc"); continue; } } catch { } /// Automatically accept a quest. if (s_Controller != null && !string.IsNullOrEmpty(s_EQ2.PendingQuestName) && s_EQ2.PendingQuestName != "None") { Program.Log("Quest offered: \"{0}\".", s_EQ2.PendingQuestName); if (s_Controller.m_ePositioningStance == PlayerController.PositioningStance.DoNothing) { Program.Log("Character is in do-nothing stance; ignoring offered quest."); } else { /// Stolen from "EQ2Quest.iss". The question I have: isn't AcceptPendingQuest() redundant then? /// eq2ui_popup_rewardpack.xml EQ2UIPage QuestPage = s_Extension.EQ2UIPage("Popup", "RewardPack"); if (QuestPage.IsValid) { EQ2UIElement QuestAcceptButton = QuestPage.Child("button", "RewardPack.Accept"); if (QuestAcceptButton.IsValid) { Program.Log("Automatically accepting quest \"{0}\"...", s_EQ2.PendingQuestName); s_EQ2.AcceptPendingQuest(); QuestAcceptButton.LeftClick(); } } } } unchecked { s_lFrameCount++; } /// Make sure the parse engine always knows the current character name. /// Unfortunately, there's no way to know the current language at this time. if (Name != strPreviousName) { s_ParseThread.PostNewNameLanguageMessage(Name, ChatEventArgs.GameLanguageType.Unknown); strPreviousName = Name; } /// If the subclass changes (startup, betrayal, etc), resync. /// The null check on SubClass is because it comes up as null when reviving. /// s_Controller is guaranteed to be non-null after this block (otherwise the program would have exited). /// TODO: State variables contained in the prior controller will be lost. Maybe make them static? if (!string.IsNullOrEmpty(Me.SubClass) && Me.SubClass != strPreviousSubClass) { Program.Log("New class found: \"{0}\"", Me.SubClass); strPreviousSubClass = Me.SubClass; s_bRefreshKnowledgeBook = true; switch (strPreviousSubClass.ToLower()) { case "coercer": s_Controller = new CoercerController(); break; case "defiler": s_Controller = new DefilerController(); break; case "dirge": s_Controller = new DirgeController(); break; case "fury": s_Controller = new FuryController(); break; case "illusionist": s_Controller = new IllusionistController(); break; case "inquisitor": s_Controller = new InquisitorController(); break; case "mystic": s_Controller = new MysticController(); break; case "templar": s_Controller = new TemplarController(); break; case "troubador": s_Controller = new TroubadorController(); break; case "warden": s_Controller = new WardenController(); break; case "warlock": s_Controller = new WarlockController(); break; case "wizard": s_Controller = new WizardController(); break; default: { Program.Log("Unrecognized or unsupported subclass type: {0}.", Me.SubClass); Program.Log("Will use generic controller without support for spells or combat arts."); s_Controller = new PlayerController(); break; } } /// Build the name of the INI file. string strFileName = string.Format("{0}.{1}.ini", ServerName, Name); s_strCurrentINIFilePath = Path.Combine(Program.ConfigurationFolderPath, strFileName); if (File.Exists(s_strCurrentINIFilePath)) { s_Controller.ReadINISettings(); } s_Controller.WriteINISettings(); SetWindowText(string.Format("{0} ({1})", Name, Me.SubClass)); ApplyGameSettings(); } /// If the size of the knowledge book changes, defer a resync. /// NOTE: If the user equips or unequips an ability-changing item, /// the ability table will be hosed but we'll have no way of knowing to force a refresh. if (s_Controller.AbilityCountChanged) { s_bRefreshKnowledgeBook = true; } /// Only if the knowledge book is intact can we safely assume that regular actions are OK. /// DoNextAction() might set s_bRefreshKnowledgeBook to true. This is fine. if (!s_bRefreshKnowledgeBook) { /// Handle all the log events that were generated by the parse thread so far. ConsoleLogEventArgs NewArgs = null; while (s_ChatEventQueue.Dequeue(ref NewArgs)) { if (NewArgs is ChatEventArgs) { s_Controller.OnLogChat(NewArgs as ChatEventArgs); } else { s_Controller.OnLogNarrative(NewArgs); } } s_Controller.DoNextAction(); s_Controller.UpdateEndOfRoundStatistics(); } /// Do certain checks only every 5th frame. if ((s_lFrameCount % 5) == 0) { /// Supposedly Process.VirtualMemorySize64 can return negative values because of casting bugs. Process CurrentProcess = Process.GetCurrentProcess(); long lActualVirtualAllocation = CurrentProcess.VirtualMemorySize64; if (lActualVirtualAllocation > (long)s_Controller.m_ulVirtualAllocationProcessTerminationThreshold && lActualVirtualAllocation < (long)(4 * CustomFormatter.GB)) /// This check is to prevent impossible values from causing crashes. { /// GAME OVER. using (StreamWriter OutputFile = Program.OpenCrashLog()) OutputFile.WriteLine("Process terminating immediately: current virtual allocation is {0}.", CustomFormatter.FormatByteCount(CurrentProcess.VirtualMemorySize64, "0.00")); CurrentProcess.Kill(); } if (s_Controller.m_bKillBotWhenCamping && Me.IsCamping) { Program.Log("Camping detected; aborting bot!"); s_bContinueBot = false; } } } finally { Frame.Unlock(); } /// If we have to refresh the knowledge book, then do it outside of the main lock. /// This is because we'll use frame waits and can't risk breaking cached data. if (s_bRefreshKnowledgeBook) { s_Controller.RefreshKnowledgeBook(); s_bRefreshKnowledgeBook = false; } /// Skip frames as configured. for (int iIndex = 0; iIndex < s_Controller.m_iFrameSkip; iIndex++) { Frame.Wait(false); unchecked { s_lFrameCount++; } } }while (s_bContinueBot); /// Don't overwrite files that already exist unless told to; people might have special comments in place. if (!File.Exists(s_strCurrentINIFilePath) || s_Controller.m_bWriteBackINI) { s_Controller.WriteINISettings(); } Program.Log("Shutting down parser thread..."); s_ParseThread.PostQuitMessageAndShutdownQueue(true); if (s_ParseThread.WaitForTermination(TimeSpan.FromSeconds(30.0))) { Program.Log("Parser thread terminated."); } else { Program.Log("Parser thread timed out."); } return; }
private void OnConsoleLogEvent(object sender, ConsoleLogEventArgs e) { syncedQueue.Enqueue($"[{e.Date}][Process {e.ProcessId}] {e.Msg}"); }
/// <summary> /// The console logs from the javascript application /// </summary> /// <param name="sender"></param> /// <param name="e"></param> void onConsoleLog(object sender, ConsoleLogEventArgs e) { WriteToConsole("onConsoleLog"); }
/************************************************************************************/ protected void ParseEngine_LineNotRecognized(object objSender, ConsoleLogEventArgs args) { PlayerController.EnqueueLogEvent(args); return; }