manual detected games

This commit is contained in:
iAmAsval 2021-12-20 20:15:08 +01:00
parent 227dafae53
commit 1d25732fbf
10 changed files with 227 additions and 35 deletions

@ -1 +1 @@
Subproject commit 370b35d1e0e981501d5f18c574cb55e20ac3000d
Subproject commit 9bf51502f7318ca82d289b39df15a26ef1dbce60

View File

@ -205,6 +205,16 @@ namespace FModel.Settings
set => SetProperty(ref _imageMergerMargin, value);
}
// <gameDirectory as string, settings>
// can't refactor to use this data layout for everything
// because it will wipe old user settings that relies on FGame
private IDictionary<string, GameSelectorViewModel.DetectedGame> _manualGames = new Dictionary<string, GameSelectorViewModel.DetectedGame>();
public IDictionary<string, GameSelectorViewModel.DetectedGame> ManualGames
{
get => _manualGames;
set => SetProperty(ref _manualGames, value);
}
private IDictionary<FGame, string> _presets = new Dictionary<FGame, string>
{
{FGame.Unknown, Constants._NO_PRESET_TRIGGER},

View File

@ -35,14 +35,21 @@ namespace FModel.ViewModels
{
await _threadWorkerView.Begin(_ =>
{
if (!UserSettings.Default.AesKeys.TryGetValue(_cue4Parse.Game, out _keysFromSettings) || _keysFromSettings == null)
if (_cue4Parse.Game == FGame.Unknown &&
UserSettings.Default.ManualGames.TryGetValue(UserSettings.Default.GameDirectory, out var settings))
{
_keysFromSettings = new AesResponse
{
MainKey = string.Empty,
DynamicKeys = null
};
_keysFromSettings = settings.AesKeys;
}
else
{
_keysFromSettings = UserSettings.Default.AesKeys[_cue4Parse.Game];
}
_keysFromSettings ??= new AesResponse
{
MainKey = string.Empty,
DynamicKeys = null
};
_mainKey.Key = FixKey(_keysFromSettings.MainKey);
AesKeys = new FullyObservableCollection<FileItem>(EnumerateAesKeys());
@ -102,7 +109,11 @@ namespace FModel.ViewModels
_cue4Parse.ClearProvider();
await _cue4Parse.LoadVfs(AesKeys);
UserSettings.Default.AesKeys[_cue4Parse.Game] = _keysFromSettings;
if (_cue4Parse.Game == FGame.Unknown)
UserSettings.Default.ManualGames[UserSettings.Default.GameDirectory].AesKeys = _keysFromSettings;
else UserSettings.Default.AesKeys[_cue4Parse.Game] = _keysFromSettings;
Log.Information("{@Json}", UserSettings.Default);
}
@ -139,4 +150,4 @@ namespace FModel.ViewModels
}
}
}
}
}

View File

@ -61,7 +61,10 @@ namespace FModel.ViewModels
public CopyCommand CopyCommand => _copyCommand ??= new CopyCommand(this);
private CopyCommand _copyCommand;
public string TitleExtra => $"{UserSettings.Default.UpdateMode} - {CUE4Parse.Game.GetDescription()} ({UserSettings.Default.OverridedGame[CUE4Parse.Game]}){(Build != EBuildKind.Release ? $" ({Build})" : "")}";
public string TitleExtra =>
$"{UserSettings.Default.UpdateMode} - {CUE4Parse.Game.GetDescription()} (" + // FModel {UpdateMode} - {FGame} ({UE}) ({Build})
$"{(CUE4Parse.Game == FGame.Unknown && UserSettings.Default.ManualGames.TryGetValue(UserSettings.Default.GameDirectory, out var settings) ? settings.OverridedGame : UserSettings.Default.OverridedGame[CUE4Parse.Game])})" +
$"{(Build != EBuildKind.Release ? $" ({Build})" : "")}";
public LoadingModesViewModel LoadingModes { get; }
public CustomDirectoriesViewModel CustomDirectories { get; }
@ -87,7 +90,7 @@ namespace FModel.ViewModels
AvoidEmptyGameDirectoryAndSetEGame(false);
CUE4Parse = new CUE4ParseViewModel(UserSettings.Default.GameDirectory);
CustomDirectories = new CustomDirectoriesViewModel(CUE4Parse.Game);
CustomDirectories = new CustomDirectoriesViewModel(CUE4Parse.Game, UserSettings.Default.GameDirectory);
SettingsView = new SettingsViewModel(CUE4Parse.Game);
AesManager = new AesManagerViewModel(CUE4Parse);
MapViewer = new MapViewerViewModel(CUE4Parse);

View File

