diff --git a/CollapseLauncher/XAMLs/MainApp/Pages/Dialogs/SimpleDialogs.cs b/CollapseLauncher/XAMLs/MainApp/Pages/Dialogs/SimpleDialogs.cs index cc587d290..053d3478e 100644 --- a/CollapseLauncher/XAMLs/MainApp/Pages/Dialogs/SimpleDialogs.cs +++ b/CollapseLauncher/XAMLs/MainApp/Pages/Dialogs/SimpleDialogs.cs @@ -523,29 +523,30 @@ await SpawnDialog( ContentDialogTheme.Success ); - public static async Task Dialog_ChangePlaytime(UIElement Content) => + public static async Task Dialog_StopGame(UIElement Content) => await SpawnDialog( - Lang._Dialogs.ChangePlaytimeTitle, - Lang._Dialogs.ChangePlaytimeSubtitle, + Lang._Dialogs.StopGameTitle, + Lang._Dialogs.StopGameSubtitle, Content, Lang._Misc.NoCancel, Lang._Misc.Yes, null, ContentDialogButton.Primary, ContentDialogTheme.Warning - ); + ); - public static async Task Dialog_StopGame(UIElement Content) => + #region Playtime Dialogs + public static async Task Dialog_ChangePlaytime(UIElement Content) => await SpawnDialog( - Lang._Dialogs.StopGameTitle, - Lang._Dialogs.StopGameSubtitle, + Lang._Dialogs.ChangePlaytimeTitle, + Lang._Dialogs.ChangePlaytimeSubtitle, Content, Lang._Misc.NoCancel, Lang._Misc.Yes, null, ContentDialogButton.Primary, ContentDialogTheme.Warning - ); + ); public static async Task Dialog_ResetPlaytime(UIElement Content) { @@ -566,6 +567,25 @@ public static async Task Dialog_ResetPlaytime(UIElement Con ); } + public static async void Dialog_InvalidPlaytime(UIElement Content, int elapsedSeconds = 0) + { + StackPanel stack = new StackPanel() { Orientation = Orientation.Vertical }; + + stack.Children.Add(new TextBlock() { Text = Lang._Dialogs.InvalidPlaytimeSubtitle1, TextWrapping = TextWrapping.Wrap, Margin = new Thickness(0, 4, 0, 4) }); + stack.Children.Add(new TextBlock() { Text = Lang._Dialogs.InvalidPlaytimeSubtitle2, TextWrapping = TextWrapping.Wrap, Margin = new Thickness(0, 4, 0, 4) }); + stack.Children.Add(new TextBlock() { Text = string.Format(Lang._HomePage.GamePlaytime_Display, elapsedSeconds / 3600, elapsedSeconds % 3600 / 60), FontWeight = FontWeights.Bold, HorizontalAlignment = HorizontalAlignment.Center, Margin = new Thickness(0, 4, 0, 4) }); + stack.Children.Add(new TextBlock() { Text = Lang._Dialogs.InvalidPlaytimeSubtitle3, TextWrapping = TextWrapping.Wrap, HorizontalAlignment = HorizontalAlignment.Center, FontWeight = FontWeights.Bold, Margin = new Thickness(0, 4, 0, -2) }); + + await SpawnDialog( + Lang._Dialogs.InvalidPlaytimeTitle, + stack, + Content, + Lang._Misc.Close, + dialogTheme: ContentDialogTheme.Warning + ); + } + #endregion + public static async Task Dialog_MeteredConnectionWarning(UIElement Content) { TextBlock texts = new TextBlock { TextWrapping = TextWrapping.Wrap }; diff --git a/CollapseLauncher/XAMLs/MainApp/Pages/HomePage.xaml.cs b/CollapseLauncher/XAMLs/MainApp/Pages/HomePage.xaml.cs index 7fda42b2b..14f0c3716 100644 --- a/CollapseLauncher/XAMLs/MainApp/Pages/HomePage.xaml.cs +++ b/CollapseLauncher/XAMLs/MainApp/Pages/HomePage.xaml.cs @@ -54,13 +54,13 @@ public sealed partial class HomePage : Page private HomeMenuPanel MenuPanels { get => regionNewsProp; } private CancellationTokenSource PageToken { get; set; } private CancellationTokenSource CarouselToken { get; set; } - private CancellationTokenSource PlaytimeToken { get; set; } - + private int barwidth; private int consoleWidth; public static int RefreshRateDefault { get; } = 200; public static int RefreshRateSlow { get; } = 1000; + private static int _refreshRate; /// @@ -72,9 +72,9 @@ public static int RefreshRate get => _refreshRate; set { - #if DEBUG +#if DEBUG LogWriteLine($"HomePage Refresh Rate changed to {value}", LogType.Debug, true); - #endif +#endif _refreshRate = value; } } @@ -88,10 +88,10 @@ public static int RefreshRate #region PageMethod public HomePage() { - RefreshRate = RefreshRateDefault; + RefreshRate = RefreshRateDefault; this.Loaded += StartLoadedRoutine; - m_homePage = this; + m_homePage = this; InitializeConsoleValues(); } @@ -130,7 +130,6 @@ private async void StartLoadedRoutine(object sender, RoutedEventArgs e) CurrentGameProperty = GamePropertyVault.GetCurrentGameProperty(); PageToken = new CancellationTokenSource(); CarouselToken = new CancellationTokenSource(); - PlaytimeToken = new CancellationTokenSource(); this.InitializeComponent(); @@ -172,13 +171,14 @@ private async void StartLoadedRoutine(object sender, RoutedEventArgs e) if (await CurrentGameProperty._GameInstall.TryShowFailedGameConversionState()) return; CheckRunningGameInstance(PageToken.Token); + UpdatePlaytime(); + if (m_arguments.StartGame != null && m_arguments.StartGame.Play) { if (CurrentGameProperty._GameVersion.IsGameInstalled()) StartGame(null, null); m_arguments.StartGame.Play = false; } - AutoUpdatePlaytimeCounter(false, PlaytimeToken.Token); StartCarouselAutoScroll(CarouselToken.Token); } @@ -198,7 +198,6 @@ private void Page_Unloaded(object sender, RoutedEventArgs e) IsPageUnload = true; PageToken.Cancel(); CarouselToken.Cancel(); - PlaytimeToken.Cancel(); } #endregion @@ -455,7 +454,7 @@ private async void HideImageEventImg(bool hide) #region Open Link from Tag private void OpenImageLinkFromTag(object sender, PointerRoutedEventArgs e) { - if (!e.GetCurrentPoint((UIElement) sender).Properties.IsLeftButtonPressed) return; + if (!e.GetCurrentPoint((UIElement)sender).Properties.IsLeftButtonPressed) return; SpawnWebView2.SpawnWebView2Window(((ImageEx.ImageEx)sender).Tag.ToString(), this.Content); } @@ -800,7 +799,7 @@ private void RaiseBackgroundInstallationStatus(GameInstallStateEnum GameInstalla CurrentGameProperty._GameInstall.StatusChanged += GameInstall_StatusChanged; } } - + private async void CheckRunningGameInstance(CancellationToken Token) { FontFamily FF = Application.Current.Resources["FontAwesomeSolid"] as FontFamily; @@ -826,7 +825,7 @@ private async void CheckRunningGameInstance(CancellationToken Token) while (CurrentGameProperty.IsGameRunning) { _cachedIsGameRunning = true; - + if (StartGameBtn.IsEnabled) LauncherBtn.Translation -= Shadow16; @@ -844,15 +843,15 @@ private async void CheckRunningGameInstance(CancellationToken Token) PlaytimeIdleStack.Visibility = Visibility.Collapsed; PlaytimeRunningStack.Visibility = Visibility.Visible; - #if !DISABLEDISCORD +#if !DISABLEDISCORD AppDiscordPresence.SetActivity(ActivityType.Play, 0); - #endif - +#endif + await Task.Delay(RefreshRate, Token); } _cachedIsGameRunning = false; - + if (!StartGameBtn.IsEnabled) LauncherBtn.Translation += Shadow16; @@ -869,11 +868,11 @@ private async void CheckRunningGameInstance(CancellationToken Token) PlaytimeIdleStack.Visibility = Visibility.Visible; PlaytimeRunningStack.Visibility = Visibility.Collapsed; - - #if !DISABLEDISCORD + +#if !DISABLEDISCORD AppDiscordPresence.SetActivity(ActivityType.Idle, 0); - #endif - +#endif + await Task.Delay(RefreshRate, Token); } } @@ -1253,9 +1252,9 @@ private async void StartGame(object sender, RoutedEventArgs e) // && GetAppConfigValue("ForceGIHDREnable").ToBool()) ? // NormalizePath(GameDirPath) : // Path.GetDirectoryName(NormalizePath(GameDirPath)); - proc.StartInfo.UseShellExecute = false; + proc.StartInfo.UseShellExecute = false; proc.StartInfo.WorkingDirectory = NormalizePath(GameDirPath); - proc.StartInfo.Verb = "runas"; + proc.StartInfo.Verb = "runas"; proc.Start(); // Start the resizable window payload (also use the same token as PlaytimeToken) @@ -1287,8 +1286,7 @@ private async void StartGame(object sender, RoutedEventArgs e) break; } - StartPlaytimeCounter(CurrentGameProperty._GameVersion.GamePreset.ConfigRegistryLocation, proc, CurrentGameProperty._GameVersion.GamePreset); - AutoUpdatePlaytimeCounter(true, PlaytimeToken.Token); + StartPlaytimeCounter(proc, CurrentGameProperty._GameVersion.GamePreset); if (GetAppConfigValue("LowerCollapsePrioOnGameLaunch").ToBool()) CollapsePrioControl(proc); @@ -1303,9 +1301,9 @@ private async void StartGame(object sender, RoutedEventArgs e) while ((toTargetProc = CurrentGameProperty.GetGameProcessWithActiveWindow()) == null) { await Task.Delay(1000); // Waiting the process to be found and assigned to "toTargetProc" variable. - // This is where the magic happen. When the "toTargetProc" doesn't meet the comparison to be compared as null, - // it will instead returns a non-null value and assign it to "toTargetProc" variable, - // which it will break the loop and execute the next code below it. + // This is where the magic happen. When the "toTargetProc" doesn't meet the comparison to be compared as null, + // it will instead returns a non-null value and assign it to "toTargetProc" variable, + // which it will break the loop and execute the next code below it. } // Assign the priority to the process and write a log (just for displaying any info) @@ -1755,19 +1753,19 @@ private async void ChangePlaytimeButton_Click(object sender, RoutedEventArgs e) { if (await Dialog_ChangePlaytime(this) != ContentDialogResult.Primary) return; - int playtimemins = int.Parse("0" + MinutePlaytimeTextBox.Text); - int playtimehours = int.Parse("0" + HourPlaytimeTextBox.Text); - int FinalPlaytimeMinutes = playtimemins % 60; - int FinalPlaytimeHours = playtimehours + playtimemins / 60; - if (FinalPlaytimeHours > 99999) { FinalPlaytimeHours = 99999; FinalPlaytimeMinutes = 59; } - MinutePlaytimeTextBox.Text = FinalPlaytimeMinutes.ToString(); - HourPlaytimeTextBox.Text = FinalPlaytimeHours.ToString(); + int playtimeMins = int.Parse("0" + MinutePlaytimeTextBox.Text); + int playtimeHours = int.Parse("0" + HourPlaytimeTextBox.Text); + int finalPlaytimeMinutes = playtimeMins % 60; + int finalPlaytimeHours = playtimeHours + playtimeMins / 60; + if (finalPlaytimeHours > 99999) { finalPlaytimeHours = 99999; finalPlaytimeMinutes = 59; } + MinutePlaytimeTextBox.Text = finalPlaytimeMinutes.ToString(); + HourPlaytimeTextBox.Text = finalPlaytimeHours.ToString(); - int FinalPlaytime = FinalPlaytimeHours * 3600 + FinalPlaytimeMinutes * 60; + int finalPlaytime = finalPlaytimeHours * 3600 + finalPlaytimeMinutes * 60; - SavePlaytimetoRegistry(CurrentGameProperty._GameVersion.GamePreset.ConfigRegistryLocation, FinalPlaytime); + SavePlaytimeToRegistry(CurrentGameProperty._GameVersion.GamePreset.ConfigRegistryLocation, finalPlaytime); LogWriteLine($"Playtime counter changed to {HourPlaytimeTextBox.Text + "h " + MinutePlaytimeTextBox.Text + "m"}. (Previous value: {PlaytimeMainBtn.Text})"); - UpdatePlaytime(false, FinalPlaytime); + UpdatePlaytime(false, finalPlaytime); PlaytimeFlyout.Hide(); } @@ -1775,7 +1773,7 @@ private async void ResetPlaytimeButton_Click(object sender, RoutedEventArgs e) { if (await Dialog_ResetPlaytime(this) != ContentDialogResult.Primary) return; - SavePlaytimetoRegistry(CurrentGameProperty._GameVersion.GamePreset.ConfigRegistryLocation, 0); + SavePlaytimeToRegistry(CurrentGameProperty._GameVersion.GamePreset.ConfigRegistryLocation, 0); LogWriteLine($"Playtime counter changed to 0h 0m. (Previous value: {PlaytimeMainBtn.Text})"); UpdatePlaytime(false, 0); PlaytimeFlyout.Hide(); @@ -1789,19 +1787,21 @@ private void NumberValidationTextBox(TextBox sender, TextBoxBeforeTextChangingEv #endregion #region Playtime Tracker Method - private void UpdatePlaytime(bool reg = true, int CPtV = 0) + public void UpdatePlaytime(bool readRegistry = true, int currentPlaytimeValue = 0) { - int CurrentPlaytimeValue = reg ? ReadPlaytimeFromRegistry(CurrentGameProperty._GameVersion.GamePreset.ConfigRegistryLocation) : CPtV; - HourPlaytimeTextBox.Text = (CurrentPlaytimeValue / 3600).ToString(); - MinutePlaytimeTextBox.Text = (CurrentPlaytimeValue % 3600 / 60).ToString(); - PlaytimeMainBtn.Text = HourPlaytimeTextBox.Text + "h " + MinutePlaytimeTextBox.Text + "m"; + if (readRegistry) + currentPlaytimeValue = ReadPlaytimeFromRegistry(CurrentGameProperty._GameVersion.GamePreset.ConfigRegistryLocation); + + HourPlaytimeTextBox.Text = (currentPlaytimeValue / 3600).ToString(); + MinutePlaytimeTextBox.Text = (currentPlaytimeValue % 3600 / 60).ToString(); + PlaytimeMainBtn.Text = string.Format(Lang._HomePage.GamePlaytime_Display, HourPlaytimeTextBox.Text, MinutePlaytimeTextBox.Text); } - private static int ReadPlaytimeFromRegistry(string RegionRegKey) + private static int ReadPlaytimeFromRegistry(string regionRegistryKey) { try { - return (int)Registry.CurrentUser.OpenSubKey(RegionRegKey, true).GetValue("CollapseLauncher_Playtime", 0); + return (int)Registry.CurrentUser.OpenSubKey(regionRegistryKey, true).GetValue("CollapseLauncher_Playtime", 0); } catch (Exception ex) { @@ -1811,11 +1811,11 @@ private static int ReadPlaytimeFromRegistry(string RegionRegKey) } - private static void SavePlaytimetoRegistry(string RegionRegKey, int value) + private static void SavePlaytimeToRegistry(string regionRegistryKey, int value) { try { - Registry.CurrentUser.OpenSubKey(RegionRegKey, true).SetValue("CollapseLauncher_Playtime", value, RegistryValueKind.DWord); + Registry.CurrentUser.OpenSubKey(regionRegistryKey, true).SetValue("CollapseLauncher_Playtime", value, RegistryValueKind.DWord); } catch (Exception ex) { @@ -1823,120 +1823,97 @@ private static void SavePlaytimetoRegistry(string RegionRegKey, int value) } } - private async static void StartPlaytimeCounter(string oldRegionRegistryKey, Process proc, PresetConfigV2 gamePreset) + private async void StartPlaytimeCounter(Process proc, PresetConfigV2 gamePreset) { - int saveFrequencyinSeconds = 60; + int currentPlaytime = ReadPlaytimeFromRegistry(gamePreset.ConfigRegistryLocation); - int currentPlaytime = ReadPlaytimeFromRegistry(oldRegionRegistryKey); - int elapsedSeconds = 0; + DateTime begin = DateTime.Now; + int numOfLoops = 0; - var inGameTimer = new DispatcherTimer - { - Interval = TimeSpan.FromSeconds(1) - }; - inGameTimer.Tick += (o, e) => - { - elapsedSeconds++; - - if (elapsedSeconds % saveFrequencyinSeconds == 0) - { - //LogWriteLine($"Added \"fake\" {saveFrequencyinSeconds} seconds to {OldRegionRK.Split('\\')[2]} playtime.", LogType.Default, true); - SavePlaytimetoRegistry(oldRegionRegistryKey, currentPlaytime + elapsedSeconds); - } - }; - inGameTimer.Start(); +#if DEBUG + LogWriteLine($"{gamePreset.ProfileName} - Started session at {begin.ToLongTimeString()}."); +#endif - await proc.WaitForExitAsync(); - if (gamePreset.GameType == GameType.Honkai) + using (var inGameTimer = new System.Timers.Timer()) { - try + inGameTimer.Interval = 60000; + inGameTimer.Elapsed += (o, e) => { - while (true) - { - Process[] pname = Process.GetProcessesByName(gamePreset.GameExecutableName.Split('.')[0]); - switch (pname.Length) - { - case 0: - break; - case 1: - proc = pname[0]; - LogWriteLine($"Found the main HI3 process [{pname[0].Id}]"); - await proc.WaitForExitAsync(); - break; - default: - await Task.Delay(5000); - continue; - } - break; - } + numOfLoops++; - } - catch (Exception e) - { - LogWriteLine($"Failed to find the main BH3 process [{e}]"); - } - } - SavePlaytimetoRegistry(oldRegionRegistryKey, currentPlaytime + elapsedSeconds); - LogWriteLine($"Added {elapsedSeconds}s [{elapsedSeconds / 3600}h {elapsedSeconds % 3600 / 60}m {elapsedSeconds % 3600 % 60}s] to {oldRegionRegistryKey.Split('\\')[2]} playtime.", LogType.Default, true); - inGameTimer.Stop(); - } + DateTime now = DateTime.Now; + int elapsedSeconds = (int)(now - begin).TotalSeconds; + if (elapsedSeconds < 0) + elapsedSeconds = numOfLoops * 60; - private async void AutoUpdatePlaytimeCounter(bool bootByCollapse = false, CancellationToken token = new CancellationToken()) - { - string regionKey = CurrentGameProperty._GameVersion.GamePreset.ConfigRegistryLocation; - int oldTime = ReadPlaytimeFromRegistry(regionKey); - UpdatePlaytime(false, oldTime); - - bool dynamicUpdate = true; - - try - { - await Task.Delay(2000, token); - - if (!dynamicUpdate) - { - while (_cachedIsGameRunning) { } - UpdatePlaytime(); - return; - } + if (GamePropertyVault.GetCurrentGameProperty()._GamePreset.ProfileName == gamePreset.ProfileName) + m_homePage?.DispatcherQueue.TryEnqueue(() => + { + m_homePage.UpdatePlaytime(false, currentPlaytime + elapsedSeconds); + }); +#if DEBUG + LogWriteLine($"{gamePreset.ProfileName} - {elapsedSeconds}s elapsed. ({now.ToLongTimeString()})"); +#endif + SavePlaytimeToRegistry(gamePreset.ConfigRegistryLocation, currentPlaytime + elapsedSeconds); + }; - int elapsedSeconds = 0; + inGameTimer.Start(); - if (bootByCollapse) + if (gamePreset.GameType == GameType.Honkai) { - while (_cachedIsGameRunning) + string processNameStr = Path.GetFileNameWithoutExtension(gamePreset.GameExecutableName); + while (true) { - await Task.Delay(60000, token); - elapsedSeconds += 60; - UpdatePlaytime(false, oldTime + elapsedSeconds); - } - UpdatePlaytime(); - return; - } - - if (_cachedIsGameRunning) - { - await Task.Delay(60000, token); - int newTime = ReadPlaytimeFromRegistry(regionKey); - if (newTime == oldTime) return; - //int CurrentSeconds = int.Parse(Newtime.Split(' ')[2].Split('s')[0]) * 1000; - //await Task.Delay(60000 - CurrentSeconds, token); + // Try get the honkaiProc and auto-dispose it if the routine finishes, + // then get the first process + Process honkaiProc = Process.GetProcessesByName(processNameStr).FirstOrDefault(); + + // If the honkaiProc is not null and also has the main window handle, + // then continue to go through. + // + // It replaces the switch statement where it checks for the .Length > 1 + // since the first process (process[0]) is not the actual active process. + // + // So, if it doesn't have one (IntPtr == Zero), then continue the loop until + // the actual process found. + if (honkaiProc != null && honkaiProc.MainWindowHandle != IntPtr.Zero) + { + // Assign the old proc with honkaiProc. + proc = honkaiProc; - } + // Wait the process + LogWriteLine($"Found the main HI3 process [{proc.Id}]"); + await proc.WaitForExitAsync(); + break; + } - while (_cachedIsGameRunning) - { - UpdatePlaytime(false, oldTime + elapsedSeconds); - elapsedSeconds += 60; - await Task.Delay(60000, token); + // If the process hasn't spawn yet or still has no MainWindowHandle, + // then delay before continue to another loop routine. + await Task.Delay(5000); + } } + // If not Honkai, then wait the process as usual + else await proc.WaitForExitAsync(); - UpdatePlaytime(); + inGameTimer.Stop(); } - catch + DateTime end = DateTime.Now; + int elapsedSeconds = (int)(end - begin).TotalSeconds; + if (elapsedSeconds < 0) { + LogWriteLine($"[HomePage::StartPlaytimeCounter] Date difference cannot be lower than 0. ({elapsedSeconds}s)", LogType.Error); + elapsedSeconds = numOfLoops * 60; + Dialog_InvalidPlaytime(m_mainPage?.Content, elapsedSeconds); } + + SavePlaytimeToRegistry(gamePreset.ConfigRegistryLocation, currentPlaytime + elapsedSeconds); + LogWriteLine($"Added {elapsedSeconds}s [{elapsedSeconds / 3600}h {elapsedSeconds % 3600 / 60}m {elapsedSeconds % 3600 % 60}s] to {gamePreset.ProfileName} playtime.", LogType.Default, true); + if (GamePropertyVault.GetCurrentGameProperty()._GamePreset.ProfileName == gamePreset.ProfileName) + m_homePage?.DispatcherQueue.TryEnqueue(() => + { + m_homePage.UpdatePlaytime(false, currentPlaytime + elapsedSeconds); + }); } #endregion diff --git a/Hi3Helper.Core/Lang/Locale/LangDialogs.cs b/Hi3Helper.Core/Lang/Locale/LangDialogs.cs index 051b65bb9..a8704a924 100644 --- a/Hi3Helper.Core/Lang/Locale/LangDialogs.cs +++ b/Hi3Helper.Core/Lang/Locale/LangDialogs.cs @@ -76,6 +76,10 @@ public sealed class LangDialogs public string ResetPlaytimeSubtitle { get; set; } = LangFallback?._Dialogs.ResetPlaytimeSubtitle; public string ResetPlaytimeSubtitle2 { get; set; } = LangFallback?._Dialogs.ResetPlaytimeSubtitle2; public string ResetPlaytimeSubtitle3 { get; set; } = LangFallback?._Dialogs.ResetPlaytimeSubtitle3; + public string InvalidPlaytimeTitle { get; set; } = LangFallback?._Dialogs.ResetPlaytimeSubtitle; + public string InvalidPlaytimeSubtitle1 { get; set; } = LangFallback?._Dialogs.InvalidPlaytimeSubtitle1; + public string InvalidPlaytimeSubtitle2 { get; set; } = LangFallback?._Dialogs.InvalidPlaytimeSubtitle2; + public string InvalidPlaytimeSubtitle3 { get; set; } = LangFallback?._Dialogs.InvalidPlaytimeSubtitle3; public string MigrationTitle { get; set; } = LangFallback?._Dialogs.MigrationTitle; public string MigrationSubtitle { get; set; } = LangFallback?._Dialogs.MigrationSubtitle; public string NeedInstallMediaPackTitle { get; set; } = LangFallback?._Dialogs.NeedInstallMediaPackTitle; diff --git a/Hi3Helper.Core/Lang/Locale/LangHomePage.cs b/Hi3Helper.Core/Lang/Locale/LangHomePage.cs index 4a0c6f7b4..11e9dc405 100644 --- a/Hi3Helper.Core/Lang/Locale/LangHomePage.cs +++ b/Hi3Helper.Core/Lang/Locale/LangHomePage.cs @@ -58,6 +58,7 @@ public sealed class LangHomePage public string GamePlaytime_Idle_InvalidTimeBlock { get; set; } = LangFallback?._HomePage.GamePlaytime_Idle_InvalidTimeBlock; public string GamePlaytime_Running_Info1 { get; set; } = LangFallback?._HomePage.GamePlaytime_Running_Info1; public string GamePlaytime_Running_Info2 { get; set; } = LangFallback?._HomePage.GamePlaytime_Running_Info2; + public string GamePlaytime_Display { get; set; } = LangFallback?._HomePage.GamePlaytime_Display; public string PostPanel_Events { get; set; } = LangFallback?._HomePage.PostPanel_Events; public string PostPanel_Notices { get; set; } = LangFallback?._HomePage.PostPanel_Notices; public string PostPanel_Info { get; set; } = LangFallback?._HomePage.PostPanel_Info; diff --git a/Hi3Helper.Core/Lang/en_US.json b/Hi3Helper.Core/Lang/en_US.json index 085952717..2ac660559 100644 --- a/Hi3Helper.Core/Lang/en_US.json +++ b/Hi3Helper.Core/Lang/en_US.json @@ -123,6 +123,7 @@ "PauseCancelDownloadBtn": "Pause/Cancel", "PauseCancelBtn": "Pause/Cancel", "DownloadBtn": "Download Game", + "GameSettingsBtn": "Quick Settings", "GameSettings_Panel1": "Quick Settings", "GameSettings_Panel1OpenGameFolder": "Open Game Folder", @@ -140,6 +141,7 @@ "GameSettings_Panel4ShowSocialMediaPanel": "Show Social Media Panel", "GameSettings_Panel4CreateShortcutBtn": "Create shortcut", "GameSettings_Panel4AddToSteamBtn": "Add to Steam", + "GamePlaytime_Panel1": "Edit Playtime", "GamePlaytime_Idle_Panel1Hours": "Hours", "GamePlaytime_Idle_Panel1Minutes": "Minutes", @@ -148,6 +150,8 @@ "GamePlaytime_Idle_InvalidTimeBlock": "Invalid values provided.", "GamePlaytime_Running_Info1": "An instance of this game is currently running, therefore playtime can't be edited.", "GamePlaytime_Running_Info2": "Please be aware that fully closing Collapse will stop playtime tracking (saving what was played until that point) & only sessions started using Collapse will be tracked.", + "GamePlaytime_Display": "{0}h {1}m", + "PostPanel_Events": "Events", "PostPanel_Notices": "Notices", "PostPanel_Info": "Info", @@ -656,24 +660,35 @@ "CookbookLocateSubtitle5": "to locate the downloaded Cookbook file before continuing.\r\n\r\n", "CookbookLocateSubtitle6": "Note:\r\n", "CookbookLocateSubtitle7": "Here is the name of the Cookbook file you need to download:\r\n", + "PrivilegeMustRunTitle": "Collapse requires privilege elevation!", "PrivilegeMustRunSubtitle": "Collapse requires administrative privileges to function properly. Would you like to restart Collapse and run it as administrator?", + "ReleaseChannelChangeTitle": "Change Release Channel", "ReleaseChannelChangeSubtitle1": "You are about to change your release channel to:", "ReleaseChannelChangeSubtitle2": "Note:", "ReleaseChannelChangeSubtitle3": "This action may cause irreversible changes and/or cause things to break from your current setup. We are not responsible for any loss or corruption of data associated with your game.", + "ChangePlaytimeTitle": "Are you sure you want to change your playtime?", "ChangePlaytimeSubtitle": "Changing your playtime means overwriting the current value with the one you just inputted. \n\nDo you wish to proceed?\n\nNote: This has no impact on how Collapse operates and you can change this value again at any time when not playing the game.", "ResetPlaytimeTitle": "Are you sure you want to reset your playtime?", "ResetPlaytimeSubtitle": "Resetting your playtime means setting the playtime counter back to 0. This is a ", "ResetPlaytimeSubtitle2": "destructive", "ResetPlaytimeSubtitle3": " action, meaning that you cannot undo this once you confirm. \n\nDo you wish to proceed?\n\nNote: This has no impact on how Collapse operates and you can change this value again at any time when not playing the game.", + "InvalidPlaytimeTitle": "There was a problem saving this session's playtime", + "InvalidPlaytimeSubtitle1": "The difference between the starting and ending times results in a negative number.", + "InvalidPlaytimeSubtitle2": "A fallback value is saved every minute and will be used instead:", + "InvalidPlaytimeSubtitle3": "Please refrain from adjusting the computer clock while in-game.", + "LocateExePathTitle": "Locate Executable Install Path", "LocateExePathSubtitle": "Please point Collapse to the location of your application's executable:", + "CannotUseAppLocationForGameDirTitle": "Folder is invalid!", "CannotUseAppLocationForGameDirSubtitle": "You can't use this folder as it is being used as a system folder or being used for main executable of the app. Please choose another folder!", + "StopGameTitle": "Force Stop Game", "StopGameSubtitle": "Are you sure you want to force stop current running game?\r\nYou may lose some in-game progress.", + "MeteredConnectionWarningTitle": "Metered Connection Detected!", "MeteredConnectionWarningSubtitle": "Your current internet connection was detected as being 'Metered'! Continuing the update process may incur additional charges from your internet provider. Do you wish to proceed?",