mirror of
https://github.com/4sval/FModel.git
synced 2026-03-22 01:34:37 -05:00
224 lines
8.2 KiB
C#
224 lines
8.2 KiB
C#
using FModel.Extensions;
|
|
using FModel.Framework;
|
|
using FModel.Services;
|
|
using FModel.Settings;
|
|
using FModel.ViewModels.Commands;
|
|
using FModel.Views;
|
|
using FModel.Views.Resources.Controls;
|
|
using Ionic.Zip;
|
|
using Oodle.NET;
|
|
using System;
|
|
using System.Diagnostics;
|
|
using System.IO;
|
|
using System.Threading.Tasks;
|
|
using System.Windows;
|
|
using MessageBox = AdonisUI.Controls.MessageBox;
|
|
using MessageBoxButton = AdonisUI.Controls.MessageBoxButton;
|
|
using MessageBoxImage = AdonisUI.Controls.MessageBoxImage;
|
|
using OodleCUE4 = CUE4Parse.Compression.Oodle;
|
|
|
|
namespace FModel.ViewModels;
|
|
|
|
public class ApplicationViewModel : ViewModel
|
|
{
|
|
private EBuildKind _build;
|
|
public EBuildKind Build
|
|
{
|
|
get => _build;
|
|
private init
|
|
{
|
|
SetProperty(ref _build, value);
|
|
RaisePropertyChanged(nameof(TitleExtra));
|
|
}
|
|
}
|
|
|
|
private FStatus _status;
|
|
public FStatus Status
|
|
{
|
|
get => _status;
|
|
private init => SetProperty(ref _status, value);
|
|
}
|
|
|
|
public RightClickMenuCommand RightClickMenuCommand => _rightClickMenuCommand ??= new RightClickMenuCommand(this);
|
|
private RightClickMenuCommand _rightClickMenuCommand;
|
|
public MenuCommand MenuCommand => _menuCommand ??= new MenuCommand(this);
|
|
private MenuCommand _menuCommand;
|
|
public CopyCommand CopyCommand => _copyCommand ??= new CopyCommand(this);
|
|
private CopyCommand _copyCommand;
|
|
|
|
public string InitialWindowTitle => $"FModel {UserSettings.Default.UpdateMode}";
|
|
public string GameDisplayName => CUE4Parse.Provider.GameDisplayName ?? "Unknown";
|
|
public string TitleExtra => $"({UserSettings.Default.CurrentDir.UeVersion}){(Build != EBuildKind.Release ? $" ({Build})" : "")}";
|
|
|
|
public LoadingModesViewModel LoadingModes { get; }
|
|
public CustomDirectoriesViewModel CustomDirectories { get; }
|
|
public CUE4ParseViewModel CUE4Parse { get; }
|
|
public SettingsViewModel SettingsView { get; }
|
|
public AesManagerViewModel AesManager { get; }
|
|
public AudioPlayerViewModel AudioPlayer { get; }
|
|
private OodleCompressor _oodle;
|
|
|
|
public ApplicationViewModel()
|
|
{
|
|
Status = new FStatus();
|
|
#if DEBUG
|
|
Build = EBuildKind.Debug;
|
|
#elif RELEASE
|
|
Build = EBuildKind.Release;
|
|
#else
|
|
Build = EBuildKind.Unknown;
|
|
#endif
|
|
LoadingModes = new LoadingModesViewModel();
|
|
|
|
UserSettings.Default.CurrentDir = AvoidEmptyGameDirectory(false);
|
|
if (UserSettings.Default.CurrentDir is null)
|
|
{
|
|
//If no game is selected, many things will break before a shutdown request is processed in the normal way.
|
|
//A hard exit is preferable to an unhandled expection in this case
|
|
Environment.Exit(0);
|
|
}
|
|
|
|
CUE4Parse = new CUE4ParseViewModel();
|
|
CustomDirectories = new CustomDirectoriesViewModel();
|
|
SettingsView = new SettingsViewModel();
|
|
AesManager = new AesManagerViewModel(CUE4Parse);
|
|
AudioPlayer = new AudioPlayerViewModel();
|
|
|
|
Status.SetStatus(EStatusKind.Ready);
|
|
}
|
|
|
|
public DirectorySettings AvoidEmptyGameDirectory(bool bAlreadyLaunched)
|
|
{
|
|
var gameDirectory = UserSettings.Default.GameDirectory;
|
|
if (!bAlreadyLaunched && UserSettings.Default.PerDirectory.TryGetValue(gameDirectory, out var currentDir))
|
|
return currentDir;
|
|
|
|
var gameLauncherViewModel = new GameSelectorViewModel(gameDirectory);
|
|
var result = new DirectorySelector(gameLauncherViewModel).ShowDialog();
|
|
if (!result.HasValue || !result.Value) return null;
|
|
|
|
UserSettings.Default.GameDirectory = gameLauncherViewModel.SelectedDirectory.GameDirectory;
|
|
if (!bAlreadyLaunched || UserSettings.Default.CurrentDir.Equals(gameLauncherViewModel.SelectedDirectory))
|
|
return gameLauncherViewModel.SelectedDirectory;
|
|
|
|
// UserSettings.Save(); // ??? change key then change game, key saved correctly what?
|
|
UserSettings.Default.CurrentDir = gameLauncherViewModel.SelectedDirectory;
|
|
RestartWithWarning();
|
|
return null;
|
|
}
|
|
|
|
public void RestartWithWarning()
|
|
{
|
|
MessageBox.Show("It looks like you just changed something.\nFModel will restart to apply your changes.", "Uh oh, a restart is needed", MessageBoxButton.OK, MessageBoxImage.Warning);
|
|
Restart();
|
|
}
|
|
|
|
public void Restart()
|
|
{
|
|
var path = Path.GetFullPath(Environment.GetCommandLineArgs()[0]);
|
|
if (path.EndsWith(".dll"))
|
|
{
|
|
new Process
|
|
{
|
|
StartInfo = new ProcessStartInfo
|
|
{
|
|
FileName = "dotnet",
|
|
Arguments = $"\"{Path.GetFullPath(Environment.GetCommandLineArgs()[0])}\"",
|
|
UseShellExecute = false,
|
|
RedirectStandardOutput = false,
|
|
RedirectStandardError = false,
|
|
CreateNoWindow = true
|
|
}
|
|
}.Start();
|
|
}
|
|
else if (path.EndsWith(".exe"))
|
|
{
|
|
new Process
|
|
{
|
|
StartInfo = new ProcessStartInfo
|
|
{
|
|
FileName = path,
|
|
UseShellExecute = false,
|
|
RedirectStandardOutput = false,
|
|
RedirectStandardError = false,
|
|
CreateNoWindow = true
|
|
}
|
|
}.Start();
|
|
}
|
|
|
|
Application.Current.Shutdown();
|
|
}
|
|
|
|
public async Task UpdateProvider(bool isLaunch)
|
|
{
|
|
if (!isLaunch && !AesManager.HasChange) return;
|
|
|
|
CUE4Parse.ClearProvider();
|
|
await ApplicationService.ThreadWorkerView.Begin(cancellationToken =>
|
|
{
|
|
CUE4Parse.LoadVfs(cancellationToken, AesManager.AesKeys);
|
|
CUE4Parse.Provider.LoadIniConfigs();
|
|
AesManager.SetAesKeys();
|
|
});
|
|
RaisePropertyChanged(nameof(GameDisplayName));
|
|
}
|
|
|
|
public async Task InitVgmStream()
|
|
{
|
|
var vgmZipFilePath = Path.Combine(UserSettings.Default.OutputDirectory, ".data", "vgmstream-win.zip");
|
|
if (File.Exists(vgmZipFilePath)) return;
|
|
|
|
await ApplicationService.ApiEndpointView.DownloadFileAsync("https://github.com/vgmstream/vgmstream/releases/latest/download/vgmstream-win.zip", vgmZipFilePath);
|
|
if (new FileInfo(vgmZipFilePath).Length > 0)
|
|
{
|
|
var zip = ZipFile.Read(vgmZipFilePath);
|
|
var zipDir = vgmZipFilePath.SubstringBeforeLast("\\");
|
|
foreach (var e in zip) e.Extract(zipDir, ExtractExistingFileAction.OverwriteSilently);
|
|
}
|
|
else
|
|
{
|
|
FLogger.Append(ELog.Error, () => FLogger.Text("Could not download VgmStream", Constants.WHITE, true));
|
|
}
|
|
}
|
|
|
|
public async Task InitOodle()
|
|
{
|
|
var dataDir = Directory.CreateDirectory(Path.Combine(UserSettings.Default.OutputDirectory, ".data"));
|
|
var oodlePath = Path.Combine(dataDir.FullName, OodleCUE4.OODLE_DLL_NAME);
|
|
|
|
if (File.Exists(OodleCUE4.OODLE_DLL_NAME))
|
|
{
|
|
File.Move(OodleCUE4.OODLE_DLL_NAME, oodlePath, true);
|
|
}
|
|
else if (!File.Exists(oodlePath))
|
|
{
|
|
var result = await OodleCUE4.DownloadOodleDll(oodlePath);
|
|
if (!result) return;
|
|
}
|
|
|
|
if (File.Exists("oo2core_8_win64.dll"))
|
|
File.Delete("oo2core_8_win64.dll");
|
|
|
|
_oodle = new OodleCompressor(oodlePath);
|
|
|
|
unsafe
|
|
{
|
|
OodleCUE4.DecompressFunc = (bufferPtr, bufferSize, outputPtr, outputSize, a, b, c, d, e, f, g, h, i, threadModule) =>
|
|
_oodle.Decompress(new IntPtr(bufferPtr), bufferSize, new IntPtr(outputPtr), outputSize,
|
|
(OodleLZ_FuzzSafe) a, (OodleLZ_CheckCRC) b, (OodleLZ_Verbosity) c, d, e, f, g, h, i, (OodleLZ_Decode_ThreadPhase) threadModule);
|
|
}
|
|
}
|
|
|
|
public async Task InitImGuiSettings(bool forceDownload)
|
|
{
|
|
var imgui = Path.Combine(/*UserSettings.Default.OutputDirectory, ".data", */"imgui.ini");
|
|
if (File.Exists(imgui) && !forceDownload) return;
|
|
|
|
await ApplicationService.ApiEndpointView.DownloadFileAsync("https://cdn.fmodel.app/d/configurations/imgui.ini", imgui);
|
|
if (new FileInfo(imgui).Length == 0)
|
|
{
|
|
FLogger.Append(ELog.Error, () => FLogger.Text("Could not download ImGui settings", Constants.WHITE, true));
|
|
}
|
|
}
|
|
}
|