diff --git a/PokemonGo-UWP/App.xaml.cs b/PokemonGo-UWP/App.xaml.cs index 6a4241419..d8da50fd7 100644 --- a/PokemonGo-UWP/App.xaml.cs +++ b/PokemonGo-UWP/App.xaml.cs @@ -40,7 +40,7 @@ sealed partial class App : BootStrapper /// Stores the current instance for the app. /// private readonly DisplayRequest _displayRequest; - + #endregion #region Properties @@ -83,7 +83,7 @@ public App() private static async void App_UnhandledException(object sender, UnhandledExceptionEventArgs e) { e.Handled = true; - await ExceptionHandler.HandleException(); + await ExceptionHandler.HandleException(new Exception(e.Message)); // We should be logging these exceptions too so they can be tracked down. HockeyClient.Current.TrackException(e.Exception); } @@ -96,7 +96,7 @@ private static void TaskScheduler_UnobservedTaskException(object sender, Unobser } /// - /// + /// /// /// /// @@ -195,7 +195,7 @@ public override async Task OnInitializeAsync(IActivatedEventArgs args) } /// - /// + /// /// /// /// diff --git a/PokemonGo-UWP/Entities/FortDataWrapper.cs b/PokemonGo-UWP/Entities/FortDataWrapper.cs index 8c3904a83..a1d4dd07f 100644 --- a/PokemonGo-UWP/Entities/FortDataWrapper.cs +++ b/PokemonGo-UWP/Entities/FortDataWrapper.cs @@ -59,11 +59,11 @@ public FortDataWrapper(FortData fortData) /// the actual capture method. /// public DelegateCommand TrySearchPokestop => _trySearchPokestop ?? ( - _trySearchPokestop = new DelegateCommand(() => + _trySearchPokestop = new DelegateCommand(async () => { NavigationHelper.NavigationState["CurrentPokestop"] = this; // Disable map update - GameClient.ToggleUpdateTimer(false); + await GameClient.ToggleUpdateTimer(false); BootStrapper.Current.NavigationService.Navigate(typeof(SearchPokestopPage)); }, () => true) ); diff --git a/PokemonGo-UWP/Entities/MapPokemonWrapper.cs b/PokemonGo-UWP/Entities/MapPokemonWrapper.cs index 075cb56ae..a8f3c30fd 100644 --- a/PokemonGo-UWP/Entities/MapPokemonWrapper.cs +++ b/PokemonGo-UWP/Entities/MapPokemonWrapper.cs @@ -32,11 +32,11 @@ public MapPokemonWrapper(MapPokemon mapPokemon) /// We're just navigating to the capture page, reporting that the player wants to capture the selected Pokemon. /// public DelegateCommand TryCatchPokemon => _tryCatchPokemon ?? ( - _tryCatchPokemon = new DelegateCommand(() => + _tryCatchPokemon = new DelegateCommand(async () => { NavigationHelper.NavigationState["CurrentPokemon"] = this; // Disable map update - GameClient.ToggleUpdateTimer(false); + await GameClient.ToggleUpdateTimer(false); BootStrapper.Current.NavigationService.Navigate(typeof(CapturePokemonPage)); }, () => true) ); diff --git a/PokemonGo-UWP/Utils/GameClient.cs b/PokemonGo-UWP/Utils/GameClient.cs index 53604b0b0..69e8782e2 100644 --- a/PokemonGo-UWP/Utils/GameClient.cs +++ b/PokemonGo-UWP/Utils/GameClient.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Collections.ObjectModel; +using System.Diagnostics; using System.Linq; using System.Threading.Tasks; using Windows.ApplicationModel; @@ -12,6 +13,7 @@ using PokemonGo.RocketAPI.Enums; using PokemonGo.RocketAPI.Extensions; using PokemonGo_UWP.Entities; +using PokemonGo_UWP.ViewModels; using POGOProtos.Data; using POGOProtos.Data.Player; using POGOProtos.Enums; @@ -23,6 +25,7 @@ using POGOProtos.Settings; using POGOProtos.Settings.Master; using Q42.WinRT.Data; +using Template10.Common; using Template10.Utils; using Universal_Authenticator_v2.Views; @@ -56,13 +59,11 @@ public async Task HandleApiFailure(RequestEnvelope request, Respon await Task.Delay(500); _retryCount++; - if (_retryCount%5 == 0) - { - // Let's try to refresh the session by getting a new token - await - (_clientSettings.AuthType == AuthType.Google - ? DoGoogleLogin(_clientSettings.GoogleUsername, _clientSettings.GooglePassword) - : DoPtcLogin(_clientSettings.PtcUsername, _clientSettings.PtcPassword)); + if (_retryCount % 5 == 0) + { + await DoRelogin(); + Debug.WriteLine("[Relogin] Stopping API via ApiHandledException."); + throw new ApiHandledException("Relogin completed."); } return ApiOperation.Retry; @@ -234,15 +235,15 @@ public static async Task InitializeClient() } catch (Exception e) { - if (e is PokemonGo.RocketAPI.Exceptions.AccessTokenExpiredException) - { - await Relogin(); - } - else throw; + if (e is PokemonGo.RocketAPI.Exceptions.AccessTokenExpiredException) + { + await Relogin(); + } + else throw; } } - public static async Task Relogin() - { + public static async Task Relogin() + { switch (_clientSettings.AuthType) { case AuthType.Ptc: @@ -266,7 +267,7 @@ public static async Task Relogin() /// /// /// true if login worked - public static async Task DoPtcLogin(string username, string password) + public static async Task DoPtcLogin(string username, string password) { _clientSettings = new Settings { @@ -303,7 +304,7 @@ public static async Task DoGoogleLogin(string email, string password) AuthType = AuthType.Google }; - _client = new Client(_clientSettings, new ApiFailure(), DeviceInfos.Instance); + _client = new Client(_clientSettings, new ApiFailure(), DeviceInfos.Instance); // Get Google token var authToken = await _client.Login.DoLogin(); // Update current token even if it's null @@ -333,6 +334,29 @@ public static void DoLogout() NearbyPokestops.Clear(); } + public static async Task DoRelogin() + { + Debug.WriteLine("[Relogin] Started."); + DoLogout(); + + var token = _client.AuthToken; + + await + (_clientSettings.AuthType == AuthType.Google + ? DoGoogleLogin(_clientSettings.GoogleUsername, _clientSettings.GooglePassword) + : DoPtcLogin(_clientSettings.PtcUsername, _clientSettings.PtcPassword)); + + if (token != _client.AuthToken) + Debug.WriteLine("[Relogin] Token successfuly changed."); + + Debug.WriteLine("[Relogin] Reloading gps and playerdata."); + await GameView.StartGpsDataService(); + await GameView.UpdatePlayerData(true); + Debug.WriteLine("[Relogin] Restarting MapUpdate timer."); + _lastUpdate = DateTime.Now; + await ToggleUpdateTimer(); + } + #endregion #region Data Updating @@ -340,6 +364,7 @@ public static void DoLogout() private static Geolocator _geolocator; public static Geoposition Geoposition { get; private set; } + public static GameMapPageViewModel GameView { get; set; } private static DispatcherTimer _mapUpdateTimer; @@ -375,7 +400,7 @@ public static async Task InitializeDataUpdate() GameSetting = await DataCache.GetAsync(nameof(GameSetting), async () => (await _client.Download.GetSettings()).Settings, - DateTime.Now.AddMonths(1)); + DateTime.Now.AddMonths(1)); // Update geolocator settings based on server _geolocator.MovementThreshold = GameSetting.MapSettings.GetMapObjectsMinDistanceMeters; _mapUpdateTimer = new DispatcherTimer @@ -388,9 +413,17 @@ public static async Task InitializeDataUpdate() if ((DateTime.Now - _lastUpdate).Seconds <= GameSetting.MapSettings.GetMapObjectsMinRefreshSeconds) return; Logger.Write("Updating map"); - await UpdateMapObjects(); + + try + { + await UpdateMapObjects(); + } + catch (Exception ex) + { + await ExceptionHandler.HandleException(ex); + } }; - // Update before starting timer + // Update before starting timer Busy.SetBusy(true, Resources.CodeResources.GetString("GettingUserDataText")); await UpdateMapObjects(); await UpdateInventory(); @@ -407,7 +440,7 @@ public static async Task InitializeDataUpdate() /// Toggles the update timer based on the isEnabled value /// /// - public static async void ToggleUpdateTimer(bool isEnabled = true) + public static async Task ToggleUpdateTimer(bool isEnabled = true) { if (isEnabled) { @@ -429,7 +462,7 @@ public static async void ToggleUpdateTimer(bool isEnabled = true) /// /// private static async Task UpdateMapObjects() - { + { // Get all map objects from server var mapObjects = await GetMapObjects(Geoposition); _lastUpdate = DateTime.Now; @@ -443,7 +476,7 @@ private static async Task UpdateMapObjects() // update nearby pokemons var newNearByPokemons = mapObjects.Item1.MapCells.SelectMany(x => x.NearbyPokemons).ToArray(); Logger.Write($"Found {newNearByPokemons.Length} nearby pokemons"); - // for this collection the ordering is important, so we follow a slightly different update mechanism + // for this collection the ordering is important, so we follow a slightly different update mechanism NearbyPokemons.UpdateByIndexWith(newNearByPokemons, x => new NearbyPokemonWrapper(x)); // update poke stops on map (gyms are ignored for now) @@ -527,14 +560,14 @@ public static async Task UpdatePlayerStats(bool checkFor // Update candies CandyInventory.AddRange(from item in InventoryDelta.InventoryItems - where item.InventoryItemData?.Candy != null - where item.InventoryItemData?.Candy.FamilyId != PokemonFamilyId.FamilyUnset - group item by item.InventoryItemData?.Candy.FamilyId into family - select new Candy - { - FamilyId = family.FirstOrDefault().InventoryItemData.Candy.FamilyId, - Candy_ = family.FirstOrDefault().InventoryItemData.Candy.Candy_ - },true); + where item.InventoryItemData?.Candy != null + where item.InventoryItemData?.Candy.FamilyId != PokemonFamilyId.FamilyUnset + group item by item.InventoryItemData?.Candy.FamilyId into family + select new Candy + { + FamilyId = family.FirstOrDefault().InventoryItemData.Candy.FamilyId, + Candy_ = family.FirstOrDefault().InventoryItemData.Candy.Candy_ + }, true); return null; } @@ -618,7 +651,7 @@ public static async Task UpdateInventory() .GroupBy(item => item.InventoryItemData.Item) .Select(item => item.First().InventoryItemData.Item), true); - // Update incbuators + // Update incbuators FreeIncubatorsInventory.AddRange(fullInventory.Where(item => item.InventoryItemData.EggIncubators != null) .SelectMany(item => item.InventoryItemData.EggIncubators.EggIncubator) .Where(item => item != null && item.PokemonId == 0), true); @@ -632,13 +665,13 @@ public static async Task UpdateInventory() EggsInventory.AddRange(fullInventory.Select(item => item.InventoryItemData.PokemonData) .Where(item => item != null && item.IsEgg), true); - // Update Pokedex + // Update Pokedex PokedexInventory.AddRange(fullInventory.Where(item => item.InventoryItemData.PokedexEntry != null) .Select(item => item.InventoryItemData.PokedexEntry), true); // Update Player stats PlayerStats = - fullInventory.First(item => item.InventoryItemData.PlayerStats != null).InventoryItemData.PlayerStats; + fullInventory.First(item => item.InventoryItemData.PlayerStats != null).InventoryItemData.PlayerStats; } @@ -646,7 +679,7 @@ public static async Task UpdateInventory() #region Pokemon Handling - #region Pokedex + #region Pokedex /// /// Gets extra data for the current pokemon @@ -687,7 +720,7 @@ public static async Task CatchPokemon(ulong encounterId, s var random = new Random(); return await - _client.Encounter.CatchPokemon(encounterId, spawnpointId, captureItem, random.NextDouble()*1.95D, + _client.Encounter.CatchPokemon(encounterId, spawnpointId, captureItem, random.NextDouble() * 1.95D, random.NextDouble(), 1, hitPokemon); } @@ -709,7 +742,7 @@ public static async Task UseCaptureItem(ulong encounterI #region Power Up & Evolving & Transfer /// - /// + /// /// /// /// @@ -719,7 +752,7 @@ public static async Task PowerUpPokemon(PokemonData poke } /// - /// + /// /// /// /// diff --git a/PokemonGo-UWP/Utils/Helpers/ExceptionHandler.cs b/PokemonGo-UWP/Utils/Helpers/ExceptionHandler.cs index 411028e9e..14ecdb820 100644 --- a/PokemonGo-UWP/Utils/Helpers/ExceptionHandler.cs +++ b/PokemonGo-UWP/Utils/Helpers/ExceptionHandler.cs @@ -4,14 +4,26 @@ using Template10.Common; using Universal_Authenticator_v2.Views; using System; +using System.Diagnostics; namespace PokemonGo_UWP.Utils { + internal class ApiHandledException : Exception + { + public ApiHandledException(string reloginCompleted) : base(reloginCompleted) + { + } + } public static class ExceptionHandler { public static async Task HandleException(Exception e = null) { - if (e.GetType().Namespace.Equals("PokemonGo.RocketAPI.Exceptions")) + if (e != null && (e.GetType().FullName.Contains("ApiHandledException") || e.Message == "Relogin completed.")) + { + Debug.WriteLine("[Relogin] ApiHandledException from API handled."); + Debug.WriteLine("[Relogin] Successfuly ended."); + } + else if (e != null && e.GetType().Namespace.Equals("PokemonGo.RocketAPI.Exceptions")) { await new MessageDialog(Resources.CodeResources.GetString("LoginExpired")).ShowAsyncQueue(); diff --git a/PokemonGo-UWP/ViewModels/CapturePokemonPageViewModel.cs b/PokemonGo-UWP/ViewModels/CapturePokemonPageViewModel.cs index 41ab8c2d8..381fb5682 100644 --- a/PokemonGo-UWP/ViewModels/CapturePokemonPageViewModel.cs +++ b/PokemonGo-UWP/ViewModels/CapturePokemonPageViewModel.cs @@ -190,10 +190,10 @@ public CaptureAward CurrentCaptureAward /// Going back to map page /// public DelegateCommand EscapeEncounterCommand => _escapeEncounterCommand ?? ( - _escapeEncounterCommand = new DelegateCommand(() => + _escapeEncounterCommand = new DelegateCommand(async () => { // Re-enable update timer - GameClient.ToggleUpdateTimer(); + await GameClient.ToggleUpdateTimer(); NavigationService.GoBack(); }, () => true)); @@ -314,7 +314,7 @@ await GameClient.CatchPokemon(CurrentPokemon.EncounterId, CurrentPokemon.Spawnpo GameClient.CatchablePokemons.Remove(CurrentPokemon); GameClient.NearbyPokemons.Remove(nearbyPokemon); // We just go back because there's nothing else to do - GameClient.ToggleUpdateTimer(); + await GameClient.ToggleUpdateTimer(); break; case CatchPokemonResponse.Types.CatchStatus.CatchMissed: Logger.Write($"We missed {CurrentPokemon.PokemonId}"); diff --git a/PokemonGo-UWP/ViewModels/GameMapPageViewModel.cs b/PokemonGo-UWP/ViewModels/GameMapPageViewModel.cs index 72b8a4e54..e3513ed76 100644 --- a/PokemonGo-UWP/ViewModels/GameMapPageViewModel.cs +++ b/PokemonGo-UWP/ViewModels/GameMapPageViewModel.cs @@ -22,7 +22,7 @@ namespace PokemonGo_UWP.ViewModels { public class GameMapPageViewModel : ViewModelBase { - #region Lifecycle Handlers + #region Lifecycle Handlers /// /// @@ -36,14 +36,14 @@ public override async Task OnNavigatedToAsync(object parameter, NavigationMode m // Prevent from going back to other pages NavigationService.ClearHistory(); if (parameter == null || mode == NavigationMode.Back) return; - var gameMapNavigationMode = (GameMapNavigationModes) parameter; + var gameMapNavigationMode = (GameMapNavigationModes)parameter; // We just resumed from suspension so we restart update service and we get data from suspension state if (suspensionState.Any()) { - // Recovering the state - PlayerProfile = (PlayerData) suspensionState[nameof(PlayerProfile)]; - PlayerStats = (PlayerStats) suspensionState[nameof(PlayerStats)]; + // Recovering the state + PlayerProfile = (PlayerData)suspensionState[nameof(PlayerProfile)]; + PlayerStats = (PlayerStats)suspensionState[nameof(PlayerStats)]; // Restarting update service await StartGpsDataService(); return; @@ -56,19 +56,20 @@ public override async Task OnNavigatedToAsync(object parameter, NavigationMode m // App just started, so we get GPS access and eventually initialize the client await StartGpsDataService(); await UpdatePlayerData(true); - GameClient.ToggleUpdateTimer(); + await GameClient.ToggleUpdateTimer(); + GameClient.GameView = this; break; case GameMapNavigationModes.SettingsUpdate: - // We navigated back from Settings page after changing the Map provider, but this is managed in the page itself + // We navigated back from Settings page after changing the Map provider, but this is managed in the page itself break; case GameMapNavigationModes.PokestopUpdate: - // We came here after the catching page so we need to restart map update timer and update player data. We also check for level up. - GameClient.ToggleUpdateTimer(); + // We came here after the catching page so we need to restart map update timer and update player data. We also check for level up. + await GameClient.ToggleUpdateTimer(); await UpdatePlayerData(true); break; case GameMapNavigationModes.PokemonUpdate: - // As above - GameClient.ToggleUpdateTimer(); + // As above + await GameClient.ToggleUpdateTimer(); await UpdatePlayerData(true); break; default: @@ -94,7 +95,7 @@ public override async Task OnNavigatedFromAsync(IDictionary susp #endregion - #region Game Management Vars + #region Game Management Vars /// /// Player's profile, we use it just for the username @@ -113,7 +114,7 @@ public override async Task OnNavigatedFromAsync(IDictionary susp #endregion - #region Bindable Game Vars + #region Bindable Game Vars public ElementTheme CurrentTheme { @@ -193,7 +194,7 @@ public LevelUpRewardsResponse LevelUpResponse /// Waits for GPS auth and, if auth is given, starts updating data /// /// - private async Task StartGpsDataService() + public async Task StartGpsDataService() { await Dispatcher.DispatchAsync(async () => { @@ -218,7 +219,7 @@ await Dispatcher.DispatchAsync(async () => /// /// /// - private async Task UpdatePlayerData(bool checkForLevelUp = false) + public async Task UpdatePlayerData(bool checkForLevelUp = false) { await GameClient.UpdateProfile(); LevelUpResponse = await GameClient.UpdatePlayerStats(checkForLevelUp); diff --git a/PokemonGo-UWP/ViewModels/SearchPokeStopPageViewModel.cs b/PokemonGo-UWP/ViewModels/SearchPokeStopPageViewModel.cs index b7db430f5..464dfb1dc 100644 --- a/PokemonGo-UWP/ViewModels/SearchPokeStopPageViewModel.cs +++ b/PokemonGo-UWP/ViewModels/SearchPokeStopPageViewModel.cs @@ -158,10 +158,10 @@ public FortSearchResponse CurrentSearchResponse /// Going back to map page /// public DelegateCommand AbandonPokestop => _abandonPokestop ?? ( - _abandonPokestop = new DelegateCommand(() => + _abandonPokestop = new DelegateCommand(async () => { // Re-enable update timer - GameClient.ToggleUpdateTimer(); + await GameClient.ToggleUpdateTimer(); NavigationService.GoBack(); }, () => true) ); diff --git a/PokemonGo-UWP/Views/PlayerProfilePage.xaml.cs b/PokemonGo-UWP/Views/PlayerProfilePage.xaml.cs index a51f0fe58..b4a3288c3 100644 --- a/PokemonGo-UWP/Views/PlayerProfilePage.xaml.cs +++ b/PokemonGo-UWP/Views/PlayerProfilePage.xaml.cs @@ -9,8 +9,9 @@ public PlayerProfilePage() InitializeComponent(); } - private void GridView_ItemClick(object sender, ItemClickEventArgs e) { - ViewModel.NavigateToDetailPage(sender, e); + private void GridView_ItemClick(object sender, ItemClickEventArgs e) + { + //ViewModel.NavigateToDetailPage(sender, e); } } } \ No newline at end of file