From e09ab5e4336224f19a0df072fc38684a3f60c599 Mon Sep 17 00:00:00 2001 From: SternI Date: Thu, 2 Apr 2026 17:03:33 +0200 Subject: [PATCH] Make on-demand download timeout configurable. --- FModel/Settings/DirectorySettings.cs | 7 ++++ FModel/ViewModels/CUE4ParseViewModel.cs | 2 +- FModel/ViewModels/SettingsViewModel.cs | 12 ++++++- FModel/Views/SettingsView.xaml | 23 +++++++++++++ FModel/Views/SettingsView.xaml.cs | 45 +++++++++++++++++++++++-- 5 files changed, 84 insertions(+), 5 deletions(-) diff --git a/FModel/Settings/DirectorySettings.cs b/FModel/Settings/DirectorySettings.cs index 8cf126c7..47d7c057 100644 --- a/FModel/Settings/DirectorySettings.cs +++ b/FModel/Settings/DirectorySettings.cs @@ -106,6 +106,13 @@ public class DirectorySettings : ViewModel, ICloneable set => SetProperty(ref _criwareDecryptionKey, value); } + private uint _onDemandTimeout = 120; + public uint OnDemandTimeout + { + get => Math.Max(_onDemandTimeout, 60); + set => SetProperty(ref _onDemandTimeout, Math.Max(_onDemandTimeout, 60)); + } + private bool Equals(DirectorySettings other) { return GameDirectory == other.GameDirectory && UeVersion == other.UeVersion; diff --git a/FModel/ViewModels/CUE4ParseViewModel.cs b/FModel/ViewModels/CUE4ParseViewModel.cs index 26af56c6..4c9212e9 100644 --- a/FModel/ViewModels/CUE4ParseViewModel.cs +++ b/FModel/ViewModels/CUE4ParseViewModel.cs @@ -231,7 +231,7 @@ public class CUE4ParseViewModel : ViewModel { ChunkHostUri = new Uri("https://download.epicgames.com/", UriKind.Absolute), ChunkCacheDirectory = Directory.CreateDirectory(Path.Combine(UserSettings.Default.OutputDirectory, ".data")), - Timeout = TimeSpan.FromSeconds(30) + Timeout = TimeSpan.FromSeconds(UserSettings.Default.CurrentDir.OnDemandTimeout) }; switch (Provider) diff --git a/FModel/ViewModels/SettingsViewModel.cs b/FModel/ViewModels/SettingsViewModel.cs index 626f4227..ca0c4897 100644 --- a/FModel/ViewModels/SettingsViewModel.cs +++ b/FModel/ViewModels/SettingsViewModel.cs @@ -172,6 +172,13 @@ public class SettingsViewModel : ViewModel set => SetProperty(ref _criwareDecryptionKey, value); } + private uint _onDemandTimeout = 120; + public uint OnDemandTimeout + { + get => Math.Max(_onDemandTimeout, 60); + set => SetProperty(ref _onDemandTimeout, Math.Max(_onDemandTimeout, 60)); + } + public bool SocketSettingsEnabled => SelectedMeshExportFormat == EMeshFormat.ActorX; public bool CompressionSettingsEnabled => SelectedMeshExportFormat == EMeshFormat.UEFormat; @@ -237,6 +244,7 @@ public class SettingsViewModel : ViewModel _optionsSnapshot = UserSettings.Default.CurrentDir.Versioning.Options; _mapStructTypesSnapshot = UserSettings.Default.CurrentDir.Versioning.MapStructTypes; _criwareDecryptionKey = UserSettings.Default.CurrentDir.CriwareDecryptionKey; + _onDemandTimeout = UserSettings.Default.CurrentDir.OnDemandTimeout; AesEndpoint = UserSettings.Default.CurrentDir.Endpoints[0]; MappingEndpoint = UserSettings.Default.CurrentDir.Endpoints[1]; @@ -273,6 +281,7 @@ public class SettingsViewModel : ViewModel SelectedMaterialExportFormat = _materialExportFormatSnapshot; SelectedTextureExportFormat = _textureExportFormatSnapshot; CriwareDecryptionKey = _criwareDecryptionKey; + OnDemandTimeout = _onDemandTimeout; SelectedAesReload = UserSettings.Default.AesReload; SelectedDiscordRpc = UserSettings.Default.DiscordRpc; @@ -314,7 +323,8 @@ public class SettingsViewModel : ViewModel UserSettings.Default.CurrentDir.Versioning.Options = SelectedOptions; UserSettings.Default.CurrentDir.Versioning.MapStructTypes = SelectedMapStructTypes; UserSettings.Default.CurrentDir.CriwareDecryptionKey = CriwareDecryptionKey; - + UserSettings.Default.CurrentDir.OnDemandTimeout = OnDemandTimeout; + UserSettings.Default.AssetLanguage = SelectedAssetLanguage; UserSettings.Default.CompressedAudioMode = SelectedCompressedAudio; UserSettings.Default.CosmeticStyle = SelectedCosmeticStyle; diff --git a/FModel/Views/SettingsView.xaml b/FModel/Views/SettingsView.xaml index b38b62d5..115fe1af 100644 --- a/FModel/Views/SettingsView.xaml +++ b/FModel/Views/SettingsView.xaml @@ -44,6 +44,7 @@ + @@ -268,6 +269,28 @@ TextChanged="CriwareKeyBox_TextChanged" Loaded="CriwareKeyBox_Loaded"/> + + + + + diff --git a/FModel/Views/SettingsView.xaml.cs b/FModel/Views/SettingsView.xaml.cs index ba73d7f8..ce22e32d 100644 --- a/FModel/Views/SettingsView.xaml.cs +++ b/FModel/Views/SettingsView.xaml.cs @@ -6,6 +6,7 @@ using System.Linq; using System.Windows; using System.Windows.Controls; using System.Windows.Documents; +using System.Windows.Input; using FModel.Services; using FModel.Settings; using FModel.ViewModels; @@ -61,8 +62,6 @@ public partial class SettingsView _applicationView.CUE4Parse.Provider.ReadScriptData = UserSettings.Default.ReadScriptData; _applicationView.CUE4Parse.Provider.ReadShaderMaps = UserSettings.Default.ReadShaderMaps; - - UserSettings.Save(); } private void OnBrowseOutput(object sender, RoutedEventArgs e) @@ -76,7 +75,6 @@ public partial class SettingsView UserSettings.Default.PropertiesDirectory = path; UserSettings.Default.TextureDirectory = path; UserSettings.Default.AudioDirectory = path; - UserSettings.Default.CodeDirectory = path; } private void OnBrowseDirectories(object sender, RoutedEventArgs e) @@ -274,4 +272,45 @@ public partial class SettingsView Process.Start(new ProcessStartInfo(hyperlink.NavigateUri.AbsoluteUri) { UseShellExecute = true }); } + + private void OnDemandTimeout_Loaded(object sender, RoutedEventArgs e) + { + if (sender is not TextBox textBox) + return; + textBox.Text = _applicationView.SettingsView.OnDemandTimeout.ToString(); + } + + private void OnDemandTimeout_TextChanged(object sender, TextChangedEventArgs e) + { + if (sender is not TextBox textBox) + return; + + string input = textBox.Text?.Trim() ?? string.Empty; + if (string.IsNullOrEmpty(input)) + return; + + if (uint.TryParse(input, out uint seconds)) + _applicationView.SettingsView.OnDemandTimeout = seconds; + else + textBox.Text = uint.MaxValue.ToString(); + } + + private void OnDemandTimeout_PreviewTextInput(object sender, TextCompositionEventArgs e) + { + e.Handled = !e.Text.All(char.IsDigit); + } + + private void OnDemandTimeout_Pasting(object sender, DataObjectPastingEventArgs e) + { + if (e.DataObject.GetDataPresent(typeof(string))) + { + var text = (string)e.DataObject.GetData(typeof(string)); + if (!text.All(char.IsDigit)) + e.CancelCommand(); + } + else + { + e.CancelCommand(); + } + } }