From e09ab5e4336224f19a0df072fc38684a3f60c599 Mon Sep 17 00:00:00 2001 From: SternI Date: Thu, 2 Apr 2026 17:03:33 +0200 Subject: [PATCH 1/3] 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 8cf126c74..47d7c0578 100644 --- a/FModel/Settings/DirectorySettings.cs +++ b/FModel/Settings/DirectorySettings.cs @@ -106,6 +106,13 @@ public ulong CriwareDecryptionKey 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 26af56c67..4c9212e9b 100644 --- a/FModel/ViewModels/CUE4ParseViewModel.cs +++ b/FModel/ViewModels/CUE4ParseViewModel.cs @@ -231,7 +231,7 @@ await _threadWorkerView.Begin(cancellationToken => { 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 626f4227d..ca0c48979 100644 --- a/FModel/ViewModels/SettingsViewModel.cs +++ b/FModel/ViewModels/SettingsViewModel.cs @@ -172,6 +172,13 @@ public ulong CriwareDecryptionKey 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 void Initialize() _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 void Initialize() SelectedMaterialExportFormat = _materialExportFormatSnapshot; SelectedTextureExportFormat = _textureExportFormatSnapshot; CriwareDecryptionKey = _criwareDecryptionKey; + OnDemandTimeout = _onDemandTimeout; SelectedAesReload = UserSettings.Default.AesReload; SelectedDiscordRpc = UserSettings.Default.DiscordRpc; @@ -314,7 +323,8 @@ public bool Save(out List whatShouldIDo) 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 b38b62d5d..115fe1af9 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 ba73d7f8a..ce22e32d4 100644 --- a/FModel/Views/SettingsView.xaml.cs +++ b/FModel/Views/SettingsView.xaml.cs @@ -6,6 +6,7 @@ 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 @@ private async void OnClick(object sender, RoutedEventArgs e) _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 @@ private void OnBrowseOutput(object sender, RoutedEventArgs e) 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 @@ private void OnHyperlinkClick(object sender, RoutedEventArgs e) 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(); + } + } } From f9fedae1a0d4f27aebeccaf09901431a58daa0cd Mon Sep 17 00:00:00 2001 From: SternI Date: Thu, 2 Apr 2026 20:20:06 +0200 Subject: [PATCH 2/3] HTTP request timeout configurable for all requests --- FModel/Framework/FRestRequest.cs | 3 ++- FModel/Settings/DirectorySettings.cs | 7 ------- FModel/Settings/UserSettings.cs | 7 +++++++ FModel/ViewModels/CUE4ParseViewModel.cs | 2 +- FModel/ViewModels/SettingsViewModel.cs | 12 ++---------- FModel/Views/SettingsView.xaml | 14 +++++++------- FModel/Views/SettingsView.xaml.cs | 20 ++++++++++++-------- 7 files changed, 31 insertions(+), 34 deletions(-) diff --git a/FModel/Framework/FRestRequest.cs b/FModel/Framework/FRestRequest.cs index b09cf30c7..7d786dbc6 100644 --- a/FModel/Framework/FRestRequest.cs +++ b/FModel/Framework/FRestRequest.cs @@ -1,11 +1,12 @@ using System; +using FModel.Settings; using RestSharp; namespace FModel.Framework; public class FRestRequest : RestRequest { - private const int TimeoutSeconds = 5; + private int TimeoutSeconds = UserSettings.Default.HttpRequestTimeout; public FRestRequest(string url, Method method = Method.Get) : base(url, method) { diff --git a/FModel/Settings/DirectorySettings.cs b/FModel/Settings/DirectorySettings.cs index 47d7c0578..8cf126c74 100644 --- a/FModel/Settings/DirectorySettings.cs +++ b/FModel/Settings/DirectorySettings.cs @@ -106,13 +106,6 @@ public ulong CriwareDecryptionKey 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/Settings/UserSettings.cs b/FModel/Settings/UserSettings.cs index bca1427de..5f90cde3e 100644 --- a/FModel/Settings/UserSettings.cs +++ b/FModel/Settings/UserSettings.cs @@ -544,5 +544,12 @@ public bool PreviewTexturesAssetExplorer get => _previewTexturesAssetExplorer; set => SetProperty(ref _previewTexturesAssetExplorer, value); } + + private int _httpRequestTimeout = 30; + public int HttpRequestTimeout + { + get => _httpRequestTimeout; + set => SetProperty(ref _httpRequestTimeout, Math.Max(value, 30)); + } } } diff --git a/FModel/ViewModels/CUE4ParseViewModel.cs b/FModel/ViewModels/CUE4ParseViewModel.cs index 4c9212e9b..4a7156922 100644 --- a/FModel/ViewModels/CUE4ParseViewModel.cs +++ b/FModel/ViewModels/CUE4ParseViewModel.cs @@ -231,7 +231,7 @@ await _threadWorkerView.Begin(cancellationToken => { ChunkHostUri = new Uri("https://download.epicgames.com/", UriKind.Absolute), ChunkCacheDirectory = Directory.CreateDirectory(Path.Combine(UserSettings.Default.OutputDirectory, ".data")), - Timeout = TimeSpan.FromSeconds(UserSettings.Default.CurrentDir.OnDemandTimeout) + Timeout = TimeSpan.FromSeconds(UserSettings.Default.HttpRequestTimeout) }; switch (Provider) diff --git a/FModel/ViewModels/SettingsViewModel.cs b/FModel/ViewModels/SettingsViewModel.cs index ca0c48979..0ea9e52d0 100644 --- a/FModel/ViewModels/SettingsViewModel.cs +++ b/FModel/ViewModels/SettingsViewModel.cs @@ -172,13 +172,6 @@ public ulong CriwareDecryptionKey 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; @@ -205,6 +198,7 @@ public uint OnDemandTimeout private string _codeSnapshot; private string _modelSnapshot; private string _gameSnapshot; + private int _httpRequestTimeout; private ETexturePlatform _uePlatformSnapshot; private EGame _ueGameSnapshot; private IList _customVersionsSnapshot; @@ -238,13 +232,13 @@ public void Initialize() _codeSnapshot = UserSettings.Default.CodeDirectory; _modelSnapshot = UserSettings.Default.ModelDirectory; _gameSnapshot = UserSettings.Default.GameDirectory; + _httpRequestTimeout = UserSettings.Default.HttpRequestTimeout; _uePlatformSnapshot = UserSettings.Default.CurrentDir.TexturePlatform; _ueGameSnapshot = UserSettings.Default.CurrentDir.UeVersion; _customVersionsSnapshot = UserSettings.Default.CurrentDir.Versioning.CustomVersions; _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]; @@ -281,7 +275,6 @@ public void Initialize() SelectedMaterialExportFormat = _materialExportFormatSnapshot; SelectedTextureExportFormat = _textureExportFormatSnapshot; CriwareDecryptionKey = _criwareDecryptionKey; - OnDemandTimeout = _onDemandTimeout; SelectedAesReload = UserSettings.Default.AesReload; SelectedDiscordRpc = UserSettings.Default.DiscordRpc; @@ -323,7 +316,6 @@ public bool Save(out List whatShouldIDo) 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; diff --git a/FModel/Views/SettingsView.xaml b/FModel/Views/SettingsView.xaml index 115fe1af9..e0382da86 100644 --- a/FModel/Views/SettingsView.xaml +++ b/FModel/Views/SettingsView.xaml @@ -272,11 +272,11 @@ - + PreviewTextInput="HttpRequestTimeoutBox_PreviewTextInput" + DataObject.Pasting="HttpRequestTimeoutBox_Pasting" + Loaded="HttpRequestTimeoutBox_Loaded" + TextChanged="HttpRequestTimeoutBox_TextChanged"/> diff --git a/FModel/Views/SettingsView.xaml.cs b/FModel/Views/SettingsView.xaml.cs index ce22e32d4..4e95522c2 100644 --- a/FModel/Views/SettingsView.xaml.cs +++ b/FModel/Views/SettingsView.xaml.cs @@ -62,6 +62,8 @@ private async void OnClick(object sender, RoutedEventArgs e) _applicationView.CUE4Parse.Provider.ReadScriptData = UserSettings.Default.ReadScriptData; _applicationView.CUE4Parse.Provider.ReadShaderMaps = UserSettings.Default.ReadShaderMaps; + + UserSettings.Save(); } private void OnBrowseOutput(object sender, RoutedEventArgs e) @@ -75,6 +77,7 @@ private void OnBrowseOutput(object sender, RoutedEventArgs e) UserSettings.Default.PropertiesDirectory = path; UserSettings.Default.TextureDirectory = path; UserSettings.Default.AudioDirectory = path; + UserSettings.Default.CodeDirectory = path; } private void OnBrowseDirectories(object sender, RoutedEventArgs e) @@ -273,34 +276,35 @@ private void OnHyperlinkClick(object sender, RoutedEventArgs e) Process.Start(new ProcessStartInfo(hyperlink.NavigateUri.AbsoluteUri) { UseShellExecute = true }); } - private void OnDemandTimeout_Loaded(object sender, RoutedEventArgs e) + private void HttpRequestTimeoutBox_Loaded(object sender, RoutedEventArgs e) { if (sender is not TextBox textBox) return; - textBox.Text = _applicationView.SettingsView.OnDemandTimeout.ToString(); + textBox.Text = UserSettings.Default.HttpRequestTimeout.ToString(); } - private void OnDemandTimeout_TextChanged(object sender, TextChangedEventArgs e) + private void HttpRequestTimeoutBox_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; + if (int.TryParse(input, out int seconds)) + UserSettings.Default.HttpRequestTimeout = seconds; else - textBox.Text = uint.MaxValue.ToString(); + textBox.Text = int.MaxValue.ToString(); } - private void OnDemandTimeout_PreviewTextInput(object sender, TextCompositionEventArgs e) + private void HttpRequestTimeoutBox_PreviewTextInput(object sender, TextCompositionEventArgs e) { e.Handled = !e.Text.All(char.IsDigit); } - private void OnDemandTimeout_Pasting(object sender, DataObjectPastingEventArgs e) + private void HttpRequestTimeoutBox_Pasting(object sender, DataObjectPastingEventArgs e) { if (e.DataObject.GetDataPresent(typeof(string))) { From c21004c2d14d7db4bc26e4e444d2ba10732de213 Mon Sep 17 00:00:00 2001 From: SternI Date: Fri, 3 Apr 2026 21:25:59 +0200 Subject: [PATCH 3/3] Removed HttpRequestTimeout setting from ui --- FModel/Settings/UserSettings.cs | 4 +-- FModel/ViewModels/SettingsViewModel.cs | 2 -- FModel/Views/SettingsView.xaml | 24 --------------- FModel/Views/SettingsView.xaml.cs | 42 -------------------------- 4 files changed, 2 insertions(+), 70 deletions(-) diff --git a/FModel/Settings/UserSettings.cs b/FModel/Settings/UserSettings.cs index 5f90cde3e..7c67942a2 100644 --- a/FModel/Settings/UserSettings.cs +++ b/FModel/Settings/UserSettings.cs @@ -545,11 +545,11 @@ public bool PreviewTexturesAssetExplorer set => SetProperty(ref _previewTexturesAssetExplorer, value); } - private int _httpRequestTimeout = 30; + private int _httpRequestTimeout = 60; public int HttpRequestTimeout { get => _httpRequestTimeout; - set => SetProperty(ref _httpRequestTimeout, Math.Max(value, 30)); + set => SetProperty(ref _httpRequestTimeout, value); } } } diff --git a/FModel/ViewModels/SettingsViewModel.cs b/FModel/ViewModels/SettingsViewModel.cs index 0ea9e52d0..0ca1c3ea1 100644 --- a/FModel/ViewModels/SettingsViewModel.cs +++ b/FModel/ViewModels/SettingsViewModel.cs @@ -198,7 +198,6 @@ public ulong CriwareDecryptionKey private string _codeSnapshot; private string _modelSnapshot; private string _gameSnapshot; - private int _httpRequestTimeout; private ETexturePlatform _uePlatformSnapshot; private EGame _ueGameSnapshot; private IList _customVersionsSnapshot; @@ -232,7 +231,6 @@ public void Initialize() _codeSnapshot = UserSettings.Default.CodeDirectory; _modelSnapshot = UserSettings.Default.ModelDirectory; _gameSnapshot = UserSettings.Default.GameDirectory; - _httpRequestTimeout = UserSettings.Default.HttpRequestTimeout; _uePlatformSnapshot = UserSettings.Default.CurrentDir.TexturePlatform; _ueGameSnapshot = UserSettings.Default.CurrentDir.UeVersion; _customVersionsSnapshot = UserSettings.Default.CurrentDir.Versioning.CustomVersions; diff --git a/FModel/Views/SettingsView.xaml b/FModel/Views/SettingsView.xaml index e0382da86..e95914684 100644 --- a/FModel/Views/SettingsView.xaml +++ b/FModel/Views/SettingsView.xaml @@ -44,7 +44,6 @@ - @@ -268,29 +267,6 @@ TextAlignment="Right" TextChanged="CriwareKeyBox_TextChanged" Loaded="CriwareKeyBox_Loaded"/> - - - - - - diff --git a/FModel/Views/SettingsView.xaml.cs b/FModel/Views/SettingsView.xaml.cs index 4e95522c2..b600177d7 100644 --- a/FModel/Views/SettingsView.xaml.cs +++ b/FModel/Views/SettingsView.xaml.cs @@ -275,46 +275,4 @@ private void OnHyperlinkClick(object sender, RoutedEventArgs e) Process.Start(new ProcessStartInfo(hyperlink.NavigateUri.AbsoluteUri) { UseShellExecute = true }); } - - private void HttpRequestTimeoutBox_Loaded(object sender, RoutedEventArgs e) - { - if (sender is not TextBox textBox) - return; - textBox.Text = UserSettings.Default.HttpRequestTimeout.ToString(); - } - - private void HttpRequestTimeoutBox_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 (int.TryParse(input, out int seconds)) - UserSettings.Default.HttpRequestTimeout = seconds; - else - textBox.Text = int.MaxValue.ToString(); - } - - private void HttpRequestTimeoutBox_PreviewTextInput(object sender, TextCompositionEventArgs e) - { - e.Handled = !e.Text.All(char.IsDigit); - } - - private void HttpRequestTimeoutBox_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(); - } - } }