Merge pull request #73 from erri120/ui-stuff

Massive rework by erri120, thanks!
This commit is contained in:
Timothy Baldridge 2019-10-11 10:06:43 -06:00 committed by GitHub
commit 2f35012d03
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
39 changed files with 1013 additions and 433 deletions

View File

@ -2,7 +2,7 @@
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:Wabbajack"
StartupUri="ModeSelectionWindow.xaml"
StartupUri="UI\ModeSelectionWindow.xaml"
ShutdownMode="OnExplicitShutdown">
<Application.Resources>
<ResourceDictionary>

View File

@ -1,5 +1,4 @@
using System;
using System.Runtime.InteropServices;
using System.Windows;
using Wabbajack.Common;
using Wabbajack.Updater;
@ -16,8 +15,8 @@ namespace Wabbajack
var args = Environment.GetCommandLineArgs();
if (args.Length > 1)
{
Utils.SetLoggerFn(f => {});
WorkQueue.Init((a, b, c) => {}, (a, b) => {});
Utils.SetLoggerFn(f => { });
WorkQueue.Init((a, b, c) => { }, (a, b) => { });
var updater = new CheckForUpdates(args[1]);
if (updater.FindOutdatedMods())
{

View File

@ -4,6 +4,7 @@ using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Diagnostics;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Net.Http;
using System.Reflection;
@ -14,11 +15,19 @@ using System.Windows.Media.Imaging;
using System.Windows.Threading;
using Wabbajack.Common;
using Wabbajack.NexusApi;
using Wabbajack.UI;
namespace Wabbajack
{
public enum TaskMode { INSTALLING, BUILDING }
internal class AppState : ViewModel, IDataErrorInfo
{
public const bool GcCollect = true;
private SlideShow _slideShow;
public bool installing = false;
private string _mo2Folder;
private ModList _modList;
@ -27,18 +36,16 @@ namespace Wabbajack
public volatile bool Dirty;
private readonly Dispatcher dispatcher;
public readonly Dispatcher dispatcher;
public AppState(Dispatcher d, string mode)
public AppState(Dispatcher d, TaskMode mode)
{
var image = new BitmapImage();
image.BeginInit();
image.StreamSource = Assembly.GetExecutingAssembly().GetManifestResourceStream("Wabbajack.banner.png");
image.EndInit();
_wabbajackLogo = image;
_splashScreenImage = image;
_wabbajackLogo = UIUtils.BitmapImageFromResource("Wabbajack.UI.banner.png");
_splashScreenImage = _wabbajackLogo;
_noneImage = UIUtils.BitmapImageFromResource("Wabbajack.UI.none.jpg");
_nextIcon = UIUtils.BitmapImageFromResource("Wabbajack.UI.Icons.next.png");
SetupSlideshow();
_slideShow = new SlideShow(this, true);
if (Assembly.GetEntryAssembly().Location.ToLower().Contains("\\downloads\\"))
{
@ -57,30 +64,21 @@ namespace Wabbajack
Dirty = false;
dispatcher = d;
var th = new Thread(() => UpdateLoop());
th.Priority = ThreadPriority.BelowNormal;
th.IsBackground = true;
th.Start();
}
private void SetupSlideshow()
{
var files = NexusApiClient.CachedSlideShow;
if (files.Any())
slideshowThread = new Thread(UpdateLoop)
{
SlideShowElements = files.ToList();
}
Priority = ThreadPriority.BelowNormal,
IsBackground = true
};
slideshowThread.Start();
}
public Random _random = new Random();
public List<SlideShowItem> SlideShowElements = new List<SlideShowItem>();
private DateTime _lastSlideShowUpdate = new DateTime();
public ObservableCollection<string> Log { get; } = new ObservableCollection<string>();
public ObservableCollection<CPUStatus> Status { get; } = new ObservableCollection<CPUStatus>();
private string _Mode;
public string Mode { get => _Mode; set => this.RaiseAndSetIfChanged(ref _Mode, value); }
private TaskMode _Mode;
public TaskMode Mode { get => _Mode; set => this.RaiseAndSetIfChanged(ref _Mode, value); }
private string _ModListName;
public string ModListName { get => _ModListName; set => this.RaiseAndSetIfChanged(ref _ModListName, value); }
@ -108,8 +106,8 @@ namespace Wabbajack
}
}
private int _QueueProgress;
public int QueueProgress { get => _QueueProgress; set => this.RaiseAndSetIfChanged(ref _QueueProgress, value); }
private int _queueProgress;
public int QueueProgress { get => _queueProgress; set => this.RaiseAndSetIfChanged(ref _queueProgress, value); }
private List<CPUStatus> InternalStatus { get; } = new List<CPUStatus>();
public string LogFile { get; }
@ -119,7 +117,7 @@ namespace Wabbajack
{
get
{
if (_changePath == null) _changePath = new LambdaCommand(() => true, () => ExecuteChangePath());
if (_changePath == null) _changePath = new LambdaCommand(() => true, ExecuteChangePath);
return _changePath;
}
}
@ -130,7 +128,7 @@ namespace Wabbajack
get
{
if (_changeDownloadPath == null)
_changeDownloadPath = new LambdaCommand(() => true, () => ExecuteChangeDownloadPath());
_changeDownloadPath = new LambdaCommand(() => true, ExecuteChangeDownloadPath);
return _changeDownloadPath;
}
}
@ -140,7 +138,7 @@ namespace Wabbajack
{
get
{
if (_begin == null) _begin = new LambdaCommand(() => true, () => ExecuteBegin());
if (_begin == null) _begin = new LambdaCommand(() => true, ExecuteBegin);
return _begin;
}
}
@ -150,8 +148,7 @@ namespace Wabbajack
{
get
{
if (_showReportCommand == null) _showReportCommand = new LambdaCommand(() => true, () => ShowReport());
return _showReportCommand;
return _showReportCommand ?? (_showReportCommand = new LambdaCommand(() => true, ShowReport));
}
}
@ -160,13 +157,58 @@ namespace Wabbajack
{
get
{
if (_visitNexusSiteCommand == null) _visitNexusSiteCommand = new LambdaCommand(() => true, () => VisitNexusSite());
return _visitNexusSiteCommand;
return _visitNexusSiteCommand ??
(_visitNexusSiteCommand = new LambdaCommand(() => true, VisitNexusSite));
}
}
public string _nexusSiteURL = null;
public ICommand OpenModListPropertiesCommand
{
get
{
return new LambdaCommand(() => true, OpenModListProperties);
}
}
public ICommand SlideShowNextItem
{
get
{
return new LambdaCommand(() => true, _slideShow.UpdateSlideShowItem);
}
}
private void ExecuteChangePath()
{
if (Mode == TaskMode.INSTALLING)
{
var folder = UIUtils.ShowFolderSelectionDialog("Select Installation directory");
if (folder == null) return;
Location = folder;
if (DownloadLocation == null)
DownloadLocation = Path.Combine(Location, "downloads");
}
else
{
var folder = UIUtils.ShowFolderSelectionDialog("Select Your MO2 profile directory");
Location = folder;
}
}
private void ExecuteChangeDownloadPath()
{
var folder = UIUtils.ShowFolderSelectionDialog("Select a location for MO2 downloads");
if (folder != null) DownloadLocation = folder;
}
private void ShowReport()
{
var file = Path.GetTempFileName() + ".html";
File.WriteAllText(file, HTMLReport);
Process.Start(file);
}
public string _nexusSiteURL = null;
private void VisitNexusSite()
{
if (_nexusSiteURL != null && _nexusSiteURL.StartsWith("https://"))
@ -175,6 +217,64 @@ namespace Wabbajack
}
}
private ModlistPropertiesWindow modlistPropertiesWindow;
public string newImagePath;
public string readmePath;
public bool ChangedProperties;
private void OpenModListProperties()
{
if (UIReady)
{
if (modlistPropertiesWindow == null)
{
modlistPropertiesWindow = new ModlistPropertiesWindow(this);
newImagePath = null;
ChangedProperties = false;
}
if(!modlistPropertiesWindow.IsClosed)
modlistPropertiesWindow.Show();
else
{
modlistPropertiesWindow = null;
OpenModListProperties();
}
}
}
public bool HasReadme { get; set; }
public ICommand OpenReadme
{
get
{
return new LambdaCommand(()=> true,OpenReadmeWindow);
}
}
private void OpenReadmeWindow()
{
if (!UIReady || string.IsNullOrEmpty(_modList.Readme)) return;
var text = "";
using (var fs = new FileStream(_modListPath, FileMode.Open, FileAccess.Read, FileShare.Read))
using (var ar = new ZipArchive(fs, ZipArchiveMode.Read))
using (var ms = new MemoryStream())
{
var entry = ar.GetEntry(_modList.Readme);
using (var e = entry.Open())
e.CopyTo(ms);
ms.Seek(0, SeekOrigin.Begin);
using (var sr = new StreamReader(ms))
{
string line;
while ((line = sr.ReadLine()) != null)
text += line+Environment.NewLine;
//text = sr.ReadToEnd();
}
}
var viewer = new TextViewer(text, _ModListName);
viewer.Show();
}
private bool _uiReady = false;
public bool UIReady
@ -183,7 +283,8 @@ namespace Wabbajack
set => this.RaiseAndSetIfChanged(ref _uiReady, value);
}
private BitmapImage _wabbajackLogo = null;
private readonly BitmapImage _wabbajackLogo = null;
public readonly BitmapImage _noneImage = null;
private BitmapImage _splashScreenImage = null;
public BitmapImage SplashScreenImage
{
@ -197,6 +298,8 @@ namespace Wabbajack
private string _SplashScreenModName = "Wabbajack";
public string SplashScreenModName { get => _SplashScreenModName; set => this.RaiseAndSetIfChanged(ref _SplashScreenModName, value); }
private BitmapImage _nextIcon = null;
public BitmapImage NextIcon { get => _nextIcon; set => this.RaiseAndSetIfChanged(ref _nextIcon, value); }
private string _SplashScreenAuthorName = "Halgari & the Wabbajack Team";
public string SplashScreenAuthorName { get => _SplashScreenAuthorName; set => this.RaiseAndSetIfChanged(ref _SplashScreenAuthorName, value); }
@ -205,6 +308,27 @@ namespace Wabbajack
private string _SplashScreenSummary;
public string SplashScreenSummary { get => _SplashScreenSummary; set => this.RaiseAndSetIfChanged(ref _SplashScreenSummary, value); }
private bool _splashShowNSFW = true;
public bool SplashShowNSFW { get => _splashShowNSFW; set => this.RaiseAndSetIfChanged(ref _splashShowNSFW, value); }
private readonly Thread slideshowThread = null;
private bool _enableSlideShow = true;
public bool EnableSlideShow
{
get => _enableSlideShow;
set
{
RaiseAndSetIfChanged(ref _enableSlideShow, value);
if (!slideshowThread.IsAlive) return;
if (!_enableSlideShow)
{
ApplyModlistProperties();
}
else
{
_slideShow.UpdateSlideShowItem();
}
}
}
public string Error => "Error";
@ -220,23 +344,22 @@ namespace Wabbajack
{
validationMessage = null;
}
else if (Mode == "Building" && Location != null && Directory.Exists(Location) && File.Exists(Path.Combine(Location, "modlist.txt")))
else switch (Mode)
{
Location = Path.Combine(Location, "modlist.txt");
validationMessage = null;
ConfigureForBuild();
}
else if (Mode == "Installing" && Location != null && Directory.Exists(Location) && !Directory.EnumerateFileSystemEntries(Location).Any())
{
validationMessage = null;
}
else if (Mode == "Installing" && Location != null && Directory.Exists(Location) && Directory.EnumerateFileSystemEntries(Location).Any())
{
validationMessage = "You have selected a non-empty directory. Installing the modlist here might result in a broken install!";
}
else
{
validationMessage = "Invalid Mod Organizer profile directory";
case TaskMode.BUILDING when Location != null && Directory.Exists(Location) && File.Exists(Path.Combine(Location, "modlist.txt")):
Location = Path.Combine(Location, "modlist.txt");
validationMessage = null;
ConfigureForBuild();
break;
case TaskMode.INSTALLING when Location != null && Directory.Exists(Location) && !Directory.EnumerateFileSystemEntries(Location).Any():
validationMessage = null;
break;
case TaskMode.INSTALLING when Location != null && Directory.Exists(Location) && Directory.EnumerateFileSystemEntries(Location).Any():
validationMessage = "You have selected a non-empty directory. Installing the modlist here might result in a broken install!";
break;
default:
validationMessage = "Invalid Mod Organizer profile directory";
break;
}
break;
}
@ -250,7 +373,7 @@ namespace Wabbajack
if (Dirty)
lock (InternalStatus)
{
var data = InternalStatus.ToArray();
CPUStatus[] data = InternalStatus.ToArray();
dispatcher.Invoke(() =>
{
for (var idx = 0; idx < data.Length; idx += 1)
@ -262,69 +385,48 @@ namespace Wabbajack
Dirty = false;
}
if (SlideShowElements.Any())
if (_slideShow.SlidesQueue.Any())
{
if (DateTime.Now - _lastSlideShowUpdate > TimeSpan.FromSeconds(10))
{
var idx = _random.Next(0, SlideShowElements.Count);
try
{
var element = SlideShowElements[idx];
var data = new MemoryStream();
using (var stream = new HttpClient().GetStreamSync("asdas" + element.ImageURL))
stream.CopyTo(data);
data.Seek(0, SeekOrigin.Begin);
dispatcher.Invoke(() =>
{
var bitmap = new BitmapImage();
bitmap.BeginInit();
bitmap.CacheOption = BitmapCacheOption.OnLoad;
bitmap.StreamSource = data;
bitmap.EndInit();
SplashScreenImage = bitmap;
SplashScreenModName = element.ModName;
SplashScreenAuthorName = element.AuthorName;
SplashScreenSummary = element.ModSummary;
_nexusSiteURL = element.ModURL;
_lastSlideShowUpdate = DateTime.Now;
});
}
catch (Exception ex)
{
}
_slideShow.UpdateSlideShowItem();
}
}
Thread.Sleep(1000);
Thread.Sleep(10000);
}
}
public bool Running { get; set; } = true;
internal void ConfigureForInstall(string source, ModList modlist)
private void ApplyModlistProperties()
{
_modList = modlist;
_modListPath = source;
Mode = "Installing";
ModListName = _modList.Name;
HTMLReport = _modList.ReportHTML;
Location = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
SlideShowElements = modlist.Archives.OfType<NexusMod>().Select(m => new SlideShowItem
SplashScreenModName = _modList.Name;
SplashScreenAuthorName = _modList.Author;
_nexusSiteURL = _modList.Website;
SplashScreenSummary = _modList.Description;
if (!string.IsNullOrEmpty(_modList.Image) && _modList.Image.Length == 36)
{
ModName = NexusApiUtils.FixupSummary(m.ModName),
AuthorName = NexusApiUtils.FixupSummary(m.Author),
ModSummary = NexusApiUtils.FixupSummary(m.Summary),
ImageURL = m.SlideShowPic,
ModURL = m.NexusURL,
}).ToList();
SplashScreenImage = _wabbajackLogo;
using (var fs = new FileStream(_modListPath, FileMode.Open, FileAccess.Read, FileShare.Read))
using (var ar = new ZipArchive(fs, ZipArchiveMode.Read))
using (var ms = new MemoryStream())
{
var entry = ar.GetEntry(_modList.Image);
using (var e = entry.Open())
e.CopyTo(ms);
var image = new BitmapImage();
image.BeginInit();
image.CacheOption = BitmapCacheOption.OnLoad;
image.StreamSource = ms;
image.EndInit();
image.Freeze();
SplashScreenImage = image;
}
}
else
{
SplashScreenImage = _wabbajackLogo;
}
}
public void LogMsg(string msg)
@ -351,31 +453,6 @@ namespace Wabbajack
QueueProgress = total;
}
private void ExecuteChangePath()
{
if (Mode == "Installing")
{
var folder = UIUtils.ShowFolderSelectionDialog("Select Installation directory");
if (folder != null)
{
Location = folder;
if (DownloadLocation == null)
DownloadLocation = Path.Combine(Location, "downloads");
}
}
else
{
var folder = UIUtils.ShowFolderSelectionDialog("Select Your MO2 profile directory");
Location = folder;
}
}
private void ExecuteChangeDownloadPath()
{
var folder = UIUtils.ShowFolderSelectionDialog("Select a location for MO2 downloads");
if (folder != null) DownloadLocation = folder;
}
private void ConfigureForBuild()
{
var profile_folder = Path.GetDirectoryName(Location);
@ -385,7 +462,7 @@ namespace Wabbajack
var profile_name = Path.GetFileName(profile_folder);
ModListName = profile_name;
Mode = "Building";
Mode = TaskMode.BUILDING;
var tmp_compiler = new Compiler(mo2folder);
DownloadLocation = tmp_compiler.MO2DownloadsFolder;
@ -393,21 +470,37 @@ namespace Wabbajack
_mo2Folder = mo2folder;
}
private void ShowReport()
internal void ConfigureForInstall(string source, ModList modlist)
{
var file = Path.GetTempFileName() + ".html";
File.WriteAllText(file, HTMLReport);
Process.Start(file);
_modList = modlist;
_modListPath = source;
HasReadme = !string.IsNullOrEmpty(_modList.Readme);
Mode = TaskMode.INSTALLING;
ModListName = _modList.Name;
HTMLReport = _modList.ReportHTML;
Location = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
ApplyModlistProperties();
_slideShow.SlideShowElements = modlist.Archives.OfType<NexusMod>().Select(m =>
new Slide(NexusApiUtils.FixupSummary(m.ModName),m.ModID,
NexusApiUtils.FixupSummary(m.Summary), NexusApiUtils.FixupSummary(m.Author),
m.Adult,m.NexusURL,m.SlideShowPic)).ToList();
_slideShow.PreloadSlideShow();
}
private void ExecuteBegin()
{
UIReady = false;
if (Mode == "Installing")
if (Mode == TaskMode.INSTALLING)
{
var installer = new Installer(_modListPath, _modList, Location);
installer.DownloadFolder = DownloadLocation;
installing = true;
var installer = new Installer(_modListPath, _modList, Location)
{
DownloadFolder = DownloadLocation
};
var th = new Thread(() =>
{
UIReady = false;
@ -425,15 +518,28 @@ namespace Wabbajack
finally
{
UIReady = true;
Running = false;
installing = false;
slideshowThread.Abort();
}
});
th.Priority = ThreadPriority.BelowNormal;
})
{
Priority = ThreadPriority.BelowNormal
};
th.Start();
}
else if (_mo2Folder != null)
{
var compiler = new Compiler(_mo2Folder);
compiler.MO2Profile = ModListName;
var compiler = new Compiler(_mo2Folder)
{
MO2Profile = ModListName,
ModListName = ChangedProperties ? SplashScreenModName : null,
ModListAuthor = ChangedProperties ? SplashScreenAuthorName : null,
ModListDescription = ChangedProperties ? SplashScreenSummary : null,
ModListImage = ChangedProperties ? newImagePath : null,
ModListWebsite = ChangedProperties ? _nexusSiteURL : null,
ModListReadme = ChangedProperties ? readmePath : null
};
var th = new Thread(() =>
{
UIReady = false;
@ -454,8 +560,10 @@ namespace Wabbajack
{
UIReady = true;
}
});
th.Priority = ThreadPriority.BelowNormal;
})
{
Priority = ThreadPriority.BelowNormal
};
th.Start();
}
else