@ -106,15 +106,31 @@ namespace FModel.ViewModels
customVersions: UserSettings.Default.OverridedCustomVersions[Game],
optionOverrides: UserSettings.Default.OverridedOptions[Game]);
if (Game == FGame.StateOfDecay2)
Provider = new DefaultFileProvider(new DirectoryInfo(gameDirectory), new List<DirectoryInfo>
{
new(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData) + "\\StateOfDecay2\\Saved\\Paks"),
new(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData) + "\\StateOfDecay2\\Saved\\DisabledPaks")
},
SearchOption.AllDirectories, true, versions);
else
Provider = new DefaultFileProvider(gameDirectory, SearchOption.AllDirectories, true, versions);
switch (Game)
{
case FGame.StateOfDecay2:
{
Provider = new DefaultFileProvider(new DirectoryInfo(gameDirectory), new List<DirectoryInfo>
{
new(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData) + "\\StateOfDecay2\\Saved\\Paks"),
new(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData) + "\\StateOfDecay2\\Saved\\DisabledPaks")
},
SearchOption.AllDirectories, true, versions);
break;
}
case FGame.Unknown when UserSettings.Default.ManualGames.TryGetValue(gameDirectory, out var settings):
{
versions = new VersionContainer(settings.OverridedGame,
customVersions: settings.OverridedCustomVersions,
optionOverrides: settings.OverridedOptions);
goto default;
}
default:
{
Provider = new DefaultFileProvider(gameDirectory, SearchOption.AllDirectories, true, versions);
break;
}
}
break;
}
@ -248,7 +264,7 @@ namespace FModel.ViewModels
file.FileCount = vfs.FileCount;
}
Game = Provider.GameName.ToEnum(Game);
// Game = Provider.GameName.ToEnum(Game);
});
}

View File

@ -55,10 +55,12 @@ namespace FModel.ViewModels
public ReadOnlyObservableCollection<Control> Directories { get; }
private readonly FGame _game;
private readonly string _gameDirectoryAtLaunch;
public CustomDirectoriesViewModel(FGame game)
public CustomDirectoriesViewModel(FGame game, string directory)
{
_game = game;
_gameDirectoryAtLaunch = directory;
_directories = new ObservableCollection<Control>(EnumerateDirectories());
Directories = new ReadOnlyObservableCollection<Control>(_directories);
}
@ -89,12 +91,15 @@ namespace FModel.ViewModels
public void Save()
{
UserSettings.Default.CustomDirectories[_game] = new List<CustomDirectory>();
var cd = new List<CustomDirectory>();
for (var i = 2; i < _directories.Count; i++)
{
if (_directories[i] is not MenuItem m) continue;
UserSettings.Default.CustomDirectories[_game].Add(new CustomDirectory(m.Header.ToString(), m.Tag.ToString()));
cd.Add(new CustomDirectory(m.Header.ToString(), m.Tag.ToString()));
}
if (_game == FGame.Unknown) UserSettings.Default.ManualGames[_gameDirectoryAtLaunch].CustomDirectories = cd;
else UserSettings.Default.CustomDirectories[_game] = cd;
}
private IEnumerable<Control> EnumerateDirectories()
@ -109,7 +114,12 @@ namespace FModel.ViewModels
};
yield return new Separator();
foreach (var setting in UserSettings.Default.CustomDirectories[_game])
IList<CustomDirectory> cd;
if (_game == FGame.Unknown && UserSettings.Default.ManualGames.TryGetValue(_gameDirectoryAtLaunch, out var settings))
cd = settings.CustomDirectories;
else cd = UserSettings.Default.CustomDirectories[_game];
foreach (var setting in cd)
{
if (setting.DirectoryPath.EndsWith('/'))
setting.DirectoryPath = setting.DirectoryPath[..^1];
@ -157,4 +167,4 @@ namespace FModel.ViewModels
};
}
}
}
}

View File

