public static async Task Execute(ISession session, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); TinyIoC.TinyIoCContainer.Current.Resolve <MultiAccountManager>().ThrowIfSwitchAccountRequested(); try { var playerStats = (await session.Inventory.GetPlayerStats().ConfigureAwait(false)).FirstOrDefault(); if (playerStats == null) { return; } var kmWalked = playerStats.KmWalked; var incubators = (await session.Inventory.GetEggIncubators().ConfigureAwait(false)) .Where(x => x.UsesRemaining > 0 || x.ItemId == ItemId.ItemIncubatorBasicUnlimited) .OrderByDescending(x => x.ItemId == ItemId.ItemIncubatorBasicUnlimited) .ToList(); var unusedEggs = (await session.Inventory.GetEggs().ConfigureAwait(false)) .Where(x => string.IsNullOrEmpty(x.EggIncubatorId)) .OrderBy(x => x.EggKmWalkedTarget - x.EggKmWalkedStart) .ToList(); var rememberedIncubatorsFilePath = Path.Combine(session.LogicSettings.ProfilePath, "temp", "incubators.json"); var rememberedIncubators = GetRememberedIncubators(rememberedIncubatorsFilePath); var pokemons = (await session.Inventory.GetPokemons().ConfigureAwait(false)).ToList(); var eggIncubatorStatusEvent = new EggIncubatorStatusEvent(); // Check if eggs in remembered incubator usages have since hatched // (instead of calling session.Client.Inventory.GetHatchedEgg(), which doesn't seem to work properly) foreach (var incubator in rememberedIncubators) { var hatched = pokemons.FirstOrDefault(x => !x.IsEgg && x.Id == incubator.PokemonId); if (hatched == null) { continue; } //Still Needs some work - TheWizard1328 var stats = session.RuntimeStatistics; // Total Km walked var KMs = eggIncubatorStatusEvent.KmToWalk; //playerStats.KmWalked - hatched.EggKmWalkedStart; // Total Km Walked(hatched.EggKmWalkedStart=0) var stardust1 = session.Inventory.GetStarDust(); // Total trainer Stardust var stardust2 = stats.TotalStardust; // Total trainer Stardust var ExpAwarded1 = playerStats.Experience; // Total Player Exp - TheWizard1328 var ExpAwarded2 = stats.TotalExperience; // Session Exp - TheWizard1328 var TotCandy = session.Inventory.GetCandyCount(hatched.PokemonId); //Temp logger line personal testing info - TheWizard1328 #if DEBUG Logger.Write($"Hatch: eISE.KmWalked: {eggIncubatorStatusEvent.KmWalked:0.00} | eISE.KmToWalk: {eggIncubatorStatusEvent.KmToWalk:0.00} | " + $"XP1: {ExpAwarded1} | XP2: {ExpAwarded2} | SD1: {stardust1} | SD2: {stardust2}", LogLevel.Egg, ConsoleColor.DarkYellow); #endif if (session.LogicSettings.NotificationConfig.EnablePushBulletNotification) { await PushNotificationClient.SendNotification(session, $"Egg has hatched.", $"Pokemon: {hatched.PokemonId}\n" + $"Lvl: {PokemonInfo.GetLevel(hatched)}\n" + $"CP: {hatched.Cp}\n" + $"IV: {Math.Round(PokemonInfo.CalculatePokemonPerfection(hatched), 2)}\n", true).ConfigureAwait(false); } session.EventDispatcher.Send(new EggHatchedEvent { Dist = KMs, //Still working on this - TheWizard1328 Id = hatched.Id, PokemonId = hatched.PokemonId, Level = PokemonInfo.GetLevel(hatched), Cp = hatched.Cp, MaxCp = PokemonInfo.CalculateMaxCp(hatched.PokemonId), Perfection = Math.Round(PokemonInfo.CalculatePokemonPerfection(hatched), 2), HXP = ExpAwarded1, HSD = stardust2, // This still needs work too to display the total SD after hatching - TheWizard1328 HCandy = await TotCandy, }); } var newRememberedIncubators = new List <IncubatorUsage>(); foreach (var incubator in incubators) { cancellationToken.ThrowIfCancellationRequested(); TinyIoC.TinyIoCContainer.Current.Resolve <MultiAccountManager>().ThrowIfSwitchAccountRequested(); if (incubator.PokemonId == 0) { // Unlimited incubators prefer short eggs, limited incubators prefer long eggs // Special case: If only one incubator is available at all, it will prefer long eggs var egg = (incubator.ItemId == ItemId.ItemIncubatorBasicUnlimited && incubators.Count > 1) ? unusedEggs.FirstOrDefault() : unusedEggs.LastOrDefault(); if (egg == null) { continue; } // Skip (save) limited incubators depending on user choice in config if (!session.LogicSettings.UseLimitedEggIncubators && incubator.ItemId != ItemId.ItemIncubatorBasicUnlimited) { continue; } var response = await session.Client.Inventory.UseItemEggIncubator(incubator.Id, egg.Id).ConfigureAwait(false); unusedEggs.Remove(egg); newRememberedIncubators.Add(new IncubatorUsage { IncubatorId = incubator.Id, PokemonId = egg.Id }); session.EventDispatcher.Send(new EggIncubatorStatusEvent { IncubatorId = incubator.Id, WasAddedNow = true, PokemonId = egg.Id, KmToWalk = egg.EggKmWalkedTarget, KmRemaining = response.EggIncubator.TargetKmWalked - kmWalked }); } else { newRememberedIncubators.Add(new IncubatorUsage { IncubatorId = incubator.Id, PokemonId = incubator.PokemonId }); session.EventDispatcher.Send(new EggIncubatorStatusEvent { IncubatorId = incubator.Id, PokemonId = incubator.PokemonId, KmToWalk = incubator.TargetKmWalked - incubator.StartKmWalked, KmRemaining = incubator.TargetKmWalked - kmWalked }); } } if (!newRememberedIncubators.SequenceEqual(rememberedIncubators)) { SaveRememberedIncubators(newRememberedIncubators, rememberedIncubatorsFilePath); } } catch (Exception) { } }
private static async Task HandleEventAsync(ErrorEvent errorEvent, ISession session) { await PushNotificationClient.SendNotification(session, "Error occured", errorEvent.Message).ConfigureAwait(false); }
private static void HandleEvent(ErrorEvent errorEvent, ISession session) { PushNotificationClient.SendNotification(session, "Error occured", errorEvent.Message); }
private static void HandleEvent(PokemonCaptureEvent pokemonCaptureEvent, ISession session) { Func <ItemId, string> returnRealBallName = a => { // ReSharper disable once SwitchStatementMissingSomeCases switch (a) { case ItemId.ItemPokeBall: return(session.Translation.GetTranslation(TranslationString.Pokeball)); case ItemId.ItemGreatBall: return(session.Translation.GetTranslation(TranslationString.GreatPokeball)); case ItemId.ItemUltraBall: return(session.Translation.GetTranslation(TranslationString.UltraPokeball)); case ItemId.ItemMasterBall: return(session.Translation.GetTranslation(TranslationString.MasterPokeball)); default: return(session.Translation.GetTranslation(TranslationString.CommonWordUnknown)); } }; var catchType = pokemonCaptureEvent.CatchType; string strStatus; switch (pokemonCaptureEvent.Status) { case CatchPokemonResponse.Types.CatchStatus.CatchError: strStatus = session.Translation.GetTranslation(TranslationString.CatchStatusError); break; case CatchPokemonResponse.Types.CatchStatus.CatchEscape: strStatus = session.Translation.GetTranslation(TranslationString.CatchStatusEscape); break; case CatchPokemonResponse.Types.CatchStatus.CatchFlee: strStatus = session.Translation.GetTranslation(TranslationString.CatchStatusFlee); break; case CatchPokemonResponse.Types.CatchStatus.CatchMissed: strStatus = session.Translation.GetTranslation(TranslationString.CatchStatusMissed); break; case CatchPokemonResponse.Types.CatchStatus.CatchSuccess: strStatus = session.Translation.GetTranslation(TranslationString.CatchStatusSuccess); break; default: strStatus = pokemonCaptureEvent.Status.ToString(); break; } var catchStatus = pokemonCaptureEvent.Attempt > 1 ? session.Translation.GetTranslation(TranslationString.CatchStatusAttempt, strStatus, pokemonCaptureEvent.Attempt) : session.Translation.GetTranslation(TranslationString.CatchStatus, strStatus); var familyCandies = pokemonCaptureEvent.Candy?.Candy_ > 0 ? session.Translation.GetTranslation(TranslationString.Candies, pokemonCaptureEvent.Candy.Candy_) : ""; string message; if (pokemonCaptureEvent.Status == CatchPokemonResponse.Types.CatchStatus.CatchSuccess) { if (session.LogicSettings.NotificationConfig.EnablePushBulletNotification && pokemonCaptureEvent.Shiny == "Yes") { PushNotificationClient.SendNotification(session, $"Shiny Pokemon Captured", $"{session.Translation.GetPokemonTranslation(pokemonCaptureEvent.Id)}\n" + $"Lvl: {pokemonCaptureEvent.Level}\n" + $"IV: {pokemonCaptureEvent.Perfection.ToString("0.00")}\n" + $"CP: {pokemonCaptureEvent.Cp}/{pokemonCaptureEvent.MaxCp}\n" + $"Lat: {pokemonCaptureEvent.Latitude.ToString("0.000000")}\n" + $"Lon: {pokemonCaptureEvent.Longitude.ToString("0.000000")}", true).ConfigureAwait(false); } if (session.LogicSettings.NotificationConfig.EnablePushBulletNotification && pokemonCaptureEvent.Perfection >= session.LogicSettings.FavoriteMinIvPercentage) { PushNotificationClient.SendNotification(session, $"High IV Pokemon Captured", $"{session.Translation.GetPokemonTranslation(pokemonCaptureEvent.Id)}\n" + $"Lvl: {pokemonCaptureEvent.Level}\n" + $"IV: {pokemonCaptureEvent.Perfection.ToString("0.00")}\n" + $"CP: {pokemonCaptureEvent.Cp}/{pokemonCaptureEvent.MaxCp}\n" + $"Lat: {pokemonCaptureEvent.Latitude.ToString("0.000000")}\n" + $"Lon: {pokemonCaptureEvent.Longitude.ToString("0.000000")}", true).ConfigureAwait(false); } message = session.Translation.GetTranslation(TranslationString.EventPokemonCaptureSuccess, catchStatus, catchType, session.Translation.GetPokemonTranslation(pokemonCaptureEvent.Id).PadRight(12, ' '), pokemonCaptureEvent.Level.ToString("0.0").PadLeft(4, ' '), pokemonCaptureEvent.Cp.ToString("0").PadLeft(4, ' '), pokemonCaptureEvent.MaxCp.ToString("0").PadLeft(4, ' '), pokemonCaptureEvent.Perfection.ToString("0.00").PadLeft(6, ' '), pokemonCaptureEvent.Probability.ToString("0.00").PadLeft(6, ' '), pokemonCaptureEvent.Distance.ToString("F2"), returnRealBallName(pokemonCaptureEvent.Pokeball).PadRight(10, ' '), pokemonCaptureEvent.BallAmount.ToString("0").PadLeft(3, ' '), pokemonCaptureEvent.Exp.ToString("0").PadLeft(4, ' '), pokemonCaptureEvent.Stardust.ToString("0").PadLeft(4, ' '), familyCandies, pokemonCaptureEvent.Latitude.ToString("0.000000"), pokemonCaptureEvent.Longitude.ToString("0.000000"), pokemonCaptureEvent.Move1.ToString().PadRight(16, ' '), pokemonCaptureEvent.Move2.ToString().PadRight(16, ' '), pokemonCaptureEvent.Rarity.ToString().PadRight(10, ' '), pokemonCaptureEvent.CaptureReason, pokemonCaptureEvent.Shiny.ToString().PadRight(3, ' '), pokemonCaptureEvent.Form, pokemonCaptureEvent.Costume, pokemonCaptureEvent.Gender ); Logger.Write(message, LogLevel.Caught); } else { if (pokemonCaptureEvent.Status == CatchPokemonResponse.Types.CatchStatus.CatchFlee) { if (session.LogicSettings.NotificationConfig.EnablePushBulletNotification && pokemonCaptureEvent.Shiny == "Yes") { PushNotificationClient.SendNotification(session, $"Shiny Pokemon Ran Away", $"{session.Translation.GetPokemonTranslation(pokemonCaptureEvent.Id)}\n" + $"Lvl: {pokemonCaptureEvent.Level}\n" + $"IV: {pokemonCaptureEvent.Perfection.ToString("0.00")}\n" + $"CP: {pokemonCaptureEvent.Cp}/{pokemonCaptureEvent.MaxCp}\n" + $"Lat: {pokemonCaptureEvent.Latitude.ToString("0.000000")}\n" + $"Lon: {pokemonCaptureEvent.Longitude.ToString("0.000000")}", true).ConfigureAwait(false); } if (session.LogicSettings.NotificationConfig.EnablePushBulletNotification && pokemonCaptureEvent.Perfection >= session.LogicSettings.FavoriteMinIvPercentage) { PushNotificationClient.SendNotification(session, $"High IV Pokemon Ran Away", $"{session.Translation.GetPokemonTranslation(pokemonCaptureEvent.Id)}\n" + $"Lvl: {pokemonCaptureEvent.Level}\n" + $"IV: {pokemonCaptureEvent.Perfection.ToString("0.00")}\n" + $"CP: {pokemonCaptureEvent.Cp}/{pokemonCaptureEvent.MaxCp}\n" + $"Lat: {pokemonCaptureEvent.Latitude.ToString("0.000000")}\n" + $"Lon: {pokemonCaptureEvent.Longitude.ToString("0.000000")}", true).ConfigureAwait(false); } } message = session.Translation.GetTranslation(TranslationString.EventPokemonCaptureFailed, catchStatus, catchType, session.Translation.GetPokemonTranslation(pokemonCaptureEvent.Id).PadRight(12, ' '), pokemonCaptureEvent.Level.ToString("0.0").PadLeft(4, ' '), pokemonCaptureEvent.Cp.ToString("0").PadLeft(4, ' '), pokemonCaptureEvent.MaxCp.ToString("0").PadLeft(4, ' '), pokemonCaptureEvent.Perfection.ToString("0.00").PadLeft(6, ' '), pokemonCaptureEvent.Probability.ToString("0.00").PadLeft(6, ' '), pokemonCaptureEvent.Distance.ToString("F2"), returnRealBallName(pokemonCaptureEvent.Pokeball).PadRight(10, ' '), pokemonCaptureEvent.BallAmount.ToString("0").PadLeft(3, ' '), pokemonCaptureEvent.Exp.ToString("0").PadLeft(4, ' '), pokemonCaptureEvent.Latitude.ToString("0.000000"), pokemonCaptureEvent.Longitude.ToString("0.000000"), pokemonCaptureEvent.Move1.ToString().PadRight(15, ' '), pokemonCaptureEvent.Move2.ToString().PadRight(15, ' '), pokemonCaptureEvent.Rarity.ToString().PadRight(10, ' ') ); Logger.Write(message, LogLevel.Flee); } }
public async Task Start(IState initialState, ISession session, string subPath, bool excelConfigAllowed = false) { var manager = TinyIoCContainer.Current.Resolve <MultiAccountManager>(); GlobalSettings globalSettings = null; var state = initialState; var profilePath = Path.Combine(Directory.GetCurrentDirectory(), subPath); var profileConfigPath = Path.Combine(profilePath, "config"); globalSettings = GlobalSettings.Load(subPath); FileSystemWatcher configWatcher = new FileSystemWatcher() { Path = profileConfigPath, Filter = "config.json", NotifyFilter = NotifyFilters.LastWrite, EnableRaisingEvents = true }; configWatcher.Changed += (sender, e) => { if (e.ChangeType == WatcherChangeTypes.Changed) { globalSettings = GlobalSettings.Load(subPath); session.LogicSettings = new LogicSettings(globalSettings); // BUG: duplicate boolean negation will take no effect configWatcher.EnableRaisingEvents = !configWatcher.EnableRaisingEvents; configWatcher.EnableRaisingEvents = !configWatcher.EnableRaisingEvents; Logger.Write(" ##### config.json ##### ", LogLevel.Info); } }; //watch the excel config file if (excelConfigAllowed) { // TODO - await is legal here! USE it or use pragma to suppress compilerwarning and write a comment why it is not used // TODO: Attention - do not touch (add pragma) when you do not know what you are doing ;) // jjskuld - Ignore CS4014 warning for now. #pragma warning disable 4014 Run(async() => { while (true) { try { FileInfo inf = new FileInfo($"{profileConfigPath}\\config.xlsm"); if (inf.LastWriteTime > DateTime.Now.AddSeconds(-5)) { globalSettings = ExcelConfigHelper.ReadExcel(globalSettings, inf.FullName); session.LogicSettings = new LogicSettings(globalSettings); Logger.Write(" ##### config.xlsm ##### ", LogLevel.Info); } await Delay(5000).ConfigureAwait(false); } catch (Exception) { // TODO Bad practice! Wanna log this? } } }); #pragma warning restore 4014 } int apiCallFailured = 0; do { try { state = await state.Execute(session, session.CancellationTokenSource.Token).ConfigureAwait(false); // Exit the bot if both catching and looting has reached its limits if ((UseNearbyPokestopsTask._pokestopLimitReached || UseNearbyPokestopsTask._pokestopTimerReached) && session.Stats.CatchThresholdExceeds(session)) { session.EventDispatcher.Send(new ErrorEvent { Message = session.Translation.GetTranslation(TranslationString.ExitDueToLimitsReached) }); session.CancellationTokenSource.Cancel(); // A bit rough here; works but can be improved await Delay(10000).ConfigureAwait(false); state = null; session.CancellationTokenSource.Dispose(); Environment.Exit(0); } } catch (APIBadRequestException) { session.EventDispatcher.Send(new ErrorEvent() { Message = "An unexpected error has occured. Logging in again... (Bad API Request)" }); /* changed state if bad request * * if (manager.AllowMultipleBot()) * ReInitializeSession(session, globalSettings); * state = new LoginState();*/ await Delay(1000).ConfigureAwait(false); state = _initialState; } catch (AccountNotVerifiedException) { if (manager.AllowMultipleBot()) { ReInitializeSession(session, globalSettings); state = new LoginState(); } else { Console.Read(); Environment.Exit(0); } } catch (ActiveSwitchAccountManualException ex) { session.EventDispatcher.Send(new WarnEvent { Message = "Switch bot account requested by: User" }); ReInitializeSession(session, globalSettings, ex.RequestedAccount); state = new LoginState(); } catch (ActiveSwitchByPokemonException rsae) { if (rsae.Snipe && rsae.EncounterData != null) { session.EventDispatcher.Send(new WarnEvent { Message = $"Detected a good pokemon with snipe {rsae.EncounterData.PokemonId.ToString()} IV:{rsae.EncounterData.IV} Move:{rsae.EncounterData.Move1}/ Move:{rsae.EncounterData.Move2} LV: Move:{rsae.EncounterData.Level}" }); } else { session.EventDispatcher.Send(new WarnEvent { Message = "Encountered a good pokemon, switch bots to catch him too." }); if (session.LogicSettings.NotificationConfig.EnablePushBulletNotification) { await PushNotificationClient.SendNotification(session, $"Switch bot account", $"Encountered a good pokemon, switch bots to catch him too.", true).ConfigureAwait(false); } } session.ReInitSessionWithNextBot(rsae.Bot, session.Client.CurrentLatitude, session.Client.CurrentLongitude, session.Client.CurrentAltitude); state = new LoginState(rsae.LastEncounterPokemonId, rsae.EncounterData); } catch (ActiveSwitchByRuleException se) { session.EventDispatcher.Send(new WarnEvent { Message = $"Switch bot account activated by: {se.MatchedRule.ToString()} - {se.ReachedValue}" }); //if (session.LogicSettings.NotificationConfig.EnablePushBulletNotification) // await PushNotificationClient.SendNotification(session, $"Switch bot account", $"Activated by: {se.MatchedRule.ToString()} - {se.ReachedValue}", true).ConfigureAwait(false); if (se.MatchedRule == SwitchRules.EmptyMap) { TinyIoCContainer.Current.Resolve <MultiAccountManager>().BlockCurrentBot(90); ReInitializeSession(session, globalSettings); } else if (se.MatchedRule == SwitchRules.PokestopSoftban) { TinyIoCContainer.Current.Resolve <MultiAccountManager>().BlockCurrentBot(); ReInitializeSession(session, globalSettings); } else if (se.MatchedRule == SwitchRules.CatchFlee) { TinyIoCContainer.Current.Resolve <MultiAccountManager>().BlockCurrentBot(60); ReInitializeSession(session, globalSettings); } else { if (se.MatchedRule == SwitchRules.CatchLimitReached || se.MatchedRule == SwitchRules.SpinPokestopReached) { // TODO - await is legal here! USE it or use pragma to suppress compilerwarning and write a comment why it is not used // TODO: Attention - do not touch (add pragma) when you do not know what you are doing ;) // jjskuld - Ignore CS4014 warning for now. if (session.LogicSettings.NotificationConfig.EnablePushBulletNotification) { await PushNotificationClient.SendNotification(session, $"{se.MatchedRule} - {session.Settings.Username}", $"This bot has reach limit, it will be blocked for {session.LogicSettings.MultipleBotConfig.OnLimitPauseTimes} mins for safety.", true).ConfigureAwait(false); } session.EventDispatcher.Send(new WarnEvent() { Message = $"You reach limited. bot will sleep for {session.LogicSettings.MultipleBotConfig.OnLimitPauseTimes} min" }); TinyIoCContainer.Current.Resolve <MultiAccountManager>().BlockCurrentBot(session.LogicSettings.MultipleBotConfig.OnLimitPauseTimes); ReInitializeSession(session, globalSettings); } else { ReInitializeSession(session, globalSettings); } } //return to login state state = new LoginState(); } catch (InvalidResponseException e) { session.EventDispatcher.Send(new ErrorEvent { Message = $"Niantic Servers unstable, throttling API Calls. {e.Message}" }); await Delay(1000).ConfigureAwait(false); if (manager.AllowMultipleBot()) { apiCallFailured++; if (apiCallFailured > 20) { apiCallFailured = 0; TinyIoCContainer.Current.Resolve <MultiAccountManager>().BlockCurrentBot(30); ReInitializeSession(session, globalSettings); } } state = new LoginState(); } catch (SessionInvalidatedException e) { session.EventDispatcher.Send(new ErrorEvent { Message = $"Hashing Servers errors, throttling calls. {e.Message}" }); await Delay(1000).ConfigureAwait(false); if (manager.AllowMultipleBot()) { apiCallFailured++; if (apiCallFailured > 3) { apiCallFailured = 0; TinyIoCContainer.Current.Resolve <MultiAccountManager>().BlockCurrentBot(30); ReInitializeSession(session, globalSettings); } } // Resetting position session.EventDispatcher.Send(new ErrorEvent { Message = $"Resetting position before relogging in." }); // TheWizard1328 - Changed this to CurrentLocation from DefaultLocation because Bot would JUMP back to DefaultLocation and could be considered as teleporting even in a short distance. session.Client.Player.UpdatePlayerLocation(session.Client.CurrentLatitude, session.Client.CurrentLongitude, session.Client.CurrentAltitude, 0); state = new LoginState(); } catch (OperationCanceledException) { session.EventDispatcher.Send(new ErrorEvent { Message = "Current Operation was canceled." }); if (manager.AllowMultipleBot()) { TinyIoCContainer.Current.Resolve <MultiAccountManager>().BlockCurrentBot(30); ReInitializeSession(session, globalSettings); } state = new LoginState(); } catch (PtcLoginException ex) { if (session.LogicSettings.NotificationConfig.EnablePushBulletNotification) { await PushNotificationClient.SendNotification(session, $"PTC Login failed!!!! {session.Settings.Username}", session.Translation.GetTranslation(TranslationString.PtcLoginFail), true).ConfigureAwait(false); } if (manager.AllowMultipleBot()) { TinyIoCContainer.Current.Resolve <MultiAccountManager>().BlockCurrentBot(60); //need remove acc ReInitializeSession(session, globalSettings); state = new LoginState(); } else { session.EventDispatcher.Send(new ErrorEvent { RequireExit = true, Message = session.Translation.GetTranslation(TranslationString.ExitNowAfterEnterKey) }); session.EventDispatcher.Send(new ErrorEvent { RequireExit = true, Message = session.Translation.GetTranslation(TranslationString.PtcLoginFail) + $" ({ex.Message})" }); Console.ReadKey(); Environment.Exit(1); } } catch (LoginFailedException) { // TODO - await is legal here! USE it or use pragma to suppress compilerwarning and write a comment why it is not used // TODO: Attention - do not touch (add pragma) when you do not know what you are doing ;) // jjskuld - Ignore CS4014 warning for now. if (session.LogicSettings.NotificationConfig.EnablePushBulletNotification) { await PushNotificationClient.SendNotification(session, $"Banned!!!! {session.Settings.Username}", session.Translation.GetTranslation(TranslationString.AccountBanned), true).ConfigureAwait(false); } if (manager.AllowMultipleBot()) { var accountManager = TinyIoCContainer.Current.Resolve <MultiAccountManager>(); var currentAccount = accountManager?.GetCurrentAccount(); currentAccount.AccountActive = false; accountManager.UpdateLocalAccount(currentAccount); globalSettings.Auth.Bots[(int)currentAccount.Id].AccountActive = false; globalSettings.Auth.Save(Path.Combine(globalSettings.ProfileConfigPath, "auth.json")); TinyIoCContainer.Current.Resolve <MultiAccountManager>().BlockCurrentBot(24 * 60); //need remove acc ReInitializeSession(session, globalSettings); state = new LoginState(); } else { session.EventDispatcher.Send(new ErrorEvent { RequireExit = true, Message = session.Translation.GetTranslation(TranslationString.ExitNowAfterEnterKey) }); Console.ReadKey(); Environment.Exit(1); } } catch (MinimumClientVersionException ex) { // We need to terminate the client. session.EventDispatcher.Send(new ErrorEvent { Message = session.Translation.GetTranslation(TranslationString.MinimumClientVersionException, ex.CurrentApiVersion.ToString(), ex.MinimumClientVersion.ToString()) }); session.EventDispatcher.Send(new ErrorEvent { RequireExit = true, Message = session.Translation.GetTranslation(TranslationString.ExitNowAfterEnterKey) }); Console.ReadKey(); Environment.Exit(1); } catch (TokenRefreshException ex) { session.EventDispatcher.Send(new ErrorEvent() { Message = ex.Message }); if (manager.AllowMultipleBot()) { ReInitializeSession(session, globalSettings); } state = new LoginState(); } catch (PtcOfflineException) { session.EventDispatcher.Send(new ErrorEvent { Message = session.Translation.GetTranslation(TranslationString.PtcOffline) }); session.EventDispatcher.Send(new NoticeEvent { Message = session.Translation.GetTranslation(TranslationString.TryingAgainIn, 15) }); await Delay(1000).ConfigureAwait(false); state = _initialState; } catch (GoogleOfflineException) { session.EventDispatcher.Send(new ErrorEvent { Message = session.Translation.GetTranslation(TranslationString.GoogleOffline) }); session.EventDispatcher.Send(new NoticeEvent { Message = session.Translation.GetTranslation(TranslationString.TryingAgainIn, 15) }); await Delay(15000).ConfigureAwait(false); state = _initialState; } catch (AccessTokenExpiredException) { session.EventDispatcher.Send(new NoticeEvent { Message = "Access Token Expired. Logging in again..." }); state = _initialState; } catch (CaptchaException captchaException) { var resolved = await CaptchaManager.SolveCaptcha(session, captchaException.Url).ConfigureAwait(false); if (!resolved) { if (session.LogicSettings.NotificationConfig.EnablePushBulletNotification) { await PushNotificationClient.SendNotification(session, $"Captcha required {session.Settings.Username}", session.Translation.GetTranslation(TranslationString.CaptchaShown), true).ConfigureAwait(false); } session.EventDispatcher.Send(new WarnEvent { Message = session.Translation.GetTranslation(TranslationString.CaptchaShown) }); Logger.Debug("Captcha not resolved"); if (manager.AllowMultipleBot()) { Logger.Debug("Change account"); TinyIoCContainer.Current.Resolve <MultiAccountManager>().BlockCurrentBot(15); ReInitializeSession(session, globalSettings); state = new LoginState(); } else { session.EventDispatcher.Send(new ErrorEvent { Message = session.Translation.GetTranslation(TranslationString.ExitNowAfterEnterKey) }); Console.ReadKey(); Environment.Exit(0); } } else { //resolve captcha state = new LoginState(); } } catch (HasherException ex) { session.EventDispatcher.Send(new ErrorEvent { Message = ex.Message }); // session.EventDispatcher.Send(new ErrorEvent { Message = session.Translation.GetTranslation(TranslationString.ExitNowAfterEnterKey) }); state = new IdleState(); //Console.ReadKey(); //System.Environment.Exit(1); } catch (Exception ex) { session.EventDispatcher.Send(new ErrorEvent { Message = "Pokemon Servers might be offline / unstable. Trying again..." }); session.EventDispatcher.Send(new ErrorEvent { Message = "Error: " + ex }); if (state is LoginState) { } else { state = _initialState; } } } while (state != null); configWatcher.EnableRaisingEvents = false; configWatcher.Dispose(); }
//TODO : Need add BotManager to manage all feature related to multibot, public bool ReInitSessionWithNextBot(AuthConfig bot = null, double lat = 0, double lng = 0, double att = 0) { this.CatchBlockTime = DateTime.Now; //remove any block var currentAccount = this.accounts.FirstOrDefault(x => (x.AuthType == PokemonGo.RocketAPI.Enums.AuthType.Ptc && x.PtcUsername == this.Settings.PtcUsername) || (x.AuthType == PokemonGo.RocketAPI.Enums.AuthType.Google && x.GoogleUsername == this.Settings.GoogleUsername)); if (LoggedTime != DateTime.MinValue) { currentAccount.RuntimeTotal += (DateTime.Now - LoggedTime).TotalMinutes; } this.accounts = this.accounts.OrderByDescending(p => p.RuntimeTotal).ToList(); var first = this.accounts.First(); if (first.RuntimeTotal >= 100000) { first.RuntimeTotal = this.accounts.Min(p => p.RuntimeTotal); } var nextBot = bot != null ? bot : this.accounts.LastOrDefault(p => p != currentAccount && p.ReleaseBlockTime < DateTime.Now); if (nextBot != null) { Logger.Write($"Switching to {nextBot.GoogleUsername}{nextBot.PtcUsername}..."); string body = ""; File.Delete("runtime.log"); List <string> logs = new List <string>(); foreach (var item in this.Accounts) { int day = (int)item.RuntimeTotal / 1440; int hour = (int)(item.RuntimeTotal - (day * 1400)) / 60; int min = (int)(item.RuntimeTotal - (day * 1400) - hour * 60); body = body + $"{item.GoogleUsername}{item.PtcUsername} {day:00}:{hour:00}:{min:00}:00\r\n"; logs.Add($"{item.GoogleUsername}{item.PtcUsername};{item.RuntimeTotal}"); } File.AppendAllLines("runtime.log", logs); PushNotificationClient.SendNotification(this, $"Account changed to {nextBot.GoogleUsername}{nextBot.PtcUsername}", body); this.Settings.AuthType = nextBot.AuthType; this.Settings.GooglePassword = nextBot.GooglePassword; this.Settings.GoogleUsername = nextBot.GoogleUsername; this.Settings.PtcPassword = nextBot.PtcPassword; this.Settings.PtcUsername = nextBot.PtcUsername; this.Settings.DefaultAltitude = att == 0 ? this.Client.CurrentAltitude : att; this.Settings.DefaultLatitude = lat == 0 ? this.Client.CurrentLatitude : lat; this.Settings.DefaultLongitude = lng == 0 ? this.Client.CurrentLongitude : lng; this.Stats = new SessionStats(this); this.Reset(this.Settings, this.LogicSettings); CancellationTokenSource.Cancel(); this.CancellationTokenSource = new CancellationTokenSource(); this.EventDispatcher.Send(new BotSwitchedEvent() { }); if (this.LogicSettings.MultipleBotConfig.DisplayList) { foreach (var item in this.accounts) { Logger.Write($"{item.PtcUsername}{item.GoogleUsername} \tRuntime : {item.RuntimeTotal:0.00} min "); } } } return(nextBot != null); }
//TODO : Need add BotManager to manage all feature related to multibot, public bool ReInitSessionWithNextBot(Account bot = null, double lat = 0, double lng = 0, double att = 0) { CatchBlockTime = DateTime.Now; //remove any block MSniperServiceTask.BlockSnipe(); VisibleForts.Clear(); Forts.Clear(); var manager = TinyIoCContainer.Current.Resolve <MultiAccountManager>(); var session = TinyIoCContainer.Current.Resolve <ISession>(); var nextBot = manager.GetSwitchableAccount(bot); var Account = !string.IsNullOrEmpty(nextBot.Nickname) ? nextBot.Nickname : nextBot.Username; var TotXP = 0; for (int i = 0; i < nextBot.Level + 1; i++) { TotXP = TotXP + Statistics.GetXpDiff(i); } long?XP = nextBot.CurrentXp; if (XP == null) { XP = 0; } long?SD = nextBot.Stardust; if (SD == null) { SD = 0; } long?Lvl = nextBot.Level; if (Lvl == null) { Lvl = 0; } var NLevelXP = nextBot.NextLevelXp; if (nextBot.NextLevelXp == null) { NLevelXP = 0; } Logger.Write($"Account changed to {Account}", LogLevel.BotStats); if (session.LogicSettings.NotificationConfig.EnablePushBulletNotification) { PushNotificationClient.SendNotification(session, $"Account changed to", $"{Account}\n" + $"Lvl: {Lvl}\n" + $"XP : {XP:#,##0}({(double)XP / ((double)NLevelXP) * 100:#0.00}%)\n" + $"SD : {SD:#,##0}", true).ConfigureAwait(false); } if (nextBot != null) { manager.SwitchAccounts(nextBot); } Settings.DefaultAltitude = att == 0 ? Client.CurrentAltitude : att; Settings.DefaultLatitude = lat == 0 ? Client.CurrentLatitude : lat; Settings.DefaultLongitude = lng == 0 ? Client.CurrentLongitude : lng; Stats = new SessionStats(this); Reset(Settings, LogicSettings); //CancellationTokenSource.Cancel(); CancellationTokenSource = new CancellationTokenSource(); EventDispatcher.Send(new BotSwitchedEvent(nextBot) { }); if (LogicSettings.MultipleBotConfig.DisplayList) { manager.DumpAccountList(); } return(true); }
public void SwitchAccounts(Account newAccount) { if (newAccount == null) { return; } var runningAccount = GetCurrentAccount(); if (runningAccount != null) { runningAccount.IsRunning = 0; var now = DateTime.Now; if (runningAccount.LastRuntimeUpdatedAt.HasValue) { runningAccount.RuntimeTotal += (now - TimeUtil.GetDateTimeFromMilliseconds(runningAccount.LastRuntimeUpdatedAt.Value)).TotalMinutes; } runningAccount.LastRuntimeUpdatedAt = now.ToUnixTime(); UpdateLocalAccount(runningAccount); } newAccount.IsRunning = 1; newAccount.LoggedTime = DateTime.Now.ToUnixTime(); newAccount.LastRuntimeUpdatedAt = newAccount.LoggedTime; UpdateLocalAccount(newAccount); // Update current auth config with new account. _globalSettings.Auth.CurrentAuthConfig.AuthType = (AuthType)newAccount.AuthType; _globalSettings.Auth.CurrentAuthConfig.Username = newAccount.Username; _globalSettings.Auth.CurrentAuthConfig.Password = newAccount.Password; string body = ""; foreach (var item in Accounts) { body = body + $"{item.Username} - {item.GetRuntime()}\r\n"; } var session = TinyIoCContainer.Current.Resolve <ISession>(); var Account = !string.IsNullOrEmpty(newAccount.Nickname) ? newAccount.Nickname : newAccount.Username; var TotXP = 0; for (int i = 0; i < newAccount.Level + 1; i++) { TotXP = TotXP + Statistics.GetXpDiff(i); } long?XP = newAccount.CurrentXp; if (XP == null) { XP = 0; } long?SD = newAccount.Stardust; if (SD == null) { SD = 0; } var NLevelXP = newAccount.NextLevelXp; if (newAccount.NextLevelXp == null) { NLevelXP = 0; } Logger.Write($"Account changed to {Account}", LogLevel.BotStats); Logger.Write($"Lvl: {newAccount.Level} | XP: {XP}({(double)XP / ((double)NLevelXP) * 100:#0.00}%) | SD: {SD}", LogLevel.BotStats); if (session.LogicSettings.NotificationConfig.EnablePushBulletNotification == true) { PushNotificationClient.SendNotification(session, $"Account changed to", $"{Account}\n" + $"Lvl: {newAccount.Level}\n" + $"XP : {XP:#,##0}({(double)XP / ((double)NLevelXP) * 100:#0.00}%)\n" + $"SD : {SD:#,##0}\n", true).ConfigureAwait(false); } }
/// <summary> /// Because this function sometime being called inside loop, return true it mean we don't want break look, false it mean not need to call this , break a loop from caller function /// </summary> /// <param name="session"></param> /// <param name="cancellationToken"></param> /// <param name="encounter"></param> /// <param name="pokemon"></param> /// <param name="currentFortData"></param> /// <param name="sessionAllowTransfer"></param> /// <returns></returns> public static async Task <bool> Execute(ISession session, CancellationToken cancellationToken, dynamic encounter, MapPokemon pokemon, FortData currentFortData, bool sessionAllowTransfer) { var manager = TinyIoCContainer.Current.Resolve <MultiAccountManager>(); manager.ThrowIfSwitchAccountRequested(); // If the encounter is null nothing will work below, so exit now if (encounter == null) { return(true); } var totalBalls = (await session.Inventory.GetItems().ConfigureAwait(false)).Where(x => x.ItemId == ItemId.ItemPokeBall || x.ItemId == ItemId.ItemGreatBall || x.ItemId == ItemId.ItemUltraBall).Sum(x => x.Count); if (session.SaveBallForByPassCatchFlee && totalBalls < BALL_REQUIRED_TO_BYPASS_CATCHFLEE) { return(false); } // Exit if user defined max limits reached if (session.Stats.CatchThresholdExceeds(session)) { if (manager.AllowMultipleBot() && session.LogicSettings.MultipleBotConfig.SwitchOnCatchLimit && TinyIoCContainer.Current.Resolve <MultiAccountManager>().AllowSwitch()) { throw new ActiveSwitchByRuleException() { MatchedRule = SwitchRules.CatchLimitReached, ReachedValue = session.LogicSettings.CatchPokemonLimit }; } return(false); } using (var block = new BlockableScope(session, BotActions.Catch)) { if (!await block.WaitToRun().ConfigureAwait(false)) { return(true); } AmountOfBerries = new Dictionary <ItemId, int>(); cancellationToken.ThrowIfCancellationRequested(); float probability = encounter.CaptureProbability?.CaptureProbability_[0]; PokemonData encounteredPokemon; long unixTimeStamp; ulong _encounterId; string _spawnPointId; // Calling from CatchNearbyPokemonTask and SnipePokemonTask if (encounter is EncounterResponse && (encounter?.Status == EncounterResponse.Types.Status.EncounterSuccess)) { encounteredPokemon = encounter.WildPokemon?.PokemonData; unixTimeStamp = encounter.WildPokemon?.LastModifiedTimestampMs + encounter.WildPokemon?.TimeTillHiddenMs; _spawnPointId = encounter.WildPokemon?.SpawnPointId; _encounterId = encounter.WildPokemon?.EncounterId; } // Calling from CatchIncensePokemonTask else if (encounter is IncenseEncounterResponse && (encounter?.Result == IncenseEncounterResponse.Types.Result.IncenseEncounterSuccess)) { encounteredPokemon = encounter?.PokemonData; unixTimeStamp = pokemon.ExpirationTimestampMs; _spawnPointId = pokemon.SpawnPointId; _encounterId = pokemon.EncounterId; } // Calling from CatchLurePokemon else if (encounter is DiskEncounterResponse && encounter?.Result == DiskEncounterResponse.Types.Result.Success && !(currentFortData == null)) { encounteredPokemon = encounter?.PokemonData; unixTimeStamp = currentFortData.LureInfo.LureExpiresTimestampMs; _spawnPointId = currentFortData.Id; _encounterId = currentFortData.LureInfo.EncounterId; } else { return(true); // No success to work with, exit } // Check for pokeballs before proceeding var pokeball = await GetBestBall(session, encounteredPokemon, probability).ConfigureAwait(false); if (pokeball == ItemId.ItemUnknown) { Logger.Write(session.Translation.GetTranslation(TranslationString.ZeroPokeballInv)); return(false); } // Calculate CP and IV var pokemonCp = encounteredPokemon?.Cp; var pokemonIv = PokemonInfo.CalculatePokemonPerfection(encounteredPokemon); var lv = PokemonInfo.GetLevel(encounteredPokemon); // Calculate distance away var latitude = encounter is EncounterResponse || encounter is IncenseEncounterResponse ? pokemon.Latitude : currentFortData.Latitude; var longitude = encounter is EncounterResponse || encounter is IncenseEncounterResponse ? pokemon.Longitude : currentFortData.Longitude; var distance = LocationUtils.CalculateDistanceInMeters(session.Client.CurrentLatitude, session.Client.CurrentLongitude, latitude, longitude); if (session.LogicSettings.ActivateMSniper) { var newdata = new MSniperServiceTask.EncounterInfo() { EncounterId = _encounterId.ToString(), Iv = Math.Round(pokemonIv, 2), Latitude = latitude.ToString("G17", CultureInfo.InvariantCulture), Longitude = longitude.ToString("G17", CultureInfo.InvariantCulture), PokemonId = (int)(encounteredPokemon?.PokemonId ?? 0), PokemonName = encounteredPokemon?.PokemonId.ToString(), SpawnPointId = _spawnPointId, Move1 = PokemonInfo.GetPokemonMove1(encounteredPokemon).ToString(), Move2 = PokemonInfo.GetPokemonMove2(encounteredPokemon).ToString(), Expiration = unixTimeStamp }; session.EventDispatcher.Send(newdata); } DateTime expiredDate = new DateTime(1970, 1, 1, 0, 0, 0).AddMilliseconds(Convert.ToDouble(unixTimeStamp)); var encounterEV = new EncounteredEvent() { Latitude = latitude, Longitude = longitude, PokemonId = encounteredPokemon.PokemonId, IV = pokemonIv, Level = (int)lv, Expires = expiredDate.ToUniversalTime(), ExpireTimestamp = unixTimeStamp, SpawnPointId = _spawnPointId, EncounterId = _encounterId.ToString(), Move1 = PokemonInfo.GetPokemonMove1(encounteredPokemon).ToString(), Move2 = PokemonInfo.GetPokemonMove2(encounteredPokemon).ToString(), }; //add catch to avoid snipe duplicate string uniqueCacheKey = CatchPokemonTask.GetUsernameGeoLocationCacheKey(session.Settings.Username, encounterEV.PokemonId, encounterEV.Latitude, encounterEV.Longitude); session.Cache.Add(uniqueCacheKey, encounterEV, DateTime.Now.AddMinutes(30)); session.EventDispatcher.Send(encounterEV); if (IsNotMetWithCatchCriteria(session, encounteredPokemon, pokemonIv, lv, pokemonCp)) { session.EventDispatcher.Send(new NoticeEvent { Message = session.Translation.GetTranslation(TranslationString.PokemonSkipped, encounteredPokemon.PokemonId) }); session.Cache.Add(CatchPokemonTask.GetEncounterCacheKey(_encounterId), encounteredPokemon, expiredDate); Logger.Write( $"Filter catch not met. {encounteredPokemon.PokemonId.ToString()} IV {pokemonIv} lv {lv} {pokemonCp} move1 {PokemonInfo.GetPokemonMove1(encounteredPokemon)} move 2 {PokemonInfo.GetPokemonMove2(encounteredPokemon)}"); return(true); } CatchPokemonResponse caughtPokemonResponse = null; var lastThrow = CatchPokemonResponse.Types.CatchStatus.CatchSuccess; // Initializing lastThrow var attemptCounter = 1; // Main CatchPokemon-loop do { if (session.LogicSettings.UseHumanlikeDelays) { await DelayingUtils.DelayAsync(session.LogicSettings.BeforeCatchDelay, 0, session.CancellationTokenSource.Token).ConfigureAwait(false); } if ((session.LogicSettings.MaxPokeballsPerPokemon > 0 && attemptCounter > session.LogicSettings.MaxPokeballsPerPokemon)) { break; } pokeball = await GetBestBall(session, encounteredPokemon, probability).ConfigureAwait(false); if (pokeball == ItemId.ItemUnknown) { session.EventDispatcher.Send(new NoPokeballEvent { Id = encounter is EncounterResponse ? pokemon.PokemonId : encounter?.PokemonData.PokemonId, Cp = encounteredPokemon.Cp }); return(false); } // Determine whether to use berries or not if (lastThrow != CatchPokemonResponse.Types.CatchStatus.CatchMissed) { //AmountOfBerries++; //if (AmountOfBerries <= session.LogicSettings.MaxBerriesToUsePerPokemon) await UseBerry(session, encounterEV.PokemonId, _encounterId, _spawnPointId, pokemonIv, pokemonCp ?? 10000, //unknown CP pokemon, want to use berry encounterEV.Level, probability, cancellationToken).ConfigureAwait(false); } bool hitPokemon = true; //default to excellent throw var normalizedRecticleSize = 1.95; //default spin var spinModifier = 1.0; //Humanized throws if (session.LogicSettings.EnableHumanizedThrows) { //thresholds: https://gist.github.com/anonymous/077d6dea82d58b8febde54ae9729b1bf var spinTxt = "Curve"; var hitTxt = "Excellent"; if (pokemonCp > session.LogicSettings.ForceExcellentThrowOverCp || pokemonIv > session.LogicSettings.ForceExcellentThrowOverIv) { normalizedRecticleSize = Random.NextDouble() * (1.95 - 1.7) + 1.7; } else if (pokemonCp >= session.LogicSettings.ForceGreatThrowOverCp || pokemonIv >= session.LogicSettings.ForceGreatThrowOverIv) { normalizedRecticleSize = Random.NextDouble() * (1.95 - 1.3) + 1.3; hitTxt = "Great"; } else { var regularThrow = 100 - (session.LogicSettings.ExcellentThrowChance + session.LogicSettings.GreatThrowChance + session.LogicSettings.NiceThrowChance); var rnd = Random.Next(1, 101); if (rnd <= regularThrow) { normalizedRecticleSize = Random.NextDouble() * (1 - 0.1) + 0.1; hitTxt = "Ordinary"; } else if (rnd <= regularThrow + session.LogicSettings.NiceThrowChance) { normalizedRecticleSize = Random.NextDouble() * (1.3 - 1) + 1; hitTxt = "Nice"; } else if (rnd <= regularThrow + session.LogicSettings.NiceThrowChance + session.LogicSettings.GreatThrowChance) { normalizedRecticleSize = Random.NextDouble() * (1.7 - 1.3) + 1.3; hitTxt = "Great"; } if (Random.NextDouble() * 100 > session.LogicSettings.CurveThrowChance) { spinModifier = 0.0; spinTxt = "Straight"; } } // Round to 2 decimals normalizedRecticleSize = Math.Round(normalizedRecticleSize, 2); // Missed throw check int missChance = Random.Next(1, 101); if (missChance <= session.LogicSettings.ThrowMissPercentage && session.LogicSettings.EnableMissedThrows) { hitPokemon = false; } Logger.Write($"(Threw ball) {hitTxt} throw, {spinTxt}-ball, HitPokemon = {hitPokemon}...", LogLevel.Debug); } if (CatchFleeContinuouslyCount >= 3 && session.LogicSettings.ByPassCatchFlee) { MSniperServiceTask.BlockSnipe(); if (totalBalls <= BALL_REQUIRED_TO_BYPASS_CATCHFLEE) { Logger.Write("You don't have enough balls to bypass catchflee"); return(false); } List <ItemId> ballToByPass = new List <ItemId>(); var numPokeBalls = await session.Inventory.GetItemAmountByType(ItemId.ItemPokeBall).ConfigureAwait(false); for (int i = 0; i < numPokeBalls - 1; i++) { ballToByPass.Add(ItemId.ItemPokeBall); } var numGreatBalls = await session.Inventory.GetItemAmountByType(ItemId.ItemGreatBall).ConfigureAwait(false); for (int i = 0; i < numGreatBalls - 1; i++) { ballToByPass.Add(ItemId.ItemGreatBall); } var numUltraBalls = await session.Inventory.GetItemAmountByType(ItemId.ItemUltraBall).ConfigureAwait(false); for (int i = 0; i < numUltraBalls - 1; i++) { ballToByPass.Add(ItemId.ItemUltraBall); } bool catchMissed = true; Random r = new Random(); for (int i = 0; i < ballToByPass.Count - 1; i++) { if (i > 130 && r.Next(0, 100) <= 30) { catchMissed = false; } else { catchMissed = true; } caughtPokemonResponse = await session.Client.Encounter.CatchPokemon( encounter is EncounterResponse || encounter is IncenseEncounterResponse ?pokemon.EncounterId : _encounterId, encounter is EncounterResponse || encounter is IncenseEncounterResponse ?pokemon.SpawnPointId : currentFortData.Id, ballToByPass[i], 1.0, 1.0, !catchMissed).ConfigureAwait(false); await session.Inventory.UpdateInventoryItem(ballToByPass[i]).ConfigureAwait(false); await Task.Delay(100).ConfigureAwait(false); Logger.Write($"CatchFlee By pass: {ballToByPass[i].ToString()} , Attempt {i}, result {caughtPokemonResponse.Status}"); if (session.LogicSettings.NotificationConfig.EnablePushBulletNotification && i == 0) { await PushNotificationClient.SendNotification(session, "Catch Flee Soft Ban", "Attempting to bypass Catch Flee Soft Ban.", true).ConfigureAwait(false); } if (session.LogicSettings.NotificationConfig.EnablePushBulletNotification && caughtPokemonResponse.Status == CatchPokemonResponse.Types.CatchStatus.CatchSuccess) { await PushNotificationClient.SendNotification(session, "Catch Flee Soft Ban", "Catch Flee Soft Ban bypassed.", true).ConfigureAwait(false); } if (caughtPokemonResponse.Status != CatchPokemonResponse.Types.CatchStatus.CatchMissed) { session.SaveBallForByPassCatchFlee = false; CatchFleeContinuouslyCount = 0; break; } } } else { caughtPokemonResponse = await session.Client.Encounter.CatchPokemon( encounter is EncounterResponse || encounter is IncenseEncounterResponse ?pokemon.EncounterId : _encounterId, encounter is EncounterResponse || encounter is IncenseEncounterResponse ?pokemon.SpawnPointId : currentFortData.Id, pokeball, normalizedRecticleSize, spinModifier, hitPokemon).ConfigureAwait(false); await session.Inventory.UpdateInventoryItem(pokeball).ConfigureAwait(false); } var evt = new PokemonCaptureEvent() { Status = caughtPokemonResponse.Status, CaptureReason = caughtPokemonResponse.CaptureReason, Latitude = latitude, Longitude = longitude }; lastThrow = caughtPokemonResponse.Status; // sets lastThrow status if (caughtPokemonResponse.Status == CatchPokemonResponse.Types.CatchStatus.CatchSuccess) { evt.Shiny = (await session.Inventory.GetPokemons().ConfigureAwait(false)).First(x => x.Id == caughtPokemonResponse.CapturedPokemonId).PokemonDisplay.Shiny ? "Yes" : "No"; evt.Form = (await session.Inventory.GetPokemons().ConfigureAwait(false)).First(x => x.Id == caughtPokemonResponse.CapturedPokemonId).PokemonDisplay.Form.ToString().Replace("Unown", "").Replace("Unset", "Normal"); evt.Costume = (await session.Inventory.GetPokemons().ConfigureAwait(false)).First(x => x.Id == caughtPokemonResponse.CapturedPokemonId).PokemonDisplay.Costume.ToString().Replace("Unset", "Regular"); evt.Gender = (await session.Inventory.GetPokemons().ConfigureAwait(false)).First(x => x.Id == caughtPokemonResponse.CapturedPokemonId).PokemonDisplay.Gender.ToString(); var totalExp = 0; var stardust = caughtPokemonResponse.CaptureAward.Stardust.Sum(); var totalStarDust = session.Inventory.UpdateStarDust(stardust); var CaptuerXP = caughtPokemonResponse.CaptureAward.Xp.Sum(); if (encounteredPokemon != null) { encounteredPokemon.Id = caughtPokemonResponse.CapturedPokemonId; } foreach (var xp in caughtPokemonResponse.CaptureAward.Xp) { totalExp += xp; } //This accounts for XP for CatchFlee if (totalExp < 1) { totalExp = 25; } evt.Exp = totalExp; evt.Stardust = stardust; evt.UniqueId = caughtPokemonResponse.CapturedPokemonId; evt.Candy = await session.Inventory.GetCandyFamily(pokemon.PokemonId).ConfigureAwait(false); evt.totalStarDust = totalStarDust; if (session.LogicSettings.AutoFavoriteShinyOnCatch) { if (evt.Shiny == "Yes") { await FavoritePokemonTask.Execute(session, encounteredPokemon.Id, true); Logger.Write($"You've caught a Shiny Pokemon ({encounteredPokemon.Nickname}) and it has been Favorited."); } } } if (caughtPokemonResponse.Status == CatchPokemonResponse.Types.CatchStatus.CatchSuccess || caughtPokemonResponse.Status == CatchPokemonResponse.Types.CatchStatus.CatchFlee) { // Also count catch flee against the catch limit if (session.LogicSettings.UseCatchLimit) { session.Stats.AddPokemonTimestamp(DateTime.Now.Ticks); session.EventDispatcher.Send(new CatchLimitUpdate(session.Stats.GetNumPokemonsInLast24Hours(), session.LogicSettings.CatchPokemonLimit)); } } evt.CatchType = encounter is EncounterResponse ? session.Translation.GetTranslation(TranslationString.CatchTypeNormal) : encounter is DiskEncounterResponse ? session.Translation.GetTranslation(TranslationString.CatchTypeLure) : session.Translation.GetTranslation(TranslationString.CatchTypeIncense); evt.CatchTypeText = encounter is EncounterResponse ? "normal" : encounter is DiskEncounterResponse ? "lure" : "incense"; evt.Id = encounter is EncounterResponse ? pokemon.PokemonId : encounter?.PokemonData.PokemonId; evt.EncounterId = _encounterId; evt.Move1 = PokemonInfo.GetPokemonMove1(encounteredPokemon); evt.Move2 = PokemonInfo.GetPokemonMove2(encounteredPokemon); evt.Expires = pokemon?.ExpirationTimestampMs ?? 0; evt.SpawnPointId = _spawnPointId; evt.Level = PokemonInfo.GetLevel(encounteredPokemon); evt.Cp = encounteredPokemon.Cp; evt.MaxCp = PokemonInfo.CalculateMaxCp(encounteredPokemon.PokemonId); evt.Perfection = Math.Round(PokemonInfo.CalculatePokemonPerfection(encounteredPokemon), 2); evt.Probability = Math.Round(probability * 100, 2); evt.Distance = distance; evt.Pokeball = pokeball; evt.Attempt = attemptCounter; //await session.Inventory.RefreshCachedInventory().ConfigureAwait(false); evt.BallAmount = await session.Inventory.GetItemAmountByType(pokeball).ConfigureAwait(false); evt.Rarity = PokemonGradeHelper.GetPokemonGrade(evt.Id).ToString(); session.EventDispatcher.Send(evt); attemptCounter++; // If Humanlike delays are used if (session.LogicSettings.UseHumanlikeDelays) { switch (caughtPokemonResponse.Status) { case CatchPokemonResponse.Types.CatchStatus.CatchError: await DelayingUtils.DelayAsync(session.LogicSettings.CatchErrorDelay, 0, session.CancellationTokenSource.Token).ConfigureAwait(false); break; case CatchPokemonResponse.Types.CatchStatus.CatchSuccess: await DelayingUtils.DelayAsync(session.LogicSettings.CatchSuccessDelay, 0, session.CancellationTokenSource.Token).ConfigureAwait(false); break; case CatchPokemonResponse.Types.CatchStatus.CatchEscape: await DelayingUtils.DelayAsync(session.LogicSettings.CatchEscapeDelay, 0, session.CancellationTokenSource.Token).ConfigureAwait(false); break; case CatchPokemonResponse.Types.CatchStatus.CatchFlee: await DelayingUtils.DelayAsync(session.LogicSettings.CatchFleeDelay, 0, session.CancellationTokenSource.Token).ConfigureAwait(false); break; case CatchPokemonResponse.Types.CatchStatus.CatchMissed: await DelayingUtils.DelayAsync(session.LogicSettings.CatchMissedDelay, 0, session.CancellationTokenSource.Token).ConfigureAwait(false); break; default: break; } } else { await DelayingUtils.DelayAsync(session.LogicSettings.DelayBetweenPlayerActions, 0, session.CancellationTokenSource.Token).ConfigureAwait(false); } } while (caughtPokemonResponse.Status == CatchPokemonResponse.Types.CatchStatus.CatchMissed || caughtPokemonResponse.Status == CatchPokemonResponse.Types.CatchStatus.CatchEscape); if (caughtPokemonResponse.Status == CatchPokemonResponse.Types.CatchStatus.CatchFlee) { CatchFleeContinuouslyCount++; if (CatchFleeContinuouslyCount >= 3 && session.LogicSettings.ByPassCatchFlee) { session.SaveBallForByPassCatchFlee = true; Logger.Write("Seems your bot has been CatchFlee Softban, Bot will start save 100 balls to by pass it."); if (session.LogicSettings.NotificationConfig.EnablePushBulletNotification) { await PushNotificationClient.SendNotification(session, "CatchFlee Soft Ban", "Seems your bot has been catch flee softban, Bot will start save 100 balls to by pass it.", true).ConfigureAwait(false); } } if (manager.AllowMultipleBot() && !session.LogicSettings.ByPassCatchFlee) { if (CatchFleeContinuouslyCount > session.LogicSettings.MultipleBotConfig.CatchFleeCount && TinyIoCContainer.Current.Resolve <MultiAccountManager>().AllowSwitch()) { CatchFleeContinuouslyCount = 0; session.SaveBallForByPassCatchFlee = false; throw new ActiveSwitchByRuleException() { MatchedRule = SwitchRules.CatchFlee, ReachedValue = session.LogicSettings.MultipleBotConfig.CatchFleeCount }; } } } else { //reset if not catch flee. if (caughtPokemonResponse.Status != CatchPokemonResponse.Types.CatchStatus.CatchMissed) { CatchFleeContinuouslyCount = 0; MSniperServiceTask.UnblockSnipe(); } } session.Actions.RemoveAll(x => x == BotActions.Catch); if (MultipleBotConfig.IsMultiBotActive(session.LogicSettings, manager)) { ExecuteSwitcher(session, encounterEV); } if (session.LogicSettings.TransferDuplicatePokemonOnCapture && session.LogicSettings.TransferDuplicatePokemon && sessionAllowTransfer && caughtPokemonResponse != null && caughtPokemonResponse.Status == CatchPokemonResponse.Types.CatchStatus.CatchSuccess) { if (session.LogicSettings.UseNearActionRandom) { await HumanRandomActionTask.TransferRandom(session, cancellationToken).ConfigureAwait(false); } else { await TransferDuplicatePokemonTask.Execute(session, cancellationToken).ConfigureAwait(false); } } } return(true); }
public void Reset(ISettings settings, ILogicSettings logicSettings) { KnownLatitudeBeforeSnipe = 0; KnownLongitudeBeforeSnipe = 0; if (GlobalSettings.Auth.DeviceConfig.UseRandomDeviceId) { settings.DeviceId = DeviceConfig.GetDeviceId(settings.Username); Logger.Debug($"Username : {Settings.Username} , Device ID :{Settings.DeviceId}"); } Client = new Client(settings); // ferox wants us to set this manually var inv = new Inventory(this, Client, logicSettings, null); try { inv = new Inventory(this, Client, logicSettings, async() => { var candy = (await Inventory.GetPokemonFamilies().ConfigureAwait(false)).ToList(); try { candy = (await Inventory.GetPokemonFamilies().ConfigureAwait(false)).ToList(); } catch { #if DEBUG var OldNot = TinyIoCContainer.Current.Resolve <ISession>().LogicSettings.NotificationConfig.EnablePushBulletNotification; TinyIoCContainer.Current.Resolve <ISession>().LogicSettings.NotificationConfig.EnablePushBulletNotification = true; await PushNotificationClient.SendNotification(TinyIoCContainer.Current.Resolve <ISession>(), $"Candy ERROR.", $"Check your code.", true).ConfigureAwait(false); TinyIoCContainer.Current.Resolve <ISession>().LogicSettings.NotificationConfig.EnablePushBulletNotification = OldNot; #endif } var pokemonSettings = (await Inventory.GetPokemonSettings().ConfigureAwait(false)).ToList(); EventDispatcher.Send(new InventoryRefreshedEvent(null, pokemonSettings, candy)); }); } catch { #if DEBUG var OldNot = TinyIoCContainer.Current.Resolve <ISession>().LogicSettings.NotificationConfig.EnablePushBulletNotification; TinyIoCContainer.Current.Resolve <ISession>().LogicSettings.NotificationConfig.EnablePushBulletNotification = true; PushNotificationClient.SendNotification(TinyIoCContainer.Current.Resolve <ISession>(), $"Candy ERROR.", $"Check your code.", true).ConfigureAwait(false); TinyIoCContainer.Current.Resolve <ISession>().LogicSettings.NotificationConfig.EnablePushBulletNotification = OldNot; #endif // Null } Inventory = inv; //Inventory = new Inventory(this, Client, logicSettings, async () => //{ // var candy = (await Inventory.GetPokemonFamilies().ConfigureAwait(false)).ToList(); // var pokemonSettings = (await Inventory.GetPokemonSettings().ConfigureAwait(false)).ToList(); // EventDispatcher.Send(new InventoryRefreshedEvent(null, pokemonSettings, candy)); //}); Navigation = new Navigation(Client, logicSettings); Navigation.WalkStrategy.UpdatePositionEvent += (session, lat, lng, s) => EventDispatcher.Send(new UpdatePositionEvent { Latitude = lat, Longitude = lng, Speed = s }); Navigation.WalkStrategy.UpdatePositionEvent += LoadSaveState.SaveLocationToDisk; }
public static float kmWalked; // = playerStats.KmWalked; public static async Task Execute(ISession session, CancellationToken cancellationToken, ulong eggId, string incubatorId) { var incubators = (await session.Inventory.GetEggIncubators().ConfigureAwait(false)) .Where(x => x.UsesRemaining > 0 || x.ItemId == ItemId.ItemIncubatorBasicUnlimited) .FirstOrDefault(x => x.Id == incubatorId); var unusedEggs = (await session.Inventory.GetEggs().ConfigureAwait(false)) .Where(x => string.IsNullOrEmpty(x.EggIncubatorId)) .FirstOrDefault(x => x.Id == eggId); if (incubators == null || unusedEggs == null) { return; } var rememberedIncubatorsFilePath = Path.Combine(session.LogicSettings.ProfilePath, "temp", "incubators.json"); var rememberedIncubators = GetRememberedIncubators(rememberedIncubatorsFilePath); var response = await session.Client.Inventory.UseItemEggIncubator(incubators.Id, unusedEggs.Id).ConfigureAwait(false); var newRememberedIncubators = new List <IncubatorUsage>(); var playerStats = (await session.Inventory.GetPlayerStats().ConfigureAwait(false)).FirstOrDefault(); #if DEBUG if (session.LogicSettings.NotificationConfig.PushBulletApiKey != null) { var OldNot = session.LogicSettings.NotificationConfig.EnablePushBulletNotification; session.LogicSettings.NotificationConfig.EnablePushBulletNotification = true; await PushNotificationClient.SendNotification(session, $"Session paused.", $"Check your code.", true).ConfigureAwait(false); session.LogicSettings.NotificationConfig.EnablePushBulletNotification = OldNot; } #endif kmWalked = playerStats.KmWalked; var eggs = 0; if (response.Result == UseItemEggIncubatorResponse.Types.Result.Success) { eggs += 1; newRememberedIncubators.Add(new IncubatorUsage { IncubatorId = incubators.Id, PokemonId = unusedEggs.Id }); session.EventDispatcher.Send(new EggIncubatorStatusEvent { Eggs = eggs, IncubatorId = incubators.Id, WasAddedNow = true, PokemonId = unusedEggs.Id, KmToWalk = unusedEggs.EggKmWalkedTarget, KmRemaining = response.EggIncubator.TargetKmWalked }); if (!newRememberedIncubators.SequenceEqual(rememberedIncubators)) { SaveRememberedIncubators(newRememberedIncubators, rememberedIncubatorsFilePath); } } else { //error output } }
public async Task Start(IState initialState, ISession session, string subPath, bool excelConfigAllowed = false) { GlobalSettings globalSettings = null; var state = initialState; var profilePath = Path.Combine(Directory.GetCurrentDirectory(), subPath); var profileConfigPath = Path.Combine(profilePath, "config"); globalSettings = GlobalSettings.Load(subPath); FileSystemWatcher configWatcher = new FileSystemWatcher(); configWatcher.Path = profileConfigPath; configWatcher.Filter = "config.json"; configWatcher.NotifyFilter = NotifyFilters.LastWrite; configWatcher.EnableRaisingEvents = true; configWatcher.Changed += (sender, e) => { if (e.ChangeType == WatcherChangeTypes.Changed) { globalSettings = GlobalSettings.Load(subPath); session.LogicSettings = new LogicSettings(globalSettings); configWatcher.EnableRaisingEvents = !configWatcher.EnableRaisingEvents; configWatcher.EnableRaisingEvents = !configWatcher.EnableRaisingEvents; Logger.Write(" ##### config.json ##### ", LogLevel.Info); } }; //watch the excel config file if (excelConfigAllowed) { Task.Run(async() => { while (true) { try { FileInfo inf = new FileInfo($"{profileConfigPath}\\config.xlsm"); if (inf.LastWriteTime > DateTime.Now.AddSeconds(-5)) { globalSettings = ExcelConfigHelper.ReadExcel(globalSettings, inf.FullName); session.LogicSettings = new LogicSettings(globalSettings); Logger.Write(" ##### config.xlsm ##### ", LogLevel.Info); } await Task.Delay(5000); } catch (Exception) { } } }); } int apiCallFailured = 0; do { try { state = await state.Execute(session, session.CancellationTokenSource.Token); // Exit the bot if both catching and looting has reached its limits if ((UseNearbyPokestopsTask._pokestopLimitReached || UseNearbyPokestopsTask._pokestopTimerReached) && session.Stats.CatchThresholdExceeds(session)) { session.EventDispatcher.Send(new ErrorEvent { Message = session.Translation.GetTranslation(TranslationString.ExitDueToLimitsReached) }); session.CancellationTokenSource.Cancel(); // A bit rough here; works but can be improved await Task.Delay(10000); state = null; session.CancellationTokenSource.Dispose(); Environment.Exit(0); } } catch (APIBadRequestException ex) { Logger.Write("Bad Request - If you see this message please conpy error log & screenshot send back to dev asap.", level: LogLevel.Error); session.EventDispatcher.Send(new ErrorEvent() { Message = ex.Message }); Logger.Write(ex.StackTrace, level: LogLevel.Error); if (session.LogicSettings.AllowMultipleBot) { session.ReInitSessionWithNextBot(); } state = new LoginState(); } catch (AccountNotVerifiedException ex) { if (session.LogicSettings.AllowMultipleBot) { session.ReInitSessionWithNextBot(); state = new LoginState(); } else { Console.Read(); Environment.Exit(0); } } catch (ActiveSwitchByPokemonException rsae) { session.EventDispatcher.Send(new WarnEvent { Message = "Encountered a good pokemon , switch another bot to catch him too." }); session.ReInitSessionWithNextBot(rsae.Bot, session.Client.CurrentLatitude, session.Client.CurrentLongitude, session.Client.CurrentAltitude); state = new LoginState(rsae.LastEncounterPokemonId); } catch (ActiveSwitchByRuleException se) { session.EventDispatcher.Send(new WarnEvent { Message = $"Switch bot account activated by : {se.MatchedRule.ToString()} - {se.ReachedValue} " }); if (se.MatchedRule == SwitchRules.EmptyMap) { session.BlockCurrentBot(90); session.ReInitSessionWithNextBot(); } else if (se.MatchedRule == SwitchRules.PokestopSoftban) { session.BlockCurrentBot(); session.ReInitSessionWithNextBot(); } else if (se.MatchedRule == SwitchRules.CatchFlee) { session.BlockCurrentBot(60); session.ReInitSessionWithNextBot(); } else { if (se.MatchedRule == SwitchRules.CatchLimitReached || se.MatchedRule == SwitchRules.SpinPokestopReached) { PushNotificationClient.SendNotification(session, $"{se.MatchedRule} - {session.Settings.GoogleUsername}{session.Settings.PtcUsername}", "This bot has reach limit, it will be blocked for 60 mins for safety.", true); session.EventDispatcher.Send(new WarnEvent() { Message = "You reach limited. bot will sleep for 60 min" }); session.BlockCurrentBot(60); if (!session.LogicSettings.AllowMultipleBot) { await Task.Delay(60 * 1000 * 60); } else { session.ReInitSessionWithNextBot(); } } else { if (session.LogicSettings.MultipleBotConfig.StartFromDefaultLocation) { session.ReInitSessionWithNextBot(null, globalSettings.LocationConfig.DefaultLatitude, globalSettings.LocationConfig.DefaultLongitude, session.Client.CurrentAltitude); } else { session.ReInitSessionWithNextBot(); //current location } } } //return to login state state = new LoginState(); } catch (InvalidResponseException) { session.EventDispatcher.Send(new ErrorEvent { Message = "Niantic Servers unstable, throttling API Calls." }); await Task.Delay(1000); if (session.LogicSettings.AllowMultipleBot) { apiCallFailured++; if (apiCallFailured > 20) { apiCallFailured = 0; session.BlockCurrentBot(30); session.ReInitSessionWithNextBot(); } } state = new LoginState(); } catch (OperationCanceledException) { session.EventDispatcher.Send(new ErrorEvent { Message = "Current Operation was canceled." }); if (session.LogicSettings.AllowMultipleBot) { session.BlockCurrentBot(30); session.ReInitSessionWithNextBot(); } state = new LoginState(); } catch (LoginFailedException ex) { PushNotificationClient.SendNotification(session, $"Banned!!!! {session.Settings.PtcUsername}{session.Settings.GoogleUsername}", session.Translation.GetTranslation(TranslationString.AccountBanned), true); if (session.LogicSettings.AllowMultipleBot) { session.BlockCurrentBot(24 * 60); //need remove acc session.ReInitSessionWithNextBot(); state = new LoginState(); } else { session.EventDispatcher.Send(new ErrorEvent { Message = session.Translation.GetTranslation(TranslationString.ExitNowAfterEnterKey) }); Console.ReadKey(); System.Environment.Exit(1); } } catch (MinimumClientVersionException ex) { // We need to terminate the client. session.EventDispatcher.Send(new ErrorEvent { Message = session.Translation.GetTranslation(TranslationString.MinimumClientVersionException, ex.CurrentApiVersion.ToString(), ex.MinimumClientVersion.ToString()) }); session.EventDispatcher.Send(new ErrorEvent { Message = session.Translation.GetTranslation(TranslationString.ExitNowAfterEnterKey) }); Console.ReadKey(); System.Environment.Exit(1); } catch (TokenRefreshException ex) { session.EventDispatcher.Send(new ErrorEvent() { Message = ex.Message }); if (session.LogicSettings.AllowMultipleBot) { session.ReInitSessionWithNextBot(); } state = new LoginState(); } catch (PtcOfflineException) { session.EventDispatcher.Send(new ErrorEvent { Message = session.Translation.GetTranslation(TranslationString.PtcOffline) }); session.EventDispatcher.Send(new NoticeEvent { Message = session.Translation.GetTranslation(TranslationString.TryingAgainIn, 15) }); await Task.Delay(15000); state = _initialState; } catch (GoogleOfflineException) { session.EventDispatcher.Send(new ErrorEvent { Message = session.Translation.GetTranslation(TranslationString.GoogleOffline) }); session.EventDispatcher.Send(new NoticeEvent { Message = session.Translation.GetTranslation(TranslationString.TryingAgainIn, 15) }); await Task.Delay(15000); state = _initialState; } catch (AccessTokenExpiredException) { session.EventDispatcher.Send(new NoticeEvent { Message = "Access Token Expired. Logging in again..." }); state = _initialState; } catch (CaptchaException captchaException) { var resolved = await CaptchaManager.SolveCaptcha(session, captchaException.Url); if (!resolved) { PushNotificationClient.SendNotification(session, $"Captcha required {session.Settings.PtcUsername}{session.Settings.GoogleUsername}", session.Translation.GetTranslation(TranslationString.CaptchaShown), true); session.EventDispatcher.Send(new WarnEvent { Message = session.Translation.GetTranslation(TranslationString.CaptchaShown) }); if (session.LogicSettings.AllowMultipleBot) { session.BlockCurrentBot(15); if (!session.ReInitSessionWithNextBot()) { await PushNotificationClient.SendNotification(session, "All accounts are being blocked", "Non of yours account available to switch, bot will sleep for 30 mins", true); await Task.Delay(30 * 60 * 1000); } state = new LoginState(); } else { session.EventDispatcher.Send(new ErrorEvent { Message = session.Translation.GetTranslation(TranslationString.ExitNowAfterEnterKey) }); Console.ReadKey(); Environment.Exit(0); } } else { //resolve captcha state = new LoginState(); } } catch (HasherException ex) { session.EventDispatcher.Send(new ErrorEvent { Message = ex.Message }); session.EventDispatcher.Send(new ErrorEvent { Message = session.Translation.GetTranslation(TranslationString.ExitNowAfterEnterKey) }); Console.ReadKey(); System.Environment.Exit(1); } catch (Exception ex) { session.EventDispatcher.Send(new ErrorEvent { Message = "Pokemon Servers might be offline / unstable. Trying again..." }); session.EventDispatcher.Send(new ErrorEvent { Message = "Error: " + ex }); if (state is LoginState) { } else { state = _initialState; } } } while (state != null); configWatcher.EnableRaisingEvents = false; configWatcher.Dispose(); }