mirror of
https://github.com/wabbajack-tools/wabbajack.git
synced 2024-08-30 18:42:17 +00:00
Merge branch 'master' into set-screen-size
This commit is contained in:
commit
7191804ff2
@ -31,7 +31,7 @@ namespace Compression.BSA.Test
|
||||
public static void Setup(TestContext testContext)
|
||||
{
|
||||
Queue = new WorkQueue();
|
||||
Utils.LogMessages.Subscribe(f => testContext.WriteLine(f));
|
||||
Utils.LogMessages.Subscribe(f => testContext.WriteLine(f.ShortDescription));
|
||||
if (!Directory.Exists(_stagingFolder))
|
||||
Directory.CreateDirectory(_stagingFolder);
|
||||
|
||||
|
@ -30,6 +30,7 @@ namespace Wabbajack.Common
|
||||
public static string WABBAJACK_INCLUDE = "WABBAJACK_INCLUDE";
|
||||
public static string WABBAJACK_ALWAYS_ENABLE = "WABBAJACK_ALWAYS_ENABLE";
|
||||
public static string WABBAJACK_NOMATCH_INCLUDE = "WABBAJACK_NOMATCH_INCLUDE";
|
||||
public static string WABBAJACK_VORTEX_MANUAL = "WABBAJACK_VORTEX_MANUAL";
|
||||
|
||||
public static string GAME_PATH_MAGIC_BACK = "{--||GAME_PATH_MAGIC_BACK||--}";
|
||||
public static string GAME_PATH_MAGIC_DOUBLE_BACK = "{--||GAME_PATH_MAGIC_DOUBLE_BACK||--}";
|
||||
|
@ -10,6 +10,8 @@ using Compression.BSA;
|
||||
using ICSharpCode.SharpZipLib.GZip;
|
||||
using Newtonsoft.Json;
|
||||
using OMODFramework;
|
||||
using Wabbajack.Common.StatusFeed;
|
||||
using Wabbajack.Common.StatusFeed.Errors;
|
||||
|
||||
namespace Wabbajack.Common
|
||||
{
|
||||
@ -46,11 +48,11 @@ namespace Wabbajack.Common
|
||||
else if (source.EndsWith(".exe"))
|
||||
ExtractAllWithInno(source, dest);
|
||||
else
|
||||
ExtractAllWith7Zip(source, dest);
|
||||
ExtractAllWith7Zip(queue, source, dest);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Utils.Log($"Error while extracting {source}");
|
||||
queue.Log($"Error while extracting {source}");
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
@ -152,14 +154,14 @@ namespace Wabbajack.Common
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Utils.Log($"While Extracting {source}");
|
||||
queue.Log($"While Extracting {source}");
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
|
||||
private static void ExtractAllWith7Zip(string source, string dest)
|
||||
private static void ExtractAllWith7Zip(WorkQueue queue, string source, string dest)
|
||||
{
|
||||
Utils.Log($"Extracting {Path.GetFileName(source)}");
|
||||
queue.Log(new GenericInfo($"Extracting {Path.GetFileName(source)}", $"The contents of {source} are being extracted to {dest} using 7zip.exe"));
|
||||
|
||||
var info = new ProcessStartInfo
|
||||
{
|
||||
@ -204,11 +206,11 @@ namespace Wabbajack.Common
|
||||
}
|
||||
|
||||
p.WaitForExit();
|
||||
if (p.ExitCode != 0)
|
||||
if (p.ExitCode == 0)
|
||||
{
|
||||
Utils.Log(p.StandardOutput.ReadToEnd());
|
||||
Utils.Log($"Extraction error extracting {source}");
|
||||
return;
|
||||
}
|
||||
queue.Log(new _7zipReturnError(p.ExitCode, source, dest, p.StandardOutput.ReadToEnd()));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
15
Wabbajack.Common/StatusFeed/AErrorMessage.cs
Normal file
15
Wabbajack.Common/StatusFeed/AErrorMessage.cs
Normal file
@ -0,0 +1,15 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Wabbajack.Common.StatusFeed
|
||||
{
|
||||
public abstract class AErrorMessage : Exception, IError
|
||||
{
|
||||
public DateTime Timestamp { get; } = DateTime.Now;
|
||||
public abstract string ShortDescription { get; }
|
||||
public abstract string ExtendedDescription { get; }
|
||||
}
|
||||
}
|
15
Wabbajack.Common/StatusFeed/AStatusMessage.cs
Normal file
15
Wabbajack.Common/StatusFeed/AStatusMessage.cs
Normal file
@ -0,0 +1,15 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Wabbajack.Common.StatusFeed
|
||||
{
|
||||
public abstract class AStatusMessage : IStatusMessage
|
||||
{
|
||||
public DateTime Timestamp { get; } = DateTime.Now;
|
||||
public abstract string ShortDescription { get; }
|
||||
public abstract string ExtendedDescription { get; }
|
||||
}
|
||||
}
|
33
Wabbajack.Common/StatusFeed/Errors/7zipReturnError.cs
Normal file
33
Wabbajack.Common/StatusFeed/Errors/7zipReturnError.cs
Normal file
@ -0,0 +1,33 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Wabbajack.Common.StatusFeed.Errors
|
||||
{
|
||||
public class _7zipReturnError : AStatusMessage, IError
|
||||
{
|
||||
private string _destination;
|
||||
private string _filename;
|
||||
private int _code;
|
||||
private string _7zip_output;
|
||||
public override string ShortDescription => $"7Zip returned an error while executing";
|
||||
|
||||
public override string ExtendedDescription =>
|
||||
$@"7Zip.exe should always return 0 when it finishes executing. While extracting {_filename} 7Zip encountered some error and
|
||||
instead returned {_code} which indicates there was an error. The archive might be corrupt or in a format that 7Zip cannot handle. Please verify the file is valid and that you
|
||||
haven't run out of disk space in the {_destination} folder.
|
||||
|
||||
7Zip Output:
|
||||
{_7zip_output}";
|
||||
|
||||
public _7zipReturnError(int code, string filename, string destination, string output)
|
||||
{
|
||||
_code = code;
|
||||
_filename = filename;
|
||||
_destination = destination;
|
||||
_7zip_output = output;
|
||||
}
|
||||
}
|
||||
}
|
22
Wabbajack.Common/StatusFeed/Errors/FileExtractionError.cs
Normal file
22
Wabbajack.Common/StatusFeed/Errors/FileExtractionError.cs
Normal file
@ -0,0 +1,22 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Wabbajack.Common.StatusFeed.Errors
|
||||
{
|
||||
class FileExtractionError : AStatusMessage, IError
|
||||
{
|
||||
private string _filename;
|
||||
private string _destination;
|
||||
public override string ShortDescription { get; }
|
||||
public override string ExtendedDescription { get; }
|
||||
|
||||
public FileExtractionError(string filename, string destination)
|
||||
{
|
||||
_filename = filename;
|
||||
_destination = destination;
|
||||
}
|
||||
}
|
||||
}
|
21
Wabbajack.Common/StatusFeed/Errors/UnconvertedError.cs
Normal file
21
Wabbajack.Common/StatusFeed/Errors/UnconvertedError.cs
Normal file
@ -0,0 +1,21 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Wabbajack.Common.StatusFeed.Errors
|
||||
{
|
||||
public class UnconvertedError : AErrorMessage
|
||||
{
|
||||
private string _msg;
|
||||
|
||||
public UnconvertedError(string msg)
|
||||
{
|
||||
_msg = msg;
|
||||
}
|
||||
|
||||
public override string ShortDescription { get => _msg; }
|
||||
public override string ExtendedDescription { get; } = "";
|
||||
}
|
||||
}
|
25
Wabbajack.Common/StatusFeed/GenericInfo.cs
Normal file
25
Wabbajack.Common/StatusFeed/GenericInfo.cs
Normal file
@ -0,0 +1,25 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Wabbajack.Common.StatusFeed
|
||||
{
|
||||
public class GenericInfo : AStatusMessage, IInfo
|
||||
{
|
||||
public override string ShortDescription { get; }
|
||||
public override string ExtendedDescription { get;}
|
||||
|
||||
public GenericInfo(string short_description, string long_description = "")
|
||||
{
|
||||
ShortDescription = short_description;
|
||||
ExtendedDescription = long_description;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return ShortDescription;
|
||||
}
|
||||
}
|
||||
}
|
12
Wabbajack.Common/StatusFeed/IError.cs
Normal file
12
Wabbajack.Common/StatusFeed/IError.cs
Normal file
@ -0,0 +1,12 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Wabbajack.Common.StatusFeed
|
||||
{
|
||||
public interface IError : IStatusMessage
|
||||
{
|
||||
}
|
||||
}
|
13
Wabbajack.Common/StatusFeed/IInfo.cs
Normal file
13
Wabbajack.Common/StatusFeed/IInfo.cs
Normal file
@ -0,0 +1,13 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Wabbajack.Common.StatusFeed
|
||||
{
|
||||
public interface IInfo : IStatusMessage
|
||||
{
|
||||
|
||||
}
|
||||
}
|
15
Wabbajack.Common/StatusFeed/IStatusMessage.cs
Normal file
15
Wabbajack.Common/StatusFeed/IStatusMessage.cs
Normal file
@ -0,0 +1,15 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Wabbajack.Common.StatusFeed
|
||||
{
|
||||
public interface IStatusMessage
|
||||
{
|
||||
DateTime Timestamp { get; }
|
||||
string ShortDescription { get; }
|
||||
string ExtendedDescription { get; }
|
||||
}
|
||||
}
|
43
Wabbajack.Common/StatusFeed/IUserIntervention.cs
Normal file
43
Wabbajack.Common/StatusFeed/IUserIntervention.cs
Normal file
@ -0,0 +1,43 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Wabbajack.Common.StatusFeed
|
||||
{
|
||||
/// <summary>
|
||||
/// Defines a message that requires user interaction. The user must perform some action
|
||||
/// or make a choice.
|
||||
/// </summary>
|
||||
public interface IUserIntervention<T> : IStatusMessage
|
||||
{
|
||||
/// <summary>
|
||||
/// The user didn't make a choice, so this action should be aborted
|
||||
/// </summary>
|
||||
void Cancel();
|
||||
|
||||
/// <summary>
|
||||
/// The user has provided the required information.
|
||||
/// </summary>
|
||||
/// <param name="result"></param>
|
||||
void Resume(T result);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Defines a message that requires user interaction. The user must perform some action
|
||||
/// or make a choice.
|
||||
/// </summary>
|
||||
public interface IUserIntervention : IStatusMessage
|
||||
{
|
||||
/// <summary>
|
||||
/// The user didn't make a choice, so this action should be aborted
|
||||
/// </summary>
|
||||
void Cancel();
|
||||
|
||||
/// <summary>
|
||||
/// Resume without any further information
|
||||
/// </summary>
|
||||
void Resume();
|
||||
}
|
||||
}
|
@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Reactive.Subjects;
|
||||
using Wabbajack.Common.StatusFeed;
|
||||
|
||||
namespace Wabbajack.Common
|
||||
{
|
||||
|
@ -151,6 +151,9 @@ namespace Wabbajack.Common
|
||||
InstallFolders.Do(p =>
|
||||
{
|
||||
var workshop = Path.Combine(p, "workshop");
|
||||
if(!Directory.Exists(workshop))
|
||||
return;
|
||||
|
||||
Directory.EnumerateFiles(workshop, "*.acf", SearchOption.TopDirectoryOnly).Do(f =>
|
||||
{
|
||||
if (Path.GetFileName(f) != $"appworkshop_{game.AppId}.acf")
|
||||
|
@ -16,6 +16,8 @@ using Ceras;
|
||||
using ICSharpCode.SharpZipLib.BZip2;
|
||||
using IniParser;
|
||||
using Newtonsoft.Json;
|
||||
using ReactiveUI;
|
||||
using Wabbajack.Common.StatusFeed;
|
||||
using YamlDotNet.Serialization;
|
||||
using YamlDotNet.Serialization.NamingConventions;
|
||||
using Directory = System.IO.Directory;
|
||||
@ -44,8 +46,8 @@ namespace Wabbajack.Common
|
||||
File.Delete(LogFile);
|
||||
}
|
||||
|
||||
private static readonly Subject<string> LoggerSubj = new Subject<string>();
|
||||
public static IObservable<string> LogMessages => LoggerSubj;
|
||||
private static readonly Subject<IStatusMessage> LoggerSubj = new Subject<IStatusMessage>();
|
||||
public static IObservable<IStatusMessage> LogMessages => LoggerSubj;
|
||||
|
||||
private static readonly string[] Suffix = {"B", "KB", "MB", "GB", "TB", "PB", "EB"}; // Longs run out around EB
|
||||
|
||||
@ -53,15 +55,30 @@ namespace Wabbajack.Common
|
||||
|
||||
private static DateTime _startTime;
|
||||
|
||||
|
||||
public static void Log(string msg)
|
||||
{
|
||||
Log(new GenericInfo(msg));
|
||||
}
|
||||
|
||||
public static T Log<T>(T msg) where T : IStatusMessage
|
||||
{
|
||||
lock (_lock)
|
||||
{
|
||||
msg = $"{(DateTime.Now - _startTime).TotalSeconds:0.##} - {msg}";
|
||||
|
||||
File.AppendAllText(LogFile, msg + "\r\n");
|
||||
}
|
||||
LoggerSubj.OnNext(msg);
|
||||
return msg;
|
||||
}
|
||||
|
||||
public static void Error(AErrorMessage err)
|
||||
{
|
||||
lock (_lock)
|
||||
{
|
||||
File.AppendAllText(LogFile, err.ShortDescription + "\r\n");
|
||||
}
|
||||
LoggerSubj.OnNext(err);
|
||||
throw err;
|
||||
}
|
||||
|
||||
public static void LogToFile(string msg)
|
||||
@ -668,10 +685,11 @@ namespace Wabbajack.Common
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
public static void Warning(string s)
|
||||
{
|
||||
Log($"WARNING: {s}");
|
||||
}
|
||||
}*/
|
||||
|
||||
public static TV GetOrDefault<TK, TV>(this Dictionary<TK, TV> dict, TK key)
|
||||
{
|
||||
@ -708,11 +726,12 @@ namespace Wabbajack.Common
|
||||
return tv.ToJSON().FromJSONString<T>();
|
||||
}
|
||||
|
||||
/*
|
||||
public static void Error(string msg)
|
||||
{
|
||||
Log(msg);
|
||||
throw new Exception(msg);
|
||||
}
|
||||
}*/
|
||||
|
||||
public static Stream GetEmbeddedResourceStream(string name)
|
||||
{
|
||||
@ -738,7 +757,6 @@ namespace Wabbajack.Common
|
||||
.Build();
|
||||
return d.Deserialize<T>(new StringReader(s));
|
||||
}
|
||||
|
||||
public static void LogStatus(string s)
|
||||
{
|
||||
Status(s);
|
||||
|
@ -108,6 +108,16 @@
|
||||
<Compile Include="GOGHandler.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="SplittingStream.cs" />
|
||||
<Compile Include="StatusFeed\AErrorMessage.cs" />
|
||||
<Compile Include="StatusFeed\AStatusMessage.cs" />
|
||||
<Compile Include="StatusFeed\Errors\7zipReturnError.cs" />
|
||||
<Compile Include="StatusFeed\Errors\FileExtractionError.cs" />
|
||||
<Compile Include="StatusFeed\Errors\UnconvertedError.cs" />
|
||||
<Compile Include="StatusFeed\GenericInfo.cs" />
|
||||
<Compile Include="StatusFeed\IError.cs" />
|
||||
<Compile Include="StatusFeed\IInfo.cs" />
|
||||
<Compile Include="StatusFeed\IStatusMessage.cs" />
|
||||
<Compile Include="StatusFeed\IUserIntervention.cs" />
|
||||
<Compile Include="StatusFileStream.cs" />
|
||||
<Compile Include="StatusUpdate.cs" />
|
||||
<Compile Include="SteamHandler.cs" />
|
||||
|
@ -5,6 +5,7 @@ using System.Linq;
|
||||
using System.Reactive.Linq;
|
||||
using System.Reactive.Subjects;
|
||||
using System.Threading;
|
||||
using Wabbajack.Common.StatusFeed;
|
||||
|
||||
namespace Wabbajack.Common
|
||||
{
|
||||
@ -21,13 +22,26 @@ namespace Wabbajack.Common
|
||||
private readonly Subject<CPUStatus> _Status = new Subject<CPUStatus>();
|
||||
public IObservable<CPUStatus> Status => _Status;
|
||||
|
||||
public List<Thread> Threads { get; private set; }
|
||||
private static readonly Subject<IStatusMessage> _messages = new Subject<IStatusMessage>();
|
||||
public IObservable<IStatusMessage> Messages => _messages;
|
||||
|
||||
public static List<Thread> Threads { get; private set; }
|
||||
|
||||
public WorkQueue(int threadCount = 0)
|
||||
{
|
||||
StartThreads(threadCount == 0 ? Environment.ProcessorCount : threadCount);
|
||||
}
|
||||
|
||||
public void Log(IStatusMessage msg)
|
||||
{
|
||||
_messages.OnNext(msg);
|
||||
}
|
||||
|
||||
public void Log(string msg)
|
||||
{
|
||||
_messages.OnNext(new GenericInfo(msg));
|
||||
}
|
||||
|
||||
private void StartThreads(int threadCount)
|
||||
{
|
||||
ThreadCount = threadCount;
|
||||
|
@ -0,0 +1,39 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Alphaleonis.Win32.Filesystem;
|
||||
using Wabbajack.Common.StatusFeed;
|
||||
|
||||
namespace Wabbajack.Lib.CompilationSteps.CompilationErrors
|
||||
{
|
||||
public class InvalidGameESMError : AErrorMessage
|
||||
{
|
||||
private readonly string _hash;
|
||||
private readonly string _path;
|
||||
private readonly CleanedESM _esm;
|
||||
private string _gameFileName => Path.GetFileName(_esm.To);
|
||||
public override string ShortDescription
|
||||
{
|
||||
get =>
|
||||
$"Game file {_gameFileName} has a hash of {_hash} which does not match the expected value of {_esm.SourceESMHash}";
|
||||
}
|
||||
|
||||
public override string ExtendedDescription
|
||||
{
|
||||
get =>
|
||||
$@"This modlist is setup to perform automatic cleaning of the stock game file {_gameFileName} in order to perform this cleaning Wabbajack must first verify that the
|
||||
source file is in the correct state. It seems that the file in your game directory has a hash of {_hash} instead of the expect hash of {_esm.SourceESMHash}. This could be caused by
|
||||
the modlist expecting a different of the game than you currently have installed, or perhaps you have already cleaned the file. You could attempt to fix this error by re-installing
|
||||
the game, and then attempting to re-install this modlist. Also verify that the version of the game you have installed matches the version expected by this modlist.";
|
||||
}
|
||||
|
||||
public InvalidGameESMError(CleanedESM esm, string hash, string path)
|
||||
{
|
||||
_hash = hash;
|
||||
_path = path;
|
||||
_esm = esm;
|
||||
}
|
||||
}
|
||||
}
|
@ -5,6 +5,7 @@ using Alphaleonis.Win32.Filesystem;
|
||||
using Compression.BSA;
|
||||
using Newtonsoft.Json;
|
||||
using Wabbajack.Common;
|
||||
using Wabbajack.Common.StatusFeed.Errors;
|
||||
|
||||
namespace Wabbajack.Lib.CompilationSteps
|
||||
{
|
||||
@ -72,7 +73,7 @@ namespace Wabbajack.Lib.CompilationSteps
|
||||
foreach (var match in matches)
|
||||
{
|
||||
if (match is IgnoredDirectly)
|
||||
Utils.Error($"File required for BSA {source.Path} creation doesn't exist: {match.To}");
|
||||
Utils.Error(new UnconvertedError($"File required for BSA {source.Path} creation doesn't exist: {match.To}"));
|
||||
_mo2Compiler.ExtraFiles.Add(match);
|
||||
}
|
||||
|
||||
@ -100,4 +101,4 @@ namespace Wabbajack.Lib.CompilationSteps
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using Wabbajack.Common;
|
||||
using Wabbajack.Common.StatusFeed.Errors;
|
||||
using Wabbajack.Lib.NexusApi;
|
||||
using Wabbajack.Lib.Validation;
|
||||
|
||||
@ -45,12 +46,12 @@ namespace Wabbajack.Lib.Downloaders
|
||||
var status = client.GetUserStatus();
|
||||
if (!client.IsAuthenticated)
|
||||
{
|
||||
Utils.Error($"Authenticating for the Nexus failed. A nexus account is required to automatically download mods.");
|
||||
Utils.Error(new UnconvertedError($"Authenticating for the Nexus failed. A nexus account is required to automatically download mods."));
|
||||
return;
|
||||
}
|
||||
|
||||
if (status.is_premium) return;
|
||||
Utils.Error($"Automated installs with Wabbajack requires a premium nexus account. {client.Username} is not a premium account.");
|
||||
Utils.Error(new UnconvertedError($"Automated installs with Wabbajack requires a premium nexus account. {client.Username} is not a premium account."));
|
||||
}
|
||||
|
||||
public class State : AbstractDownloadState
|
||||
|
@ -7,8 +7,10 @@ using Alphaleonis.Win32.Filesystem;
|
||||
using IniParser;
|
||||
using IniParser.Parser;
|
||||
using Wabbajack.Common;
|
||||
using Wabbajack.Lib.CompilationSteps.CompilationErrors;
|
||||
using Wabbajack.Lib.Downloaders;
|
||||
using Wabbajack.Lib.NexusApi;
|
||||
using Wabbajack.Lib.StatusMessages;
|
||||
using Wabbajack.Lib.Validation;
|
||||
using Directory = Alphaleonis.Win32.Filesystem.Directory;
|
||||
using File = Alphaleonis.Win32.Filesystem.File;
|
||||
@ -62,12 +64,7 @@ namespace Wabbajack.Lib
|
||||
|
||||
if (Directory.Exists(Path.Combine(OutputFolder, "mods")) && WarnOnOverwrite)
|
||||
{
|
||||
if (MessageBox.Show(
|
||||
"There already appears to be a Mod Organizer 2 install in this folder, are you sure you wish to continue" +
|
||||
" with installation? If you do, you may render both your existing install and the new modlist inoperable.",
|
||||
"Existing MO2 installation in install folder",
|
||||
MessageBoxButton.YesNo,
|
||||
MessageBoxImage.Exclamation) == MessageBoxResult.No)
|
||||
if (Utils.Log(new ConfirmUpdateOfExistingInstall { ModListName = ModList.Name, OutputFolder = OutputFolder}).Task.Result == ConfirmUpdateOfExistingInstall.Choice.Abort)
|
||||
{
|
||||
Utils.Log("Existing installation at the request of the user, existing mods folder found.");
|
||||
return false;
|
||||
@ -149,7 +146,7 @@ namespace Wabbajack.Lib
|
||||
var hash = gameFile.FileHash();
|
||||
if (hash != esm.SourceESMHash)
|
||||
{
|
||||
Utils.Error("Game ESM hash doesn't match, is the ESM already cleaned? Please verify your local game files.");
|
||||
Utils.Error(new InvalidGameESMError(esm, hash, gameFile));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,43 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Wabbajack.Common.StatusFeed;
|
||||
|
||||
namespace Wabbajack.Lib.StatusMessages
|
||||
{
|
||||
public class ConfirmUpdateOfExistingInstall : AStatusMessage, IUserIntervention
|
||||
{
|
||||
public enum Choice
|
||||
{
|
||||
Continue,
|
||||
Abort
|
||||
}
|
||||
|
||||
public string OutputFolder { get; set; }
|
||||
public string ModListName { get; set; }
|
||||
public override string ShortDescription { get; } = "Do you want to overwrite existing files?";
|
||||
|
||||
private TaskCompletionSource<Choice> _source = new TaskCompletionSource<Choice>();
|
||||
public Task<Choice> Task => _source.Task;
|
||||
|
||||
public override string ExtendedDescription
|
||||
{
|
||||
get =>
|
||||
$@"There appears to be a modlist already installed in the output folder. If you continue with the install,
|
||||
Any files that exist in {OutputFolder} will be changed to match the files found in the {ModListName} modlist. This means that save games will be removed, custom settings
|
||||
will be reverted. Are you sure you wish to continue?";
|
||||
}
|
||||
|
||||
public void Cancel()
|
||||
{
|
||||
_source.SetResult(Choice.Abort);
|
||||
}
|
||||
|
||||
public void Resume()
|
||||
{
|
||||
_source.SetResult(Choice.Continue);
|
||||
}
|
||||
}
|
||||
}
|
@ -77,11 +77,6 @@ namespace Wabbajack.Lib.Validation
|
||||
/// <returns></returns>
|
||||
public Permissions FilePermissions(NexusDownloader.State mod)
|
||||
{
|
||||
if (mod.Author == null || mod.GameName == null || mod.ModID == null || mod.FileID == null)
|
||||
{
|
||||
Utils.Error($"Error: Null data for {mod.Author} {mod.GameName} {mod.ModID} {mod.FileID}");
|
||||
}
|
||||
|
||||
var author_permissions = AuthorPermissions.GetOrDefault(mod.Author)?.Permissions;
|
||||
var game_permissions = AuthorPermissions.GetOrDefault(mod.Author)?.Games.GetOrDefault(mod.GameName)?.Permissions;
|
||||
var mod_permissions = AuthorPermissions.GetOrDefault(mod.Author)?.Games.GetOrDefault(mod.GameName)?.Mods.GetOrDefault(mod.ModID)
|
||||
|
@ -4,6 +4,7 @@ using System.IO;
|
||||
using System.Linq;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using DynamicData;
|
||||
using Microsoft.WindowsAPICodePack.Shell;
|
||||
using Newtonsoft.Json;
|
||||
using Wabbajack.Common;
|
||||
@ -151,6 +152,40 @@ namespace Wabbajack.Lib
|
||||
Error($"Found {duplicates.Count} duplicates, exiting");
|
||||
}
|
||||
|
||||
for (var i = 0; i < AllFiles.Count; i++)
|
||||
{
|
||||
var f = AllFiles[i];
|
||||
if (!f.Path.StartsWith(Consts.GameFolderFilesDir) || !IndexedFiles.ContainsKey(f.Hash))
|
||||
continue;
|
||||
|
||||
if (!IndexedFiles.TryGetValue(f.Hash, out var value))
|
||||
continue;
|
||||
|
||||
var element = value.ElementAt(0);
|
||||
|
||||
if (!f.Path.Contains(element.Name))
|
||||
continue;
|
||||
|
||||
IndexedArchive targetArchive = null;
|
||||
IndexedArchives.Where(a => a.File.Children.Contains(element)).Do(a => targetArchive = a);
|
||||
|
||||
if (targetArchive == null)
|
||||
continue;
|
||||
|
||||
if(targetArchive.IniData?.General?.tag == null || targetArchive.IniData?.General?.tag != Consts.WABBAJACK_VORTEX_MANUAL)
|
||||
continue;
|
||||
|
||||
#if DEBUG
|
||||
Utils.Log($"Double hash for: {f.AbsolutePath}");
|
||||
#endif
|
||||
|
||||
var replace = f;
|
||||
replace.Path = Path.Combine("Manual Game Files", element.FullPath.Substring(DownloadsFolder.Length + 1).Replace('|', '\\'));
|
||||
AllFiles.RemoveAt(i);
|
||||
AllFiles.Insert(i, replace);
|
||||
//AllFiles.Replace(f, replace);
|
||||
}
|
||||
|
||||
var stack = MakeStack();
|
||||
|
||||
Info("Running Compilation Stack");
|
||||
@ -246,7 +281,11 @@ namespace Wabbajack.Lib
|
||||
VortexDeployment.files.Do(f =>
|
||||
{
|
||||
var archive = f.source;
|
||||
if(!ActiveArchives.Contains(archive)) ActiveArchives.Add(archive);
|
||||
if (ActiveArchives.Contains(archive))
|
||||
return;
|
||||
|
||||
Utils.Log($"Adding Archive {archive} to ActiveArchives");
|
||||
ActiveArchives.Add(archive);
|
||||
});
|
||||
}
|
||||
|
||||
@ -314,13 +353,31 @@ namespace Wabbajack.Lib
|
||||
ActiveArchives.Contains(Path.GetFileNameWithoutExtension(f)))
|
||||
return;
|
||||
|
||||
Utils.Log($"File {f} is not in ActiveArchives, checking if the archive is not from the Nexus");
|
||||
Utils.Log($"File {f} is not in ActiveArchives");
|
||||
var lines = File.ReadAllLines(f);
|
||||
if (lines.Length == 0 || !lines.Any(line => line.Contains("directURL=")))
|
||||
return;
|
||||
{
|
||||
if (lines.Length == 0)
|
||||
return;
|
||||
|
||||
Utils.Log($"File {f} appears to not come from the Nexus, adding to ActiveArchives");
|
||||
ActiveArchives.Add(Path.GetFileNameWithoutExtension(f));
|
||||
lines.Do(line =>
|
||||
{
|
||||
var tag = "";
|
||||
if (line.Contains("tag="))
|
||||
tag = line.Substring("tag=".Length);
|
||||
|
||||
if (tag != Consts.WABBAJACK_VORTEX_MANUAL)
|
||||
return;
|
||||
|
||||
Utils.Log($"File {f} contains the {Consts.WABBAJACK_VORTEX_MANUAL} tag, adding to ActiveArchives");
|
||||
ActiveArchives.Add(Path.GetFileNameWithoutExtension(f));
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
Utils.Log($"File {f} appears to not come from the Nexus, adding to ActiveArchives");
|
||||
ActiveArchives.Add(Path.GetFileNameWithoutExtension(f));
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@ -330,6 +387,13 @@ namespace Wabbajack.Lib
|
||||
|
||||
_steamGame.WorkshopItems.Do(item =>
|
||||
{
|
||||
var filePath = Path.Combine(DownloadsFolder, $"steamWorkshopItem_{item.ItemID}.meta");
|
||||
if (File.Exists(filePath))
|
||||
{
|
||||
Utils.Log($"File {filePath} already exists, skipping...");
|
||||
return;
|
||||
}
|
||||
|
||||
Utils.Log($"Creating meta file for {item.ItemID}");
|
||||
var metaString = "[General]\n" +
|
||||
"repository=Steam\n" +
|
||||
@ -338,14 +402,6 @@ namespace Wabbajack.Lib
|
||||
$"steamID={_steamGame.AppId}\n" +
|
||||
$"itemID={item.ItemID}\n" +
|
||||
$"itemSize={item.Size}\n";
|
||||
|
||||
var filePath = Path.Combine(DownloadsFolder, $"steamWorkshopItem_{item.ItemID}.meta");
|
||||
if (File.Exists(filePath))
|
||||
{
|
||||
Utils.Log($"File {filePath} already exists, skipping...");
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
File.WriteAllText(filePath, metaString);
|
||||
|
@ -118,6 +118,9 @@ namespace Wabbajack.Lib
|
||||
ModList.Directives.OfType<InlineFile>()
|
||||
.PMap(Queue,directive =>
|
||||
{
|
||||
if (directive.To.EndsWith(".meta"))
|
||||
return;
|
||||
|
||||
Status($"Writing included file {directive.To}");
|
||||
var outPath = Path.Combine(OutputFolder, directive.To);
|
||||
if(File.Exists(outPath)) File.Delete(outPath);
|
||||
|
@ -86,6 +86,7 @@
|
||||
<Compile Include="AInstaller.cs" />
|
||||
<Compile Include="CerasConfig.cs" />
|
||||
<Compile Include="CompilationSteps\ACompilationStep.cs" />
|
||||
<Compile Include="CompilationSteps\CompilationErrors\InvalidGameESMError.cs" />
|
||||
<Compile Include="CompilationSteps\DeconstructBSAs.cs" />
|
||||
<Compile Include="CompilationSteps\DirectMatch.cs" />
|
||||
<Compile Include="CompilationSteps\DropAll.cs" />
|
||||
@ -139,6 +140,7 @@
|
||||
<Compile Include="NexusApi\NexusApiUtils.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="ReportBuilder.cs" />
|
||||
<Compile Include="StatusMessages\ConfirmUpdateOfExistingInstall.cs" />
|
||||
<Compile Include="UI\UIUtils.cs" />
|
||||
<Compile Include="Validation\DTOs.cs" />
|
||||
<Compile Include="Validation\ValidateModlist.cs" />
|
||||
@ -222,5 +224,6 @@
|
||||
<SubType>Designer</SubType>
|
||||
</Page>
|
||||
</ItemGroup>
|
||||
<ItemGroup />
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
</Project>
|
@ -60,7 +60,7 @@ namespace Wabbajack.Lib
|
||||
merges.Where(m => m.Count() > 1)
|
||||
.Do(m =>
|
||||
{
|
||||
Utils.Warning(
|
||||
Utils.Log(
|
||||
$"WARNING, you have two patches named {m.Key.name}\\{m.Key.filename} in your zEdit profiles. We'll pick one at random, this probably isn't what you want.");
|
||||
});
|
||||
|
||||
|
@ -17,7 +17,7 @@ namespace Wabbajack.Test.ListValidation
|
||||
[ClassInitialize]
|
||||
public static void SetupNexus(TestContext context)
|
||||
{
|
||||
Utils.LogMessages.Subscribe(context.WriteLine);
|
||||
Utils.LogMessages.Subscribe(m => context.WriteLine(m.ToString()));
|
||||
var api = new NexusApiClient();
|
||||
api.ClearUpdatedModsInCache();
|
||||
}
|
||||
@ -27,7 +27,7 @@ namespace Wabbajack.Test.ListValidation
|
||||
public void Setup()
|
||||
{
|
||||
Directory.CreateDirectory(Consts.ModListDownloadFolder);
|
||||
Utils.LogMessages.Subscribe(s => TestContext.WriteLine(s));
|
||||
Utils.LogMessages.Subscribe(s => TestContext.WriteLine(s.ToString()));
|
||||
Queue = new WorkQueue();
|
||||
}
|
||||
|
||||
|
@ -18,7 +18,7 @@ namespace Wabbajack.Test
|
||||
utils = new TestUtils();
|
||||
utils.Game = Game.SkyrimSpecialEdition;
|
||||
|
||||
Utils.LogMessages.Subscribe(f => TestContext.WriteLine(f));
|
||||
Utils.LogMessages.Subscribe(f => TestContext.WriteLine(f.ShortDescription));
|
||||
|
||||
}
|
||||
|
||||
|
@ -22,7 +22,7 @@ namespace Wabbajack.Test
|
||||
Game = Game.DarkestDungeon
|
||||
};
|
||||
|
||||
Utils.LogMessages.Subscribe(f => TestContext.WriteLine(f));
|
||||
Utils.LogMessages.Subscribe(f => TestContext.WriteLine(f.ShortDescription));
|
||||
}
|
||||
|
||||
[TestCleanup]
|
||||
|
@ -30,7 +30,7 @@ namespace Wabbajack.Test
|
||||
utils = new TestUtils();
|
||||
utils.Game = Game.SkyrimSpecialEdition;
|
||||
|
||||
Utils.LogMessages.Subscribe(f => TestContext.WriteLine(f));
|
||||
Utils.LogMessages.Subscribe(f => TestContext.WriteLine(f.ToString()));
|
||||
|
||||
if (!Directory.Exists(DOWNLOAD_FOLDER))
|
||||
Directory.CreateDirectory(DOWNLOAD_FOLDER);
|
||||
|
@ -4,6 +4,7 @@ using System.Linq;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using Wabbajack.Common;
|
||||
using Wabbajack.Lib;
|
||||
using Wabbajack.Lib.CompilationSteps.CompilationErrors;
|
||||
using File = Alphaleonis.Win32.Filesystem.File;
|
||||
using Path = Alphaleonis.Win32.Filesystem.Path;
|
||||
|
||||
@ -127,7 +128,7 @@ namespace Wabbajack.Test
|
||||
// Update the file and verify that it throws an error.
|
||||
utils.GenerateRandomFileData(game_file, 20);
|
||||
var exception = Assert.ThrowsException<AggregateException>(() => Install(compiler));
|
||||
Assert.AreEqual(exception.InnerExceptions.First().Message, "Game ESM hash doesn't match, is the ESM already cleaned? Please verify your local game files.");
|
||||
Assert.IsInstanceOfType(exception.InnerExceptions.First(), typeof(InvalidGameESMError));
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
|
@ -22,7 +22,7 @@ namespace Wabbajack.VirtualFileSystem.Test
|
||||
[TestInitialize]
|
||||
public void Setup()
|
||||
{
|
||||
Utils.LogMessages.Subscribe(f => TestContext.WriteLine(f));
|
||||
Utils.LogMessages.Subscribe(f => TestContext.WriteLine(f.ShortDescription));
|
||||
if (Directory.Exists(VFS_TEST_DIR))
|
||||
Utils.DeleteDirectory(VFS_TEST_DIR);
|
||||
Directory.CreateDirectory(VFS_TEST_DIR);
|
||||
|
@ -8,6 +8,7 @@ using System.Reactive.Disposables;
|
||||
using System.Reactive.Linq;
|
||||
using System.Windows.Media.Imaging;
|
||||
using Wabbajack.Common;
|
||||
using Wabbajack.Common.StatusFeed;
|
||||
using Wabbajack.Lib;
|
||||
|
||||
namespace Wabbajack
|
||||
@ -36,7 +37,7 @@ namespace Wabbajack
|
||||
|
||||
public ObservableCollectionExtended<CPUStatus> StatusList { get; } = new ObservableCollectionExtended<CPUStatus>();
|
||||
|
||||
public ObservableCollectionExtended<string> Log => MWVM.Log;
|
||||
public ObservableCollectionExtended<IStatusMessage> Log => MWVM.Log;
|
||||
|
||||
public IReactiveCommand BackCommand { get; }
|
||||
|
||||
|
@ -17,7 +17,9 @@ using ReactiveUI.Fody.Helpers;
|
||||
using System.Windows.Media;
|
||||
using DynamicData;
|
||||
using DynamicData.Binding;
|
||||
using Wabbajack.Common.StatusFeed;
|
||||
using System.Reactive;
|
||||
using Wabbajack.Common.StatusFeed;
|
||||
|
||||
namespace Wabbajack
|
||||
{
|
||||
@ -72,7 +74,7 @@ namespace Wabbajack
|
||||
public float PercentCompleted => _percentCompleted.Value;
|
||||
|
||||
public ObservableCollectionExtended<CPUStatus> StatusList { get; } = new ObservableCollectionExtended<CPUStatus>();
|
||||
public ObservableCollectionExtended<string> Log => MWVM.Log;
|
||||
public ObservableCollectionExtended<IStatusMessage> Log => MWVM.Log;
|
||||
|
||||
private readonly ObservableAsPropertyHelper<ModManager?> _TargetManager;
|
||||
public ModManager? TargetManager => _TargetManager.Value;
|
||||
|
@ -6,8 +6,11 @@ using System;
|
||||
using System.Linq;
|
||||
using System.Reactive.Disposables;
|
||||
using System.Reactive.Linq;
|
||||
using System.Windows;
|
||||
using Wabbajack.Common;
|
||||
using Wabbajack.Common.StatusFeed;
|
||||
using Wabbajack.Lib;
|
||||
using Wabbajack.Lib.StatusMessages;
|
||||
|
||||
namespace Wabbajack
|
||||
{
|
||||
@ -24,7 +27,7 @@ namespace Wabbajack
|
||||
[Reactive]
|
||||
public ViewModel ActivePane { get; set; }
|
||||
|
||||
public ObservableCollectionExtended<string> Log { get; } = new ObservableCollectionExtended<string>();
|
||||
public ObservableCollectionExtended<IStatusMessage> Log { get; } = new ObservableCollectionExtended<IStatusMessage>();
|
||||
|
||||
public readonly Lazy<CompilerVM> Compiler;
|
||||
public readonly Lazy<InstallerVM> Installer;
|
||||
@ -52,6 +55,10 @@ namespace Wabbajack
|
||||
.Subscribe()
|
||||
.DisposeWith(CompositeDisposable);
|
||||
|
||||
Utils.LogMessages
|
||||
.OfType<ConfirmUpdateOfExistingInstall>()
|
||||
.Subscribe(msg => ConfirmUpdate(msg));
|
||||
|
||||
if (IsStartingFromModlist(out var path))
|
||||
{
|
||||
Installer.Value.ModListLocation.TargetPath = path;
|
||||
@ -64,6 +71,15 @@ namespace Wabbajack
|
||||
}
|
||||
}
|
||||
|
||||
private void ConfirmUpdate(ConfirmUpdateOfExistingInstall msg)
|
||||
{
|
||||
var result = MessageBox.Show(msg.ExtendedDescription, msg.ShortDescription, MessageBoxButton.OKCancel);
|
||||
if (result == MessageBoxResult.OK)
|
||||
msg.Resume();
|
||||
else
|
||||
msg.Cancel();
|
||||
}
|
||||
|
||||
private static bool IsStartingFromModlist(out string modlistPath)
|
||||
{
|
||||
string[] args = Environment.GetCommandLineArgs();
|
||||
|
@ -29,7 +29,7 @@
|
||||
ScrollViewer.HorizontalScrollBarVisibility="Disabled">
|
||||
<ListBox.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<TextBlock Text="{Binding}" TextWrapping="WrapWithOverflow" />
|
||||
<TextBlock Text="{Binding ShortDescription}" TextWrapping="WrapWithOverflow" />
|
||||
</DataTemplate>
|
||||
</ListBox.ItemTemplate>
|
||||
</ListBox>
|
||||
|
Loading…
Reference in New Issue
Block a user