View File

@ -21,7 +21,7 @@ namespace Wabbajack
public static bool GetScrollOnNewItem(DependencyObject obj)
{
return (bool) obj.GetValue(ScrollOnNewItemProperty);
return (bool)obj.GetValue(ScrollOnNewItemProperty);
}
public static void SetScrollOnNewItem(DependencyObject obj, bool value)
@ -35,7 +35,7 @@ namespace Wabbajack
{
var listBox = d as ListBox;
if (listBox == null) return;
bool oldValue = (bool) e.OldValue, newValue = (bool) e.NewValue;
bool oldValue = (bool)e.OldValue, newValue = (bool)e.NewValue;
if (newValue == oldValue) return;
if (newValue)
{
@ -57,7 +57,7 @@ namespace Wabbajack
private static void ListBox_ItemsSourceChanged(object sender, EventArgs e)
{
var listBox = (ListBox) sender;
var listBox = (ListBox)sender;
if (Associations.ContainsKey(listBox))
Associations[listBox].Dispose();
Associations[listBox] = new Capture(listBox);
@ -65,7 +65,7 @@ namespace Wabbajack
private static void ListBox_Unloaded(object sender, RoutedEventArgs e)
{
var listBox = (ListBox) sender;
var listBox = (ListBox)sender;
if (Associations.ContainsKey(listBox))
Associations[listBox].Dispose();
listBox.Unloaded -= ListBox_Unloaded;
@ -73,7 +73,7 @@ namespace Wabbajack
private static void ListBox_Loaded(object sender, RoutedEventArgs e)
{
var listBox = (ListBox) sender;
var listBox = (ListBox)sender;
var incc = listBox.Items as INotifyCollectionChanged;
if (incc == null) return;
listBox.Loaded -= ListBox_Loaded;

View File

@ -1,20 +1,16 @@
using System;
using CommonMark;
using Compression.BSA;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Reflection;
using System.Runtime.Serialization.Formatters.Binary;
using System.Text;
using System.Text.RegularExpressions;
using System.Web;
using CommonMark;
using Compression.BSA;
using K4os.Compression.LZ4;
using K4os.Compression.LZ4.Streams;
using Newtonsoft.Json;
using System.IO.Compression;
using VFS;
using Wabbajack.Common;
using Wabbajack.NexusApi;
@ -37,12 +33,13 @@ namespace Wabbajack
public string MO2Profile;
public string ModListName, ModListAuthor, ModListDescription, ModListWebsite, ModListImage, ModListReadme;
public Compiler(string mo2_folder)
{
MO2Folder = mo2_folder;
MO2Ini = Path.Combine(MO2Folder, "ModOrganizer.ini").LoadIniFile();
GamePath = ((string) MO2Ini.General.gamePath).Replace("\\\\", "\\");
GamePath = ((string)MO2Ini.General.gamePath).Replace("\\\\", "\\");
}
public dynamic MO2Ini { get; }
@ -143,12 +140,12 @@ namespace Wabbajack
var mo2_files = Directory.EnumerateFiles(MO2Folder, "*", SearchOption.AllDirectories)
.Where(p => p.FileExists())
.Select(p => new RawSourceFile(VFS.Lookup(p)) {Path = p.RelativeTo(MO2Folder)});
.Select(p => new RawSourceFile(VFS.Lookup(p)) { Path = p.RelativeTo(MO2Folder) });
var game_files = Directory.EnumerateFiles(GamePath, "*", SearchOption.AllDirectories)
.Where(p => p.FileExists())
.Select(p => new RawSourceFile(VFS.Lookup(p))
{Path = Path.Combine(Consts.GameFolderFilesDir, p.RelativeTo(GamePath))});
{ Path = Path.Combine(Consts.GameFolderFilesDir, p.RelativeTo(GamePath)) });
var loot_path = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData),
"LOOT");
@ -163,7 +160,7 @@ namespace Wabbajack
loot_files = Directory.EnumerateFiles(loot_path, "userlist.yaml", SearchOption.AllDirectories)
.Where(p => p.FileExists())
.Select(p => new RawSourceFile(VFS.Lookup(p))
{ Path = Path.Combine(Consts.LOOTFolderFilesDir, p.RelativeTo(loot_path)) });
{ Path = Path.Combine(Consts.LOOTFolderFilesDir, p.RelativeTo(loot_path)) });
}
@ -280,7 +277,12 @@ namespace Wabbajack
GameType = GameRegistry.Games.Values.First(f => f.MO2Name == MO2Ini.General.gameName).Game,
Archives = SelectedArchives,
Directives = InstallDirectives,
Name = MO2Profile
Name = ModListName ?? MO2Profile,
Author = ModListAuthor ?? "",
Description = ModListDescription ?? "",
Readme = ModListReadme ?? "",
Image = ModListImage ?? "",
Website = ModListWebsite ?? ""
};
ValidateModlist.RunValidation(ModList);
@ -358,8 +360,8 @@ namespace Wabbajack
}
}
ModList.ReportHTML = "<style>"+css+"</style>"
+CommonMarkConverter.Convert(File.ReadAllText($"{ModList.Name}.md"));
ModList.ReportHTML = "<style>" + css + "</style>"
+ CommonMarkConverter.Convert(File.ReadAllText($"{ModList.Name}.md"));
}
/// <summary>
@ -485,7 +487,7 @@ namespace Wabbajack
}
else if (general.directURL != null && general.directURL.StartsWith("https://www.dropbox.com/"))
{
var uri = new UriBuilder((string) general.directURL);
var uri = new UriBuilder((string)general.directURL);
var query = HttpUtility.ParseQueryString(uri.Query);
if (query.GetValues("dl").Count() > 0)
@ -548,6 +550,7 @@ namespace Wabbajack
nm.SlideShowPic = info.picture_url;
nm.NexusURL = NexusApiUtils.GetModURL(info.game_name, info.mod_id);
nm.Summary = info.summary;
nm.Adult = info.contains_adult_content;
result = nm;
}
@ -612,6 +615,7 @@ namespace Wabbajack
Info("Generating compilation stack");
return new List<Func<RawSourceFile, Directive>>
{
IncludePropertyFiles(),
IgnoreStartsWith("logs\\"),
IncludeRegex("^downloads\\\\.*\\.meta"),
IgnoreStartsWith("downloads\\"),
@ -668,6 +672,34 @@ namespace Wabbajack
};
}
private Func<RawSourceFile, Directive> IncludePropertyFiles()
{
return source =>
{
var files = new HashSet<string>
{
ModListImage, ModListReadme
};
if (!files.Any(f => source.AbsolutePath.Equals(f))) return null;
if (!File.Exists(source.AbsolutePath)) return null;
var isBanner = source.AbsolutePath == ModListImage;
//var isReadme = source.AbsolutePath == ModListReadme;
var result = source.EvolveTo<PropertyFile>();
result.SourceDataID = IncludeFile(File.ReadAllBytes(source.AbsolutePath));
if (isBanner)
{
result.Type = PropertyType.Banner;
ModListImage = result.SourceDataID;
}
else
{
result.Type = PropertyType.Readme;
ModListReadme = result.SourceDataID;
}
return result;
};
}
private Func<RawSourceFile, Directive> IgnoreWabbajackInstallCruft()
{
var cruft_files = new HashSet<string>
@ -933,9 +965,9 @@ namespace Wabbajack
{
To = source.Path,
TempID = id,
Type = (uint) bsa.HeaderType,
FileFlags = (uint) bsa.FileFlags,
ArchiveFlags = (uint) bsa.ArchiveFlags
Type = (uint)bsa.HeaderType,
FileFlags = (uint)bsa.FileFlags,
ArchiveFlags = (uint)bsa.ArchiveFlags
};
}
@ -1081,8 +1113,8 @@ namespace Wabbajack
{
var lines = File.ReadAllLines(absolutePath);
lines = (from line in lines
where !(line.StartsWith("-") && !line.EndsWith("_separator"))
select line).ToArray();
where !(line.StartsWith("-") && !line.EndsWith("_separator"))
select line).ToArray();
return Encoding.UTF8.GetBytes(string.Join("\r\n", lines));
}