@ -8,6 +8,10 @@ using System.Collections.ObjectModel;
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
using CUE4Parse.UE4.Objects.Core.Serialization;
using CUE4Parse.UE4.Versions;
using FModel.Settings;
using FModel.ViewModels.ApiEndpoints.Models;
using Microsoft.Win32;
namespace FModel.ViewModels
@ -18,6 +22,14 @@ namespace FModel.ViewModels
{
public string GameName { get; set; }
public string GameDirectory { get; set; }
public bool IsManual { get; set; }
// the followings are only used when game is manually added
public AesResponse AesKeys { get; set; }
public EGame OverridedGame { get; set; }
public List<FCustomVersion> OverridedCustomVersions { get; set; }
public Dictionary<string, bool> OverridedOptions { get; set; }
public IList<CustomDirectory> CustomDirectories { get; set; }
}
private DetectedGame _selectedDetectedGame;
@ -33,6 +45,11 @@ namespace FModel.ViewModels
public GameSelectorViewModel(string gameDirectory)
{
_autoDetectedGames = new ObservableCollection<DetectedGame>(EnumerateDetectedGames().Where(x => x != null));
foreach (var game in UserSettings.Default.ManualGames.Values)
{
_autoDetectedGames.Add(game);
}
AutoDetectedGames = new ReadOnlyObservableCollection<DetectedGame>(_autoDetectedGames);
if (AutoDetectedGames.FirstOrDefault(x => x.GameDirectory == gameDirectory) is { } detectedGame)
@ -43,12 +60,41 @@ namespace FModel.ViewModels
SelectedDetectedGame = AutoDetectedGames.FirstOrDefault();
}
/// <summary>
/// dedicated to manual games
/// </summary>
public void AddUnknownGame(string gameName, string gameDirectory)
{
var game = new DetectedGame
{
GameName = gameName,
GameDirectory = gameDirectory,
IsManual = true,
AesKeys = null,
OverridedGame = EGame.GAME_UE4_LATEST,
OverridedCustomVersions = null,
OverridedOptions = null,
CustomDirectories = new List<CustomDirectory>()
};
UserSettings.Default.ManualGames[gameDirectory] = game;
_autoDetectedGames.Add(game);
SelectedDetectedGame = AutoDetectedGames.Last();
}
public void AddUnknownGame(string gameDirectory)
{
_autoDetectedGames.Add(new DetectedGame { GameName = gameDirectory.SubstringAfterLast('\\'), GameDirectory = gameDirectory });
SelectedDetectedGame = AutoDetectedGames.Last();
}
public void DeleteSelectedGame()
{
UserSettings.Default.ManualGames.Remove(SelectedDetectedGame.GameDirectory); // should not be a problem
_autoDetectedGames.Remove(SelectedDetectedGame);
SelectedDetectedGame = AutoDetectedGames.Last();
}
private IEnumerable<DetectedGame> EnumerateDetectedGames()
{
yield return GetUnrealEngineGame("Fortnite", "\\FortniteGame\\Content\\Paks");

View File

@ -159,9 +159,18 @@ namespace FModel.ViewModels
_gameSnapshot = UserSettings.Default.GameDirectory;
_updateModeSnapshot = UserSettings.Default.UpdateMode;
_presetSnapshot = UserSettings.Default.Presets[_game];
_ueGameSnapshot = UserSettings.Default.OverridedGame[_game];
_customVersionsSnapshot = UserSettings.Default.OverridedCustomVersions[_game];
_optionsSnapshot = UserSettings.Default.OverridedOptions[_game];
if (_game == FGame.Unknown && UserSettings.Default.ManualGames.TryGetValue(_gameSnapshot, out var settings))
{
_ueGameSnapshot = settings.OverridedGame;
_customVersionsSnapshot = settings.OverridedCustomVersions;
_optionsSnapshot = settings.OverridedOptions;
}
else
{
_ueGameSnapshot = UserSettings.Default.OverridedGame[_game];
_customVersionsSnapshot = UserSettings.Default.OverridedCustomVersions[_game];
_optionsSnapshot = UserSettings.Default.OverridedOptions[_game];
}
_assetLanguageSnapshot = UserSettings.Default.AssetLanguage;
_compressedAudioSnapshot = UserSettings.Default.CompressedAudioMode;
_cosmeticStyleSnapshot = UserSettings.Default.CosmeticStyle;
@ -255,9 +264,18 @@ namespace FModel.ViewModels
UserSettings.Default.UpdateMode = SelectedUpdateMode;
UserSettings.Default.Presets[_game] = SelectedPreset;
UserSettings.Default.OverridedGame[_game] = SelectedUeGame;
UserSettings.Default.OverridedCustomVersions[_game] = SelectedCustomVersions;
UserSettings.Default.OverridedOptions[_game] = SelectedOptions;
if (_game == FGame.Unknown)
{
UserSettings.Default.ManualGames[UserSettings.Default.GameDirectory].OverridedGame = SelectedUeGame;
UserSettings.Default.ManualGames[UserSettings.Default.GameDirectory].OverridedCustomVersions = SelectedCustomVersions;
UserSettings.Default.ManualGames[UserSettings.Default.GameDirectory].OverridedOptions = SelectedOptions;
}
else
{
UserSettings.Default.OverridedGame[_game] = SelectedUeGame;
UserSettings.Default.OverridedCustomVersions[_game] = SelectedCustomVersions;
UserSettings.Default.OverridedOptions[_game] = SelectedOptions;
}
UserSettings.Default.AssetLanguage = SelectedAssetLanguage;
UserSettings.Default.CompressedAudioMode = SelectedCompressedAudio;
UserSettings.Default.CosmeticStyle = SelectedCosmeticStyle;

View File

@ -30,7 +30,7 @@
<StackPanel Grid.Row="0" Orientation="Vertical" Margin="10 5 10 10">
<TextBlock Text="What to do?" HorizontalAlignment="Center" FontSize="20" FontWeight="SemiBold" />
<TextBlock TextAlignment="Center" TextWrapping="Wrap" HorizontalAlignment="Center"
Text="We like to make things as simple as possible. Choose between the detected games or manually select your own directory. FModel will use this information to automatically find archives to load and decrypt if needed. Make sure to not skip this step!" />
Text="We like to make things as simple as possible. Choose between the detected games or manually add your own. FModel will use this information to automatically find archives to load and decrypt if needed. Make sure to not skip this step!" />
</StackPanel>
<GroupBox Grid.Row="1" adonisExtensions:LayerExtension.Layer="2" Margin="10 10 10 18"
@ -53,7 +53,7 @@
</ComboBox.ItemTemplate>
</ComboBox>
</Grid>
<Grid>
<Grid Margin="0 0 0 5">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="5" />
@ -62,6 +62,55 @@
<TextBox Grid.Column="0" Text="{Binding SelectedDetectedGame.GameDirectory, Mode=TwoWay}" />
<Button Grid.Column="2" Content="..." HorizontalAlignment="Right" Click="OnBrowseDirectories" />
<Button Grid.Column="2" Click="OnDeleteDirectory" ToolTip="Delete Game">
<Button.Style>
<Style TargetType="Button" BasedOn="{StaticResource {x:Type Button}}">
<Setter Property="Visibility" Value="Collapsed"/>
<Style.Triggers>
<DataTrigger Binding="{Binding SelectedDetectedGame.IsManual}" Value="True">
<Setter Property="Visibility" Value="Visible" />
</DataTrigger>
</Style.Triggers>
</Style>
</Button.Style>
<Viewbox Width="16" Height="16" HorizontalAlignment="Center">
<Canvas Width="24" Height="24">
<Path Fill="{DynamicResource {x:Static adonisUi:Brushes.ForegroundBrush}}" Data="{StaticResource RemoveIcon}" />
</Canvas>
</Viewbox>
</Button>
</Grid>
<Separator Style="{StaticResource CustomSeparator}" Tag="ADD UNDETECTED GAME" />
<Grid Margin="0 5 0 0">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="5" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="10" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="5" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="5" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<TextBlock Grid.Row="0" Grid.Column="0" Text="Name" VerticalAlignment="Center" />
<TextBox x:Name="HelloMyNameIsGame" Grid.Row="0" Grid.Column="2" Grid.ColumnSpan="5" />
<TextBlock Grid.Row="2" Grid.Column="0" Text="Directory" VerticalAlignment="Center" />
<TextBox x:Name="HelloGameMyNameIsDirectory" Grid.Row="2" Grid.Column="2" />
<Button x:Name="OkGuysButWhoFuckingAsked" Grid.Row="2" Grid.Column="4" Content="..." HorizontalAlignment="Right" Click="OnBrowseManualDirectories" />
<Button Grid.Row="2" Grid.Column="6" Style="{DynamicResource {x:Static adonisUi:Styles.AccentButton}}" Padding="0"
Click="OnAddDirectory" ToolTip="Add Game" Width="{Binding ActualWidth, ElementName=OkGuysButWhoFuckingAsked}">
<Viewbox Width="16" Height="16" HorizontalAlignment="Center">
<Canvas Width="24" Height="24">
<Path Fill="{DynamicResource {x:Static adonisUi:Brushes.ForegroundBrush}}" Data="{StaticResource AddIcon}" />
</Canvas>
</Viewbox>
</Button>
</Grid>
</StackPanel>
</GroupBox>

View File

@ -32,5 +32,34 @@ namespace FModel.Views
gameLauncherViewModel.AddUnknownGame(folderBrowser.SelectedPath);
}
}
private void OnBrowseManualDirectories(object sender, RoutedEventArgs e)
{
var folderBrowser = new VistaFolderBrowserDialog {ShowNewFolderButton = false};
if (folderBrowser.ShowDialog() == true)
{
HelloGameMyNameIsDirectory.Text = folderBrowser.SelectedPath;
}
}
private void OnAddDirectory(object sender, RoutedEventArgs e)
{
if (DataContext is not GameSelectorViewModel gameLauncherViewModel||
string.IsNullOrEmpty(HelloMyNameIsGame.Text) ||
string.IsNullOrEmpty(HelloGameMyNameIsDirectory.Text))
return;
gameLauncherViewModel.AddUnknownGame(HelloMyNameIsGame.Text, HelloGameMyNameIsDirectory.Text);
HelloMyNameIsGame.Clear();
HelloGameMyNameIsDirectory.Clear();
}
private void OnDeleteDirectory(object sender, RoutedEventArgs e)
{
if (DataContext is not GameSelectorViewModel gameLauncherViewModel)
return;
gameLauncherViewModel.DeleteSelectedGame();
}
}
}
}