diff --git a/CHANGELOG.md b/CHANGELOG.md index f07739f2..0ea1ba99 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ * Adding `matchAll=` to a *mods's* `meta.ini` file will result in unconditional patching for all unmatching files or BSAs in that mod (issue #465) * Added support for non-premium Nexus downloads via manual downloading through the in-app browser. +* Downloads from Bethesda.NET are now supported. Can login via SkyrimSE or Fallout 4. ======= diff --git a/Wabbajack.Common/GameMetaData.cs b/Wabbajack.Common/GameMetaData.cs index bac276f4..f65a6ddd 100644 --- a/Wabbajack.Common/GameMetaData.cs +++ b/Wabbajack.Common/GameMetaData.cs @@ -86,7 +86,9 @@ namespace Wabbajack.Common return FileVersionInfo.GetVersionInfo(Path.Combine(GameLocation(), MainExecutable)).ProductVersion; } } - + + public bool IsInstalled => GameLocation() != null; + public string MainExecutable { get; internal set; } public string GameLocation() diff --git a/Wabbajack.Lib/Downloaders/BethesdaNet/bethnetlogin.exe b/Wabbajack.Lib/Downloaders/BethesdaNet/bethnetlogin.exe index a87eb7ed..8626d2ea 100644 Binary files a/Wabbajack.Lib/Downloaders/BethesdaNet/bethnetlogin.exe and b/Wabbajack.Lib/Downloaders/BethesdaNet/bethnetlogin.exe differ diff --git a/Wabbajack.Lib/Downloaders/BethesdaNet/bethnetlogin.py b/Wabbajack.Lib/Downloaders/BethesdaNet/bethnetlogin.py index 356d55c6..e6547b1d 100644 --- a/Wabbajack.Lib/Downloaders/BethesdaNet/bethnetlogin.py +++ b/Wabbajack.Lib/Downloaders/BethesdaNet/bethnetlogin.py @@ -7,16 +7,18 @@ import frida import sys from subprocess import Popen, PIPE import psutil, time, json +from pathlib import Path known_headers = {} shutdown = False + def on_message(message, data): msg_type, msg_data = message["payload"] if msg_type == "header": - header, value = msg_data.split(": "); + header, value = msg_data.split(": ") if header not in known_headers: - known_headers[header] = value; + known_headers[header] = value if msg_type == "data": try: data = json.loads(msg_data) @@ -25,6 +27,7 @@ def on_message(message, data): except: return + def main(target_process): session = frida.attach(target_process) @@ -64,40 +67,57 @@ def main(target_process): """) script.on('message', on_message) script.load() - - while not shutdown: - time.sleep(0.5); - + + while not shutdown and psutil.pid_exists(target_process): + time.sleep(0.5) + session.detach() - -def wait_for_game(name): + sys.exit(1) + + +def wait_for_game(started, name): + no_exe = 0 + parent_path = Path(started).parent while True: - time.sleep(1); + found = False + time.sleep(1) for proc in psutil.process_iter(): + try: + if Path(proc.exe()).parent == parent_path: + no_exe = 0 + found = True + except: + pass if proc.name() == name: - return proc.pid; - + return proc.pid + + if not found: + print("Not Found " + str(no_exe)) + no_exe += 1 + if no_exe == 3: + sys.exit(1) + + def shutdown_and_print(data): global shutdown output = {"body": json.dumps(data), "headers": known_headers} - + print(json.dumps(output)) - + for proc in psutil.process_iter(): if proc.pid == pid: - proc.kill(); + proc.kill() break - - shutdown = True; - - + + shutdown = True + if __name__ == '__main__': start = """C:\Steam\steamapps\common\Skyrim Special Edition\SkyrimSE.exe""" wait_for = "SkyrimSE.exe" if len(sys.argv) == 3: - start = sys.argv[1]; + start = sys.argv[1] wait_for = sys.argv[2] target_process = Popen([start]) - pid = wait_for_game(wait_for); - main(pid) \ No newline at end of file + pid = wait_for_game(start, wait_for) + main(pid) diff --git a/Wabbajack.Lib/Downloaders/BethesdaNetDownloader.cs b/Wabbajack.Lib/Downloaders/BethesdaNetDownloader.cs index b1425e8f..76d1d54b 100644 --- a/Wabbajack.Lib/Downloaders/BethesdaNetDownloader.cs +++ b/Wabbajack.Lib/Downloaders/BethesdaNetDownloader.cs @@ -63,13 +63,14 @@ namespace Wabbajack.Lib.Downloaders await Utils.Log(new RequestBethesdaNetLogin()).Task; } - public static async Task Login() + public static async Task Login(Game game) { - var game = Path.Combine(Game.SkyrimSpecialEdition.MetaData().GameLocation(), "SkyrimSE.exe"); + var metadata = game.MetaData(); + var gamePath = Path.Combine(metadata.GameLocation(), metadata.MainExecutable); var info = new ProcessStartInfo { FileName = @"Downloaders\BethesdaNet\bethnetlogin.exe", - Arguments = $"\"{game}\" SkyrimSE.exe", + Arguments = $"\"{gamePath}\" {metadata.MainExecutable}", RedirectStandardError = true, RedirectStandardInput = true, RedirectStandardOutput = true, @@ -87,9 +88,16 @@ namespace Wabbajack.Lib.Downloaders last_line = line; } - var result = last_line.FromJSONString(); - result.ToEcryptedJson(DataName); - return result; + try + { + var result = last_line.FromJSONString(); + result.ToEcryptedJson(DataName); + return result; + } + catch (Exception _) + { + return null; + } } public AbstractDownloadState GetDownloaderState(string url) diff --git a/Wabbajack/Resources/GameGridIcons/Fallout4.png b/Wabbajack/Resources/GameGridIcons/Fallout4.png new file mode 100644 index 00000000..4fd71b34 Binary files /dev/null and b/Wabbajack/Resources/GameGridIcons/Fallout4.png differ diff --git a/Wabbajack/Resources/GameGridIcons/SkyrimSpecialEdition.png b/Wabbajack/Resources/GameGridIcons/SkyrimSpecialEdition.png new file mode 100644 index 00000000..89faa353 Binary files /dev/null and b/Wabbajack/Resources/GameGridIcons/SkyrimSpecialEdition.png differ diff --git a/Wabbajack/View Models/UserIntervention/BethesdaNetLoginVM.cs b/Wabbajack/View Models/UserIntervention/BethesdaNetLoginVM.cs new file mode 100644 index 00000000..acd98f97 --- /dev/null +++ b/Wabbajack/View Models/UserIntervention/BethesdaNetLoginVM.cs @@ -0,0 +1,64 @@ +using System.Reactive; +using System.Reactive.Linq; +using System.Reactive.Subjects; +using System.Threading.Tasks; +using CefSharp; +using CefSharp.Wpf; +using ReactiveUI; +using ReactiveUI.Fody.Helpers; +using Wabbajack.Common; +using Wabbajack.Lib; +using Wabbajack.Lib.Downloaders; +using Wabbajack.Lib.WebAutomation; + +namespace Wabbajack +{ + public class BethesdaNetLoginVM : ViewModel, IBackNavigatingVM + { + [Reactive] + public string Instructions { get; set; } + + [Reactive] + public ViewModel NavigateBackTarget { get; set; } + + [Reactive] + public ReactiveCommand BackCommand { get; set; } + + public ReactiveCommand LoginViaSkyrimSE { get; } + public ReactiveCommand LoginViaFallout4 { get; } + + private Subject LoggingIn = new Subject(); + + private BethesdaNetLoginVM() + { + Instructions = "Login to Bethesda.NET in-game..."; + LoginViaSkyrimSE = ReactiveCommand.CreateFromTask(async () => + { + LoggingIn.OnNext(true); + Instructions = "Starting Skyrim Special Edition..."; + await BethesdaNetDownloader.Login(Game.SkyrimSpecialEdition); + LoggingIn.OnNext(false); + await BackCommand.Execute(); + }, Game.SkyrimSpecialEdition.MetaData().IsInstalled + ? LoggingIn.Select(e => !e).StartWith(true) + : Observable.Return(false)); + + LoginViaFallout4 = ReactiveCommand.CreateFromTask(async () => + { + LoggingIn.OnNext(true); + Instructions = "Starting Fallout 4..."; + await BethesdaNetDownloader.Login(Game.Fallout4); + LoggingIn.OnNext(false); + await BackCommand.Execute(); + }, Game.Fallout4.MetaData().IsInstalled + ? LoggingIn.Select(e => !e).StartWith(true) + : Observable.Return(false)); + } + + public static async Task GetNew() + { + // Make sure libraries are extracted first + return new BethesdaNetLoginVM(); + } + } +} diff --git a/Wabbajack/View Models/UserInterventionHandlers.cs b/Wabbajack/View Models/UserInterventionHandlers.cs index a7402b24..05b273b1 100644 --- a/Wabbajack/View Models/UserInterventionHandlers.cs +++ b/Wabbajack/View Models/UserInterventionHandlers.cs @@ -55,6 +55,21 @@ namespace Wabbajack MainWindow.NavigateTo(oldPane); } + private async Task WrapBethesdaNetLogin(IUserIntervention intervention) + { + CancellationTokenSource cancel = new CancellationTokenSource(); + var oldPane = MainWindow.ActivePane; + var vm = await BethesdaNetLoginVM.GetNew(); + MainWindow.NavigateTo(vm); + vm.BackCommand = ReactiveCommand.Create(() => + { + cancel.Cancel(); + MainWindow.NavigateTo(oldPane); + intervention.Cancel(); + }); + + } + public async Task Handle(IUserIntervention msg) { switch (msg) @@ -71,8 +86,7 @@ namespace Wabbajack await WrapBrowserJob(msg, (vm, cancel) => HandleManualNexusDownload(vm, cancel, c)); break; case RequestBethesdaNetLogin c: - var data = await BethesdaNetDownloader.Login(); - c.Resume(data); + await WrapBethesdaNetLogin(c); break; case AbstractNeedsLoginDownloader.RequestSiteLogin c: await WrapBrowserJob(msg, async (vm, cancel) => diff --git a/Wabbajack/Views/Interventions/BethesdaNetLoginView.xaml b/Wabbajack/Views/Interventions/BethesdaNetLoginView.xaml new file mode 100644 index 00000000..075f296b --- /dev/null +++ b/Wabbajack/Views/Interventions/BethesdaNetLoginView.xaml @@ -0,0 +1,105 @@ + + + #92000000 + + #DF000000 + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Wabbajack/Views/Interventions/BethesdaNetLoginView.xaml.cs b/Wabbajack/Views/Interventions/BethesdaNetLoginView.xaml.cs new file mode 100644 index 00000000..48cbda2f --- /dev/null +++ b/Wabbajack/Views/Interventions/BethesdaNetLoginView.xaml.cs @@ -0,0 +1,13 @@ +using System.Windows.Controls; + +namespace Wabbajack +{ + public partial class BethesdaNetLoginView : UserControl + { + public BethesdaNetLoginView() + { + InitializeComponent(); + } + } +} + diff --git a/Wabbajack/Views/MainWindow.xaml b/Wabbajack/Views/MainWindow.xaml index 3b8f0781..00adc0fd 100644 --- a/Wabbajack/Views/MainWindow.xaml +++ b/Wabbajack/Views/MainWindow.xaml @@ -37,6 +37,9 @@ + + + diff --git a/Wabbajack/Wabbajack.csproj b/Wabbajack/Wabbajack.csproj index 2f3f5727..1d6c1c6a 100644 --- a/Wabbajack/Wabbajack.csproj +++ b/Wabbajack/Wabbajack.csproj @@ -39,6 +39,8 @@ + + @@ -78,11 +80,14 @@ + + +