View File

@ -1,6 +1,6 @@
using System;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using Newtonsoft.Json;
using VFS;
using Wabbajack.Common;
@ -54,6 +54,31 @@ namespace Wabbajack
/// </summary>
public string Name;
/// <summary>
/// Author of the ModList
/// </summary>
public string Author;
/// <summary>
/// Description of the ModList
/// </summary>
public string Description;
/// <summary>
/// Hash of the banner-image
/// </summary>
public string Image;
/// <summary>
/// Website of the ModList
/// </summary>
public string Website;
/// <summary>
/// Hash of the readme
/// </summary>
public string Readme;
/// <summary>
/// Content Report in HTML form
/// </summary>
@ -91,6 +116,17 @@ namespace Wabbajack
public string SourceDataID;
}
public enum PropertyType { Banner, Readme }
/// <summary>
/// File meant to be extracted before the installation
/// </summary>
[Serializable]
public class PropertyFile : InlineFile
{
public PropertyType Type;
}
[Serializable]
public class CleanedESM : InlineFile
{
@ -202,6 +238,7 @@ namespace Wabbajack
public string ModName;
public string NexusURL;
public string Summary;
public bool Adult;
}
[Serializable]

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.0 KiB

View File

@ -1,18 +1,14 @@
using System;
using CG.Web.MegaApiClient;
using Compression.BSA;
using System;
using System.Collections.Generic;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Net.Http;
using System.Reflection;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
using System.Text;
using System.Text.RegularExpressions;
using System.Windows;
using CG.Web.MegaApiClient;
using Compression.BSA;
using K4os.Compression.LZ4.Streams;
using System.IO.Compression;
using VFS;
using Wabbajack.Common;
using Wabbajack.NexusApi;
@ -76,7 +72,7 @@ namespace Wabbajack
private byte[] LoadBytesFromPath(string path)
{
using (var fs = new FileStream(ModListArchive, FileMode.Open, FileAccess.Read, FileShare.Read))
using (var ar = new ZipArchive(fs,ZipArchiveMode.Read))
using (var ar = new ZipArchive(fs, ZipArchiveMode.Read))
using (var ms = new MemoryStream())
{
var entry = ar.GetEntry(path);
@ -218,7 +214,7 @@ namespace Wabbajack
{
HashedArchives.Do(a => VFS.AddKnown(new VirtualFile
{
Paths = new[] {a.Value},
Paths = new[] { a.Value },
Hash = a.Key
}));
VFS.RefreshIndexes();
@ -231,7 +227,7 @@ namespace Wabbajack
var updated_path = new string[f.ArchiveHashPath.Length];
f.ArchiveHashPath.CopyTo(updated_path, 0);
updated_path[0] = VFS.HashIndex[updated_path[0]].Where(e => e.IsConcrete).First().FullPath;
VFS.AddKnown(new VirtualFile {Paths = updated_path});
VFS.AddKnown(new VirtualFile { Paths = updated_path });
});
VFS.BackfillMissing();
@ -254,9 +250,9 @@ namespace Wabbajack
using (var a = new BSABuilder())
{
//a.Create(Path.Combine(Outputfolder, bsa.To), (bsa_archive_type_t)bsa.Type, entries);
a.HeaderType = (VersionType) bsa.Type;
a.FileFlags = (FileFlags) bsa.FileFlags;
a.ArchiveFlags = (ArchiveFlags) bsa.ArchiveFlags;
a.HeaderType = (VersionType)bsa.Type;
a.FileFlags = (FileFlags)bsa.FileFlags;
a.ArchiveFlags = (ArchiveFlags)bsa.ArchiveFlags;
source_files.PMap(f =>
{
@ -292,9 +288,9 @@ namespace Wabbajack
var out_path = Path.Combine(Outputfolder, directive.To);
if (File.Exists(out_path)) File.Delete(out_path);
if (directive is RemappedInlineFile)
WriteRemappedFile((RemappedInlineFile) directive);
WriteRemappedFile((RemappedInlineFile)directive);
else if (directive is CleanedESM)
GenerateCleanedESM((CleanedESM) directive);
GenerateCleanedESM((CleanedESM)directive);
else
File.WriteAllBytes(out_path, LoadBytesFromPath(directive.SourceDataID));
});
@ -362,7 +358,7 @@ namespace Wabbajack
.GroupBy(e => e.ArchiveHashPath[0])
.ToDictionary(k => k.Key);
var archives = ModList.Archives
.Select(a => new {Archive = a, AbsolutePath = HashedArchives.GetOrDefault(a.Hash)})
.Select(a => new { Archive = a, AbsolutePath = HashedArchives.GetOrDefault(a.Hash) })
.Where(a => a.AbsolutePath != null)
.ToList();

View File

@ -1,119 +0,0 @@
<Window x:Class="Wabbajack.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:Wabbajack"
mc:Ignorable="d"
Title="Wabbajack" Height="960" Width="1448"
Style="{StaticResource {x:Type Window}}" Icon="square_transparent_icon.ico" WindowStyle="ToolWindow"
ResizeMode="NoResize"
Closing="Window_Closing">
<Grid Margin="16">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="460"/>
<RowDefinition Height="10" />
<RowDefinition Height="Auto" />
<RowDefinition />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="700"></ColumnDefinition>
<ColumnDefinition Width="700"></ColumnDefinition>
</Grid.ColumnDefinitions>
<StackPanel Grid.Row="0" Orientation="Horizontal" Margin="0, 16, 0, 16">
<TextBlock Text="{Binding Mode}" FontSize="16" FontWeight="Bold" />
<TextBlock Text=" : " FontSize="16" />
<TextBlock Text="{Binding ModListName}" FontSize="16" />
</StackPanel>
<!-- Slideshow -->
<Image Grid.Row="1" Grid.Column="0" Source="{Binding SplashScreenImage}" Stretch="Uniform" Margin="5"></Image>
<Grid Grid.Row="1" Grid.Column="1" Margin="5">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"></RowDefinition>
<RowDefinition Height="Auto"></RowDefinition>
<RowDefinition Height="*"></RowDefinition>
<RowDefinition Height="Auto"></RowDefinition>
</Grid.RowDefinitions>
<TextBlock Text="{Binding SplashScreenModName}" Grid.Row="0" FontSize="30" FontWeight="Bold"></TextBlock>
<TextBlock Text="{Binding SplashScreenAuthorName}" Grid.Row="1" FontSize="15" FontWeight="Bold"></TextBlock>
<TextBlock Text="{Binding SplashScreenSummary}" TextWrapping="Wrap" Grid.Row="2" FontSize="15" FontWeight="Bold"></TextBlock>
<Button Height="30" Grid.Row="3" Grid.Column="1" Command="{Binding VisitNexusSiteCommand}">
<TextBlock Text="View Nexus Site" FontSize="15" FontWeight="Bold"></TextBlock>
</Button>
</Grid>
<!-- End Slideshow-->
<TextBlock Text="Log:" Grid.Row="3" FontSize="14" Margin="0, 16, 0, 8" />
<ListBox local:AutoScrollBehavior.ScrollOnNewItem="True" Grid.Row="4" ItemsSource="{Binding Log}" />
<Grid HorizontalAlignment="Stretch" Grid.Row="5" Grid.Column="0" Grid.RowSpan="2" Margin="10">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition MinHeight="10" />
<RowDefinition />
</Grid.RowDefinitions>
<Label Grid.Row="0" Content="{Binding LocationLabel}" Grid.Column="0" />
<TextBox Grid.Row="0" Grid.Column="1" Text="{Binding Location, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True, NotifyOnValidationError=True}" IsEnabled="{Binding UIReady}"/>
<Button Grid.Row="0" Content="Select" MinWidth="80" Grid.Column="2" Command="{Binding ChangePath}" IsEnabled="{Binding UIReady}"/>
<Label Grid.Row="2" Content="Download Location:" Grid.Column="0" />
<TextBox Grid.Row="2" Grid.Column="1" Text="{Binding DownloadLocation}" IsEnabled="{Binding UIReady}"/>
<Button Grid.Row="2" Content="Select" MinWidth="80" Grid.Column="2" Command="{Binding ChangeDownloadPath}" IsEnabled="{Binding UIReady}"/>
</Grid>
<!-- Work Queue Start -->
<ProgressBar Grid.Row="2" Grid.Column="0" Grid.ColumnSpan="2" Value="{Binding QueueProgress}" Minimum="0" Maximum="100" Background="#444444" />
<TextBlock Text="Work Queue:" Grid.Row="3" Grid.Column="1" FontSize="14" Margin="0, 16, 0, 8" />
<ListBox Grid.Row="4" Grid.Column="1" ItemsSource="{Binding Status}" Width="Auto" HorizontalAlignment="Stretch">
<ListBox.ItemTemplate>
<DataTemplate>
<Grid HorizontalAlignment="Stretch">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<ProgressBar Minimum="0" Maximum="100" Value="{Binding Progress, Mode=OneTime}" Width="100"
Grid.Column="0">
<ProgressBar.Style>
<Style TargetType="ProgressBar">
<Setter Property="Visibility" Value="Visible" />
<Style.Triggers>
<DataTrigger Binding="{Binding Progress}" Value="0">
<Setter Property="Visibility" Value="Collapsed" />
</DataTrigger>
</Style.Triggers>
</Style>
</ProgressBar.Style>
</ProgressBar>
<TextBlock Text=" CPU " Grid.Column="1" />
<TextBlock Text="{Binding ID}" Grid.Column="2" />
<TextBlock Text=" - " Grid.Column="3" />
<TextBlock Text="{Binding Msg}" Grid.Column="4" />
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<!-- Work Queue End-->
<Button Content="View Modlist Contents" Grid.Row="5" Grid.Column="1" Height="30" Visibility="{Binding ShowReportButton}"
Command="{Binding ShowReportCommand}" Margin="10" />
<Button Content="Begin" Grid.Row="6" Height="30" Grid.Column="1" Command="{Binding Begin}" IsEnabled="{Binding UIReady}" Margin="10"/>
</Grid>
</Window>

View File

@ -1,8 +1,4 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Wabbajack.NexusApi
{
@ -47,15 +43,7 @@ namespace Wabbajack.NexusApi
public string uploaded_by;
public string uploaded_users_profile_url;
public string picture_url;
}
public class SlideShowItem
{
public string ImageURL;
public string ModName;
public string ModSummary;
public string AuthorName;
public string ModURL;
public bool contains_adult_content;
}
public class EndorsementResponse

View File

@ -11,8 +11,8 @@ using System.Reflection;
using System.Security.Authentication;
using System.Threading.Tasks;
using Wabbajack.Common;
using static Wabbajack.NexusApi.NexusApiUtils;
using WebSocketSharp;
using static Wabbajack.NexusApi.NexusApiUtils;
namespace Wabbajack.NexusApi
{
@ -258,11 +258,11 @@ namespace Wabbajack.NexusApi
}
public static IEnumerable<SlideShowItem> CachedSlideShow
public static IEnumerable<UI.Slide> CachedSlideShow
{
get
{
if (!Directory.Exists(Consts.NexusCacheDirectory)) return new SlideShowItem[] { };
if (!Directory.Exists(Consts.NexusCacheDirectory)) return new UI.Slide[] { };
return Directory.EnumerateFiles(Consts.NexusCacheDirectory)
.Where(f => f.EndsWith(".json"))
@ -280,14 +280,7 @@ namespace Wabbajack.NexusApi
})
.Where(m => m != null)
.Where(m => m._internal_version == CACHED_VERSION_NUMBER && m.picture_url != null)
.Select(m => new SlideShowItem
{
ImageURL = m.picture_url,
ModName = FixupSummary(m.name),
AuthorName = FixupSummary(m.author),
ModURL = GetModURL(m.game_name, m.mod_id),
ModSummary = FixupSummary(m.summary)
});
.Select(m => new UI.Slide(m.name,m.mod_id,m.summary,m.author,m.contains_adult_content,GetModURL(m.game_name,m.mod_id),m.picture_url));
}
}

