merge master
3
.gitmodules
vendored
@ -1,3 +0,0 @@
|
||||
[submodule "OMOD-Framework"]
|
||||
path = OMOD-Framework
|
||||
url = https://github.com/erri120/OMOD-Framework.git
|
@ -42,9 +42,8 @@ The installer may have selected other options as well but these are the most imp
|
||||
### Starting development
|
||||
|
||||
1) **Fork and clone the project:** go to the Github repo page, click the fork button, copy the url from the forked repo, navigate to your project folder, open Git Bash or normal command prompt and type `git clone url name` and replace url with the copied url and name with the folder name
|
||||
2) **Initialize the submodules** using `git submodule init` and `git submodule update`
|
||||
3) **Open Wabbajack.sln** in Visual Studio 2019
|
||||
4) **Download NuGet Packages** by selecting the solution and *Right Click*->*Restore NuGet Packages*
|
||||
2) **Open Wabbajack.sln** in Visual Studio 2019
|
||||
3) **Download NuGet Packages** by selecting the solution and *Right Click*->*Restore NuGet Packages*
|
||||
|
||||
It may take a while for Visual Studio to download all packages and update all References so be patience. Once all packages are downloaded go and try building Wabbajack. If the build is successful than good job, if not head over to the *#wabbajack-development* channel on the discord and talk about your build error.
|
||||
|
||||
|
@ -174,7 +174,7 @@ Look at the [`RECIPES.md`] file, we keep a knowledgebase of how to deal with giv
|
||||
|
||||
**How do I contribute to Wabbajack?**
|
||||
|
||||
Look at the [`CONTRIBUTION.md`](https://github.com/halgari/wabbajack/blob/master/CONTRIBUTING.md) file for detailed guidelines.
|
||||
Look at the [`CONTRIBUTING.md`](https://github.com/halgari/wabbajack/blob/master/CONTRIBUTING.md) file for detailed guidelines.
|
||||
|
||||
**Why does each modlist install another copy of Mod Organizer 2?**
|
||||
|
||||
|
@ -61,7 +61,7 @@ directURL=http://enbdev.com/enbseries_skyrimse_v0390.zip
|
||||
directURLHeaders=Referer:http://enbdev.com/download_mod_tesskyrimse.html
|
||||
```
|
||||
|
||||
**NOTE:** The author of ENBSeries has a habbit of updating the program without changing the version number. If you get
|
||||
**NOTE:** The author of ENBSeries has a habit of updating the program without changing the version number. If you get
|
||||
install errors stating that the hash of the downloaded file wasn't what was expected, update your ENBSeries to the latest
|
||||
version and recompile the modlist.
|
||||
|
||||
@ -100,4 +100,4 @@ If you have a file that comes from Dropbox, the process is simple:
|
||||
1) Download the file
|
||||
2) Copy it into the MO2 downloads folder
|
||||
3) Install it via MO2
|
||||
4) Update the .meta file for the archive to point to the dropbox URL
|
||||
4) Update the .meta file for the archive to point to the dropbox URL
|
||||
|
30
VS Snippets/guiprop.snippet
Normal file
@ -0,0 +1,30 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<CodeSnippets xmlns="http://schemas.microsoft.com/VisualStudio/2005/CodeSnippet">
|
||||
<CodeSnippet Format="1.0.0">
|
||||
<Header>
|
||||
<Title>Notify property changed property</Title>
|
||||
<Shortcut>guiprop</Shortcut>
|
||||
<Description>Code snippet for a NotifyingPropertyChanged variable</Description>
|
||||
<SnippetTypes>
|
||||
<SnippetType>Expansion</SnippetType>
|
||||
</SnippetTypes>
|
||||
</Header>
|
||||
<Snippet>
|
||||
<Declarations>
|
||||
<Literal>
|
||||
<ID>type</ID>
|
||||
<ToolTip>Property type</ToolTip>
|
||||
<Default>int</Default>
|
||||
</Literal>
|
||||
<Literal>
|
||||
<ID>property</ID>
|
||||
<ToolTip>Property name</ToolTip>
|
||||
<Default>MyProperty</Default>
|
||||
</Literal>
|
||||
</Declarations>
|
||||
<Code Language="csharp"><![CDATA[private $type$ _$property$;
|
||||
public $type$ $property$ { get => _$property$; set => this.RaiseAndSetIfChanged(ref _$property$, value); }$end$]]>
|
||||
</Code>
|
||||
</Snippet>
|
||||
</CodeSnippet>
|
||||
</CodeSnippets>
|
@ -53,8 +53,11 @@
|
||||
<Reference Include="AlphaFS, Version=2.2.0.0, Culture=neutral, PublicKeyToken=4d31a58f7d7ad5c9, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\AlphaFS.2.2.6\lib\net452\AlphaFS.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="ICSharpCode.SharpZipLib, Version=1.1.0.145, Culture=neutral, PublicKeyToken=1b03e6acf1164f73, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\SharpZipLib.1.1.0\lib\net45\ICSharpCode.SharpZipLib.dll</HintPath>
|
||||
<Reference Include="erri120.OMODFramework, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\erri120.OMODFramework.1.0.0\lib\net472\erri120.OMODFramework.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="ICSharpCode.SharpZipLib, Version=1.2.0.246, Culture=neutral, PublicKeyToken=1b03e6acf1164f73, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\SharpZipLib.1.2.0\lib\net45\ICSharpCode.SharpZipLib.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="INIFileParser, Version=2.5.2.0, Culture=neutral, PublicKeyToken=79af7b307b65cf3c, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\ini-parser.2.5.2\lib\net20\INIFileParser.dll</HintPath>
|
||||
@ -71,6 +74,9 @@
|
||||
<Reference Include="protobuf-net, Version=2.4.0.0, Culture=neutral, PublicKeyToken=257b51d87d2e4d67, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\protobuf-net.2.4.0\lib\net40\protobuf-net.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="SevenZip, Version=19.0.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\SevenZip.19.0.0\lib\net20\SevenZip.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Configuration" />
|
||||
<Reference Include="System.Core" />
|
||||
|
@ -1,12 +1,13 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<packages>
|
||||
<package id="AlphaFS" version="2.2.6" targetFramework="net472" />
|
||||
<package id="erri120.OMODFramework" version="1.0.0" targetFramework="net472" />
|
||||
<package id="ini-parser" version="2.5.2" targetFramework="net472" />
|
||||
<package id="murmurhash" version="1.0.3" targetFramework="net472" />
|
||||
<package id="Newtonsoft.Json" version="12.0.2" targetFramework="net472" />
|
||||
<package id="Newtonsoft.Json.Bson" version="1.0.2" targetFramework="net472" />
|
||||
<package id="protobuf-net" version="2.4.0" targetFramework="net472" />
|
||||
<package id="SharpZipLib" version="1.1.0" targetFramework="net472" />
|
||||
<package id="SevenZip" version="19.0.0" targetFramework="net472" />
|
||||
<package id="SharpZipLib" version="1.2.0" targetFramework="net472" />
|
||||
<package id="System.Runtime.Numerics" version="4.3.0" targetFramework="net472" />
|
||||
</packages>
|
@ -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>
|
||||
|
@ -1,5 +1,4 @@
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Windows;
|
||||
using Wabbajack.Common;
|
||||
using Wabbajack.Updater;
|
||||
@ -20,8 +19,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())
|
||||
{
|
||||
|
@ -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,59 +15,44 @@ using System.Windows.Media.Imaging;
|
||||
using System.Windows.Threading;
|
||||
using Wabbajack.Common;
|
||||
using Wabbajack.NexusApi;
|
||||
using Wabbajack.UI;
|
||||
|
||||
namespace Wabbajack
|
||||
{
|
||||
internal class AppState : INotifyPropertyChanged, IDataErrorInfo
|
||||
public enum TaskMode { INSTALLING, BUILDING }
|
||||
internal class AppState : ViewModel, IDataErrorInfo
|
||||
{
|
||||
private ICommand _begin;
|
||||
public const bool GcCollect = true;
|
||||
|
||||
private ICommand _changeDownloadPath;
|
||||
private SlideShow _slideShow;
|
||||
|
||||
private ICommand _changePath;
|
||||
private string _downloadLocation;
|
||||
|
||||
private string _htmlReport;
|
||||
|
||||
private bool _ignoreMissingFiles;
|
||||
private string _location;
|
||||
public bool installing = false;
|
||||
|
||||
private string _mo2Folder;
|
||||
|
||||
|
||||
private string _mode;
|
||||
private ModList _modList;
|
||||
private string _modListName;
|
||||
|
||||
private int _queueProgress;
|
||||
|
||||
private ICommand _showReportCommand;
|
||||
private ICommand _visitNexusSiteCommand;
|
||||
|
||||
private readonly DateTime _startTime;
|
||||
|
||||
public volatile bool Dirty;
|
||||
|
||||
private readonly Dispatcher dispatcher;
|
||||
public readonly Dispatcher dispatcher;
|
||||
|
||||
public AppState(Dispatcher d, string mode)
|
||||
public AppState(Dispatcher d, TaskMode mode)
|
||||
{
|
||||
_wabbajackLogo = UIUtils.BitmapImageFromResource("Wabbajack.UI.banner.png");
|
||||
_splashScreenImage = _wabbajackLogo;
|
||||
_noneImage = UIUtils.BitmapImageFromResource("Wabbajack.UI.none.jpg");
|
||||
_nextIcon = UIUtils.BitmapImageFromResource("Wabbajack.UI.Icons.next.png");
|
||||
|
||||
var image = new BitmapImage();
|
||||
image.BeginInit();
|
||||
image.StreamSource = Assembly.GetExecutingAssembly().GetManifestResourceStream("Wabbajack.banner.png");
|
||||
image.EndInit();
|
||||
_wabbajackLogo = image;
|
||||
_splashScreenImage = image;
|
||||
|
||||
SetupSlideshow();
|
||||
_slideShow = new SlideShow(this, true);
|
||||
|
||||
if (Assembly.GetEntryAssembly().Location.ToLower().Contains("\\downloads\\"))
|
||||
{
|
||||
MessageBox.Show(
|
||||
"This app seems to be running inside a folder called `Downloads`, such folders are often highly monitored by antivirus software and they can often " +
|
||||
"conflict with the operations Wabbajack needs to perform. Please move this executable outside of your `Downloads` folder and then restart the app.",
|
||||
"Cannot run inside `Downloads`",
|
||||
"This app seems to be running inside a folder called 'Downloads', such folders are often highly monitored by antivirus software and they can often " +
|
||||
"conflict with the operations Wabbajack needs to perform. Please move this executable outside of your 'Downloads' folder and then restart the app.",
|
||||
"Cannot run inside 'Downloads'",
|
||||
MessageBoxButton.OK,
|
||||
MessageBoxImage.Error);
|
||||
Environment.Exit(1);
|
||||
@ -77,383 +63,130 @@ namespace Wabbajack
|
||||
Mode = mode;
|
||||
Dirty = false;
|
||||
dispatcher = d;
|
||||
Log = new ObservableCollection<string>();
|
||||
Status = new ObservableCollection<CPUStatus>();
|
||||
InternalStatus = new List<CPUStatus>();
|
||||
|
||||
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 DateTime lastSlideShowUpdate = new DateTime();
|
||||
|
||||
public ObservableCollection<string> Log { get; }
|
||||
public ObservableCollection<CPUStatus> Status { get; }
|
||||
public ObservableCollection<string> Log { get; } = new ObservableCollection<string>();
|
||||
public ObservableCollection<CPUStatus> Status { get; } = new ObservableCollection<CPUStatus>();
|
||||
|
||||
public string Mode
|
||||
{
|
||||
get => _mode;
|
||||
set
|
||||
{
|
||||
_mode = value;
|
||||
OnPropertyChanged("Mode");
|
||||
}
|
||||
}
|
||||
private TaskMode _Mode;
|
||||
public TaskMode Mode { get => _Mode; set => this.RaiseAndSetIfChanged(ref _Mode, value); }
|
||||
|
||||
public string ModListName
|
||||
{
|
||||
get => _modListName;
|
||||
set
|
||||
{
|
||||
_modListName = value;
|
||||
OnPropertyChanged("ModListName");
|
||||
}
|
||||
}
|
||||
private string _ModListName;
|
||||
public string ModListName { get => _ModListName; set => this.RaiseAndSetIfChanged(ref _ModListName, value); }
|
||||
|
||||
public string Location
|
||||
{
|
||||
get => _location;
|
||||
set
|
||||
{
|
||||
_location = value;
|
||||
OnPropertyChanged("Location");
|
||||
}
|
||||
}
|
||||
|
||||
private string _Location;
|
||||
public string Location { get => _Location; set => this.RaiseAndSetIfChanged(ref _Location, value); }
|
||||
|
||||
public string DownloadLocation
|
||||
{
|
||||
get => _downloadLocation;
|
||||
set
|
||||
{
|
||||
_downloadLocation = value;
|
||||
OnPropertyChanged("DownloadLocation");
|
||||
}
|
||||
}
|
||||
private string _LocationLabel;
|
||||
public string LocationLabel { get => _LocationLabel; set => this.RaiseAndSetIfChanged(ref _LocationLabel, value); }
|
||||
|
||||
private string _DownloadLocation;
|
||||
public string DownloadLocation { get => _DownloadLocation; set => this.RaiseAndSetIfChanged(ref _DownloadLocation, value); }
|
||||
|
||||
public Visibility ShowReportButton => _htmlReport == null ? Visibility.Collapsed : Visibility.Visible;
|
||||
|
||||
private string _htmlReport;
|
||||
public string HTMLReport
|
||||
{
|
||||
get => _htmlReport;
|
||||
set
|
||||
{
|
||||
_htmlReport = value;
|
||||
OnPropertyChanged("HTMLReport");
|
||||
OnPropertyChanged("ShowReportButton");
|
||||
RaisePropertyChanged();
|
||||
RaisePropertyChanged(nameof(ShowReportButton));
|
||||
}
|
||||
}
|
||||
|
||||
public int QueueProgress
|
||||
{
|
||||
get => _queueProgress;
|
||||
set
|
||||
{
|
||||
if (value != _queueProgress)
|
||||
{
|
||||
_queueProgress = value;
|
||||
OnPropertyChanged("QueueProgress");
|
||||
}
|
||||
}
|
||||
}
|
||||
private int _queueProgress;
|
||||
public int QueueProgress { get => _queueProgress; set => this.RaiseAndSetIfChanged(ref _queueProgress, value); }
|
||||
|
||||
|
||||
private List<CPUStatus> InternalStatus { get; }
|
||||
private List<CPUStatus> InternalStatus { get; } = new List<CPUStatus>();
|
||||
public string LogFile { get; }
|
||||
|
||||
private ICommand _changePath;
|
||||
public ICommand ChangePath
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_changePath == null) _changePath = new LambdaCommand(() => true, () => ExecuteChangePath());
|
||||
if (_changePath == null) _changePath = new LambdaCommand(() => true, ExecuteChangePath);
|
||||
return _changePath;
|
||||
}
|
||||
}
|
||||
|
||||
private ICommand _changeDownloadPath;
|
||||
public ICommand ChangeDownloadPath
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_changeDownloadPath == null)
|
||||
_changeDownloadPath = new LambdaCommand(() => true, () => ExecuteChangeDownloadPath());
|
||||
_changeDownloadPath = new LambdaCommand(() => true, ExecuteChangeDownloadPath);
|
||||
return _changeDownloadPath;
|
||||
}
|
||||
}
|
||||
|
||||
private ICommand _begin;
|
||||
public ICommand Begin
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_begin == null) _begin = new LambdaCommand(() => true, () => ExecuteBegin());
|
||||
if (_begin == null) _begin = new LambdaCommand(() => true, ExecuteBegin);
|
||||
return _begin;
|
||||
}
|
||||
}
|
||||
|
||||
private ICommand _showReportCommand;
|
||||
public ICommand ShowReportCommand
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_showReportCommand == null) _showReportCommand = new LambdaCommand(() => true, () => ShowReport());
|
||||
return _showReportCommand;
|
||||
return _showReportCommand ?? (_showReportCommand = new LambdaCommand(() => true, ShowReport));
|
||||
}
|
||||
}
|
||||
|
||||
private ICommand _visitNexusSiteCommand;
|
||||
public ICommand VisitNexusSiteCommand
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_visitNexusSiteCommand == null) _visitNexusSiteCommand = new LambdaCommand(() => true, () => VisitNexusSite());
|
||||
return _visitNexusSiteCommand;
|
||||
return _visitNexusSiteCommand ??
|
||||
(_visitNexusSiteCommand = new LambdaCommand(() => true, VisitNexusSite));
|
||||
}
|
||||
}
|
||||
|
||||
public string _nexusSiteURL = null;
|
||||
|
||||
private void VisitNexusSite()
|
||||
{
|
||||
if (_nexusSiteURL != null && _nexusSiteURL.StartsWith("https://"))
|
||||
{
|
||||
Process.Start(_nexusSiteURL);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private bool _uiReady = false;
|
||||
public bool UIReady
|
||||
{
|
||||
get => _uiReady;
|
||||
set
|
||||
{
|
||||
_uiReady = value;
|
||||
OnPropertyChanged("UIReady");
|
||||
}
|
||||
}
|
||||
|
||||
private BitmapImage _wabbajackLogo = null;
|
||||
private BitmapImage _splashScreenImage = null;
|
||||
public BitmapImage SplashScreenImage
|
||||
{
|
||||
get => _splashScreenImage;
|
||||
set
|
||||
{
|
||||
_splashScreenImage = value;
|
||||
OnPropertyChanged("SplashScreenImage");
|
||||
}
|
||||
}
|
||||
|
||||
public string _splashScreenModName = "Wabbajack";
|
||||
public string SplashScreenModName
|
||||
{
|
||||
get => _splashScreenModName;
|
||||
set
|
||||
{
|
||||
_splashScreenModName = value;
|
||||
OnPropertyChanged("SplashScreenModName");
|
||||
}
|
||||
}
|
||||
|
||||
public string _splashScreenAuthorName = "Halgari & the Wabbajack Team";
|
||||
public string SplashScreenAuthorName
|
||||
{
|
||||
get => _splashScreenAuthorName;
|
||||
set
|
||||
{
|
||||
_splashScreenAuthorName = value;
|
||||
OnPropertyChanged("SplashScreenAuthorName");
|
||||
}
|
||||
}
|
||||
|
||||
public string _splashScreenSummary = "";
|
||||
private string _modListPath;
|
||||
|
||||
public string SplashScreenSummary
|
||||
{
|
||||
get => _splashScreenSummary;
|
||||
set
|
||||
{
|
||||
_splashScreenSummary = value;
|
||||
OnPropertyChanged("SplashScreenSummary");
|
||||
}
|
||||
}
|
||||
|
||||
public event PropertyChangedEventHandler PropertyChanged;
|
||||
|
||||
public void OnPropertyChanged(string name)
|
||||
{
|
||||
if(PropertyChanged != null)
|
||||
{
|
||||
PropertyChanged(this, new PropertyChangedEventArgs(name));
|
||||
}
|
||||
}
|
||||
public string Error
|
||||
{
|
||||
get { return "Error"; }
|
||||
}
|
||||
|
||||
public string this[string columnName]
|
||||
public ICommand OpenModListPropertiesCommand
|
||||
{
|
||||
get
|
||||
{
|
||||
return Validate(columnName);
|
||||
}
|
||||
}
|
||||
private string Validate(string columnName)
|
||||
{
|
||||
string validationMessage = null;
|
||||
switch (columnName)
|
||||
{
|
||||
case "Location":
|
||||
if (Location == null)
|
||||
{
|
||||
validationMessage = null;
|
||||
}
|
||||
else if (Location != null && Directory.Exists(Location) && File.Exists(Path.Combine(Location, "modlist.txt")))
|
||||
{
|
||||
Location = Path.Combine(Location, "modlist.txt");
|
||||
validationMessage = null;
|
||||
ConfigureForBuild();
|
||||
}
|
||||
else
|
||||
{
|
||||
validationMessage = "Invalid Mod Organizer profile directory";
|
||||
}
|
||||
break;
|
||||
}
|
||||
return validationMessage;
|
||||
}
|
||||
|
||||
private void UpdateLoop()
|
||||
{
|
||||
while (Running)
|
||||
{
|
||||
if (Dirty)
|
||||
lock (InternalStatus)
|
||||
{
|
||||
var data = InternalStatus.ToArray();
|
||||
dispatcher.Invoke(() =>
|
||||
{
|
||||
for (var idx = 0; idx < data.Length; idx += 1)
|
||||
if (idx >= Status.Count)
|
||||
Status.Add(data[idx]);
|
||||
else if (Status[idx] != data[idx])
|
||||
Status[idx] = data[idx];
|
||||
});
|
||||
Dirty = false;
|
||||
}
|
||||
|
||||
if (SlideShowElements.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(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)
|
||||
{
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
Thread.Sleep(1000);
|
||||
return new LambdaCommand(() => true, OpenModListProperties);
|
||||
}
|
||||
}
|
||||
|
||||
public bool Running { get; set; } = true;
|
||||
|
||||
internal void ConfigureForInstall(string source, ModList modlist)
|
||||
public ICommand SlideShowNextItem
|
||||
{
|
||||
_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
|
||||
get
|
||||
{
|
||||
ModName = NexusApiUtils.FixupSummary(m.ModName),
|
||||
AuthorName = NexusApiUtils.FixupSummary(m.Author),
|
||||
ModSummary = NexusApiUtils.FixupSummary(m.Summary),
|
||||
ImageURL = m.SlideShowPic,
|
||||
ModURL = m.NexusURL,
|
||||
}).ToList();
|
||||
}
|
||||
|
||||
public void LogMsg(string msg)
|
||||
{
|
||||
dispatcher.Invoke(() => Log.Add(msg));
|
||||
}
|
||||
|
||||
public void SetProgress(int id, string msg, int progress)
|
||||
{
|
||||
lock (InternalStatus)
|
||||
{
|
||||
Dirty = true;
|
||||
while (id >= InternalStatus.Count) InternalStatus.Add(new CPUStatus());
|
||||
|
||||
InternalStatus[id] = new CPUStatus {ID = id, Msg = msg, Progress = progress};
|
||||
return new LambdaCommand(() => true, _slideShow.UpdateSlideShowItem);
|
||||
}
|
||||
}
|
||||
|
||||
public void SetQueueSize(int max, int current)
|
||||
{
|
||||
if (max == 0)
|
||||
max = 1;
|
||||
var total = current * 100 / max;
|
||||
QueueProgress = total;
|
||||
}
|
||||
|
||||
private void ExecuteChangePath()
|
||||
{
|
||||
if (Mode == "Installing")
|
||||
if (Mode == TaskMode.INSTALLING)
|
||||
{
|
||||
var folder = UIUtils.ShowFolderSelectionDialog("Select Installation directory");
|
||||
if (folder != null)
|
||||
{
|
||||
Location = folder;
|
||||
if (_downloadLocation == null)
|
||||
DownloadLocation = Path.Combine(Location, "downloads");
|
||||
}
|
||||
if (folder == null) return;
|
||||
Location = folder;
|
||||
if (DownloadLocation == null)
|
||||
DownloadLocation = Path.Combine(Location, "downloads");
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -468,6 +201,258 @@ namespace Wabbajack
|
||||
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://"))
|
||||
{
|
||||
Process.Start(_nexusSiteURL);
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
{
|
||||
get => _uiReady;
|
||||
set => this.RaiseAndSetIfChanged(ref _uiReady, value);
|
||||
}
|
||||
|
||||
private readonly BitmapImage _wabbajackLogo = null;
|
||||
public readonly BitmapImage _noneImage = null;
|
||||
private BitmapImage _splashScreenImage = null;
|
||||
public BitmapImage SplashScreenImage
|
||||
{
|
||||
get => _splashScreenImage;
|
||||
set
|
||||
{
|
||||
_splashScreenImage = value;
|
||||
RaisePropertyChanged();
|
||||
}
|
||||
}
|
||||
|
||||
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); }
|
||||
|
||||
private string _modListPath;
|
||||
|
||||
private string _SplashScreenSummary;
|
||||
public string SplashScreenSummary { get => _SplashScreenSummary; set => this.RaiseAndSetIfChanged(ref _SplashScreenSummary, value); }
|
||||
private bool _splashShowNSFW = false;
|
||||
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";
|
||||
|
||||
public string this[string columnName] => Validate(columnName);
|
||||
|
||||
private string Validate(string columnName)
|
||||
{
|
||||
string validationMessage = null;
|
||||
switch (columnName)
|
||||
{
|
||||
case "Location":
|
||||
if (Location == null)
|
||||
{
|
||||
validationMessage = null;
|
||||
}
|
||||
else switch (Mode)
|
||||
{
|
||||
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;
|
||||
}
|
||||
return validationMessage;
|
||||
}
|
||||
|
||||
private void UpdateLoop()
|
||||
{
|
||||
while (Running)
|
||||
{
|
||||
if (Dirty)
|
||||
lock (InternalStatus)
|
||||
{
|
||||
CPUStatus[] data = InternalStatus.ToArray();
|
||||
dispatcher.Invoke(() =>
|
||||
{
|
||||
for (var idx = 0; idx < data.Length; idx += 1)
|
||||
if (idx >= Status.Count)
|
||||
Status.Add(data[idx]);
|
||||
else if (Status[idx] != data[idx])
|
||||
Status[idx] = data[idx];
|
||||
});
|
||||
Dirty = false;
|
||||
}
|
||||
|
||||
if (_slideShow.SlidesQueue.Any())
|
||||
{
|
||||
if (DateTime.Now - lastSlideShowUpdate > TimeSpan.FromSeconds(10))
|
||||
{
|
||||
_slideShow.UpdateSlideShowItem();
|
||||
}
|
||||
}
|
||||
Thread.Sleep(1000);
|
||||
}
|
||||
}
|
||||
|
||||
public bool Running { get; set; } = true;
|
||||
private void ApplyModlistProperties()
|
||||
{
|
||||
SplashScreenModName = _modList.Name;
|
||||
SplashScreenAuthorName = _modList.Author;
|
||||
_nexusSiteURL = _modList.Website;
|
||||
SplashScreenSummary = _modList.Description;
|
||||
if (!string.IsNullOrEmpty(_modList.Image) && _modList.Image.Length == 36)
|
||||
{
|
||||
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)
|
||||
{
|
||||
dispatcher.Invoke(() => Log.Add(msg));
|
||||
}
|
||||
|
||||
public void SetProgress(int id, string msg, int progress)
|
||||
{
|
||||
lock (InternalStatus)
|
||||
{
|
||||
Dirty = true;
|
||||
while (id >= InternalStatus.Count) InternalStatus.Add(new CPUStatus());
|
||||
|
||||
InternalStatus[id] = new CPUStatus { ID = id, Msg = msg, Progress = progress };
|
||||
}
|
||||
}
|
||||
|
||||
public void SetQueueSize(int max, int current)
|
||||
{
|
||||
if (max == 0)
|
||||
max = 1;
|
||||
var total = current * 100 / max;
|
||||
QueueProgress = total;
|
||||
}
|
||||
|
||||
private void ConfigureForBuild()
|
||||
{
|
||||
var profile_folder = Path.GetDirectoryName(Location);
|
||||
@ -477,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;
|
||||
@ -485,22 +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;
|
||||
@ -518,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;
|
||||
@ -547,8 +560,10 @@ namespace Wabbajack
|
||||
{
|
||||
UIReady = true;
|
||||
}
|
||||
});
|
||||
th.Priority = ThreadPriority.BelowNormal;
|
||||
})
|
||||
{
|
||||
Priority = ThreadPriority.BelowNormal
|
||||
};
|
||||
th.Start();
|
||||
}
|
||||
else
|
||||
@ -556,15 +571,13 @@ namespace Wabbajack
|
||||
Utils.Log("Cannot compile modlist: no valid Mod Organizer profile directory selected.");
|
||||
UIReady = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
public class CPUStatus
|
||||
{
|
||||
public int Progress { get; internal set; }
|
||||
public string Msg { get; internal set; }
|
||||
public int ID { get; internal set; }
|
||||
}
|
||||
public class CPUStatus
|
||||
{
|
||||
public int Progress { get; internal set; }
|
||||
public string Msg { get; internal set; }
|
||||
public int ID { get; internal set; }
|
||||
}
|
||||
}
|
@ -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;
|
||||
|
@ -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>
|
||||
@ -432,11 +434,7 @@ namespace Wabbajack
|
||||
using (var a = new BSAReader(Path.Combine(MO2Folder, bsa.To)))
|
||||
{
|
||||
var file = a.Files.First(e => e.Path == Path.Combine(to.Split('\\').Skip(2).ToArray()));
|
||||
using (var ms = new MemoryStream())
|
||||
{
|
||||
file.CopyDataTo(ms);
|
||||
return ms.ToArray();
|
||||
}
|
||||
return file.GetData();
|
||||
}
|
||||
}
|
||||
|
||||
@ -489,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)
|
||||
@ -552,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;
|
||||
}
|
||||
@ -616,6 +615,7 @@ namespace Wabbajack
|
||||
Info("Generating compilation stack");
|
||||
return new List<Func<RawSourceFile, Directive>>
|
||||
{
|
||||
IncludePropertyFiles(),
|
||||
IgnoreStartsWith("logs\\"),
|
||||
IncludeRegex("^downloads\\\\.*\\.meta"),
|
||||
IgnoreStartsWith("downloads\\"),
|
||||
@ -672,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>
|
||||
@ -928,16 +956,23 @@ namespace Wabbajack
|
||||
ExtraFiles.Add(match);
|
||||
}
|
||||
|
||||
;
|
||||
|
||||
CreateBSA directive;
|
||||
using (var bsa = new BSAReader(source.AbsolutePath))
|
||||
{
|
||||
directive = new CreateBSA
|
||||
{
|
||||
To = source.Path,
|
||||
State = bsa.State,
|
||||
FileStates = bsa.Files.Select(f => f.State).ToList()
|
||||
TempID = id,
|
||||
Type = (uint)bsa.HeaderType,
|
||||
FileFlags = (uint)bsa.FileFlags,
|
||||
ArchiveFlags = (uint)bsa.ArchiveFlags
|
||||
};
|
||||
}
|
||||
|
||||
;
|
||||
|
||||
return directive;
|
||||
};
|
||||
}
|
||||
@ -1078,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));
|
||||
}
|
||||
|
||||
|
@ -1,7 +1,6 @@
|
||||
using System;
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Compression.BSA;
|
||||
using Newtonsoft.Json;
|
||||
using VFS;
|
||||
using Wabbajack.Common;
|
||||
|
||||
@ -55,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>
|
||||
@ -92,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
|
||||
{
|
||||
@ -132,9 +167,15 @@ namespace Wabbajack
|
||||
[Serializable]
|
||||
public class CreateBSA : Directive
|
||||
{
|
||||
public string IsCompressed;
|
||||
public bool ShareData;
|
||||
public string TempID;
|
||||
public ArchiveStateObject State { get; set; }
|
||||
public List<FileStateObject> FileStates { get; set; }
|
||||
public uint Type;
|
||||
public uint Version;
|
||||
|
||||
public uint FileFlags { get; set; }
|
||||
public bool Compress { get; set; }
|
||||
public uint ArchiveFlags { get; set; }
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
@ -197,6 +238,7 @@ namespace Wabbajack
|
||||
public string ModName;
|
||||
public string NexusURL;
|
||||
public string Summary;
|
||||
public bool Adult;
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
|
Before Width: | Height: | Size: 2.6 KiB |
Before Width: | Height: | Size: 2.2 KiB |
@ -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();
|
||||
@ -251,15 +247,19 @@ namespace Wabbajack
|
||||
.ToList();
|
||||
|
||||
if (source_files.Count > 0)
|
||||
using (var a = bsa.State.MakeBuilder())
|
||||
using (var a = new BSABuilder())
|
||||
{
|
||||
var indexed = bsa.FileStates.ToDictionary(d => d.Path);
|
||||
//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;
|
||||
|
||||
source_files.PMap(f =>
|
||||
{
|
||||
Status($"Adding {f} to BSA");
|
||||
using (var fs = File.OpenRead(Path.Combine(source_dir, f)))
|
||||
{
|
||||
a.AddFile(indexed[f.ToLower()], fs);
|
||||
a.AddFile(f, fs);
|
||||
}
|
||||
});
|
||||
|
||||
@ -288,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));
|
||||
});
|
||||
@ -358,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();
|
||||
|
||||
|
@ -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="MO2 Profile:" 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>
|
@ -1,100 +0,0 @@
|
||||
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;
|
||||
|
||||
namespace Wabbajack
|
||||
{
|
||||
/// <summary>
|
||||
/// Interaction logic for MainWindow.xaml
|
||||
/// </summary>
|
||||
public partial class MainWindow : Window
|
||||
{
|
||||
private AppState _state;
|
||||
|
||||
public enum RunMode
|
||||
{
|
||||
Compile,
|
||||
Install
|
||||
}
|
||||
|
||||
public MainWindow(RunMode mode, string source)
|
||||
{
|
||||
_mode = mode;
|
||||
_source = source;
|
||||
var args = Environment.GetCommandLineArgs();
|
||||
var DebugMode = false;
|
||||
string MO2Folder = null, InstallFolder = null, MO2Profile = null;
|
||||
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
public MainWindow Start()
|
||||
{
|
||||
_context = new AppState(Dispatcher, "Building");
|
||||
DataContext = _context;
|
||||
WorkQueue.Init((id, msg, progress) => _context.SetProgress(id, msg, progress),
|
||||
(max, current) => _context.SetQueueSize(max, current));
|
||||
|
||||
Utils.SetLoggerFn(s => _context.LogMsg(s));
|
||||
Utils.SetStatusFn((msg, progress) => WorkQueue.Report(msg, progress));
|
||||
UIUtils.Dispatcher = Dispatcher;
|
||||
|
||||
_context._nexusSiteURL = "https://github.com/halgari/wabbajack";
|
||||
var thread = new Thread(() => { SetupWindow(_mode, _source, _context); });
|
||||
thread.Start();
|
||||
return this;
|
||||
}
|
||||
|
||||
private void SetupWindow(RunMode mode, string source, AppState context)
|
||||
{
|
||||
if (mode == RunMode.Compile)
|
||||
{
|
||||
Utils.Log("Compiler ready to execute");
|
||||
context.Location = Path.GetDirectoryName(source);
|
||||
}
|
||||
else if (mode == RunMode.Install)
|
||||
{
|
||||
context.UIReady = false;
|
||||
var modlist = Installer.LoadFromFile(source);
|
||||
if (modlist == null)
|
||||
{
|
||||
MessageBox.Show("Invalid Modlist, or file not found.", "Invalid Modlist", MessageBoxButton.OK,
|
||||
MessageBoxImage.Error);
|
||||
Dispatcher.Invoke(() =>
|
||||
{
|
||||
context.Running = false;
|
||||
ExitWhenClosing = false;
|
||||
var window = new ModeSelectionWindow();
|
||||
window.ShowActivated = true;
|
||||
window.Show();
|
||||
Close();
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
context.ConfigureForInstall(source, modlist);
|
||||
}
|
||||
}
|
||||
|
||||
context.UIReady = true;
|
||||
}
|
||||
|
||||
|
||||
internal bool ExitWhenClosing = true;
|
||||
private RunMode _mode;
|
||||
private string _source;
|
||||
private AppState _context;
|
||||
|
||||
private void Window_Closing(object sender, CancelEventArgs e)
|
||||
{
|
||||
if (ExitWhenClosing)
|
||||
Application.Current.Shutdown();
|
||||
}
|
||||
}
|
||||
}
|
@ -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
|
||||
|
@ -11,18 +11,18 @@ 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
|
||||
{
|
||||
public class NexusApiClient : INotifyPropertyChanged
|
||||
public class NexusApiClient : ViewModel
|
||||
{
|
||||
private static readonly string API_KEY_CACHE_FILE = "nexus.key_cache";
|
||||
|
||||
private static readonly uint CACHED_VERSION_NUMBER = 1;
|
||||
|
||||
|
||||
|
||||
private readonly HttpClient _httpClient;
|
||||
|
||||
|
||||
@ -136,9 +136,8 @@ namespace Wabbajack.NexusApi
|
||||
_dailyRemaining = Math.Min(dailyRemaining, hourlyRemaining);
|
||||
_hourlyRemaining = Math.Min(dailyRemaining, hourlyRemaining);
|
||||
}
|
||||
OnPropertyChanged(nameof(DailyRemaining));
|
||||
OnPropertyChanged(nameof(HourlyRemaining));
|
||||
|
||||
RaisePropertyChanged(nameof(DailyRemaining));
|
||||
RaisePropertyChanged(nameof(HourlyRemaining));
|
||||
}
|
||||
|
||||
#endregion
|
||||
@ -157,7 +156,7 @@ namespace Wabbajack.NexusApi
|
||||
headers.Add("Application-Name", Consts.AppName);
|
||||
headers.Add("Application-Version", $"{Assembly.GetEntryAssembly().GetName().Version}");
|
||||
}
|
||||
|
||||
|
||||
private T Get<T>(string url)
|
||||
{
|
||||
Task<HttpResponseMessage> responseTask = _httpClient.GetAsync(url, HttpCompletionOption.ResponseHeadersRead);
|
||||
@ -171,7 +170,7 @@ namespace Wabbajack.NexusApi
|
||||
return stream.FromJSON<T>();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
public string GetNexusDownloadLink(NexusMod archive, bool cache = false)
|
||||
{
|
||||
@ -214,7 +213,7 @@ namespace Wabbajack.NexusApi
|
||||
Directory.CreateDirectory(Consts.NexusCacheDirectory);
|
||||
|
||||
ModInfo result = null;
|
||||
TOP:
|
||||
TOP:
|
||||
var path = Path.Combine(Consts.NexusCacheDirectory, $"mod-info-{archive.GameName}-{archive.ModID}.json");
|
||||
try
|
||||
{
|
||||
@ -250,7 +249,7 @@ namespace Wabbajack.NexusApi
|
||||
Utils.Status($"Endorsing ${mod.GameName} - ${mod.ModID}");
|
||||
var url = $"https://api.nexusmods.com/v1/games/{ConvertGameName(mod.GameName)}/mods/{mod.ModID}/endorse.json";
|
||||
|
||||
var content = new FormUrlEncodedContent(new Dictionary<string, string> {{"version", mod.Version}});
|
||||
var content = new FormUrlEncodedContent(new Dictionary<string, string> { { "version", mod.Version } });
|
||||
|
||||
using (var stream = _httpClient.PostStreamSync(url, content))
|
||||
{
|
||||
@ -259,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"))
|
||||
@ -281,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));
|
||||
}
|
||||
}
|
||||
|
||||
@ -297,18 +289,6 @@ namespace Wabbajack.NexusApi
|
||||
{
|
||||
public string URI { get; set; }
|
||||
}
|
||||
|
||||
|
||||
#region INotifyPropertyChanged
|
||||
|
||||
public event PropertyChangedEventHandler PropertyChanged;
|
||||
|
||||
private void OnPropertyChanged(string name)
|
||||
{
|
||||
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
}
|
@ -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
|
||||
{
|
||||
|
@ -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)
|
||||
)]
|
||||
|
||||
|
||||
|
@ -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;
|
||||
|
BIN
Wabbajack/UI/Icons/discord.png
Normal file
After Width: | Height: | Size: 3.6 KiB |
Before Width: | Height: | Size: 4.2 KiB After Width: | Height: | Size: 4.2 KiB |
BIN
Wabbajack/UI/Icons/github_light.png
Normal file
After Width: | Height: | Size: 3.9 KiB |
BIN
Wabbajack/UI/Icons/next.png
Normal file
After Width: | Height: | Size: 243 B |
BIN
Wabbajack/UI/Icons/patreon.png
Normal file
After Width: | Height: | Size: 15 KiB |
BIN
Wabbajack/UI/Icons/patreon_light.png
Normal file
After Width: | Height: | Size: 2.0 KiB |
Before Width: | Height: | Size: 92 KiB After Width: | Height: | Size: 92 KiB |
173
Wabbajack/UI/MainWindow.xaml
Normal 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 HasReadme}">
|
||||
<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>
|
118
Wabbajack/UI/MainWindow.xaml.cs
Normal file
@ -0,0 +1,118 @@
|
||||
using Alphaleonis.Win32.Filesystem;
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.Threading;
|
||||
using System.Windows;
|
||||
using Wabbajack.Common;
|
||||
using Application = System.Windows.Application;
|
||||
using MessageBox = System.Windows.MessageBox;
|
||||
|
||||
namespace Wabbajack
|
||||
{
|
||||
/// <summary>
|
||||
/// Interaction logic for MainWindow.xaml
|
||||
/// </summary>
|
||||
public partial class MainWindow : Window
|
||||
{
|
||||
private AppState _state;
|
||||
|
||||
public enum RunMode
|
||||
{
|
||||
Compile,
|
||||
Install
|
||||
}
|
||||
|
||||
public MainWindow(RunMode mode, string source)
|
||||
{
|
||||
var args = Environment.GetCommandLineArgs();
|
||||
var DebugMode = false;
|
||||
string MO2Folder = null, InstallFolder = null, MO2Profile = null;
|
||||
|
||||
InitializeComponent();
|
||||
|
||||
var context = new AppState(Dispatcher, TaskMode.BUILDING);
|
||||
context.LogMsg($"Wabbajack Build - {ThisAssembly.Git.Sha}");
|
||||
SetupHandlers(context);
|
||||
DataContext = context;
|
||||
WorkQueue.Init((id, msg, progress) => context.SetProgress(id, msg, progress),
|
||||
(max, current) => context.SetQueueSize(max, current));
|
||||
|
||||
Utils.SetLoggerFn(s => context.LogMsg(s));
|
||||
Utils.SetStatusFn((msg, progress) => WorkQueue.Report(msg, progress));
|
||||
UIUtils.Dispatcher = Dispatcher;
|
||||
|
||||
_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)
|
||||
{
|
||||
Utils.Log("Compiler ready to execute");
|
||||
context.Location = Path.GetDirectoryName(source);
|
||||
context.LocationLabel = "MO2 Profile:";
|
||||
}
|
||||
else if (mode == RunMode.Install)
|
||||
{
|
||||
context.UIReady = false;
|
||||
context.LocationLabel = "Installation Location:";
|
||||
var modlist = Installer.LoadFromFile(source);
|
||||
if (modlist == null)
|
||||
{
|
||||
MessageBox.Show("Invalid Modlist, or file not found.", "Invalid Modlist", MessageBoxButton.OK,
|
||||
MessageBoxImage.Error);
|
||||
Dispatcher.Invoke(() =>
|
||||
{
|
||||
context.Running = false;
|
||||
ExitWhenClosing = false;
|
||||
var window = new ModeSelectionWindow
|
||||
{
|
||||
ShowActivated = true
|
||||
};
|
||||
window.Show();
|
||||
Close();
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
context.ConfigureForInstall(source, modlist);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
context.UIReady = true;
|
||||
}).Start();
|
||||
}
|
||||
|
||||
private void SetupHandlers(AppState state)
|
||||
{
|
||||
_state = state;
|
||||
AppDomain.CurrentDomain.UnhandledException += AppHandler;
|
||||
}
|
||||
|
||||
private void AppHandler(object sender, UnhandledExceptionEventArgs e)
|
||||
{
|
||||
_state.LogMsg("Uncaught error:");
|
||||
_state.LogMsg(((Exception)e.ExceptionObject).ExceptionToString());
|
||||
}
|
||||
|
||||
|
||||
internal bool ExitWhenClosing = true;
|
||||
|
||||
private void Window_Closing(object sender, CancelEventArgs e)
|
||||
{
|
||||
if (ExitWhenClosing)
|
||||
Application.Current.Shutdown();
|
||||
}
|
||||
}
|
||||
}
|
@ -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>
|
@ -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;
|
||||
}
|
||||
|
61
Wabbajack/UI/ModlistPropertiesWindow.xaml
Normal 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>
|
79
Wabbajack/UI/ModlistPropertiesWindow.xaml.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
202
Wabbajack/UI/SlideShow.cs
Normal file
@ -0,0 +1,202 @@
|
||||
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 (SlidesQueue.Contains(randomSlide)) 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;
|
||||
}
|
||||
|
||||
_appState.lastSlideShowUpdate = DateTime.Now;
|
||||
|
||||
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; }
|
||||
}
|
||||
}
|
15
Wabbajack/UI/TextViewer.xaml
Normal 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>
|
14
Wabbajack/UI/TextViewer.xaml.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
@ -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)
|
Before Width: | Height: | Size: 190 KiB After Width: | Height: | Size: 190 KiB |
Before Width: | Height: | Size: 178 KiB After Width: | Height: | Size: 178 KiB |
BIN
Wabbajack/UI/none.jpg
Normal file
After Width: | Height: | Size: 20 KiB |
@ -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
|
||||
|
@ -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
|
||||
{
|
||||
|
@ -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");
|
||||
|
30
Wabbajack/ViewModel.cs
Normal file
@ -0,0 +1,30 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Linq;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Wabbajack
|
||||
{
|
||||
public class ViewModel : INotifyPropertyChanged
|
||||
{
|
||||
public event PropertyChangedEventHandler PropertyChanged;
|
||||
|
||||
protected void RaisePropertyChanged([CallerMemberName] string name = null)
|
||||
{
|
||||
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
|
||||
}
|
||||
|
||||
protected void RaiseAndSetIfChanged<T>(
|
||||
ref T item,
|
||||
T newItem,
|
||||
[CallerMemberName] string propertyName = null)
|
||||
{
|
||||
if (EqualityComparer<T>.Default.Equals(item, newItem)) return;
|
||||
item = newItem;
|
||||
this.RaisePropertyChanged(propertyName);
|
||||
}
|
||||
}
|
||||
}
|
@ -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,20 +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>
|
||||
@ -211,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>
|
||||
@ -223,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" />
|
||||
@ -279,7 +295,7 @@
|
||||
</BootstrapperPackage>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Resource Include="square_transparent_icon.ico" />
|
||||
<Resource Include="UI\Icons\wabbajack.ico" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="css.css" />
|
||||
@ -288,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">
|
||||
|
@ -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 =
|
||||
|