diff --git a/CUE4Parse b/CUE4Parse index 91354a05..c6292d93 160000 --- a/CUE4Parse +++ b/CUE4Parse @@ -1 +1 @@ -Subproject commit 91354a050d10aa7bc8e2e8a5cc0a839406929758 +Subproject commit c6292d935ca41a546fe15b42635ceb4220e0fe2e diff --git a/FModel/Services/DiscordService.cs b/FModel/Services/DiscordService.cs index e4ff113f..c5b36d28 100644 --- a/FModel/Services/DiscordService.cs +++ b/FModel/Services/DiscordService.cs @@ -41,7 +41,7 @@ namespace FModel.Services Details = $"{gameName} - Idling" }; - _client.OnReady += (_, args) => Log.Information("{Username}#{Discriminator} ({UserId}) is now ready", args.User.Username, args.User.Discriminator, args.User.ID); + _client.OnReady += (_, args) => Log.Information("@{Username} ({UserId}) is now ready", args.User.Username, args.User.ID); _client.SetPresence(_currentPresence); _client.Initialize(); } diff --git a/FModel/ViewModels/AboutViewModel.cs b/FModel/ViewModels/AboutViewModel.cs new file mode 100644 index 00000000..6c0478d3 --- /dev/null +++ b/FModel/ViewModels/AboutViewModel.cs @@ -0,0 +1,70 @@ +using System.Text; +using System.Threading.Tasks; +using FModel.Framework; +using FModel.Services; +using FModel.ViewModels.ApiEndpoints.Models; + +namespace FModel.ViewModels; + +public class AboutViewModel : ViewModel +{ + private ApiEndpointViewModel _apiEndpointView => ApplicationService.ApiEndpointView; + + private string _descriptionLabel; + public string DescriptionLabel + { + get => _descriptionLabel; + set => SetProperty(ref _descriptionLabel, value); + } + + private string _contributorsLabel; + public string ContributorsLabel + { + get => _contributorsLabel; + set => SetProperty(ref _contributorsLabel, value); + } + + private string _donatorsLabel; + public string DonatorsLabel + { + get => _donatorsLabel; + set => SetProperty(ref _donatorsLabel, value); + } + + private string _referencesLabel; + public string ReferencesLabel + { + get => _referencesLabel; + set => SetProperty(ref _referencesLabel, value); + } + + public AboutViewModel() + { + + } + + public async Task Initialize() + { + await Task.WhenAll( + Task.Run(() => + { + DescriptionLabel = "FModel is an archive explorer for Unreal Engine games that uses CUE4Parse as its core parsing library, providing robust support for the latest UE4 and UE5 archive formats. It aims to deliver a modern and intuitive user interface, powerful features, and a comprehensive set of tools for previewing and converting game packages, empowering YOU to understand games' inner workings with ease."; + ContributorsLabel = $"FModel owes its continued existence to the passionate individuals who have generously contributed their time and expertise. Contributions from individuals such as {string.Join(", ", "GMatrixGames", "amr", "LongerWarrior", "MinshuG", "InTheShade", "Officer")}, and countless others, both in the past and those yet to come, ensure the continuous development and success of this project. If you are benefiting from FModel and would like to support its continued improvements, please consider making a donation."; + ReferencesLabel = string.Join(", ", + "Adonis UI", "AutoUpdater.NET", "AvalonEdit", "CSCore", "CUE4Parse", "DiscordRichPresence", + "EpicManifestParser", "ImGui.NET", "K4os.Compression.LZ4", "Newtonsoft.Json", "NVorbis", "Oodle.NET", + "Ookii.Dialogs.Wpf", "OpenTK", "RestSharp", "Serilog", "SixLabors.ImageSharp", "SkiaSharp"); + }), + Task.Run(() => + { + var donators = _apiEndpointView.FModelApi.GetDonators(); + if (donators == null) return; + + var sb = new StringBuilder(); + sb.AppendJoin(", ", donators); + sb.Append('.'); + DonatorsLabel = sb.ToString(); + }) + ).ConfigureAwait(false); + } +} diff --git a/FModel/ViewModels/ApiEndpoints/FModelApiEndpoint.cs b/FModel/ViewModels/ApiEndpoints/FModelApiEndpoint.cs index 8a835a30..0e1b1f85 100644 --- a/FModel/ViewModels/ApiEndpoints/FModelApiEndpoint.cs +++ b/FModel/ViewModels/ApiEndpoints/FModelApiEndpoint.cs @@ -24,6 +24,7 @@ public class FModelApiEndpoint : AbstractApiProvider { private News _news; private Info _infos; + private Donator[] _donators; private Backup[] _backups; private Game _game; private readonly IDictionary _communityDesigns = new Dictionary(); @@ -58,6 +59,19 @@ public class FModelApiEndpoint : AbstractApiProvider return _infos ?? GetInfosAsync(token, updateMode).GetAwaiter().GetResult(); } + public async Task GetDonatorsAsync() + { + var request = new FRestRequest($"https://api.fmodel.app/v1/donations/donators"); + var response = await _client.ExecuteAsync(request).ConfigureAwait(false); + Log.Information("[{Method}] [{Status}({StatusCode})] '{Resource}'", request.Method, response.StatusDescription, (int) response.StatusCode, response.ResponseUri?.OriginalString); + return response.Data; + } + + public Donator[] GetDonators() + { + return _donators ??= GetDonatorsAsync().GetAwaiter().GetResult(); + } + public async Task GetBackupsAsync(CancellationToken token, string gameName) { var request = new FRestRequest($"https://api.fmodel.app/v1/backups/{gameName}"); diff --git a/FModel/ViewModels/ApiEndpoints/Models/FModelResponse.cs b/FModel/ViewModels/ApiEndpoints/Models/FModelResponse.cs index 3f389861..6c9b8dc4 100644 --- a/FModel/ViewModels/ApiEndpoints/Models/FModelResponse.cs +++ b/FModel/ViewModels/ApiEndpoints/Models/FModelResponse.cs @@ -25,6 +25,14 @@ public class Backup [J] public long FileSize { get; private set; } } +public class Donator +{ + [J] public string Username { get; private set; } + [J] public int Count { get; private set; } + + public override string ToString() => $"{Username}{(Count > 5 ? " ❤️" : "")}"; +} + [DebuggerDisplay("{" + nameof(DisplayName) + "}")] public class Game { diff --git a/FModel/ViewModels/CUE4ParseViewModel.cs b/FModel/ViewModels/CUE4ParseViewModel.cs index 9db40ace..d069b7e7 100644 --- a/FModel/ViewModels/CUE4ParseViewModel.cs +++ b/FModel/ViewModels/CUE4ParseViewModel.cs @@ -153,13 +153,13 @@ public class CUE4ParseViewModel : ViewModel Provider = InternalGameName switch { "StateOfDecay2" => new DefaultFileProvider(new DirectoryInfo(gameDirectory), - new List + new DirectoryInfo[] { new(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData) + "\\StateOfDecay2\\Saved\\Paks"), new(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData) + "\\StateOfDecay2\\Saved\\DisabledPaks") }, SearchOption.AllDirectories, true, versionContainer), "eFootball" => new DefaultFileProvider(new DirectoryInfo(gameDirectory), - new List + new DirectoryInfo[] { new(Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData) + "\\KONAMI\\eFootball\\ST\\Download") }, SearchOption.AllDirectories, true, versionContainer), @@ -223,7 +223,7 @@ public class CUE4ParseViewModel : ViewModel } if (!_fnLive.IsMatch(fileManifest.Name)) continue; - p.Initialize(fileManifest.Name, new Stream[] { fileManifest.GetStream() } + p.RegisterVfs(fileManifest.Name, new Stream[] { fileManifest.GetStream() } , it => new FStreamArchive(it, manifest.FileManifests.First(x => x.Name.Equals(it)).GetStream(), p.Versions)); } @@ -241,7 +241,7 @@ public class CUE4ParseViewModel : ViewModel for (var i = 0; i < manifestInfo.Paks.Length; i++) { - p.Initialize(manifestInfo.Paks[i].GetFullName(), new[] { manifestInfo.GetPakStream(i) }); + p.RegisterVfs(manifestInfo.Paks[i].GetFullName(), new[] { manifestInfo.GetPakStream(i) }); } FLogger.Append(ELog.Information, () => @@ -251,18 +251,18 @@ public class CUE4ParseViewModel : ViewModel } break; - case DefaultFileProvider d: - d.Initialize(); - + case DefaultFileProvider: var buildInfoPath = Path.Combine(UserSettings.Default.GameDirectory, "..\\..\\..\\Cloud\\BuildInfo.ini"); if (File.Exists(buildInfoPath)) BuildInfo.Read(new StringReader(File.ReadAllText(buildInfoPath))); break; } + Provider.Initialize(); + foreach (var vfs in Provider.UnloadedVfs) // push files from the provider to the ui { cancellationToken.ThrowIfCancellationRequested(); - if (vfs.Length <= 365 || !_hiddenArchives.IsMatch(vfs.Name)) continue; + if (!_hiddenArchives.IsMatch(vfs.Name)) continue; GameDirectory.Add(vfs); } diff --git a/FModel/Views/About.xaml b/FModel/Views/About.xaml index af33b59a..ca498671 100644 --- a/FModel/Views/About.xaml +++ b/FModel/Views/About.xaml @@ -4,7 +4,8 @@ xmlns:local="clr-namespace:FModel" xmlns:adonisControls="clr-namespace:AdonisUI.Controls;assembly=AdonisUI" WindowStartupLocation="CenterScreen" ResizeMode="NoResize" - IconVisibility="Collapsed" Width="500" SizeToContent="Height"> + IconVisibility="Collapsed" Width="500" SizeToContent="Height" + Loaded="OnLoaded">