View File

@ -1,9 +1,4 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Wabbajack.Common;
using Wabbajack.Common;
namespace Wabbajack.NexusApi
{

View File

@ -31,11 +31,11 @@ using System.Windows;
[assembly: ThemeInfo(
ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located
//(used if a resource is not found in the page,
// or application resource dictionaries)
//(used if a resource is not found in the page,
// or application resource dictionaries)
ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located
//(used if a resource is not found in the page,
// app, or any theme specific resource dictionaries)
//(used if a resource is not found in the page,
// app, or any theme specific resource dictionaries)
)]

View File

@ -46,7 +46,10 @@ namespace Wabbajack
public void Build(Compiler c, ModList lst)
{
Text($"### {lst.Name} - Installation Summary");
Text($"### {lst.Name} by {lst.Author} - Installation Summary");
Text(lst.Description);
Text($"#### Website:");
NoWrapText($"[{lst.Website}]({lst.Website})");
var readme_file = Path.Combine(c.MO2ProfileDir, "readme.md");
if (File.Exists(readme_file))
@ -101,6 +104,9 @@ namespace Wabbajack
foreach (var directive in files.OrderBy(f => f.GetType().Name).ThenByDescending(f => f.To))
switch (directive)
{
case PropertyFile i:
NoWrapText($"* `{i.SourceDataID}` as a `{Enum.GetName(typeof(PropertyType),i.Type)}`");
break;
case FromArchive f:
//NoWrapText($"* `{f.To}` from `{f.FullPath}`");
break;

View File

Before

Width:  |  Height:  |  Size: 3.6 KiB

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

View File

Before

Width:  |  Height:  |  Size: 3.9 KiB

After

Width:  |  Height:  |  Size: 3.9 KiB

BIN
Wabbajack/UI/Icons/next.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 243 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

View File

Before

Width:  |  Height:  |  Size: 92 KiB

After

Width:  |  Height:  |  Size: 92 KiB

View File

@ -0,0 +1,173 @@
<Window x:Class="Wabbajack.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:Wabbajack"
mc:Ignorable="d"
Title="Wabbajack"
MinWidth="1280" MinHeight="960"
Width="1280" Height="960"
Style="{StaticResource {x:Type Window}}" Icon="Icons/wabbajack.ico" WindowStyle="ToolWindow"
ResizeMode="CanResize"
Closing="Window_Closing">
<Viewbox Stretch="Uniform">
<!--<Grid Width="1280" Height="960">-->
<Grid Margin="4,0,4,0">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="435"/>
<RowDefinition Height="10" />
<RowDefinition Height="Auto" />
<RowDefinition Height="320"/>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="640"/>
<ColumnDefinition Width="640"/>
</Grid.ColumnDefinitions>
<StackPanel Grid.Row="0" Orientation="Horizontal" Margin="0, 8, 0, 8">
<TextBlock Text="{Binding Mode}" FontSize="16" FontWeight="Bold" />
<TextBlock Text=" : " FontSize="16" />
<TextBlock Text="{Binding ModListName}" FontSize="16" />
</StackPanel>
<!-- Properties -->
<Grid Grid.Row="1" Grid.Column="0" Margin="0,0,2,4" Name="PropertyCompilerGrid">
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="30"/>
</Grid.RowDefinitions>
<Image Grid.Row="0" Margin="0,0,0,4" Source="{Binding SplashScreenImage}" Stretch="Fill"/>
<Button Grid.Row="1" Height="30" Command="{Binding OpenModListPropertiesCommand}" IsEnabled="{Binding UIReady}">
<TextBlock Text="Modlist Properties" FontSize="15" FontWeight="Bold"/>
</Button>
</Grid>
<Grid Grid.Row="1" Grid.Column="0" Margin="0,0,2,4" Name="PropertyInstallerGrid">
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="30"/>
</Grid.RowDefinitions>
<Image Grid.Row="0" Source="{Binding SplashScreenImage}" Stretch="Fill"/>
<Button Grid.Row="1" Height="30" Command="{Binding OpenReadme}" IsEnabled="{Binding HadReadme}">
<TextBlock Text="Open README" FontSize="15" FontWeight="Bold"/>
</Button>
</Grid>
<!-- End Properties -->
<!-- Slideshow -->
<Grid Grid.Row="1" Grid.Column="1" Margin="2,0,0,4">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<TextBlock Text="{Binding SplashScreenModName}" Grid.Row="0" FontSize="30" FontWeight="Bold"/>
<TextBlock Text="{Binding SplashScreenAuthorName}" Grid.Row="1" FontSize="15" FontWeight="Bold"/>
<TextBlock Text="{Binding SplashScreenSummary}" TextWrapping="Wrap" Grid.Row="2" FontSize="15" FontWeight="Bold"/>
<Grid Grid.Row="3" VerticalAlignment="Bottom">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="48"/>
</Grid.ColumnDefinitions>
<CheckBox Margin="0,10,0,0" Grid.Column="0" IsChecked="{Binding EnableSlideShow}" Name="EnableSlideShow">Enable the Slideshow</CheckBox>
<CheckBox Margin="4,10,0,0" Grid.Column="1" IsChecked="{Binding SplashShowNSFW}" Name="ShowNSFWContent">Show NSFW Mods in the Slideshow</CheckBox>
<Button HorizontalAlignment="Right" Height="30" Grid.Column="2" Command="{Binding SlideShowNextItem}" ToolTip="Spamming this button will result in problems">
<DockPanel>
<Image Source="{Binding NextIcon}" Stretch="Fill"/>
</DockPanel>
</Button>
</Grid>
<Button Height="30" Grid.Row="4" Command="{Binding VisitNexusSiteCommand}">
<TextBlock Text="View Nexus Site" FontSize="15" FontWeight="Bold"/>
</Button>
</Grid>
<!-- End Slideshow-->
<ProgressBar Grid.Row="2" Margin="1,0,1,0" Grid.Column="0" Grid.ColumnSpan="2" Value="{Binding QueueProgress}" Minimum="0" Maximum="100" Background="#444444" />
<!-- Log -->
<TextBlock Text="Log:" Grid.Row="3" FontSize="14" Margin="0, 16, 0, 8" />
<ListBox local:AutoScrollBehavior.ScrollOnNewItem="True" Margin="0,0,2,0" Grid.Row="4" ItemsSource="{Binding Log}" />
<!-- End Log -->
<!-- Location -->
<Grid HorizontalAlignment="Stretch" Margin="-4,10,2,10" Grid.Row="5" Grid.Column="0" Grid.RowSpan="2">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition MinHeight="10" />
<RowDefinition />
</Grid.RowDefinitions>
<Label Grid.Row="0" Content="{Binding LocationLabel}" Grid.Column="0" />
<TextBox Grid.Row="0" Grid.Column="1" Text="{Binding Location, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True, NotifyOnValidationError=True}" IsEnabled="{Binding UIReady}"/>
<Button Grid.Row="0" Content="Select" MinWidth="80" Grid.Column="2" Command="{Binding ChangePath}" IsEnabled="{Binding UIReady}"/>
<Label Grid.Row="2" Content="Download Location:" Grid.Column="0" />
<TextBox Grid.Row="2" Grid.Column="1" Text="{Binding DownloadLocation}" IsEnabled="{Binding UIReady}"/>
<Button Grid.Row="2" Content="Select" MinWidth="80" Grid.Column="2" Command="{Binding ChangeDownloadPath}" IsEnabled="{Binding UIReady}"/>
</Grid>
<!-- End Location -->
<!-- Work Queue Start -->
<TextBlock Text="Work Queue:" Grid.Row="3" Grid.Column="1" FontSize="14" Margin="2, 16, 0, 8" />
<ListBox Margin="2,0,0,0" Grid.Row="4" Grid.Column="1" ItemsSource="{Binding Status}" Width="Auto" HorizontalAlignment="Stretch">
<ListBox.ItemTemplate>
<DataTemplate>
<Grid HorizontalAlignment="Stretch">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<ProgressBar Minimum="0" Maximum="100" Value="{Binding Progress, Mode=OneTime}" Width="100"
Grid.Column="0">
<ProgressBar.Style>
<Style TargetType="ProgressBar">
<Setter Property="Visibility" Value="Visible" />
<Style.Triggers>
<DataTrigger Binding="{Binding Progress}" Value="0">
<Setter Property="Visibility" Value="Collapsed" />
</DataTrigger>
</Style.Triggers>
</Style>
</ProgressBar.Style>
</ProgressBar>
<TextBlock Text=" CPU " Grid.Column="1" />
<TextBlock Text="{Binding ID}" Grid.Column="2" />
<TextBlock Text=" - " Grid.Column="3" />
<TextBlock Text="{Binding Msg}" Grid.Column="4" />
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<!-- Work Queue End-->
<Grid Margin="2,10,0,10" Grid.Row="5" Grid.RowSpan="2" Grid.Column="1">
<Grid.RowDefinitions>
<RowDefinition Height="30"/>
<RowDefinition Height="30"/>
</Grid.RowDefinitions>
<Button Margin="0,0,0,4" Grid.Row="0" Visibility="{Binding ShowReportButton}" Command="{Binding ShowReportCommand}">
<TextBlock FontSize="13" FontWeight="Bold">View ModList Contents</TextBlock>
</Button>
<Button Margin="0,4,0,0" Grid.Row="1" Command="{Binding Begin}" IsEnabled="{Binding UIReady}">
<TextBlock FontSize="13" FontWeight="Bold">Begin</TextBlock>
</Button>
</Grid>
</Grid>
</Viewbox>
</Window>

View File

@ -1,9 +1,8 @@
using System;
using Alphaleonis.Win32.Filesystem;
using System;
using System.ComponentModel;
using System.Threading;
using System.Windows;
using System.Windows.Forms;
using Alphaleonis.Win32.Filesystem;
using Wabbajack.Common;
using Application = System.Windows.Application;
using MessageBox = System.Windows.MessageBox;
@ -31,7 +30,7 @@ namespace Wabbajack
InitializeComponent();
var context = new AppState(Dispatcher, "Building");
var context = new AppState(Dispatcher, TaskMode.BUILDING);
context.LogMsg($"Wabbajack Build - {ThisAssembly.Git.Sha}");
SetupHandlers(context);
DataContext = context;
@ -44,6 +43,17 @@ namespace Wabbajack
_state._nexusSiteURL = "https://github.com/wabbajack-tools/wabbajack";
if (mode == RunMode.Compile)
{
PropertyCompilerGrid.Visibility = Visibility.Visible;
PropertyInstallerGrid.Visibility = Visibility.Hidden;
}
else
{
PropertyCompilerGrid.Visibility = Visibility.Hidden;
PropertyInstallerGrid.Visibility = Visibility.Visible;
}
new Thread(() =>
{
if (mode == RunMode.Compile)
@ -65,8 +75,10 @@ namespace Wabbajack
{
context.Running = false;
ExitWhenClosing = false;
var window = new ModeSelectionWindow();
window.ShowActivated = true;
var window = new ModeSelectionWindow
{
ShowActivated = true
};
window.Show();
Close();
});
@ -91,7 +103,7 @@ namespace Wabbajack
private void AppHandler(object sender, UnhandledExceptionEventArgs e)
{
_state.LogMsg("Uncaught error:");
_state.LogMsg(((Exception) e.ExceptionObject).ExceptionToString());
_state.LogMsg(((Exception)e.ExceptionObject).ExceptionToString());
}

View File

@ -3,27 +3,27 @@
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
Style="{StaticResource {x:Type Window}}" Icon="square_transparent_icon.ico" WindowStyle="ToolWindow"
Style="{StaticResource {x:Type Window}}" Icon="Icons/wabbajack.ico" WindowStyle="ToolWindow"
xmlns:local="clr-namespace:Wabbajack"
mc:Ignorable="d"
Title="Wabbajack" Height="500" Width="800" ResizeMode="NoResize"
Closing="Close_Window">
<Grid Margin="20" ShowGridLines="False">
<Grid Margin="20">
<Grid.ColumnDefinitions>
<ColumnDefinition></ColumnDefinition>
<ColumnDefinition Width="30"></ColumnDefinition>
<ColumnDefinition Width="30"></ColumnDefinition>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="30"/>
<ColumnDefinition Width="30"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="30"></RowDefinition>
<RowDefinition></RowDefinition>
<RowDefinition Height="70"></RowDefinition>
<RowDefinition Height="70"></RowDefinition>
<RowDefinition Height="30"/>
<RowDefinition Height="*"/>
<RowDefinition Height="70"/>
<RowDefinition Height="70"/>
</Grid.RowDefinitions>
<Image MouseLeftButtonDown="GitHub_MouseLeftButtonDown" Margin="5,0,0,0" Grid.Row="0" Grid.Column="0" HorizontalAlignment="Right" Name="GitHub"></Image>
<Image MouseLeftButtonDown="Patreon_MouseLeftButtonDown" Margin="5,0,0,0" Grid.Row="0" Grid.Column="1" Name="Patreon"></Image>
<Image MouseLeftButtonDown="Discord_MouseLeftButtonDown" Margin="5,0,0,0" Grid.Row="0" Grid.Column="2" Name="Discord"></Image>
<Image Grid.Row="1" Grid.ColumnSpan="3" Name="Banner"></Image>
<Image MouseLeftButtonDown="GitHub_MouseLeftButtonDown" Margin="5,0,0,0" Grid.Row="0" Grid.Column="0" HorizontalAlignment="Right" Name="GitHub"/>
<Image MouseLeftButtonDown="Patreon_MouseLeftButtonDown" Margin="5,0,0,0" Grid.Row="0" Grid.Column="1" Name="Patreon"/>
<Image MouseLeftButtonDown="Discord_MouseLeftButtonDown" Margin="5,0,0,0" Grid.Row="0" Grid.Column="2" Name="Discord"/>
<Image Grid.Row="1" Grid.ColumnSpan="3" Name="Banner" Stretch="Uniform" Margin="2,0,2,0"/>
<Button Name="InstallModlist" Grid.ColumnSpan="3" Grid.Row="2" Margin="2" Click="InstallModlist_Click">
<TextBlock FontSize="40">Install a ModList</TextBlock>
</Button>

View File

@ -1,19 +1,7 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.ComponentModel;
using System.Diagnostics;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
using Wabbajack.Common;
using static Wabbajack.MainWindow;
@ -27,13 +15,13 @@ namespace Wabbajack
public ModeSelectionWindow()
{
InitializeComponent();
var bannerImage = UIUtils.BitmapImageFromResource("Wabbajack.banner_small.png");
var bannerImage = UIUtils.BitmapImageFromResource("Wabbajack.UI.banner_small.png");
Banner.Source = bannerImage;
var patreonIcon = UIUtils.BitmapImageFromResource("Wabbajack.Icons.patreon.png");
var patreonIcon = UIUtils.BitmapImageFromResource("Wabbajack.UI.Icons.patreon_light.png");
Patreon.Source = patreonIcon;
var githubIcon = UIUtils.BitmapImageFromResource("Wabbajack.Icons.github.png");
var githubIcon = UIUtils.BitmapImageFromResource("Wabbajack.UI.Icons.github_light.png");
GitHub.Source = githubIcon;
var discordIcon = UIUtils.BitmapImageFromResource("Wabbajack.Icons.discord.png");
var discordIcon = UIUtils.BitmapImageFromResource("Wabbajack.UI.Icons.discord.png");
Discord.Source = discordIcon;
}

View File

@ -0,0 +1,61 @@
<Window x:Class="Wabbajack.ModlistPropertiesWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:Wabbajack"
mc:Ignorable="d"
Title="Wabbajack (Modlist Properties)" Height="600" Width="900"
Style="{StaticResource {x:Type Window}}" Icon="Icons/wabbajack.ico" WindowStyle="ToolWindow"
ResizeMode="NoResize"
Closing="Window_Closing">
<Grid Margin="8">
<Grid.RowDefinitions>
<RowDefinition Height="300"/>
<RowDefinition Height="30"/>
<RowDefinition Height="30"/>
<RowDefinition Height="30"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Grid Grid.Column="0" Grid.Row="0" Margin="5">
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="30"/>
</Grid.RowDefinitions>
<Image Grid.Row="0" Stretch="Fill" Name="SplashScreenProperty"/>
<Button Height="30" Grid.Row="1" Click="SetSplashScreen_Click" ToolTip="Use a 1400x900 png file for the best results">
<TextBlock Text="Change splash screen image" FontSize="15" FontWeight="Bold"/>
</Button>
</Grid>
<Grid Grid.Column="1" Grid.Row="0" Margin="0 5 0 5">
<Grid.RowDefinitions>
<RowDefinition Height="30"/>
<RowDefinition Height="30"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<TextBox Grid.Row="0" Text="ModList Name" Name="ModlistNameProperty" ToolTip="Change the name of your ModList" MaxLength="50" AcceptsTab="False" FontSize="15" FontWeight="Bold" Margin="0,0,0,5"/>
<TextBox Grid.Row="1" Text="Author" Name="ModlistAuthorProperty" ToolTip="Change the name of the Author" MaxLength="50" AcceptsTab="False" FontSize="15" Margin="0 0 0 5" />
<TextBox Grid.Row="2" Text="Description (700 characters max)" Name="ModlistDescriptionProperty" ToolTip="Change the description" MaxLength="700" AcceptsReturn="True" TextWrapping="Wrap" AcceptsTab="False" FontSize="15" Margin="0,0,0,0"/>
</Grid>
<TextBox Grid.Column="0" Grid.Row="1" Grid.ColumnSpan="2" Text="Website" Name="ModlistWebsiteProperty" ToolTip="Change the website" MaxLength="80" AcceptsReturn="False" AcceptsTab="False" FontSize="15"/>
<Grid Grid.Column="0" Grid.Row="2" Grid.ColumnSpan="2" Height="30" Margin="0,10,0,-10">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<TextBox Height="30" Grid.ColumnSpan="3" Text="Readme path" Name="ModlistReadmeProperty" AcceptsReturn="False" AcceptsTab="False" FontSize="15"/>
<Button Height="30" Grid.Column="2" Content="Choose" Click="ChooseReadme_Click"/>
</Grid>
<Button Grid.Column="0" Grid.Row="3" Grid.ColumnSpan="2" Click="SaveProperties_Click" Margin="0,160,0,-160" Height="30" VerticalAlignment="Bottom">
<TextBlock Text="Save" FontSize="15" FontWeight="Bold"/>
</Button>
</Grid>
</Window>

View File

@ -0,0 +1,79 @@
using System;
using System.ComponentModel;
using System.Windows;
using System.Windows.Media.Imaging;
namespace Wabbajack
{
/// <summary>
/// Interaction logic for ModlistPropertiesWindow.xaml
/// </summary>
public partial class ModlistPropertiesWindow : Window
{
internal string newBannerFile;
internal readonly AppState state;
internal ModlistPropertiesWindow(AppState _state)
{
InitializeComponent();
var bannerImage = UIUtils.BitmapImageFromResource("Wabbajack.UI.banner.png");
SplashScreenProperty.Source = bannerImage;
newBannerFile = null;
state = _state;
}
private void Window_Closing(object sender, CancelEventArgs e)
{
//Hide();
}
private void SetSplashScreen_Click(object sender, RoutedEventArgs e)
{
var file = UIUtils.OpenFileDialog("Banner image|*.png");
if (file != null)
{
newBannerFile = file;
SplashScreenProperty.Source = new BitmapImage(new Uri(file));
}
}
private void SaveProperties_Click(object sender, RoutedEventArgs e)
{
if (state.UIReady)
{
if (newBannerFile != null)
{
BitmapImage splashScreen = new BitmapImage(new Uri(newBannerFile));
state.newImagePath = newBannerFile;
state.SplashScreenImage = splashScreen;
}
state.SplashScreenModName = ModlistNameProperty.Text;
state.SplashScreenSummary = ModlistDescriptionProperty.Text;
state.SplashScreenAuthorName = ModlistAuthorProperty.Text;
state._nexusSiteURL = ModlistWebsiteProperty.Text;
state.readmePath = ModlistReadmeProperty.Text;
state.ChangedProperties = true;
Hide();
}
}
public bool IsClosed { get; private set; }
protected override void OnClosed(EventArgs e)
{
base.OnClosed(e);
IsClosed = true;
}
private void ChooseReadme_Click(object sender, RoutedEventArgs e)
{
var file = UIUtils.OpenFileDialog("Readme|*.txt");
if (file != null)
{
ModlistReadmeProperty.Text = file;
}
}
}
}

200
Wabbajack/UI/SlideShow.cs Normal file
View File

@ -0,0 +1,200 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net.Http;
using System.Threading.Tasks;
using System.Windows.Media.Imaging;
using Wabbajack.Common;
using Wabbajack.NexusApi;
namespace Wabbajack.UI
{
public class Slide
{
public Slide(string modName, string modID, string modDescription, string modAuthor, bool isNSFW, string modUrl, string imageURL)
{
ModName = modName;
ModDescription = modDescription;
ModAuthor = modAuthor;
IsNSFW = isNSFW;
ModURL = modUrl;
ModID = modID;
ImageURL = imageURL;
}
public string ModName { get; }
public string ModDescription { get; }
public string ModAuthor { get; }
public bool IsNSFW { get; }
public string ModURL { get; }
public string ModID { get; }
public BitmapImage Image { get; set; }
public string ImageURL { get; }
}
internal class SlideShow
{
private readonly Random _random;
private Slide _lastSlide;
private const bool UseSync = false;
private const int MaxCacheSize = 10;
private readonly AppState _appState;
public SlideShow(AppState appState, bool checkCache)
{
SlideShowElements = new List<Slide>();
CachedSlides = new Dictionary<string, Slide>();
SlidesQueue = new Queue<Slide>();
_random = new Random();
_appState = appState;
if (!checkCache) return;
IEnumerable<Slide> files = NexusApiClient.CachedSlideShow;
IEnumerable<Slide> enumerable = files.ToList();
if (enumerable.Any())
{
SlideShowElements = enumerable.ToList();
}
}
public void PreloadSlideShow()
{
var turns = 0;
for (var i = 0; i < SlideShowElements.Count; i++)
{
if (turns >= 3)
break;
if (QueueRandomSlide(true, false))
turns++;
}
}
public void UpdateSlideShowItem()
{
if (!_appState.EnableSlideShow || !_appState.installing || SlidesQueue.Count==0) return;
var slide = SlidesQueue.Peek();
while (CachedSlides.Count >= MaxCacheSize)
{
var idx = _random.Next(0, SlideShowElements.Count);
var randomSlide = SlideShowElements[idx];
while (CachedSlides.ContainsKey(randomSlide.ModID) || SlidesQueue.Contains(randomSlide))
{
idx = _random.Next(0, SlideShowElements.Count);
randomSlide = SlideShowElements[idx];
}
if (!CachedSlides.ContainsKey(randomSlide.ModID)) continue;
CachedSlides.Remove(randomSlide.ModID);
if(AppState.GcCollect)
GC.Collect();
}
if (!slide.IsNSFW || (slide.IsNSFW && ShowNSFW))
{
_appState.SplashScreenImage = _appState._noneImage;
if (slide.ImageURL != null && slide.Image != null)
{
_appState.dispatcher.Invoke(() =>
{
if (!CachedSlides.ContainsKey(slide.ModID)) return;
_appState.SplashScreenImage = slide.Image;
});
}
_appState.SplashScreenModName = slide.ModName;
_appState.SplashScreenAuthorName = slide.ModAuthor;
_appState.SplashScreenSummary = slide.ModDescription;
_appState._nexusSiteURL = slide.ModURL;
}
SlidesQueue.Dequeue();
QueueRandomSlide(false, true);
}
private void CacheImage(Slide slide)
{
using (var ms = new MemoryStream())
{
if (UseSync)
{
_appState.dispatcher.Invoke(() =>
{
using (var stream = new HttpClient().GetStreamSync(slide.ImageURL))
stream.CopyTo(ms);
});
}
else
{
using (Task<Stream> stream = new HttpClient().GetStreamAsync(slide.ImageURL))
{
stream.Wait();
stream.Result.CopyTo(ms);
}
}
ms.Seek(0, SeekOrigin.Begin);
_appState.dispatcher.Invoke(() =>
{
var image = new BitmapImage();
image.BeginInit();
image.CacheOption = BitmapCacheOption.OnLoad;
image.StreamSource = ms;
image.EndInit();
image.Freeze();
slide.Image = image;
});
}
}
private bool QueueRandomSlide(bool init, bool checkLast)
{
var result = false;
var idx = _random.Next(0, SlideShowElements.Count);
var element = SlideShowElements[idx];
if (checkLast)
{
while (element == _lastSlide && (!element.IsNSFW || (element.IsNSFW && ShowNSFW)))
{
idx = _random.Next(0, SlideShowElements.Count);
element = SlideShowElements[idx];
}
}
if (element.ImageURL == null)
{
if (!init) SlidesQueue.Enqueue(element);
}
else
{
if (!CachedSlides.ContainsKey(element.ModID))
{
CacheImage(element);
CachedSlides.Add(element.ModID, element);
SlidesQueue.Enqueue(element);
result = true;
}
else
{
if(!init) SlidesQueue.Enqueue(element);
}
_lastSlide = element;
}
return result;
}
public bool ShowNSFW { get; set; }
public List<Slide> SlideShowElements { get; set; }
public Dictionary<string, Slide> CachedSlides { get; }
public Queue<Slide> SlidesQueue { get; }
}
}

View File

@ -0,0 +1,15 @@
<Window x:Class="Wabbajack.UI.TextViewer"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:Wabbajack.UI"
Style="{StaticResource {x:Type Window}}"
mc:Ignorable="d"
Icon="Icons/wabbajack.ico"
WindowStyle="ToolWindow"
Title="TextViewer" Height="450" Width="800">
<Grid>
<TextBlock FontSize="20" Name="TextBlock" TextWrapping="Wrap"/>
</Grid>
</Window>

View File

@ -0,0 +1,14 @@
using System.Windows;
namespace Wabbajack.UI
{
public partial class TextViewer : Window
{
public TextViewer(string text, string title)
{
InitializeComponent();
TextBlock.Text = text;
Title = title;
}
}
}

View File

@ -1,22 +1,17 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.WindowsAPICodePack.Dialogs;
using System;
using System.Reflection;
using System.Security.Cryptography.X509Certificates;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Windows.Media.Imaging;
using System.Windows.Threading;
using Microsoft.WindowsAPICodePack.Dialogs;
using Wabbajack.Common;
namespace Wabbajack
{
public static class UIUtils
{
public static string ShowFolderSelectionDialog(string prompt)
{
if (Dispatcher.Thread != Thread.CurrentThread)

View File

Before

Width:  |  Height:  |  Size: 190 KiB

After

Width:  |  Height:  |  Size: 190 KiB

View File

Before

Width:  |  Height:  |  Size: 178 KiB

After

Width:  |  Height:  |  Size: 178 KiB

BIN
Wabbajack/UI/none.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

View File

@ -1,8 +1,4 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Linq;
using Wabbajack.Common;
namespace Wabbajack.Updater

View File

@ -1,11 +1,4 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Wabbajack.Common;
using YamlDotNet.Serialization;
using System.Collections.Generic;
namespace Wabbajack.Validation
{

View File

@ -4,8 +4,6 @@ using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
using Wabbajack.Common;
using YamlDotNet.Serialization;
using YamlDotNet.Serialization.NamingConventions;
@ -115,7 +113,7 @@ namespace Wabbajack.Validation
var nexus_mod_permissions = modlist.Archives
.OfType<NexusMod>()
.PMap(a => (a.Hash, FilePermissions(a), a))
.ToDictionary(a => a.Hash, a => new { permissions = a.Item2, archive = a.a});
.ToDictionary(a => a.Hash, a => new { permissions = a.Item2, archive = a.a });
modlist.Directives
.OfType<PatchedFromArchive>()
@ -141,7 +139,7 @@ namespace Wabbajack.Validation
{
if (nexus_mod_permissions.TryGetValue(p.ArchiveHashPath[0], out var archive))
{
if (!(archive.permissions.CanExtractBSAs ?? true) &&
if (!(archive.permissions.CanExtractBSAs ?? true) &&
p.ArchiveHashPath.Skip(1).ButLast().Any(a => Consts.SupportedBSAs.Contains(Path.GetExtension(a))))
{
ValidationErrors.Push($"{p.To} from {archive.archive.NexusURL} is set to disallow BSA Extraction");

View File

@ -54,7 +54,7 @@
<Prefer32Bit>false</Prefer32Bit>
</PropertyGroup>
<PropertyGroup>
<ApplicationIcon>square_transparent_icon.ico</ApplicationIcon>
<ApplicationIcon>UI\Icons\wabbajack.ico</ApplicationIcon>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug %28no commandargs%29|AnyCPU'">
<DebugSymbols>true</DebugSymbols>
@ -186,21 +186,28 @@
</ApplicationDefinition>
<Compile Include="Data.cs" />
<Compile Include="LambdaCommand.cs" />
<Compile Include="UI\ModlistPropertiesWindow.xaml.cs">
<DependentUpon>ModlistPropertiesWindow.xaml</DependentUpon>
</Compile>
<Compile Include="NexusApi\Dtos.cs" />
<Compile Include="NexusApi\NexusApiUtils.cs" />
<Compile Include="ModeSelectionWindow.xaml.cs">
<Compile Include="UI\ModeSelectionWindow.xaml.cs">
<DependentUpon>ModeSelectionWindow.xaml</DependentUpon>
</Compile>
<Compile Include="ReportBuilder.cs" />
<Compile Include="Themes\LeftMarginMultiplierConverter.cs" />
<Compile Include="Themes\TreeViewItemExtensions.cs" />
<Compile Include="UIUtils.cs" />
<Compile Include="UI\SlideShow.cs" />
<Compile Include="UI\TextViewer.xaml.cs">
<DependentUpon>TextViewer.xaml</DependentUpon>
</Compile>
<Compile Include="UI\UIUtils.cs" />
<Compile Include="Updater\CheckForUpdates.cs" />
<Compile Include="Validation\DTOs.cs" />
<Compile Include="Validation\ValidateModlist.cs" />
<Compile Include="ViewModel.cs" />
<Compile Include="zEditIntegration.cs" />
<Page Include="MainWindow.xaml">
<Page Include="UI\MainWindow.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</Page>
@ -212,11 +219,15 @@
<Compile Include="AutoScrollBehavior.cs" />
<Compile Include="Compiler.cs" />
<Compile Include="Installer.cs" />
<Compile Include="MainWindow.xaml.cs">
<Compile Include="UI\MainWindow.xaml.cs">
<DependentUpon>MainWindow.xaml</DependentUpon>
<SubType>Code</SubType>
</Compile>
<Page Include="ModeSelectionWindow.xaml">
<Page Include="UI\ModeSelectionWindow.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="UI\ModlistPropertiesWindow.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
@ -224,6 +235,10 @@
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</Page>
<Page Include="UI\TextViewer.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
</ItemGroup>
<ItemGroup>
<Compile Include="NexusApi\NexusApi.cs" />
@ -280,7 +295,7 @@
</BootstrapperPackage>
</ItemGroup>
<ItemGroup>
<Resource Include="square_transparent_icon.ico" />
<Resource Include="UI\Icons\wabbajack.ico" />
</ItemGroup>
<ItemGroup>
<None Include="css.css" />
@ -289,17 +304,26 @@
<EmbeddedResource Include="css-min.css" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="banner.png" />
<EmbeddedResource Include="UI\banner.png" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="banner_small.png" />
<EmbeddedResource Include="UI\banner_small.png" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="Icons\discord.png" />
<EmbeddedResource Include="Icons\github.png" />
<EmbeddedResource Include="Icons\patreon.png" />
<EmbeddedResource Include="UI\Icons\discord.png" />
<EmbeddedResource Include="UI\Icons\github.png" />
<EmbeddedResource Include="UI\Icons\patreon.png" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="UI\Icons\next.png" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="UI\none.jpg" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="UI\Icons\github_light.png" />
<EmbeddedResource Include="UI\Icons\patreon_light.png" />
</ItemGroup>
<ItemGroup />
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<Import Project="..\packages\Fody.5.1.1\build\Fody.targets" Condition="Exists('..\packages\Fody.5.1.1\build\Fody.targets')" />
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">

View File

@ -1,12 +1,8 @@
using System;
using Alphaleonis.Win32.Filesystem;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Alphaleonis.Win32.Filesystem;
using VFS;
using Wabbajack.Common;
using Directory = Alphaleonis.Win32.Filesystem.Directory;
using File = Alphaleonis.Win32.Filesystem.File;
@ -49,9 +45,10 @@ namespace Wabbajack
.GroupBy(f => (f.name, f.filename));
merges.Where(m => m.Count() > 1)
.Do(m => {
Utils.Warning(
$"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.");
.Do(m =>
{
Utils.Warning(
$"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.");
});
var mergesIndexed =