diff --git a/CollapseLauncher/Classes/GameManagement/GameSettings/Genshin/Settings.cs b/CollapseLauncher/Classes/GameManagement/GameSettings/Genshin/Settings.cs index c9923da08..44912cac6 100644 --- a/CollapseLauncher/Classes/GameManagement/GameSettings/Genshin/Settings.cs +++ b/CollapseLauncher/Classes/GameManagement/GameSettings/Genshin/Settings.cs @@ -32,14 +32,15 @@ public override void ReloadSettings() InitializeSettings(); } + #nullable enable public override void SaveSettings() { // Save Settings base.SaveSettings(); - SettingsScreen.Save(); - SettingsGeneralData.Save(); - SettingVisibleBackground.Save(); - SettingsWindowsHDR.Save(); + SettingsScreen?.Save(); + SettingsGeneralData?.Save(); + SettingVisibleBackground?.Save(); + SettingsWindowsHDR?.Save(); } public override IGameSettingsUniversal AsIGameSettingsUniversal() => this; diff --git a/CollapseLauncher/Classes/GameManagement/GameSettings/StarRail/RegistryClass/Model.cs b/CollapseLauncher/Classes/GameManagement/GameSettings/StarRail/RegistryClass/Model.cs index 2c9a58d96..a6d0521f5 100644 --- a/CollapseLauncher/Classes/GameManagement/GameSettings/StarRail/RegistryClass/Model.cs +++ b/CollapseLauncher/Classes/GameManagement/GameSettings/StarRail/RegistryClass/Model.cs @@ -1,5 +1,6 @@ using CollapseLauncher.GameSettings.StarRail.Context; using CollapseLauncher.Interfaces; +using CollapseLauncher.Pages; using Hi3Helper; using Hi3Helper.EncTool; using Microsoft.Win32; @@ -329,6 +330,13 @@ public void Save() try { if (RegistryRoot == null) throw new NullReferenceException($"Cannot save {_ValueName} since RegistryKey is unexpectedly not initialized!"); + + if (StarRailGameSettingsPage.CheckAbTest()) + { + LogWriteLine("[StarRailGameSettings::Model] Graphics settings could not be saved due to A/B test flag is found!", + LogType.Error, true); + return; + } RegistryRoot.SetValue(_GraphicsQuality, Quality.Custom, RegistryValueKind.DWord); diff --git a/CollapseLauncher/Classes/GameManagement/GameSettings/StarRail/Settings.cs b/CollapseLauncher/Classes/GameManagement/GameSettings/StarRail/Settings.cs index 98f3838f6..1f5b42580 100644 --- a/CollapseLauncher/Classes/GameManagement/GameSettings/StarRail/Settings.cs +++ b/CollapseLauncher/Classes/GameManagement/GameSettings/StarRail/Settings.cs @@ -41,18 +41,19 @@ public override void ReloadSettings() InitializeSettings(); } + #nullable enable public override void SaveSettings() { // Save Settings base.SaveSettings(); - GraphicsSettings.Save(); - SettingsScreen.Save(); - AudioSettings_BGM.Save(); - AudioSettings_Master.Save(); - AudioSettings_SFX.Save(); - AudioSettings_VO.Save(); - AudioLanguage.Save(); - TextLanguage.Save(); + GraphicsSettings?.Save(); + SettingsScreen?.Save(); + AudioSettings_BGM?.Save(); + AudioSettings_Master?.Save(); + AudioSettings_SFX?.Save(); + AudioSettings_VO?.Save(); + AudioLanguage?.Save(); + TextLanguage?.Save(); } public override IGameSettingsUniversal AsIGameSettingsUniversal() => this; diff --git a/CollapseLauncher/Classes/GameManagement/GameSettings/Universal/RegistryClass/CollapseMiscSetting.cs b/CollapseLauncher/Classes/GameManagement/GameSettings/Universal/RegistryClass/CollapseMiscSetting.cs index 1a82be458..9498d77ca 100644 --- a/CollapseLauncher/Classes/GameManagement/GameSettings/Universal/RegistryClass/CollapseMiscSetting.cs +++ b/CollapseLauncher/Classes/GameManagement/GameSettings/Universal/RegistryClass/CollapseMiscSetting.cs @@ -17,6 +17,8 @@ internal class CollapseMiscSetting : IGameSettingsValue private const string _ValueName = "CollapseLauncher_Misc"; private bool _UseCustomArguments = true; + + private bool _UseCustomRegionBG = false; private static bool _IsDeserializing; #endregion @@ -88,6 +90,26 @@ public bool UseCustomArguments /// Use mobile layout. Currently only available for Genshin and StarRail. /// public bool LaunchMobileMode { get; set; } = false; + + /// + /// Set custom background for given region for given game. + /// + public bool UseCustomRegionBG + { + get => _UseCustomRegionBG; + set + { + _UseCustomRegionBG = value; + if (!_IsDeserializing) Save(); + } + } + +#nullable enable + /// + /// The path of the custom BG for each region + /// + public string? CustomRegionBGPath { get; set; } + #endregion #region Methods diff --git a/CollapseLauncher/Classes/Helper/Background/BackgroundMediaUtility.cs b/CollapseLauncher/Classes/Helper/Background/BackgroundMediaUtility.cs index a2b0f1c81..31a77d33d 100644 --- a/CollapseLauncher/Classes/Helper/Background/BackgroundMediaUtility.cs +++ b/CollapseLauncher/Classes/Helper/Background/BackgroundMediaUtility.cs @@ -48,7 +48,7 @@ internal enum MediaType private Grid? _parentBgImageBackgroundGrid; private Grid? _parentBgMediaPlayerBackgroundGrid; - internal MediaType CurrentAppliedMediaType = MediaType.Unknown; + internal static MediaType CurrentAppliedMediaType = MediaType.Unknown; private CancellationTokenSourceWrapper? _cancellationToken; private IBackgroundMediaLoader? _loaderStillImage; @@ -150,8 +150,6 @@ public void Dispose() _alternativeFileStream?.Dispose(); _alternativeFileStream = null; - CurrentAppliedMediaType = MediaType.Unknown; - _isCurrentRegistered = false; GC.SuppressFinalize(this); } @@ -349,7 +347,7 @@ private async Task LoadBackgroundInner(string mediaPath, bool _loaderMediaPlayer?.Show(); break; case MediaType.StillImage: - _loaderStillImage?.Show(); + _loaderStillImage?.Show(CurrentAppliedMediaType == MediaType.Media); _loaderMediaPlayer?.Hide(); break; } diff --git a/CollapseLauncher/Classes/Helper/Background/Loaders/IBackgroundMediaLoader.cs b/CollapseLauncher/Classes/Helper/Background/Loaders/IBackgroundMediaLoader.cs index c78108bf4..7277dc0ad 100644 --- a/CollapseLauncher/Classes/Helper/Background/Loaders/IBackgroundMediaLoader.cs +++ b/CollapseLauncher/Classes/Helper/Background/Loaders/IBackgroundMediaLoader.cs @@ -16,7 +16,7 @@ internal interface IBackgroundMediaLoader : IDisposable Task LoadAsync(string filePath, bool isForceRecreateCache = false, bool isRequestInit = false, CancellationToken token = default); void Dimm(); void Undimm(); - void Show(); + void Show(bool isForceShow = false); void Hide(); void Mute(); void Unmute(); diff --git a/CollapseLauncher/Classes/Helper/Background/Loaders/MediaPlayerLoader.cs b/CollapseLauncher/Classes/Helper/Background/Loaders/MediaPlayerLoader.cs index 950f9bb0b..79b76925c 100644 --- a/CollapseLauncher/Classes/Helper/Background/Loaders/MediaPlayerLoader.cs +++ b/CollapseLauncher/Classes/Helper/Background/Loaders/MediaPlayerLoader.cs @@ -1,10 +1,10 @@ using CollapseLauncher.Extension; using CollapseLauncher.Helper.Animation; using CommunityToolkit.WinUI.Animations; +using Hi3Helper; #if USEFFMPEGFORVIDEOBG using FFmpegInteropX; using Hi3Helper; - #endif using Hi3Helper.Shared.Region; using Microsoft.UI.Composition; @@ -18,6 +18,7 @@ using Windows.Media.Playback; using Windows.Storage; using Windows.Storage.FileProperties; +using static Hi3Helper.Logger; #if USEDYNAMICVIDEOPALETTE using CollapseLauncher.Extension; @@ -101,9 +102,32 @@ public void Dispose() CanvasDevice?.Dispose(); CurrentFrameBitmap?.Dispose(); #endif - CurrentMediaPlayer?.Dispose(); - InnerCancellationToken?.Dispose(); - CurrentMediaStream?.Dispose(); + try + { + CurrentMediaPlayer?.Dispose(); + } + catch (Exception ex) + { + LogWriteLine($"Error disposing CurrentMediaPlayer: {ex.Message}", LogType.Error, true); + } + + try + { + InnerCancellationToken?.Dispose(); + } + catch (Exception ex) + { + LogWriteLine($"Error disposing InnerCancellationToken: {ex.Message}", LogType.Error, true); + } + + try + { + CurrentMediaStream?.Dispose(); + } + catch (Exception ex) + { + LogWriteLine($"Error disposing CurrentMediaStream: {ex.Message}", LogType.Error, true); + } GC.SuppressFinalize(this); } @@ -387,7 +411,7 @@ await Task.WhenAll( ); } - public void Show() + public void Show(bool isForceShow = false) { BackgroundMediaUtility.SharedActionBlockQueue?.Post(ShowInner()); } diff --git a/CollapseLauncher/Classes/Helper/Background/Loaders/StillImageLoader.cs b/CollapseLauncher/Classes/Helper/Background/Loaders/StillImageLoader.cs index 54ced9190..8854a0216 100644 --- a/CollapseLauncher/Classes/Helper/Background/Loaders/StillImageLoader.cs +++ b/CollapseLauncher/Classes/Helper/Background/Loaders/StillImageLoader.cs @@ -30,7 +30,12 @@ internal class StillImageLoader : IBackgroundMediaLoader private Grid AcrylicMask { get; } private Grid OverlayTitleBar { get; } private double AnimationDuration { get; } - public bool IsBackgroundDimm { get; set; } + + public bool IsBackgroundDimm + { + get; + set; + } internal StillImageLoader( FrameworkElement parentUI, @@ -39,6 +44,7 @@ internal StillImageLoader( ImageUI? imageBackCurrent, ImageUI? imageBackLast, double animationDuration = BackgroundMediaUtility.TransitionDuration) { + GC.SuppressFinalize(this); ParentUI = parentUI; CurrentCompositor = parentUI.GetElementCompositor(); @@ -56,7 +62,7 @@ internal StillImageLoader( public void Dispose() { - GC.SuppressFinalize(this); + GC.Collect(); } public async Task LoadAsync(string filePath, bool isImageLoadForFirstTime, @@ -85,11 +91,11 @@ await Task.WhenAll( isImageLoadForFirstTime, false), ApplyAndSwitchImage(AnimationDuration, bitmapImage) ); + } finally { GC.Collect(); - GC.WaitForPendingFinalizers(); } } @@ -107,9 +113,11 @@ private async Task ApplyAndSwitchImage(double duration, BitmapImage imageToApply await Task.WhenAll( ImageBackCurrent.StartAnimation(timeSpan, CurrentCompositor - .CreateScalarKeyFrameAnimation("Opacity", 1, 0)), + .CreateScalarKeyFrameAnimation("Opacity", + 1, 0)), ImageBackLast.StartAnimation(timeSpan, - CurrentCompositor.CreateScalarKeyFrameAnimation("Opacity", + CurrentCompositor + .CreateScalarKeyFrameAnimation("Opacity", 0, 1, timeSpan * 0.8)) ); } @@ -124,10 +132,18 @@ public void Undimm() BackgroundMediaUtility.SharedActionBlockQueue?.Post(ToggleImageVisibility(false)); } - private async Task ToggleImageVisibility(bool hideImage, bool completeInvisible = false) + private async Task ToggleImageVisibility(bool hideImage, bool completeInvisible = false, bool isForceShow = false) { - if (IsBackgroundDimm == hideImage) return; - IsBackgroundDimm = hideImage; + if (isForceShow) + { + hideImage = false; + completeInvisible = false; + } + else + { + if (IsBackgroundDimm == hideImage) return; + IsBackgroundDimm = hideImage; + } TimeSpan duration = TimeSpan.FromSeconds(hideImage ? BackgroundMediaUtility.TransitionDuration @@ -141,7 +157,26 @@ private async Task ToggleImageVisibility(bool hideImage, bool completeInvisible Vector3 toTranslate = new Vector3(-((float)(ImageBackParentGrid?.ActualWidth ?? 0) * (toScale - 1f) / 2), -((float)(ImageBackParentGrid?.ActualHeight ?? 0) * (toScale - 1f) / 2), 0); - if (completeInvisible) + if (isForceShow) + { + await Task.WhenAll( + AcrylicMask.StartAnimation( + duration, + CurrentCompositor.CreateScalarKeyFrameAnimation("Opacity", hideImage ? 1f : 0f, hideImage ? 0f : 1f) + ), + OverlayTitleBar.StartAnimation( + duration, + CurrentCompositor.CreateScalarKeyFrameAnimation("Opacity", hideImage ? 0f : 1f, hideImage ? 1f : 0f) + ), + ImageBackParentGrid.StartAnimation( + duration, + CurrentCompositor.CreateVector3KeyFrameAnimation("Scale", new Vector3(hideImage ? toScale : fromScale), new Vector3(!hideImage ? toScale : fromScale)), + CurrentCompositor.CreateVector3KeyFrameAnimation("Translation", hideImage ? toTranslate : fromTranslate, !hideImage ? toTranslate : fromTranslate), + CurrentCompositor.CreateScalarKeyFrameAnimation("Opacity", 1f, 0f) + ) + ); + } + else if (completeInvisible) { await Task.WhenAll( ImageBackParentGrid.StartAnimation( @@ -170,10 +205,10 @@ await Task.WhenAll( } } - public void Show() + public void Show(bool isForceShow = false) { if (ImageBackParentGrid?.Opacity > 0f) return; - BackgroundMediaUtility.SharedActionBlockQueue?.Post(ToggleImageVisibility(false, true)); + BackgroundMediaUtility.SharedActionBlockQueue?.Post(ToggleImageVisibility(false, true, isForceShow)); } public void Hide() diff --git a/CollapseLauncher/Classes/Helper/Image/ImageLoaderHelper.cs b/CollapseLauncher/Classes/Helper/Image/ImageLoaderHelper.cs index 365f1204b..1f6e871c8 100644 --- a/CollapseLauncher/Classes/Helper/Image/ImageLoaderHelper.cs +++ b/CollapseLauncher/Classes/Helper/Image/ImageLoaderHelper.cs @@ -32,13 +32,18 @@ namespace CollapseLauncher.Helper.Image { internal static class ImageLoaderHelper { - internal static Dictionary SupportedImageFormats = + internal static readonly Dictionary SupportedImageFormats = new() { { "All supported formats", string.Join(';', BackgroundMediaUtility.SupportedImageExt.Select(x => $"*{x}")) + ';' + string.Join(';', BackgroundMediaUtility.SupportedMediaPlayerExt.Select(x => $"*{x}")) }, { "Image formats", string.Join(';', BackgroundMediaUtility.SupportedImageExt.Select(x => $"*{x}")) }, { "Video formats", string.Join(';', BackgroundMediaUtility.SupportedMediaPlayerExt.Select(x => $"*{x}")) } }; + internal static readonly Dictionary SupportedStaticImageFormats = new() + { + { "Image formats", string.Join(';', BackgroundMediaUtility.SupportedImageExt.Select(x => $"*{x}")) } + }; + #region Waifu2X private static Waifu2X _waifu2X; private static Waifu2XStatus _cachedStatus = Waifu2XStatus.NotInitialized; @@ -191,15 +196,23 @@ private static async Task SpawnImageCropperDialog(string filePath, s ContentDialogResult dialogResult = await dialogOverlay.QueueAndSpawnDialog(); if (dialogResult == ContentDialogResult.Secondary) return null; - await using (FileStream cachedFileStream = new FileStream(cachedFilePath!, StreamUtility.FileStreamCreateReadWriteOpt)) + try { - dialogOverlay.IsPrimaryButtonEnabled = false; - dialogOverlay.IsSecondaryButtonEnabled = false; - await imageCropper.SaveAsync(cachedFileStream.AsRandomAccessStream()!, BitmapFileFormat.Png); - } + await using (FileStream cachedFileStream = + new FileStream(cachedFilePath!, StreamUtility.FileStreamCreateReadWriteOpt)) + { + dialogOverlay.IsPrimaryButtonEnabled = false; + dialogOverlay.IsSecondaryButtonEnabled = false; + await imageCropper.SaveAsync(cachedFileStream.AsRandomAccessStream()!, BitmapFileFormat.Png); + } - GC.WaitForPendingFinalizers(); - GC.WaitForFullGCComplete(); + GC.WaitForPendingFinalizers(); + GC.WaitForFullGCComplete(); + } + catch (Exception ex) + { + Logger.LogWriteLine($"Exception caught at [ImageLoaderHelper::SpawnImageCropperDialog]\r\n{ex}", LogType.Error, true); + } FileInfo cachedFileInfo = new FileInfo(cachedFilePath); return await GenerateCachedStream(cachedFileInfo, ToWidth, ToHeight, true); @@ -258,15 +271,23 @@ private static async Task GenerateCachedStream(FileInfo InputFileInf if (isFromCropProcess) { string InputFileName = InputFileInfo!.FullName; - InputFileInfo.MoveTo(InputFileInfo.FullName + "_old", true); - FileInfo newCachedFileInfo = new FileInfo(InputFileName); + try + { + InputFileInfo.MoveTo(InputFileInfo.FullName + "_old", true); + FileInfo newCachedFileInfo = new FileInfo(InputFileName); + await using (FileStream newCachedFileStream = newCachedFileInfo.Open(StreamUtility.FileStreamCreateWriteOpt)) + await using (FileStream oldInputFileStream = InputFileInfo.Open(StreamUtility.FileStreamOpenReadOpt)) + await ResizeImageStream(oldInputFileStream, newCachedFileStream, ToWidth, ToHeight); - await using (FileStream newCachedFileStream = newCachedFileInfo.Open(StreamUtility.FileStreamCreateWriteOpt)) - await using (FileStream oldInputFileStream = InputFileInfo.Open(StreamUtility.FileStreamOpenReadOpt)) - await ResizeImageStream(oldInputFileStream, newCachedFileStream, ToWidth, ToHeight); + InputFileInfo.Delete(); - InputFileInfo.Delete(); - return newCachedFileInfo.Open(StreamUtility.FileStreamOpenReadOpt); + return newCachedFileInfo.Open(StreamUtility.FileStreamOpenReadOpt); + } + catch (IOException ex) + { + Logger.LogWriteLine($"[ImageLoaderHelper::GenerateCachedStream] IOException Caught! Opening InputFile instead...\r\n{ex}", LogType.Error, true); + return InputFileInfo.Open(StreamUtility.FileStreamOpenReadOpt); + } } FileInfo cachedFileInfo = GetCacheFileInfo(InputFileInfo!.FullName + InputFileInfo.Length); @@ -274,8 +295,8 @@ private static async Task GenerateCachedStream(FileInfo InputFileInf if (isCachedFileExist) return cachedFileInfo.Open(StreamUtility.FileStreamOpenReadOpt); await using (FileStream cachedFileStream = cachedFileInfo.Create()) - await using (FileStream inputFileStream = InputFileInfo.Open(StreamUtility.FileStreamOpenReadOpt)) - await ResizeImageStream(inputFileStream, cachedFileStream, ToWidth, ToHeight); + await using (FileStream inputFileStream = InputFileInfo.Open(StreamUtility.FileStreamOpenReadOpt)) + await ResizeImageStream(inputFileStream, cachedFileStream, ToWidth, ToHeight); return cachedFileInfo.Open(StreamUtility.FileStreamOpenReadOpt); } diff --git a/CollapseLauncher/XAMLs/MainApp/MainPage.xaml.cs b/CollapseLauncher/XAMLs/MainApp/MainPage.xaml.cs index d5289384d..3fc9b1280 100644 --- a/CollapseLauncher/XAMLs/MainApp/MainPage.xaml.cs +++ b/CollapseLauncher/XAMLs/MainApp/MainPage.xaml.cs @@ -10,6 +10,7 @@ using CollapseLauncher.Helper.Update; using CollapseLauncher.Interfaces; using CollapseLauncher.Pages; +using CollapseLauncher.Statics; using CommunityToolkit.WinUI; using CommunityToolkit.WinUI.Animations; using Hi3Helper; @@ -160,8 +161,7 @@ private async Task InitializeStartup() RunBackgroundCheck(); // Initialize the background image utility - CurrentBackgroundHandler = await BackgroundMediaUtility.CreateInstanceAsync(this, BackgroundAcrylicMask, BackgroundOverlayTitleBar, BackgroundNewBackGrid, BackgroundNewMediaPlayerGrid); - _localBackgroundHandler = CurrentBackgroundHandler; + await InitBackgroundHandler(); Type Page = typeof(HomePage); @@ -195,6 +195,12 @@ private async Task InitializeStartup() LockRegionChangeBtn = false; InvokeLoadingRegionPopup(false); } + + private async Task InitBackgroundHandler() + { + CurrentBackgroundHandler = await BackgroundMediaUtility.CreateInstanceAsync(this, BackgroundAcrylicMask, BackgroundOverlayTitleBar, BackgroundNewBackGrid, BackgroundNewMediaPlayerGrid); + _localBackgroundHandler = CurrentBackgroundHandler; + } #endregion #region Invokers @@ -450,81 +456,126 @@ private void BackgroundImg_IsImageHideEvent(object sender, bool e) else CurrentBackgroundHandler?.Undimm(); } - private void CustomBackgroundChanger_Event(object sender, BackgroundImgProperty e) + private async void CustomBackgroundChanger_Event(object sender, BackgroundImgProperty e) { - if (LauncherMetadataHelper.CurrentMetadataConfig?.GameLauncherApi != null) + var gameLauncherApi = LauncherMetadataHelper.CurrentMetadataConfig?.GameLauncherApi; + if (gameLauncherApi != null) { - LauncherMetadataHelper.CurrentMetadataConfig.GameLauncherApi.GameBackgroundImgLocal = e.ImgPath; - IsCustomBG = e.IsCustom; + gameLauncherApi.GameBackgroundImgLocal = e.ImgPath; + IsCustomBG = e.IsCustom; - if (e.IsCustom) - SetAndSaveConfigValue("CustomBGPath", - LauncherMetadataHelper.CurrentMetadataConfig.GameLauncherApi - .GameBackgroundImgLocal); + // if (e.IsCustom) + // SetAndSaveConfigValue("CustomBGPath", + // gameLauncherApi.GameBackgroundImgLocal); - if (!File.Exists(LauncherMetadataHelper.CurrentMetadataConfig.GameLauncherApi.GameBackgroundImgLocal)) + if (!File.Exists(gameLauncherApi.GameBackgroundImgLocal)) { LogWriteLine($"Custom background file {e.ImgPath} is missing!", LogType.Warning, true); - LauncherMetadataHelper.CurrentMetadataConfig.GameLauncherApi.GameBackgroundImgLocal = AppDefaultBG; + gameLauncherApi.GameBackgroundImgLocal = AppDefaultBG; } - CurrentBackgroundHandler - ?.LoadBackground(LauncherMetadataHelper.CurrentMetadataConfig.GameLauncherApi.GameBackgroundImgLocal, - e.IsRequestInit, e.IsForceRecreateCache, ex => - { - LauncherMetadataHelper - .CurrentMetadataConfig - .GameLauncherApi - .GameBackgroundImgLocal = - AppDefaultBG; - LogWriteLine($"An error occured while loading background {e.ImgPath}\r\n{ex}", - LogType.Error, true); - ErrorSender.SendException(ex); - }, e.ActionAfterLoaded); + var mType = BackgroundMediaUtility.GetMediaType(gameLauncherApi.GameBackgroundImgLocal); + switch (mType) + { + case BackgroundMediaUtility.MediaType.Media: + MediaPlayerFrame = new MediaPlayerElement + { + HorizontalAlignment = HorizontalAlignment.Center, + VerticalAlignment = VerticalAlignment.Center, + Stretch = Stretch.UniformToFill, + Tag = "MediaPlayer" + }; + BackgroundNewMediaPlayerGrid.Visibility = Visibility.Visible; + BackgroundNewBackGrid.Visibility = Visibility.Collapsed; + break; + case BackgroundMediaUtility.MediaType.StillImage: + FileStream imgStream = await ImageLoaderHelper.LoadImage(gameLauncherApi.GameBackgroundImgLocal); + BackgroundMediaUtility.SetAlternativeFileStream(imgStream); + BackgroundNewMediaPlayerGrid.Visibility = Visibility.Collapsed; + BackgroundNewBackGrid.Visibility = Visibility.Visible; + MediaPlayerFrame = null; + break; + default: + throw new InvalidCastException(); + } + + await InitBackgroundHandler(); + CurrentBackgroundHandler?.LoadBackground(gameLauncherApi.GameBackgroundImgLocal, e.IsRequestInit, + e.IsForceRecreateCache, ex => + { + gameLauncherApi.GameBackgroundImgLocal = AppDefaultBG; + LogWriteLine($"An error occured while loading background {e.ImgPath}\r\n{ex}", + LogType.Error, true); + ErrorSender.SendException(ex); + }, e.ActionAfterLoaded); } } internal async void ChangeBackgroundImageAsRegionAsync(bool ShowLoadingMsg = false) { + var gameLauncherApi = LauncherMetadataHelper.CurrentMetadataConfig!.GameLauncherApi!; + GamePresetProperty currentGameProperty = GetCurrentGameProperty(); + bool isUseCustomPerRegionBg = ((IGameSettingsUniversal)currentGameProperty?._GameSettings)?.SettingsCollapseMisc?.UseCustomRegionBG ?? false; + IsCustomBG = GetAppConfigValue("UseCustomBG").ToBool(); bool isAPIBackgroundAvailable = !string.IsNullOrEmpty(LauncherMetadataHelper.CurrentMetadataConfig?.GameLauncherApi?.GameBackgroundImg); - if (IsCustomBG) + + // Check if Regional Custom BG is enabled and available + if (isUseCustomPerRegionBg) { - string BGPath = GetAppConfigValue("CustomBGPath").ToString(); - if (LauncherMetadataHelper.CurrentMetadataConfig?.GameLauncherApi != null) + var regionBgPath = ((IGameSettingsUniversal)currentGameProperty._GameSettings)?.SettingsCollapseMisc?.CustomRegionBGPath; + if (!string.IsNullOrEmpty(regionBgPath) && File.Exists(regionBgPath)) { - LauncherMetadataHelper.CurrentMetadataConfig.GameLauncherApi.GameBackgroundImgLocal = - string.IsNullOrEmpty(BGPath) ? AppDefaultBG : BGPath; + if (BackgroundMediaUtility.GetMediaType(regionBgPath) == BackgroundMediaUtility.MediaType.StillImage) + { + FileStream imgStream = await ImageLoaderHelper.LoadImage(regionBgPath); + BackgroundMediaUtility.SetAlternativeFileStream(imgStream); + } + + gameLauncherApi.GameBackgroundImgLocal = regionBgPath; } } - else if (isAPIBackgroundAvailable) + // If not, then check for global Custom BG + else { - try + var BGPath = IsCustomBG ? GetAppConfigValue("CustomBGPath").ToString() : null; + if (!string.IsNullOrEmpty(BGPath)) + { + gameLauncherApi.GameBackgroundImgLocal = BGPath; + } + // If it's still not, then check if API gives any background + else if (isAPIBackgroundAvailable) { - await DownloadBackgroundImage(default); + try + { + await DownloadBackgroundImage(default); + } + catch (Exception ex) + { + ErrorSender.SendException(ex); + LogWriteLine($"Failed while downloading default background image!\r\n{ex}", LogType.Error, true); + LauncherMetadataHelper.CurrentMetadataConfig.GameLauncherApi.GameBackgroundImgLocal = AppDefaultBG; + } } - catch (Exception ex) + // IF ITS STILL NOT THERE, then use paimon cute deadge pic :) + else { - ErrorSender.SendException(ex); - LogWriteLine($"Failed while downloading default background image!\r\n{ex}", LogType.Error, true); - LauncherMetadataHelper.CurrentMetadataConfig.GameLauncherApi.GameBackgroundImgLocal = AppDefaultBG; + gameLauncherApi.GameBackgroundImgLocal = AppDefaultBG; } } - + // Use default background if the API background is empty (in-case HoYo did something catchy) if (!isAPIBackgroundAvailable && !IsCustomBG && LauncherMetadataHelper.CurrentMetadataConfig?.GameLauncherApi != null) LauncherMetadataHelper.CurrentMetadataConfig.GameLauncherApi.GameBackgroundImgLocal = AppDefaultBG; - - if ((!IsCustomBG || IsFirstStartup) && LauncherMetadataHelper.CurrentMetadataConfig?.GameLauncherApi != null) - { - BackgroundImgChanger.ChangeBackground(LauncherMetadataHelper.CurrentMetadataConfig.GameLauncherApi.GameBackgroundImgLocal, - () => - { - IsFirstStartup = false; - ColorPaletteUtility.ReloadPageTheme(this, CurrentAppTheme); - }, - IsCustomBG); - } + + // If the custom per region is enabled, then execute below + BackgroundImgChanger.ChangeBackground(gameLauncherApi.GameBackgroundImgLocal, + () => + { + IsFirstStartup = false; + ColorPaletteUtility.ReloadPageTheme(this, CurrentAppTheme); + }, + IsCustomBG || isUseCustomPerRegionBg, true, true); } #endregion diff --git a/CollapseLauncher/XAMLs/MainApp/MainWindow.xaml b/CollapseLauncher/XAMLs/MainApp/MainWindow.xaml index 107a402f4..f5e05593d 100644 --- a/CollapseLauncher/XAMLs/MainApp/MainWindow.xaml +++ b/CollapseLauncher/XAMLs/MainApp/MainWindow.xaml @@ -1,4 +1,4 @@ - - diff --git a/CollapseLauncher/XAMLs/MainApp/Pages/Dialogs/SimpleDialogs.cs b/CollapseLauncher/XAMLs/MainApp/Pages/Dialogs/SimpleDialogs.cs index 367a35cec..9917ad09e 100644 --- a/CollapseLauncher/XAMLs/MainApp/Pages/Dialogs/SimpleDialogs.cs +++ b/CollapseLauncher/XAMLs/MainApp/Pages/Dialogs/SimpleDialogs.cs @@ -1,7 +1,9 @@ using CollapseLauncher.CustomControls; using CollapseLauncher.Extension; +using CollapseLauncher.FileDialogCOM; using CollapseLauncher.Helper; using CollapseLauncher.Helper.Animation; +using CollapseLauncher.Helper.Image; using CollapseLauncher.Helper.Metadata; using CollapseLauncher.InstallManager.Base; using CollapseLauncher.Statics; @@ -20,7 +22,6 @@ using static Hi3Helper.Data.ConverterTool; using static Hi3Helper.Locale; using static Hi3Helper.Shared.Region.LauncherConfig; - using CollapseUIExt = CollapseLauncher.Extension.UIElementExtensions; namespace CollapseLauncher.Dialogs diff --git a/CollapseLauncher/XAMLs/MainApp/Pages/GameSettingsPages/StarRailGameSettingsPage.xaml.cs b/CollapseLauncher/XAMLs/MainApp/Pages/GameSettingsPages/StarRailGameSettingsPage.xaml.cs index ece700ddd..48a713cd4 100644 --- a/CollapseLauncher/XAMLs/MainApp/Pages/GameSettingsPages/StarRailGameSettingsPage.xaml.cs +++ b/CollapseLauncher/XAMLs/MainApp/Pages/GameSettingsPages/StarRailGameSettingsPage.xaml.cs @@ -88,12 +88,24 @@ private async void LoadPage() InheritApplyTextColor = ApplyText.Foreground!; #nullable enable // A/B Testing as of 2023-12-26 (HSR v1.6.0) + if (CheckAbTest()) + { + await SimpleDialogs.Dialog_GenericWarning(Content!); + } + } + + /// + /// Returns true if A/B test registry identifier is found. + /// + public static bool CheckAbTest() + { object? abValue = Registry.GetValue(@"HKEY_CURRENT_USER\Software\Cognosphere\Star Rail", _AbValueName, null); if (abValue != null) { - await SimpleDialogs.Dialog_GenericWarning(Content!); LogWriteLine($"A/B Value Found. Settings will not apply to the game.", LogType.Warning, true); + return true; } + return false; } #nullable disable private void RegistryExportClick(object sender, RoutedEventArgs e) diff --git a/CollapseLauncher/XAMLs/MainApp/Pages/HomePage.xaml b/CollapseLauncher/XAMLs/MainApp/Pages/HomePage.xaml index dc06f97ff..bdcf1ffdc 100644 --- a/CollapseLauncher/XAMLs/MainApp/Pages/HomePage.xaml +++ b/CollapseLauncher/XAMLs/MainApp/Pages/HomePage.xaml @@ -1,4 +1,4 @@ - + @@ -1914,13 +1914,47 @@ + + + + + - diff --git a/CollapseLauncher/XAMLs/MainApp/Pages/HomePage.xaml.cs b/CollapseLauncher/XAMLs/MainApp/Pages/HomePage.xaml.cs index da2521363..1640c3c5b 100644 --- a/CollapseLauncher/XAMLs/MainApp/Pages/HomePage.xaml.cs +++ b/CollapseLauncher/XAMLs/MainApp/Pages/HomePage.xaml.cs @@ -9,6 +9,7 @@ using CollapseLauncher.Helper; using CollapseLauncher.Helper.Animation; using CollapseLauncher.Helper.Image; +using CollapseLauncher.Helper.Background; using CollapseLauncher.Helper.Metadata; using CollapseLauncher.InstallManager.Base; using CollapseLauncher.Interfaces; @@ -18,6 +19,7 @@ using CommunityToolkit.WinUI.Animations; using H.NotifyIcon; using Hi3Helper; +using Hi3Helper.Data; using Hi3Helper.EncTool.WindowTool; using Hi3Helper.Screen; using Hi3Helper.Shared.ClassStruct; @@ -47,6 +49,8 @@ using Microsoft.UI.Xaml.Media; using static CollapseLauncher.Dialogs.SimpleDialogs; using static CollapseLauncher.InnerLauncherConfig; +using static CollapseLauncher.Helper.Background.BackgroundMediaUtility; +using static CollapseLauncher.FileDialogCOM.FileDialogNative; using static Hi3Helper.Data.ConverterTool; using static Hi3Helper.Locale; using static Hi3Helper.Logger; @@ -268,8 +272,8 @@ private async void StartLoadedRoutine(object sender, RoutedEventArgs e) private void Page_Unloaded(object sender, RoutedEventArgs e) { IsPageUnload = true; - if (!PageToken.IsCancelled) PageToken.Cancel(); - if (!CarouselToken.IsCancelled) CarouselToken.Cancel(); + if (!PageToken.IsDisposed && !PageToken.IsCancelled) PageToken.Cancel(); + if (!CarouselToken.IsDisposed && !CarouselToken.IsCancelled) CarouselToken.Cancel(); } #endregion @@ -1895,7 +1899,47 @@ public string CustomArgsValue public bool UseCustomArgs { get => ((IGameSettingsUniversal)CurrentGameProperty._GameSettings).SettingsCollapseMisc.UseCustomArguments; - set => ((IGameSettingsUniversal)CurrentGameProperty._GameSettings).SettingsCollapseMisc.UseCustomArguments = value; + set + { + if (CustomStartupArgsSwitch.IsOn) + { + CustomArgsTextBox.IsEnabled = true; + } + else + { + CustomArgsTextBox.IsEnabled = false; + } + + ((IGameSettingsUniversal)CurrentGameProperty._GameSettings).SettingsCollapseMisc.UseCustomArguments = value; + } + + } + + public bool UseCustomBGRegion + { + get + { + bool value = ((IGameSettingsUniversal)CurrentGameProperty?._GameSettings)?.SettingsCollapseMisc?.UseCustomRegionBG ?? false; + ChangeGameBGButton.IsEnabled = value; + return value; + } + set + { + ChangeGameBGButton.IsEnabled = value; + + var regionBgPath = ((IGameSettingsUniversal)CurrentGameProperty._GameSettings).SettingsCollapseMisc.CustomRegionBGPath; + if (string.IsNullOrEmpty(regionBgPath) || !File.Exists(regionBgPath)) + { + regionBgPath = GetAppConfigValue("CustomBGPath").ToString(); + ((IGameSettingsUniversal)CurrentGameProperty._GameSettings) + .SettingsCollapseMisc + .CustomRegionBGPath = regionBgPath; + } + + ((IGameSettingsUniversal)CurrentGameProperty._GameSettings).SettingsCollapseMisc.UseCustomRegionBG = value; + CurrentGameProperty._GameSettings.SaveSettings(); + m_mainPage?.ChangeBackgroundImageAsRegionAsync(); + } } #endregion @@ -2106,6 +2150,29 @@ private async void StopGameButton_Click(object sender, RoutedEventArgs e) StopGame(CurrentGameProperty._GameVersion.GamePreset); } + private async void ChangeGameBGButton_Click(object sender, RoutedEventArgs e) + { + var file = await GetFilePicker(ImageLoaderHelper.SupportedImageFormats); + if (string.IsNullOrEmpty(file)) return; + + var currentMediaType = GetMediaType(file); + + if (currentMediaType == MediaType.StillImage) + { + FileStream croppedImage = await ImageLoaderHelper.LoadImage(file, true, true); + + if (croppedImage == null) return; + SetAlternativeFileStream(croppedImage); + } + + if (((IGameSettingsUniversal)CurrentGameProperty?._GameSettings)?.SettingsCollapseMisc != null) + { + ((IGameSettingsUniversal)CurrentGameProperty._GameSettings).SettingsCollapseMisc.CustomRegionBGPath = file; + CurrentGameProperty._GameSettings.SaveSettings(); + } + m_mainPage?.ChangeBackgroundImageAsRegionAsync(); + } + private async void MoveGameLocationButton_Click(object sender, RoutedEventArgs e) { try diff --git a/CollapseLauncher/XAMLs/MainApp/Pages/SettingsPage.xaml b/CollapseLauncher/XAMLs/MainApp/Pages/SettingsPage.xaml index da8c6ef45..f25f65b94 100644 --- a/CollapseLauncher/XAMLs/MainApp/Pages/SettingsPage.xaml +++ b/CollapseLauncher/XAMLs/MainApp/Pages/SettingsPage.xaml @@ -122,6 +122,15 @@ +