Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Target playset selection #426

Draft
wants to merge 16 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Fronter.NET.sln.DotSettings
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,4 @@
<s:Boolean x:Key="/Default/UserDictionary/Words/=Outputtable/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Patreon/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=playset/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=playsets/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Playsets/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>
127 changes: 38 additions & 89 deletions Fronter.NET/Models/Configuration/Config.cs
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
using Avalonia.Controls.ApplicationLifetimes;
using commonItems;
using Fronter.Models.Configuration.Options;
using Fronter.Models.Database;
using Fronter.Services;
using Fronter.ViewModels;
using log4net;
using Sentry;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Globalization;
using System.IO;
using System.Linq;

Expand All @@ -20,8 +23,9 @@ public class Config {
public string SourceGame { get; private set; } = string.Empty;
public string TargetGame { get; private set; } = string.Empty;
public string? SentryDsn { get; private set; }
public string? ModAutoGenerationSource { get; private set; } = null;
public ObservableCollection<Mod> AutoLocatedMods { get; } = new();
public bool TargetPlaysetSelectionEnabled { get; private set; } = false;
public ObservableCollection<Playset> AutoLocatedPlaysets { get; } = [];
public Playset? SelectedPlayset { get; set; }
public bool CopyToTargetGameModDirectory { get; set; } = true;
public ushort ProgressOnCopyingComplete { get; set; } = 109;
public bool UpdateCheckerEnabled { get; private set; } = false;
Expand Down Expand Up @@ -92,7 +96,9 @@ private void RegisterKeys(Parser parser) {
parser.RegisterKeyword("displayName", reader => DisplayName = reader.GetString());
parser.RegisterKeyword("sourceGame", reader => SourceGame = reader.GetString());
parser.RegisterKeyword("targetGame", reader => TargetGame = reader.GetString());
parser.RegisterKeyword("autoGenerateModsFrom", reader => ModAutoGenerationSource = reader.GetString());
parser.RegisterKeyword("targetPlaysetSelectionEnabled", reader => {
TargetPlaysetSelectionEnabled = reader.GetBool();
});
parser.RegisterKeyword("copyToTargetGameModDirectory", reader => {
CopyToTargetGameModDirectory = reader.GetString().Equals("true");
});
Expand Down Expand Up @@ -162,8 +168,8 @@ private void InitSentry(string dsn) {

private void RegisterPreloadKeys(Parser parser) {
parser.RegisterRegex(CommonRegexes.String, (reader, incomingKey) => {
var valueStringOfItem = reader.GetStringOfItem();
var valueStr = valueStringOfItem.ToString().RemQuotes();
StringOfItem valueStringOfItem = reader.GetStringOfItem();
string valueStr = valueStringOfItem.ToString().RemQuotes();
var valueReader = new BufferedReader(valueStr);

foreach (var folder in RequiredFolders) {
Expand All @@ -187,13 +193,6 @@ private void RegisterPreloadKeys(Parser parser) {
option.SetCheckBoxSelectorPreloaded();
}
}
if (incomingKey.Equals("selectedMods")) {
var theList = valueReader.GetStrings();
var matchingMods = AutoLocatedMods.Where(m => theList.Contains(m.FileName));
foreach (var mod in matchingMods) {
mod.Enabled = true;
}
}
});
parser.RegisterRegex(CommonRegexes.Catchall, ParserHelpers.IgnoreAndLogItem);
}
Expand Down Expand Up @@ -223,7 +222,7 @@ private void InitializeFolders(string documentsDir) {
if (uint.TryParse(folder.SteamGameId, out uint steamId)) {
possiblePath = CommonFunctions.GetSteamInstallPath(steamId);
}
if (possiblePath is null && long.TryParse(folder.GOGGameId, out long gogId)) {
if (possiblePath is null && long.TryParse(folder.GOGGameId, CultureInfo.InvariantCulture, out long gogId)) {
possiblePath = CommonFunctions.GetGOGInstallPath(gogId);
}

Expand All @@ -242,10 +241,6 @@ private void InitializeFolders(string documentsDir) {
if (Directory.Exists(initialValue)) {
folder.Value = initialValue;
}

if (folder.Name.Equals(ModAutoGenerationSource)) {
AutoLocateMods();
}
}
}

Expand Down Expand Up @@ -318,15 +313,9 @@ public bool ExportConfiguration() {
}
writer.WriteLine($"{file.Name} = \"{file.Value}\"");
}

if (ModAutoGenerationSource is not null) {
writer.WriteLine("selectedMods = {");
foreach (var mod in AutoLocatedMods) {
if (mod.Enabled) {
writer.WriteLine($"\t\"{mod.FileName}\"");
}
}
writer.WriteLine("}");

if (SelectedPlayset is not null) {
writer.WriteLine($"selectedPlayset = {SelectedPlayset.Id}");
}

foreach (var option in Options) {
Expand Down Expand Up @@ -360,72 +349,32 @@ private static void SetSavingStatus(string locKey) {
}
}

public void AutoLocateMods() {
logger.Debug("Clearing previously located mods...");
AutoLocatedMods.Clear();
logger.Debug("Autolocating mods...");

// Do we have a mod path?
string? modPath = null;
foreach (var folder in RequiredFolders) {
if (folder.Name.Equals(ModAutoGenerationSource)) {
modPath = folder.Value;
}
}
if (modPath is null) {
logger.Warn("No folder found as source for mods autolocation.");
return;
}

// Does it exist?
if (!Directory.Exists(modPath)) {
logger.Warn($"Mod path \"{modPath}\" does not exist or can not be accessed!");
return;
}

// Are we looking at documents directory?
var combinedPath = Path.Combine(modPath, "mod");
if (Directory.Exists(combinedPath)) {
modPath = combinedPath;
}
logger.Debug($"Mods autolocation path set to: \"{modPath}\"");

// Are there mods inside?
var validModFiles = new List<string>();
foreach (var file in SystemUtils.GetAllFilesInFolder(modPath)) {
var lastDot = file.LastIndexOf('.');
if (lastDot == -1) {
continue;
}

var extension = CommonFunctions.GetExtension(file);
if (!extension.Equals("mod")) {
continue;
}

validModFiles.Add(file);
}

if (validModFiles.Count == 0) {
logger.Debug($"No mod files could be found in \"{modPath}\"");
return;
public string? TargetGameModsPath {
get {
var targetGameModPath = RequiredFolders
.FirstOrDefault(f => f?.Name == "targetGameModPath", defaultValue: null);
return targetGameModPath?.Value;
}
}

foreach (var modFile in validModFiles) {
var path = Path.Combine(modPath, modFile);
Mod theMod;
try {
theMod = new Mod(path);
} catch (IOException ex) {
logger.Warn($"Failed to parse mod file {modFile}: {ex.Message}");
continue;
}
if (string.IsNullOrEmpty(theMod.Name)) {
logger.Warn($"Mod at \"{path}\" has no defined name, skipping.");
continue;
public void AutoLocatePlaysets() {
logger.Debug("Clearing previously located playsets...");
AutoLocatedPlaysets.Clear();
logger.Debug("Autolocating playsets...");

var destModsFolder = TargetGameModsPath;
var locatedPlaysetsCount = 0;
if (destModsFolder is not null) {
var dbContext = TargetDbManager.GetLauncherDbContext(this);
if (dbContext is not null) {
foreach (var playset in dbContext.Playsets.Where(p => p.IsRemoved == null || p.IsRemoved == false )) {
AutoLocatedPlaysets.Add(playset);
}
}
AutoLocatedMods.Add(theMod);

locatedPlaysetsCount = AutoLocatedPlaysets.Count;
}
logger.Debug($"Autolocated {AutoLocatedMods.Count} mods");

logger.Debug($"Autolocated {locatedPlaysetsCount} playsets.");
}
}
18 changes: 0 additions & 18 deletions Fronter.NET/Models/Configuration/Mod.cs

This file was deleted.

6 changes: 3 additions & 3 deletions Fronter.NET/Models/Configuration/RequiredFolder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@
parser.RegisterKeyword("name", reader => Name = reader.GetString());
parser.RegisterKeyword("tooltip", reader => Tooltip = reader.GetString());
parser.RegisterKeyword("displayName", reader => DisplayName = reader.GetString());
parser.RegisterKeyword("mandatory", reader => Mandatory = reader.GetString() == "true");

Check warning on line 22 in Fronter.NET/Models/Configuration/RequiredFolder.cs

View workflow job for this annotation

GitHub Actions / test_and_check_coverage

Check warning on line 22 in Fronter.NET/Models/Configuration/RequiredFolder.cs

View workflow job for this annotation

GitHub Actions / test (self-hosted, windows)

parser.RegisterKeyword("outputtable", reader => Outputtable = reader.GetString() == "true");

Check warning on line 23 in Fronter.NET/Models/Configuration/RequiredFolder.cs

View workflow job for this annotation

GitHub Actions / test_and_check_coverage


parser.RegisterKeyword("searchPathType", reader => SearchPathType = reader.GetString());
parser.RegisterKeyword("steamGameID", reader => SteamGameId = reader.GetString());
Expand All @@ -44,9 +44,9 @@

base.Value = value;
logger.Info($"{TranslationSource.Instance[DisplayName]} set to: {value}");

if (Name == config.ModAutoGenerationSource) {
config.AutoLocateMods();
if (config.TargetPlaysetSelectionEnabled) {
config.AutoLocatePlaysets();
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ l_english:
OPTIONSTAB: "Options"
CONVERTTAB: "Convert"
MODSTAB: "Mods"
TARGET_PLAYSET_TAB: "Target Playset"
MODSDISABLED: "Mod autodetection disabled by configuration/not required."
MODSNOTFOUND: "Mods not found in mod directory."
MODSFOUND: "Mods autodetected:"
Expand Down
19 changes: 3 additions & 16 deletions Fronter.NET/Services/ModCopier.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
using Fronter.Models.Database;
using log4net;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
Expand Down Expand Up @@ -32,13 +31,11 @@ public bool CopyMod() {
return false;
}

var requiredFolders = config.RequiredFolders;
var targetGameModPath = requiredFolders.FirstOrDefault(f => f?.Name == "targetGameModPath", null);
if (targetGameModPath is null) {
string? destModsFolder = config.TargetGameModsPath;
if (destModsFolder is null) {
logger.Error("Copy failed - Target Folder isn't loaded!");
return false;
}
var destModsFolder = targetGameModPath.Value;
if (!Directory.Exists(destModsFolder)) {
logger.Error("Copy failed - Target Folder does not exist!");
return false;
Expand Down Expand Up @@ -144,7 +141,7 @@ private void CreatePlayset(string targetModsDirectory, string modName, string de
logger.Warn($"Couldn't get parent directory of \"{targetModsDirectory}\".");
return;
}
var latestDbFilePath = GetLastUpdatedLauncherDbPath(gameDocsDirectory);
var latestDbFilePath = TargetDbManager.GetLastUpdatedLauncherDbPath(gameDocsDirectory);
if (latestDbFilePath is null) {
logger.Debug("Launcher's database not found.");
return;
Expand Down Expand Up @@ -234,16 +231,6 @@ private void CreatePlayset(string targetModsDirectory, string modName, string de
}
}

private static string? GetLastUpdatedLauncherDbPath(string gameDocsDirectory) {
var possibleDbFileNames = new List<string> { "launcher-v2.sqlite", "launcher-v2_openbeta.sqlite" };
var latestDbFilePath = possibleDbFileNames
.Select(name => Path.Join(gameDocsDirectory, name))
.Where(File.Exists)
.OrderByDescending(File.GetLastWriteTimeUtc)
.FirstOrDefault(defaultValue: null);
return latestDbFilePath;
}

// Returns saved mod.
private Mod AddModToDb(LauncherDbContext dbContext, string modName, string gameRegistryId, string dirPath) {
logger.Debug($"Saving mod \"{modName}\" to DB...");
Expand Down
37 changes: 37 additions & 0 deletions Fronter.NET/Services/TargetDbManager.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
using Fronter.Models.Configuration;
using System.Collections.Generic;
using System.IO;
using System.Linq;

namespace Fronter.Services;

public class TargetDbManager {
public static string? GetLastUpdatedLauncherDbPath(string gameDocsDirectory) {
var possibleDbFileNames = new List<string> { "launcher-v2.sqlite", "launcher-v2_openbeta.sqlite" };
var latestDbFilePath = possibleDbFileNames
.Select(name => Path.Join(gameDocsDirectory, name))
.Where(File.Exists)
.OrderByDescending(File.GetLastWriteTimeUtc)
.FirstOrDefault(defaultValue: null);
return latestDbFilePath;
}

public static LauncherDbContext? GetLauncherDbContext(Config config) {
var targetGameModsPath = config.TargetGameModsPath;
if (string.IsNullOrWhiteSpace(targetGameModsPath)) {
return null;
}
var gameDocsDirectory = Directory.GetParent(targetGameModsPath)?.FullName;
if (gameDocsDirectory is null) {
return null;
}

var dbPath = GetLastUpdatedLauncherDbPath(gameDocsDirectory);
if (dbPath is null) {
return null;
}

string connectionString = $"Data Source={dbPath};";
return new LauncherDbContext(connectionString);
}
}
6 changes: 3 additions & 3 deletions Fronter.NET/ViewModels/MainWindowViewModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -59,8 +59,8 @@ public sealed class MainWindowViewModel : ViewModelBase {
internal Config Config { get; }

internal PathPickerViewModel PathPicker { get; }
internal ModsPickerViewModel ModsPicker { get; }
public bool ModsPickerTabVisible => Config.ModAutoGenerationSource is not null;
internal TargetPlaysetPickerViewModel TargetPlaysetPicker { get; }
public bool TargetPlaysetPickerTabVisible => Config.TargetPlaysetSelectionEnabled;
public OptionsViewModel Options { get; }
public bool OptionsTabVisible => Options.Items.Any();

Expand Down Expand Up @@ -104,7 +104,7 @@ public MainWindowViewModel(DataGrid logGrid) {
LogGridAppender.LogGrid = logGrid;

PathPicker = new PathPickerViewModel(Config);
ModsPicker = new ModsPickerViewModel(Config);
TargetPlaysetPicker = new TargetPlaysetPickerViewModel(Config);
Options = new OptionsViewModel(Config.Options);

// Create reactive commands.
Expand Down
27 changes: 0 additions & 27 deletions Fronter.NET/ViewModels/ModsPickerViewModel.cs

This file was deleted.

Loading
Loading