Advertisement
Guest User

Untitled

a guest
Mar 22nd, 2017
176
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 45.79 KB | None | 0 0
  1. using System;
  2. using System.Collections.Concurrent;
  3. using System.Collections.Generic;
  4. using System.Diagnostics;
  5. using System.Globalization;
  6. using System.IO;
  7. using System.IO.Pipes;
  8. using System.Linq;
  9. using System.Reflection;
  10. using System.Text.RegularExpressions;
  11. using System.Threading;
  12. using System.Windows;
  13. using System.IO;
  14. using System.Xml.Linq;
  15. using System.Xml.XPath;
  16. using System.Windows.Documents;
  17. using System.Xml.Serialization;
  18. using log4net;
  19. using log4net.Appender;
  20. using log4net.Core;
  21. using log4net.Repository.Hierarchy;
  22. using Zeta.Bot;
  23. using Zeta.Bot.Settings;
  24. using Zeta.Common;
  25. using Zeta.Common.Plugins;
  26. using Zeta.Game;
  27. using Zeta.TreeSharp;
  28. using Zeta.Bot;
  29. using Zeta.Bot.Logic;
  30. using Zeta.Bot.Profile;
  31. using Zeta.Common;
  32. using Zeta.Common.Plugins;
  33. using Zeta.Game;
  34. using Zeta.Game.Internals.Service;
  35. using Zeta.TreeSharp;
  36. using Action = Zeta.TreeSharp.Action;
  37. using UIElement = Zeta.Game.Internals.UIElement;
  38.  
  39. namespace YARPLUGIN
  40. {
  41. public class YARPLUGIN : IPlugin
  42. {
  43. // Plugin version
  44. public Version Version { get { return new Version(0, 3, 2); } }
  45.  
  46. private const bool _debug = true;
  47. private static readonly log4net.ILog DBLog = Zeta.Common.Logger.GetLoggerInstanceForType();
  48.  
  49. // Compatibility
  50. private static readonly Regex[] ReCompatibility =
  51. {
  52. /* BuddyStats Remote control action */
  53. new Regex(@"Stop command from BuddyStats", RegexOptions.Compiled), // stop command
  54. /* Emergency Stop: You need to stash an item but no valid space could be found. Stash is full? Stopping the bot to prevent infinite town-run loop. */
  55. new Regex(@".+Emergency Stop: .+", RegexOptions.Compiled), // Emergency stop
  56. /* Atom 2.0.15+ "Take a break" */
  57. new Regex(@".*Atom.*Will Stop the bot for .+ minutes\.$", RegexOptions.Compiled), // Take a break
  58. /* RadsAtom "Take a break" */
  59. new Regex(@"\[RadsAtom\].+ minutes to next break, the break will last for .+ minutes.", RegexOptions.Compiled),
  60. /* Take A Break by Ghaleon */
  61. new Regex(@"\[TakeABreak.*\] It's time to take a break.*", RegexOptions.Compiled),
  62. };
  63.  
  64. // CrashTender
  65. private static readonly Regex[] ReCrashTender =
  66. {
  67. /* Invalid Session */
  68. new Regex(@"Session is invalid!", RegexOptions.IgnoreCase | RegexOptions.Compiled),
  69. /* Session expired */
  70. new Regex(@"Session is expired", RegexOptions.IgnoreCase | RegexOptions.Compiled),
  71. /* Failed to attach to D3*/
  72. new Regex(@"Was not able to attach to any running Diablo III process, are you running the bot already\?", RegexOptions.Compiled),
  73. new Regex(@"Traceback (most recent call last):", RegexOptions.IgnoreCase | RegexOptions.Compiled),
  74. };
  75.  
  76. private static readonly Regex[] CrashExceptionRegexes =
  77. {
  78. new Regex(@"Exception during bot tick.*", RegexOptions.Compiled)
  79. };
  80. private static int crashExceptionCounter;
  81.  
  82. private static readonly Regex waitingBeforeGame = new Regex(@"Waiting (.+) seconds before next game", RegexOptions.Compiled);
  83. private static readonly Regex pluginsCompiled = new Regex(@"There are \d+ plugins", RegexOptions.Compiled | RegexOptions.CultureInvariant | RegexOptions.IgnoreCase);
  84. private static readonly Regex logMessageCapture = new Regex(@"^\[(?<Timestamp>[\d:\.]+) (?<LogLevel>[NDVE])\] (?<Message>.*)$", RegexOptions.Compiled);
  85. private static readonly Regex yarRegex = new Regex(@"^\[YetAnotherRelogger\].*", RegexOptions.Compiled);
  86. private static readonly string d3Exit = "Diablo III Exited";
  87. private static readonly string getCellWeightsException = "Zeta.Navigation.MainGridProvider.GetCellWeights";
  88.  
  89. private log4net.Core.Level initialLogLevel = null;
  90.  
  91. public class BotStats
  92. {
  93. public int Pid;
  94. public long LastRun;
  95. public long LastPulse;
  96. public long PluginPulse;
  97. public long LastGame;
  98. public bool IsPaused;
  99. public bool IsRunning;
  100. public bool IsInGame;
  101. public bool IsLoadingWorld;
  102. public long Coinage;
  103. public long Experience;
  104.  
  105. public override string ToString()
  106. {
  107. return string.Format("Pid={0} LastRun={1} LastPulse={2} PluginPulse={3} LastGame={4} IsPaused={5} IsRunning={6} IsInGame={7} IsLoadingWorld={8} Coinage={9} Experience={10}",
  108. Pid, LastRun, LastPulse, PluginPulse, LastGame, IsPaused, IsRunning, IsInGame, IsLoadingWorld, Coinage, Experience);
  109. }
  110. }
  111. #region Plugin information
  112. public string Author { get { return "rrrix and sinterlkaas"; } }
  113. public string Description { get { return "Communication plugin for YetAnotherRelogger"; } }
  114. public string Name { get { return "YAR Comms"; } }
  115. public bool Equals(IPlugin other)
  116. {
  117. return (other.Name == Name) && (other.Version == Version);
  118. }
  119. #endregion
  120.  
  121. public Window DisplayWindow { get { return null; } }
  122. private bool _allPluginsCompiled;
  123. private Thread _yarThread = null;
  124.  
  125. private BotStats _bs = new BotStats();
  126. private bool _pulseFix;
  127. private YARAppender YARAppender = new YARAppender();
  128.  
  129. public bool IsEnabled { get; set; }
  130.  
  131. public static void Log(string str)
  132. {
  133. Log(str, 0);
  134. }
  135. public static void Log(Exception ex)
  136. {
  137. Log(ex.ToString(), 0);
  138. }
  139. public static void Log(string str, params object[] args)
  140. {
  141. DBLog.InfoFormat("[YetAnotherRelogger] " + str, args);
  142. }
  143. public static void LogException(Exception ex)
  144. {
  145. Log(ex.ToString());
  146. }
  147.  
  148. #region Plugin Events
  149. public YARPLUGIN()
  150. {
  151. _bs.Pid = Process.GetCurrentProcess().Id;
  152. }
  153.  
  154. private bool _appenderAdded;
  155. private object _appenderLock = 0;
  156. public void OnInitialize()
  157. {
  158. // Force enable YAR
  159. var enabledPluginsList = PluginManager.Plugins.Where(p => p.Enabled).Select(p => p.Plugin.Name).ToList();
  160. if (!enabledPluginsList.Contains(Name))
  161. enabledPluginsList.Add(Name);
  162.  
  163. PluginManager.SetEnabledPlugins(enabledPluginsList.ToArray());
  164.  
  165. _bs = new BotStats();
  166. _bs.LastPulse = DateTime.UtcNow.Ticks;
  167.  
  168. lock (_appenderLock)
  169. {
  170. if (!_appenderAdded)
  171. {
  172. Hierarchy loggingHierarchy = (Hierarchy)LogManager.GetRepository();
  173. loggingHierarchy.Root.AddAppender(YARAppender);
  174. _appenderAdded = true;
  175. }
  176. }
  177.  
  178. Reset();
  179.  
  180. StartYarWorker();
  181.  
  182. //Pulsator.OnPulse += Pulsator_OnPulse;
  183. //TreeHooks.Instance.OnHooksCleared += Instance_OnHooksCleared;
  184.  
  185. //if (ProfileUtils.IsProfileYarKickstart)
  186. //{
  187. // Log("[YAR] Kickstart Profile detected");
  188.  
  189. // if (ZetaDia.Service.Hero.IsValid && ZetaDia.Service.Hero.HeroId > 0)
  190. // {
  191. // Log("[YAR] Logged in and hero is valid");
  192.  
  193. // var realProfile = ProfileUtils.GetProfileAttribute("LoadProfile", "profile");
  194. // if (!string.IsNullOrEmpty(realProfile))
  195. // {
  196. // Log("[YAR] Loading profile: {0}", realProfile);
  197. // ProfileManager.Load(ProfileManager.CurrentProfile.Path);
  198. // }
  199. // }
  200. //}
  201.  
  202. Log("Requesting Profile (Current={0})", ProfileManager.CurrentProfile != null ? ProfileManager.CurrentProfile.Path : "Null");
  203.  
  204. Send("RequestProfile");
  205.  
  206. Send("NewDifficultyLevel", true);
  207.  
  208. ProfileManager.OnProfileLoaded += OnProfileLoaded;
  209.  
  210. Send("Initialized");
  211. }
  212.  
  213. public class ProfileUtils
  214. {
  215. public static bool ProfileHasTag(string tagName)
  216. {
  217. var profile = ProfileManager.CurrentProfile;
  218. if (profile != null && profile.Element != null)
  219. {
  220. return profile.Element.XPathSelectElement("descendant::" + tagName) != null;
  221. }
  222. return false;
  223. }
  224.  
  225. public static XElement GetProfileTag(string tagName, XElement element = null)
  226. {
  227. if (element == null)
  228. {
  229. var profile = ProfileManager.CurrentProfile;
  230. if (profile != null && profile.Element != null)
  231. {
  232. element = profile.Element;
  233. }
  234. else
  235. {
  236. return null;
  237. }
  238. }
  239.  
  240. return element.XPathSelectElement("descendant::" + tagName);
  241. }
  242.  
  243. public static bool IsProfileYarKickstart
  244. {
  245. get
  246. {
  247. var fileNameWithoutExtension = Path.GetFileNameWithoutExtension(ProfileManager.CurrentProfile.Path);
  248. return fileNameWithoutExtension != null && fileNameWithoutExtension.ToLower().StartsWith("yar_kickstart");
  249. }
  250. }
  251.  
  252. public static string GetProfileAttribute(string tagName, string attrName, XElement element = null)
  253. {
  254. var profileTag = GetProfileTag(tagName, element);
  255. if (profileTag != null)
  256. {
  257. var behaviorAttr = profileTag.Attribute(attrName);
  258. if (behaviorAttr != null && !string.IsNullOrEmpty(behaviorAttr.Value))
  259. {
  260. return behaviorAttr.Value;
  261. }
  262. }
  263. return string.Empty;
  264. }
  265. }
  266.  
  267. void BotMain_OnStart(IBot bot)
  268. {
  269. InsertOrRemoveHook();
  270. }
  271.  
  272. void Instance_OnHooksCleared(object sender, EventArgs e)
  273. {
  274. InsertOrRemoveHook();
  275. }
  276.  
  277. public void OnEnabled()
  278. {
  279. // YAR Login Support (YARKickstart Ibot will call this from the proper thread)
  280. if (!Application.Current.CheckAccess()) return;
  281.  
  282. IsEnabled = true;
  283. Log("YAR Plugin Enabled with PID: {0}", _bs.Pid);
  284. BotMain.OnStart += BotMain_OnStart;
  285.  
  286. StartYarWorker();
  287. Send("NewDifficultyLevel", true); // Request Difficulty level
  288. Reset();
  289. }
  290.  
  291. public void OnDisabled()
  292. {
  293. IsEnabled = false;
  294. Pulsator.OnPulse -= Pulsator_OnPulse;
  295. BotMain.OnStart -= BotMain_OnStart;
  296. TreeHooks.Instance.OnHooksCleared -= Instance_OnHooksCleared;
  297.  
  298. lock (_appenderLock)
  299. {
  300. if (_appenderAdded)
  301. {
  302. Hierarchy loggingHierarchy = (Hierarchy)LogManager.GetRepository();
  303. _appenderAdded = false;
  304. loggingHierarchy.Root.RemoveAppender(YARAppender);
  305. }
  306. }
  307.  
  308. Log("YAR Plugin Disabled!");
  309.  
  310. // Pulsefix disabled plugin
  311. if (_pulseFix)
  312. {
  313. _pulseFix = false;
  314. return; // Stop here to prevent Thread abort
  315. }
  316. try
  317. {
  318. if (_yarThread.IsAlive)
  319. {
  320. // user disabled plugin abort Thread
  321. _yarThread.Abort();
  322. }
  323. }
  324. catch (ThreadAbortException) { }
  325. catch (Exception ex)
  326. {
  327. Log(ex.ToString());
  328. }
  329. }
  330.  
  331. public void OnPulse()
  332. {
  333. _bs.IsInGame = ZetaDia.IsInGame;
  334. _bs.IsLoadingWorld = ZetaDia.IsLoadingWorld;
  335.  
  336. if (!ZetaDia.IsInGame || ZetaDia.IsLoadingWorld || ZetaDia.Me == null || !ZetaDia.Me.IsValid)
  337. return;
  338.  
  339. Pulse();
  340. }
  341.  
  342. private void OnProfileLoaded(object sender, object e)
  343. {
  344. Send("NewDifficultyLevel", true); // Request Difficulty level
  345. }
  346.  
  347. private void StartYarWorker()
  348. {
  349. if (_yarThread == null || (_yarThread != null && !_yarThread.IsAlive))
  350. {
  351. Log("Starting YAR Thread");
  352. _yarThread = new Thread(YarWorker) { Name = "YARWorker", IsBackground = true };
  353. _yarThread.Start();
  354. }
  355. }
  356.  
  357. /// <summary>
  358. /// Just to make sure our ticks are ALWAYS updated!
  359. /// </summary>
  360. /// <param name="sender"></param>
  361. /// <param name="e"></param>
  362. void Pulsator_OnPulse(object sender, EventArgs e)
  363. {
  364. _bs.LastPulse = DateTime.UtcNow.Ticks;
  365.  
  366. ErrorHandling();
  367.  
  368. if (IsEnabled)
  369. StartYarWorker();
  370. }
  371.  
  372. public void OnShutdown()
  373. {
  374. _yarThread.Abort();
  375. }
  376.  
  377.  
  378. LoggingEvent[] _logBuffer;
  379.  
  380. /// <summary>
  381. /// Reads through the LogMessage queue and sends updates to YAR
  382. /// </summary>
  383. private void LogWorker()
  384. {
  385. try
  386. {
  387. _bs.IsRunning = BotMain.IsRunning;
  388.  
  389. if (BotMain.IsRunning)
  390. {
  391. _bs.IsPaused = false;
  392. _bs.LastRun = DateTime.UtcNow.Ticks;
  393. }
  394.  
  395. Queue<LoggingEvent> localQueue = new Queue<LoggingEvent>();
  396. while (YARAppender.Messages.Any())
  397. {
  398. LoggingEvent loggingEvent;
  399. if (YARAppender.Messages.TryDequeue(out loggingEvent))
  400. localQueue.Enqueue(loggingEvent);
  401. }
  402.  
  403.  
  404. if (_logBuffer == null)
  405. {
  406. _logBuffer = localQueue.ToArray();
  407. }
  408. else
  409. {
  410. lock (_logBuffer)
  411. {
  412. var newbuffer = _logBuffer.Concat(localQueue.ToArray()).ToArray();
  413. _logBuffer = newbuffer;
  414. }
  415. }
  416.  
  417. // Keep Thread alive while log buffer is not empty
  418. while (_logBuffer != null)
  419. {
  420. try
  421. {
  422. var duration = DateTime.UtcNow;
  423. LoggingEvent[] buffer;
  424. // Lock buffer and copy to local variable for scanning
  425. lock (_logBuffer)
  426. {
  427. buffer = new LoggingEvent[_logBuffer.Length + 1]; // set log new local log buffer size
  428. _logBuffer.CopyTo(buffer, 0); // copy to local
  429. _logBuffer = null; // clear buffer
  430. }
  431.  
  432.  
  433. var count = 0; // Scan counter
  434. var breakloop = false;
  435. // Scan log items
  436. foreach (LoggingEvent lm in buffer.Where(x => x != null))
  437. {
  438. string msg = lm.RenderedMessage;
  439. if (yarRegex.IsMatch(msg))
  440. continue;
  441.  
  442. count++; // add to counter
  443. var m = pluginsCompiled.Match(msg);
  444. if (m.Success)
  445. {
  446. Log("Plugins Compiled matched");
  447. _allPluginsCompiled = true;
  448. Send("AllCompiled"); // tell relogger about all plugin compile so the relogger can tell what to do next
  449. continue;
  450. }
  451.  
  452. // Find Start stop button click
  453. if (msg.Equals("Start/Stop Button Clicked!") && !BotMain.IsRunning)
  454. {
  455. Send("UserStop");
  456. crashExceptionCounter = 0;
  457. }
  458.  
  459. try
  460. {
  461. if (!ZetaDia.IsInGame && FindStartDelay(msg)) continue; // Find new start delay
  462. }
  463. catch (AccessViolationException)
  464. {
  465. if (IsGameRunning())
  466. {
  467. Send("D3Exit"); // Process has exited
  468. breakloop = true; // break out of loop
  469. }
  470. }
  471. // Crash Tender check
  472. if (ReCrashTender.Any(re => re.IsMatch(msg)))
  473. {
  474. Log("Crash message detected");
  475. Send("D3Exit"); // Restart D3
  476. breakloop = true; // break out of loop
  477. }
  478.  
  479. if (CrashExceptionRegexes.Any(re => re.IsMatch(msg)))
  480. {
  481. Log("Crash Exception detected");
  482. crashExceptionCounter++;
  483. }
  484. if (crashExceptionCounter > 1000)
  485. {
  486. Log("Detected 1000 unhandled bot tick exceptions, restarting everything");
  487. Send("D3Exit"); // Restart D3
  488. }
  489.  
  490. // YAR compatibility with other plugins
  491. if (ReCompatibility.Any(re => re.IsMatch(msg)))
  492. Send("ThirdpartyStop");
  493. if (breakloop) break; // Check if we need to break out of loop
  494. }
  495. //if (count > 1) Log("Scanned {0} log items in {1}ms", count, DateTime.UtcNow.Subtract(duration).TotalMilliseconds);
  496. }
  497. catch (Exception ex)
  498. {
  499. LogException(ex);
  500. }
  501. }
  502.  
  503. }
  504. catch (Exception ex)
  505. {
  506. Log("Exception in LogWorker: {0}", ex);
  507. }
  508. }
  509.  
  510. private static Composite _yarHook;
  511. private void InsertOrRemoveHook(bool forceInsert = false)
  512. {
  513. try
  514. {
  515. if (IsEnabled || forceInsert)
  516. {
  517. if (_yarHook == null)
  518. _yarHook = CreateYarHook();
  519.  
  520. Log("Inserting YAR Hook");
  521. TreeHooks.Instance.InsertHook("OutOfgame", 0, _yarHook);
  522. }
  523. else
  524. {
  525. if (_yarHook != null)
  526. {
  527. Log("Removing YAR Hook");
  528. TreeHooks.Instance.RemoveHook("OutOfgame", _yarHook);
  529. }
  530. }
  531. }
  532. catch (Exception ex)
  533. {
  534. Log(ex);
  535. }
  536. }
  537.  
  538. internal Composite CreateYarHook()
  539. {
  540. return new Action(ret => Pulse());
  541. }
  542.  
  543. /// <summary>
  544. /// This is called from TreeStart
  545. /// </summary>
  546. /// <returns></returns>
  547. public RunStatus Pulse()
  548. {
  549. try
  550. {
  551. // YAR Health Check
  552. _pulseCheck = true;
  553. _bs.LastPulse = DateTime.UtcNow.Ticks;
  554.  
  555. _bs.PluginPulse = DateTime.UtcNow.Ticks;
  556.  
  557. if (!ZetaDia.Service.IsValid || !ZetaDia.Service.Platform.IsConnected)
  558. {
  559. ErrorHandling();
  560.  
  561. // We handled an error, we should
  562. return RunStatus.Failure;
  563. }
  564.  
  565. if (!ZetaDia.IsInGame || ZetaDia.Me == null || !ZetaDia.Me.IsValid || ZetaDia.IsLoadingWorld)
  566. {
  567. return RunStatus.Failure;
  568. }
  569.  
  570. LogWorker();
  571.  
  572. // in-game / character data
  573. _bs.IsLoadingWorld = ZetaDia.IsLoadingWorld;
  574. _bs.Coinage = 0;
  575. _bs.Experience = 0;
  576. try
  577. {
  578. if (ZetaDia.Me != null && ZetaDia.Me.IsValid)
  579. {
  580. _bs.Coinage = ZetaDia.PlayerData.Coinage;
  581. Int64 exp;
  582. if (ZetaDia.Me.Level < 60)
  583. exp = ZetaDia.Me.CurrentExperience;
  584. else
  585. exp = ZetaDia.Me.ParagonCurrentExperience;
  586.  
  587. _bs.Experience = exp;
  588. }
  589. }
  590. catch
  591. {
  592. Log("Exception reading Coinage", 0);
  593. _bs.Coinage = -1;
  594. _bs.Experience = -1;
  595. }
  596.  
  597. if (ZetaDia.IsInGame)
  598. {
  599. _bs.LastGame = DateTime.UtcNow.Ticks;
  600. _bs.IsInGame = true;
  601. }
  602. else
  603. {
  604. if (_bs.IsInGame)
  605. {
  606. Send("GameLeft", true);
  607. }
  608. _bs.IsInGame = false;
  609. }
  610. }
  611. catch (Exception ex)
  612. {
  613. Log(ex);
  614. }
  615. return RunStatus.Failure;
  616. }
  617. #endregion
  618.  
  619. #region Logging Monitor
  620. public bool FindStartDelay(string msg)
  621. {
  622. // Waiting #.# seconds before next game...
  623. var m = waitingBeforeGame.Match(msg);
  624. if (m.Success)
  625. {
  626. Send("StartDelay " + DateTime.UtcNow.AddSeconds(double.Parse(m.Groups[1].Value, CultureInfo.InvariantCulture)).Ticks);
  627. return true;
  628. }
  629. return false;
  630. }
  631. #endregion
  632.  
  633. #region yarWorker
  634. public void YarWorker()
  635. {
  636. Log("YAR Worker Thread Started");
  637. while (true)
  638. {
  639. try
  640. {
  641. if (BotMain.BotThread != null)
  642. _bs.IsRunning = BotMain.BotThread.IsAlive;
  643. else
  644. _bs.IsRunning = false;
  645.  
  646. bool isInGame = false;
  647. try
  648. {
  649. isInGame = ZetaDia.IsInGame;
  650. }
  651. catch { }
  652. // Calculate game runs
  653. if (isInGame)
  654. {
  655. _bs.LastGame = DateTime.UtcNow.Ticks;
  656. _bs.IsInGame = true;
  657. }
  658. else
  659. {
  660. if (_bs.IsInGame)
  661. {
  662. Send("GameLeft", true);
  663. Send("NewDifficultyLevel", true); // Request Difficulty level
  664. }
  665. _bs.IsInGame = false;
  666. }
  667.  
  668. // Send stats
  669. Send("XML:" + _bs.ToXmlString(), xml: true);
  670.  
  671. LogWorker();
  672.  
  673. Thread.Sleep(750);
  674. }
  675. catch (ThreadAbortException)
  676. {
  677. Log("YAR Thread Aborted");
  678. }
  679. catch (Exception ex)
  680. {
  681. LogException(ex);
  682. }
  683. }
  684. }
  685. #endregion
  686.  
  687. #region Handle Errors and strange situations
  688.  
  689. private bool handlederror;
  690. private bool ErrorHandling()
  691. {
  692. bool errorHandled = false;
  693. if (ErrorDialog.IsVisible)
  694. {
  695. // Check if Demonbuddy found errordialog
  696. if (!handlederror)
  697. {
  698. Send("CheckConnection", pause: true);
  699. handlederror = true;
  700. errorHandled = true;
  701. }
  702. else
  703. {
  704. handlederror = false;
  705. ErrorDialog.Click();
  706. CheckForLoginScreen();
  707. errorHandled = true;
  708. }
  709. }
  710.  
  711. if (UIElementTester.isValid(_UIElement.errordialog_okbutton))
  712. {
  713. // Demonbuddy failed to find error dialog use static hash to find the OK button
  714. Send("CheckConnection", pause: true);
  715. UIElement.FromHash(_UIElement.errordialog_okbutton).Click();
  716. CheckForLoginScreen();
  717. errorHandled = true;
  718. }
  719.  
  720. handlederror = false;
  721. if (UIElementTester.isValid(_UIElement.loginscreen_username))
  722. {
  723. // We are at loginscreen
  724. Send("CheckConnection", pause: true);
  725. errorHandled = true;
  726. }
  727. return errorHandled;
  728. }
  729.  
  730. // Detect if we are booted to login screen or character selection screen
  731. private void CheckForLoginScreen()
  732. {
  733. var timeout = DateTime.UtcNow;
  734. while (DateTime.UtcNow.Subtract(timeout).TotalSeconds <= 15)
  735. {
  736. BotMain.PauseFor(TimeSpan.FromMilliseconds(600));
  737. if (UIElementTester.isValid(_UIElement.startresume_button))
  738. break;
  739. if (UIElementTester.isValid(_UIElement.loginscreen_username))
  740. { // We are at loginscreen
  741. Send("CheckConnection", pause: true);
  742. break;
  743. }
  744. Thread.Sleep(500);
  745. }
  746. }
  747. #endregion
  748.  
  749. #region PipeClientSend
  750. private bool Send(string data, bool pause = false, bool xml = false, int retry = 1, int timeout = 3000)
  751. {
  752.  
  753. var success = false;
  754. var tries = 0;
  755. if (_bs.Pid == 0)
  756. _bs.Pid = Process.GetCurrentProcess().Id;
  757.  
  758. if (!xml)
  759. data = _bs.Pid + ":" + data;
  760. else
  761. data += "\nEND";
  762.  
  763. // Pause bot
  764. if (pause)
  765. {
  766. _recieved = false;
  767. Func<bool> waitFor = Recieved;
  768. BotMain.PauseWhile(waitFor, 0, TimeSpan.FromMilliseconds((retry * timeout) + 3000));
  769. }
  770. while (!success && tries < retry)
  771. {
  772. try
  773. {
  774. tries++;
  775. using (var client = new NamedPipeClientStream(".", "YetAnotherRelogger"))
  776. {
  777. client.Connect(timeout);
  778. if (client.IsConnected)
  779. {
  780. var streamWriter = new StreamWriter(client) { AutoFlush = true };
  781. var streamReader = new StreamReader(client);
  782.  
  783. streamWriter.WriteLine(data);
  784.  
  785. var connectionTime = DateTime.UtcNow;
  786.  
  787. if (!client.IsConnected)
  788. {
  789. Log("Error: client disconnected before response received");
  790. }
  791.  
  792. while (!success && client.IsConnected)
  793. {
  794. if (DateTime.UtcNow.Subtract(connectionTime).TotalSeconds > 3)
  795. {
  796. client.Close();
  797. break;
  798. }
  799.  
  800. string responseText = string.Empty;
  801. if (!streamReader.EndOfStream)
  802. {
  803. responseText = streamReader.ReadLine();
  804. }
  805. if (string.IsNullOrWhiteSpace(responseText))
  806. {
  807. Thread.Sleep(10);
  808. continue;
  809. }
  810.  
  811. HandleResponse(responseText);
  812. success = true;
  813.  
  814. }
  815.  
  816. }
  817. else
  818. {
  819. // Failed to connect
  820. }
  821. }
  822. }
  823. catch (ThreadAbortException) { }
  824. catch (TimeoutException)
  825. {
  826. if (this.IsEnabled)
  827. {
  828. // YAR is not running, disable the plugin
  829. //Log("TimeoutException - Disabling YAR Plugin");
  830.  
  831. PluginManager.Plugins.Where(p => p.Plugin.Name == this.Name).All(p => p.Enabled = false);
  832. _yarThread.Abort();
  833. }
  834. }
  835. catch (Exception ex)
  836. {
  837. LogException(ex);
  838. OnShutdown();
  839. }
  840.  
  841. }
  842. _recieved = true;
  843. return success;
  844. }
  845. #endregion
  846.  
  847. #region HandleResponse
  848. void HandleResponse(string data)
  849. {
  850. string cmd = data.Split(' ')[0];
  851. if (data.Split(' ').Count() > 1)
  852. data = data.Substring(cmd.Length + 1);
  853. switch (cmd)
  854. {
  855. case "Restart":
  856. Log("Restarting bot");
  857. try
  858. {
  859. Log("Stopping Bot");
  860. BotMain.Stop();
  861. Application.Current.Dispatcher.BeginInvoke((System.Action)(() =>
  862. {
  863. try
  864. {
  865. Log("Starting Bot");
  866. Thread.Sleep(1000);
  867. BotMain.Start();
  868. }
  869. catch (Exception ex)
  870. {
  871. LogException(ex);
  872. }
  873. }));
  874. }
  875. catch (Exception ex)
  876. {
  877. LogException(ex);
  878. }
  879. Reset();
  880. break;
  881. case "LoadProfile":
  882. LoadProfile(data);
  883. break;
  884. case "DifficultyLevel":
  885. var difficultyLevel = Convert.ToInt32(data.Trim());
  886. if (difficultyLevel >= 0)
  887. {
  888. var difficulty = (GameDifficulty)Enum.Parse(typeof(GameDifficulty), data.Trim(), true);
  889. Log("Recieved DifficultyLevel: {0}", difficulty);
  890. CharacterSettings.Instance.GameDifficulty = difficulty;
  891. }
  892. break;
  893. case "ForceEnableAll":
  894. ForceEnableAllPlugins();
  895. break;
  896. case "ForceEnableYar":
  897. ForceEnableYar();
  898. break;
  899. case "FixPulse":
  900. FixPulse();
  901. break;
  902. case "Shutdown":
  903. Log("Received Shutdown command");
  904. SafeCloseProcess();
  905. break;
  906. case "Roger!":
  907. case "Unknown command!":
  908. break;
  909. default:
  910. Log("Unknown response! \"{0} {1}\"", cmd, data);
  911. break;
  912. }
  913. _recieved = true;
  914. }
  915.  
  916. // from Nesox
  917. private void SafeCloseProcess()
  918. {
  919. Log("Attempting to Safely Close Process");
  920. try
  921. {
  922. if (Thread.CurrentThread != Application.Current.Dispatcher.Thread)
  923. {
  924. Application.Current.Dispatcher.Invoke(new System.Action(SafeCloseProcess));
  925. return;
  926. }
  927.  
  928. Application.Current.Shutdown();
  929. }
  930. catch (Exception ex)
  931. {
  932. Log(ex.ToString());
  933. }
  934. }
  935.  
  936. #region ForceEnable Plugin(s)
  937. private void ForceEnableYar()
  938. {
  939. // Check if plugin is enabled
  940. var plugin = PluginManager.Plugins.FirstOrDefault(x => x.Plugin.Name.Equals(Name));
  941. if (plugin == null || (plugin.Enabled)) return;
  942.  
  943. Log("Force enable plugin");
  944. var plugins = PluginManager.GetEnabledPlugins().ToList();
  945. plugins.Add(Name);
  946. PluginManager.SetEnabledPlugins(plugins.ToArray());
  947. }
  948.  
  949. private void ForceEnableAllPlugins()
  950. {
  951. PluginContainer test;
  952. DateTime limit;
  953.  
  954. Application.Current.Dispatcher.Invoke(() =>
  955. {
  956. var disabledPlugins = PluginManager.Plugins.Where(p => !p.Enabled && p.Plugin.Name != "BuddyMonitor").ToList();
  957. if (!disabledPlugins.Any())
  958. return;
  959.  
  960. Log("Disabled plugins found. User requested all plugins be enabled through YAR. Enabling Plugins..");
  961.  
  962. foreach (var plugin in disabledPlugins)
  963. {
  964. try
  965. {
  966. Log("Force enable: \"{0}\"", plugin.Plugin.Name);
  967. plugin.Enabled = true;
  968. limit = DateTime.UtcNow;
  969. while ((test = PluginManager.Plugins.FirstOrDefault(x => x.Plugin.Name.Equals(plugin.Plugin.Name))) != null && !test.Enabled)
  970. {
  971. if (DateTime.UtcNow.Subtract(limit).TotalSeconds > 5)
  972. {
  973. Log("Failed to enable: Timeout ({0} seconds) \"{1}\"", DateTime.UtcNow.Subtract(limit).TotalSeconds, plugin.Plugin.Name);
  974. break;
  975. }
  976. Thread.Sleep(100);
  977. }
  978. }
  979. catch (Exception ex)
  980. {
  981. Log("Failed to enable: \"{0}\"", plugin.Plugin.Name);
  982. LogException(ex);
  983. }
  984. }
  985.  
  986. });
  987. }
  988. #endregion
  989.  
  990. #region FixPulse
  991.  
  992. private bool _pulseCheck;
  993. private void FixPulse()
  994. {
  995. DateTime timeout;
  996. Log("############## Pulse Fix ##############");
  997. // Check if plugin is enabled
  998. var plugin = PluginManager.Plugins.FirstOrDefault(x => x.Plugin.Name.Equals(Name));
  999. if (plugin != null && plugin.Enabled)
  1000. {
  1001. Log("PulseFix: Plugin is already enabled -> Disable it for now");
  1002. _pulseFix = true; // Prevent our thread from begin aborted
  1003. plugin.Enabled = false;
  1004. timeout = DateTime.UtcNow;
  1005. while (plugin.Enabled)
  1006. {
  1007. if (DateTime.UtcNow.Subtract(timeout).TotalSeconds > 10)
  1008. {
  1009. Log("PulseFix: Failed to disable plugin");
  1010. Application.Current.Shutdown(0);
  1011. return;
  1012. }
  1013. Thread.Sleep(100);
  1014. }
  1015. }
  1016. else
  1017. Log("PulseFix: Plugin is not enabled!");
  1018.  
  1019. // Force enable yar plugin
  1020. ForceEnableYar();
  1021.  
  1022. var attempt = 0;
  1023. while (!BotMain.IsRunning)
  1024. {
  1025. attempt++;
  1026. if (attempt >= 4)
  1027. {
  1028. Log("PulseFix: Fix attempts failed, closing demonbuddy!");
  1029. Application.Current.Shutdown();
  1030. }
  1031. if (BotMain.BotThread == null)
  1032. {
  1033. Log("PulseFix: Mainbot thread is not running");
  1034. Log("PulseFix: Force start bot");
  1035. BotMain.Start();
  1036. }
  1037. else if (BotMain.BotThread != null)
  1038. {
  1039. if (BotMain.IsPaused || BotMain.IsPausedForStateExecution)
  1040. Log("PulseFix: DB is Paused!");
  1041. Log("PulseFix: Force stop bot");
  1042. BotMain.BotThread.Abort();
  1043. Thread.Sleep(1000);
  1044. Log("PulseFix: Force start bot");
  1045. BotMain.Start();
  1046. }
  1047. Thread.Sleep(1000);
  1048. }
  1049.  
  1050. // Check if we get a pulse within 10 seconds
  1051. Log("PulseFix: Waiting for first pulse");
  1052. _pulseCheck = false;
  1053. timeout = DateTime.UtcNow;
  1054. while (!_pulseCheck)
  1055. {
  1056. if (DateTime.UtcNow.Subtract(timeout).TotalSeconds > 10)
  1057. {
  1058. Log("PulseFix: Failed to recieve a pulse within 10 seconds");
  1059. SafeCloseProcess();
  1060. break;
  1061. }
  1062. Thread.Sleep(100);
  1063. }
  1064. Log("############## End Fix ##############");
  1065. }
  1066. #endregion
  1067.  
  1068. bool _recieved;
  1069. bool Recieved()
  1070. {
  1071. return _recieved;
  1072. }
  1073. bool IsGameRunning()
  1074. {
  1075. return ZetaDia.Memory.Process.HasExited && !Process.GetProcesses().Any(p => p.ProcessName.StartsWith("BlizzardError") && DateTime.UtcNow.Subtract(p.StartTime).TotalSeconds <= 30);
  1076. }
  1077. #endregion
  1078.  
  1079. void Reset()
  1080. {
  1081. _bs.LastPulse = DateTime.UtcNow.Ticks;
  1082. _bs.LastRun = DateTime.UtcNow.Ticks;
  1083. _bs.LastGame = DateTime.UtcNow.Ticks;
  1084. }
  1085.  
  1086. private string ParseInnerProfile(string path = "")
  1087. {
  1088. if (string.IsNullOrEmpty(path))
  1089. return path;
  1090.  
  1091. var xml = XDocument.Load(path);
  1092.  
  1093. return ProfileUtils.GetProfileAttribute("LoadProfile", "profile", xml.Root);
  1094. }
  1095.  
  1096. private void LoadProfile(string profile)
  1097. {
  1098. //var isHardReset = ZetaDia.IsInGame || ZetaDia.IsLoadingWorld || ZetaDia.Service.Party.CurrentPartyLockReasonFlags != PartyLockReasonFlag.None;
  1099. //if (isHardReset)
  1100. //{
  1101. // //BotMain.Stop(false, "-> Hard Stop/Reset and Load new profile");
  1102. // if (ZetaDia.IsInGame)
  1103. // {
  1104. // ZetaDia.Service.Party.LeaveGame(true);
  1105. // while (ZetaDia.IsInGame)
  1106. // Thread.Sleep(250);
  1107. // }
  1108. //}
  1109.  
  1110. Log("Loading profile: {0}", profile);
  1111.  
  1112. if (ProfileManager.CurrentProfile == null || profile != ProfileManager.CurrentProfile.Path)
  1113. ProfileManager.Load(profile.Trim());
  1114.  
  1115. //if (isHardReset)
  1116. //{
  1117. // Thread.Sleep(5000);
  1118. // //BotMain.Start();
  1119. //}
  1120.  
  1121. }
  1122. }
  1123.  
  1124. #region ElementTester
  1125. public static class _UIElement
  1126. {
  1127. public static ulong leavegame_cancel = 0x3B55BA1E41247F50,
  1128. loginscreen_username = 0xDE8625FCCFFDFC28,
  1129. loginscreen_password = 0xBA2D3316B4BB4104,
  1130. loginscreen_loginbutton = 0x50893593B5DB22A9,
  1131. startresume_button = 0x51A3923949DC80B7,
  1132. errordialog_okbutton = 0xB4433DA3F648A992;
  1133. }
  1134. public static class UIElementTester
  1135. {
  1136.  
  1137. /// <summary>
  1138. /// UIElement validation check
  1139. /// </summary>
  1140. /// <param name="hash">UIElement hash to check</param>
  1141. /// <param name="isEnabled">should be enabled</param>
  1142. /// <param name="isVisible">should be visible</param>
  1143. /// <param name="bisValid">should be a valid UIElement</param>
  1144. /// <returns>true if all requirements are valid</returns>
  1145. public static bool isValid(ulong hash, bool isEnabled = true, bool isVisible = true, bool bisValid = true)
  1146. {
  1147. try
  1148. {
  1149. if (!UIElement.IsValidElement(hash))
  1150. return false;
  1151. else
  1152. {
  1153. var element = UIElement.FromHash(hash);
  1154.  
  1155. if ((isEnabled && !element.IsEnabled) || (!isEnabled && element.IsEnabled))
  1156. return false;
  1157. if ((isVisible && !element.IsVisible) || (!isVisible && element.IsVisible))
  1158. return false;
  1159. if ((bisValid && !element.IsValid) || (!bisValid && element.IsValid))
  1160. return false;
  1161.  
  1162. }
  1163. }
  1164. catch
  1165. {
  1166. return false;
  1167. }
  1168. return true;
  1169. }
  1170. }
  1171. #endregion
  1172.  
  1173. #region XmlTools
  1174. public static class XmlTools
  1175. {
  1176. public static string ToXmlString<T>(this T input)
  1177. {
  1178. using (var writer = new StringWriter())
  1179. {
  1180. input.ToXml(writer);
  1181. return writer.ToString();
  1182. }
  1183. }
  1184. public static void ToXml<T>(this T objectToSerialize, Stream stream)
  1185. {
  1186. new XmlSerializer(typeof(T)).Serialize(stream, objectToSerialize);
  1187. }
  1188.  
  1189. public static void ToXml<T>(this T objectToSerialize, StringWriter writer)
  1190. {
  1191. new XmlSerializer(typeof(T)).Serialize(writer, objectToSerialize);
  1192. }
  1193. }
  1194. #endregion
  1195.  
  1196. public class YARAppender : AppenderSkeleton
  1197. {
  1198. public static ConcurrentQueue<LoggingEvent> Messages = new ConcurrentQueue<LoggingEvent>();
  1199.  
  1200. protected override void Append(LoggingEvent loggingEvent)
  1201. {
  1202. lock (Messages)
  1203. {
  1204. Messages.Enqueue(loggingEvent);
  1205. }
  1206. }
  1207. }
  1208.  
  1209. }
  1210.  
  1211. #region Trinity Support
  1212. namespace YARPLUGIN
  1213. {
  1214. public static class TrinitySupport
  1215. {
  1216. private static bool _failed;
  1217. private static Type _gilesTrinityType;
  1218. public static bool Initialized { get; private set; }
  1219.  
  1220. public static void Initialize()
  1221. {
  1222. Initialized = true;
  1223. YARPLUGIN.Log("Initialize Trinity Support");
  1224. var asm = AppDomain.CurrentDomain.GetAssemblies().FirstOrDefault(x => x.GetName().Name.ToLower().StartsWith("trinity"));
  1225. if (asm != null)
  1226. {
  1227. try
  1228. {
  1229. _gilesTrinityType = asm.GetType("GilesTrinity.GilesTrinity");
  1230. _failed = false;
  1231. return;
  1232. }
  1233. catch (Exception ex)
  1234. {
  1235. YARPLUGIN.Log("Failed to initialize Trinity Support:");
  1236. YARPLUGIN.LogException(ex);
  1237. }
  1238. }
  1239. else
  1240. {
  1241. YARPLUGIN.Log("Trinity is not installed");
  1242. }
  1243. _failed = true;
  1244. }
  1245.  
  1246. public static bool IsEnabled
  1247. {
  1248. get
  1249. {
  1250. var plugin = PluginManager.Plugins.FirstOrDefault(p => p.Plugin.Name.Equals("Trinity"));
  1251. return (plugin != null && plugin.Enabled);
  1252. }
  1253. }
  1254.  
  1255. private static bool bDontMoveMeIAmDoingShit
  1256. {
  1257. get
  1258. {
  1259. try
  1260. {
  1261. return (bool)_gilesTrinityType.GetField("bDontMoveMeIAmDoingShit", BindingFlags.Static).GetValue(null);
  1262. }
  1263. catch (Exception ex)
  1264. {
  1265. YARPLUGIN.Log("Failed to get Trinity info:");
  1266. YARPLUGIN.LogException(ex);
  1267. return false;
  1268. }
  1269. }
  1270. }
  1271. private static bool MainBotPaused
  1272. {
  1273. get
  1274. {
  1275. try
  1276. {
  1277. return (bool)_gilesTrinityType.GetField("bMainBotPaused", BindingFlags.NonPublic | BindingFlags.Static).GetValue(null);
  1278. }
  1279. catch (Exception ex)
  1280. {
  1281. YARPLUGIN.Log("Failed to get Trinity info:");
  1282. YARPLUGIN.LogException(ex);
  1283. return false;
  1284. }
  1285. }
  1286. }
  1287. public static bool IsPaused
  1288. {
  1289. get
  1290. {
  1291. if (!Initialized) Initialize();
  1292. return !_failed && MainBotPaused;
  1293. }
  1294. }
  1295. public static bool IsBusy
  1296. {
  1297. get
  1298. {
  1299. if (!Initialized) Initialize();
  1300. return !_failed && bDontMoveMeIAmDoingShit;
  1301. }
  1302. }
  1303. }
  1304. }
  1305. #endregion
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement