mirror of
https://gitlab.com/2009scape/Saradomin-Launcher.git
synced 2026-08-01 14:19:14 -06:00
Add basic singleplayer support to launcher - Needs to make it so updating doesn't wipe player saves before release
This commit is contained in:
parent
97254662d7
commit
f0e08d2628
11 changed files with 546 additions and 11 deletions
2
Saradomin.sln.DotSettings
Normal file
2
Saradomin.sln.DotSettings
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=Singleplayer/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>
|
||||
|
|
@ -20,7 +20,7 @@ namespace Saradomin.Infrastructure.Services
|
|||
public string ClientHashURL => "https://gitlab.com/2009scape/rt4-client/-/jobs/artifacts/master/raw/client/build/libs/rt4-client.jar.sha256?job=build";
|
||||
|
||||
public string PreferredTargetFilePath =>
|
||||
CrossPlatform.Locate2009scapeExecutable(_settingsService.Launcher.InstallationDirectory);
|
||||
CrossPlatform.Locate2009scapeExecutable();
|
||||
|
||||
public event EventHandler<float> DownloadProgressChanged;
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,12 @@
|
|||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using Glitonea.Mvvm;
|
||||
|
||||
namespace Saradomin.Infrastructure.Services
|
||||
{
|
||||
public interface ISingleplayerUpdateService : IService
|
||||
{
|
||||
event EventHandler<Tuple<float, bool>> SingleplayerDownloadProgressChanged;
|
||||
Task DownloadSingleplayer();
|
||||
}
|
||||
}
|
||||
|
|
@ -4,6 +4,7 @@ using System.IO.Compression;
|
|||
using System.Net.Http;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Threading.Tasks;
|
||||
using Saradomin.Model.Settings.Launcher;
|
||||
using Saradomin.Utilities;
|
||||
|
||||
namespace Saradomin.Infrastructure.Services
|
||||
|
|
@ -59,7 +60,8 @@ namespace Saradomin.Infrastructure.Services
|
|||
|
||||
if (Path.GetExtension(downloadUrl) == ".zip")
|
||||
{
|
||||
string tempDir = Path.Combine(Path.GetTempPath(), "jre11_temp");
|
||||
// Don't use /tmp because Directory.Move doesn't work cross-partition
|
||||
string tempDir = Path.Combine(CrossPlatform.LocateDefault2009scapeHome(), "jre11_temp");
|
||||
if (Directory.Exists(tempDir)) Directory.Delete(tempDir, true);
|
||||
await Task.Run(() => ZipFile.ExtractToDirectory(downloadPath, tempDir));
|
||||
Directory.Move(Directory.GetDirectories(tempDir)[0], extractedPath);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,74 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
using System.IO.Compression;
|
||||
using System.Net.Http;
|
||||
using System.Threading.Tasks;
|
||||
using Saradomin.Utilities;
|
||||
|
||||
namespace Saradomin.Infrastructure.Services
|
||||
{
|
||||
public class SingleplayerUpdateService : ISingleplayerUpdateService
|
||||
{
|
||||
public event EventHandler<Tuple<float, bool>> SingleplayerDownloadProgressChanged;
|
||||
|
||||
public async Task DownloadSingleplayer()
|
||||
{
|
||||
SingleplayerDownloadProgressChanged?.Invoke(this, new Tuple<float, bool>(0f, false));
|
||||
string downloadUrl =
|
||||
"https://gitlab.com/2009scape/singleplayer/windows/-/archive/master/windows-master.zip";
|
||||
|
||||
string downloadPath = Path.Combine(
|
||||
CrossPlatform.LocateDefault2009scapeHome(),
|
||||
"singleplayer" + Path.GetExtension(downloadUrl)
|
||||
);
|
||||
|
||||
using (HttpClient httpClient = new HttpClient())
|
||||
{
|
||||
var response = await httpClient.GetAsync(downloadUrl, HttpCompletionOption.ResponseHeadersRead);
|
||||
var contentLength = response.Content.Headers.ContentLength ?? 40 * 1024 * 1024L;
|
||||
var totalRead = 0L;
|
||||
var buffer = new byte[8192];
|
||||
|
||||
// Create a FileStream to write the downloaded bytes to
|
||||
await using (var fileStream =
|
||||
new FileStream(downloadPath, FileMode.Create, FileAccess.Write, FileShare.None))
|
||||
{
|
||||
await using (var stream = await response.Content.ReadAsStreamAsync())
|
||||
{
|
||||
int bytesRead;
|
||||
do
|
||||
{
|
||||
bytesRead = await stream.ReadAsync(buffer, 0, buffer.Length);
|
||||
totalRead += bytesRead;
|
||||
|
||||
// Write the bytes to the FileStream
|
||||
await fileStream.WriteAsync(buffer, 0, bytesRead);
|
||||
|
||||
var progress = (float)totalRead / contentLength;
|
||||
SingleplayerDownloadProgressChanged?.Invoke(this,
|
||||
new Tuple<float, bool>(progress, false));
|
||||
} while (bytesRead > 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SingleplayerDownloadProgressChanged?.Invoke(this, new Tuple<float, bool>(1f, false));
|
||||
|
||||
if (Directory.Exists(CrossPlatform.LocateSingleplayerHome())) Directory.Delete(CrossPlatform.LocateSingleplayerHome(), true);
|
||||
|
||||
// Don't use /tmp because Directory.Move doesn't work cross-partition
|
||||
string tempDir = Path.Combine(CrossPlatform.LocateDefault2009scapeHome(), "singleplayer_temp");
|
||||
if (Directory.Exists(tempDir)) Directory.Delete(tempDir, true);
|
||||
await Task.Run(() => ZipFile.ExtractToDirectory(downloadPath, tempDir));
|
||||
foreach (string directory in Directory.GetDirectories(tempDir))
|
||||
{
|
||||
Console.WriteLine("Found directory " + directory + " in " + tempDir);
|
||||
}
|
||||
Directory.Move(Directory.GetDirectories(tempDir)[0], CrossPlatform.LocateSingleplayerHome());
|
||||
Directory.Delete(tempDir, true);
|
||||
|
||||
File.Delete(downloadPath);
|
||||
SingleplayerDownloadProgressChanged?.Invoke(this, new Tuple<float, bool>(1f, true));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -66,6 +66,10 @@
|
|||
<DependentUpon>NotificationBox.axaml</DependentUpon>
|
||||
<SubType>Code</SubType>
|
||||
</Compile>
|
||||
<Compile Update="Views\Controls\SingleplayerView.axaml.cs">
|
||||
<DependentUpon>MainWindow.axaml</DependentUpon>
|
||||
<SubType>Code</SubType>
|
||||
</Compile>
|
||||
<Compile Update="Views\Controls\SettingsView.axaml.cs">
|
||||
<DependentUpon>MainWindow.axaml</DependentUpon>
|
||||
<SubType>Code</SubType>
|
||||
|
|
@ -77,6 +81,10 @@
|
|||
<Compile Update="View\Controls\PluginManagerView.axaml.cs">
|
||||
<DependentUpon>PluginManagerView.axaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Update="View\Controls\SingleplayerView.axaml.cs">
|
||||
<DependentUpon>SingleplayerView.axaml</DependentUpon>
|
||||
<SubType>Code</SubType>
|
||||
</Compile>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ using System.Diagnostics;
|
|||
using System.IO;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using Microsoft.CodeAnalysis.Text;
|
||||
using Microsoft.Win32;
|
||||
using Mono.Unix;
|
||||
|
||||
|
|
@ -206,11 +207,31 @@ namespace Saradomin.Utilities
|
|||
);
|
||||
}
|
||||
}
|
||||
|
||||
public static string Locate2009scapeExecutable(string baseDirectory)
|
||||
|
||||
public static string LocateSingleplayerHome()
|
||||
{
|
||||
baseDirectory ??= LocateDefault2009scapeHome();
|
||||
return Path.Combine(baseDirectory, "2009scape.jar");
|
||||
return Path.Combine(LocateDefault2009scapeHome(), "singleplayer");
|
||||
}
|
||||
|
||||
public static string LocateSingleplayerExecutable()
|
||||
{
|
||||
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
|
||||
{
|
||||
return Path.Combine(LocateSingleplayerHome(), "launch.bat");
|
||||
}
|
||||
|
||||
if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
|
||||
{
|
||||
return Path.Combine(LocateSingleplayerHome(), "launch.sh");
|
||||
}
|
||||
|
||||
throw new InvalidOperationException("Unsupported OS for singleplayer: " +
|
||||
RuntimeInformation.OSArchitecture);
|
||||
}
|
||||
|
||||
public static string Locate2009scapeExecutable()
|
||||
{
|
||||
return Path.Combine(LocateDefault2009scapeHome(), "2009scape.jar");
|
||||
}
|
||||
|
||||
public static string LocateServerProfilesPath(string baseDirectory)
|
||||
|
|
@ -219,11 +240,10 @@ namespace Saradomin.Utilities
|
|||
return Path.Combine(baseDirectory, "server_profiles.json");
|
||||
}
|
||||
|
||||
public static string RunCommandAndGetOutput(string command)
|
||||
public static string RunCommandAndGetOutput(string command, Action<string> onOutputReceived = null, Action<string> onErrorReceived = null)
|
||||
{
|
||||
Process process = new Process();
|
||||
StringBuilder output = new StringBuilder();
|
||||
|
||||
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
|
||||
{
|
||||
process.StartInfo = new ProcessStartInfo("cmd.exe", "/c " + command)
|
||||
|
|
@ -250,12 +270,16 @@ namespace Saradomin.Utilities
|
|||
|
||||
process.OutputDataReceived += (_, e) =>
|
||||
{
|
||||
if (e.Data != null) output.AppendLine(e.Data);
|
||||
if (e.Data == null) return;
|
||||
output.AppendLine(e.Data);
|
||||
onOutputReceived?.Invoke(e.Data);
|
||||
};
|
||||
|
||||
process.ErrorDataReceived += (_, e) =>
|
||||
{
|
||||
if (e.Data != null) output.AppendLine(e.Data);
|
||||
if (e.Data == null) return;
|
||||
output.AppendLine(e.Data);
|
||||
onErrorReceived?.Invoke(e.Data);
|
||||
};
|
||||
|
||||
process.Start();
|
||||
|
|
|
|||
236
Saradomin/View/Controls/SingleplayerView.axaml
Normal file
236
Saradomin/View/Controls/SingleplayerView.axaml
Normal file
|
|
@ -0,0 +1,236 @@
|
|||
<UserControl x:Class="Saradomin.View.Controls.SingleplayerView"
|
||||
xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:controls="clr-namespace:Saradomin.View.Controls"
|
||||
xmlns:converters="clr-namespace:Glitonea.Mvvm.Converters;assembly=Glitonea"
|
||||
xmlns:glitonea="clr-namespace:Glitonea;assembly=Glitonea"
|
||||
xmlns:mvvm="clr-namespace:Glitonea.Mvvm;assembly=Glitonea"
|
||||
xmlns:vm="clr-namespace:Saradomin.ViewModel.Controls"
|
||||
DataContext="{mvvm:DataContextSource vm:SingleplayerViewModel}">
|
||||
<Grid Margin="0,0,2,2"
|
||||
ColumnDefinitions="400,*">
|
||||
<DockPanel Grid.Column="0">
|
||||
<HeaderedContentControl Classes="GroupBox"
|
||||
DockPanel.Dock="Top"
|
||||
Header="singleplayer logs"
|
||||
IsVisible="{Binding IsRunning}"
|
||||
>
|
||||
<ScrollViewer HorizontalAlignment="Left"
|
||||
ClipToBounds="True"
|
||||
Height="300"
|
||||
Width="390"
|
||||
Content="{Binding SingleplayerLogsTextBox}"
|
||||
HorizontalScrollBarVisibility="Auto"
|
||||
VerticalScrollBarVisibility="Visible" />
|
||||
</HeaderedContentControl>
|
||||
|
||||
<HeaderedContentControl Classes="GroupBox"
|
||||
DockPanel.Dock="Top"
|
||||
Header="singleplayer info"
|
||||
IsVisible="{Binding !IsRunning}"
|
||||
>
|
||||
<StackPanel Orientation="Vertical">
|
||||
<TextBlock
|
||||
Margin="0,0,4,0"
|
||||
Foreground="{StaticResource DarkForegroundBrush}"
|
||||
Text="Singleplayer is provided by the 2009scape team" />
|
||||
<TextBlock
|
||||
Margin="0,0,4,8"
|
||||
Foreground="{StaticResource DarkForegroundBrush}"
|
||||
Text="for advanced users only." />
|
||||
|
||||
<TextBlock
|
||||
Margin="0,0,4,0"
|
||||
Foreground="{StaticResource DarkForegroundBrush}"
|
||||
Text="2009scape official servers have free membership," />
|
||||
<TextBlock
|
||||
Margin="0,0,4,0"
|
||||
Foreground="{StaticResource DarkForegroundBrush}"
|
||||
Text="multiple exp rates, and are hosted 24/7." />
|
||||
<TextBlock
|
||||
Margin="0,0,4,0"
|
||||
Foreground="{StaticResource DarkForegroundBrush}"
|
||||
Text="In addition, your player save file" />
|
||||
<TextBlock
|
||||
Margin="0,0,4,0"
|
||||
Foreground="{StaticResource DarkForegroundBrush}"
|
||||
Text="is always exportable from the multiplayer server" />
|
||||
<TextBlock
|
||||
Margin="0,0,4,0"
|
||||
Foreground="{StaticResource DarkForegroundBrush}"
|
||||
Text="if you ever choose" />
|
||||
<TextBlock
|
||||
Margin="0,0,4,0"
|
||||
Foreground="{StaticResource DarkForegroundBrush}"
|
||||
Text="to switch to singleplayer - However," />
|
||||
<TextBlock
|
||||
Margin="0,0,4,0"
|
||||
Foreground="{StaticResource DarkForegroundBrush}"
|
||||
Text="we will not import your singleplayer save" />
|
||||
<TextBlock
|
||||
Margin="0,0,4,8"
|
||||
Foreground="{StaticResource DarkForegroundBrush}"
|
||||
Text="file into the multiplayer world." />
|
||||
|
||||
<TextBlock
|
||||
Margin="0,0,4,0"
|
||||
Foreground="{StaticResource DarkForegroundBrush}"
|
||||
Text="It is our strong recommendation" />
|
||||
<TextBlock
|
||||
Margin="0,0,4,0"
|
||||
Foreground="{StaticResource DarkForegroundBrush}"
|
||||
Text="to play the multiplayer server instead." />
|
||||
<TextBlock
|
||||
Margin="0,0,4,0"
|
||||
Foreground="{StaticResource DarkForegroundBrush}"
|
||||
Text="If you have any questions," />
|
||||
<TextBlock
|
||||
Margin="0,0,4,8"
|
||||
Foreground="{StaticResource DarkForegroundBrush}"
|
||||
Text="feel free to ask on our Discord or Forums." />
|
||||
|
||||
</StackPanel>
|
||||
</HeaderedContentControl>
|
||||
|
||||
<HeaderedContentControl Classes="GroupBox"
|
||||
DockPanel.Dock="Top"
|
||||
Header="singleplayer links">
|
||||
<StackPanel Orientation="Vertical">
|
||||
<Button
|
||||
Margin="0,0,0,0"
|
||||
Width="140"
|
||||
Height="25"
|
||||
BorderBrush="{StaticResource DarkBorderBrush}"
|
||||
BorderThickness="1"
|
||||
Classes="OutsideNavigator"
|
||||
Command="{Binding LaunchFaq}"
|
||||
Opacity="1"
|
||||
FontSize="11"
|
||||
Content="singleplayer faq"
|
||||
ZIndex="9999" />
|
||||
|
||||
<Button
|
||||
Margin="0,0,0,0"
|
||||
Width="140"
|
||||
Height="25"
|
||||
BorderBrush="{StaticResource DarkBorderBrush}"
|
||||
BorderThickness="1"
|
||||
Classes="OutsideNavigator"
|
||||
Command="{Binding LaunchForums}"
|
||||
Opacity="1"
|
||||
FontSize="11"
|
||||
Content="support forums"
|
||||
ZIndex="9999" />
|
||||
</StackPanel>
|
||||
</HeaderedContentControl>
|
||||
</DockPanel>
|
||||
<DockPanel Grid.Column="1">
|
||||
<HeaderedContentControl Classes="GroupBox"
|
||||
DockPanel.Dock="Top"
|
||||
Header="singleplayer launch">
|
||||
<StackPanel Orientation="Vertical">
|
||||
<Button
|
||||
Margin="0,0,0,0"
|
||||
Width="140"
|
||||
Height="25"
|
||||
BorderBrush="{StaticResource DarkBorderBrush}"
|
||||
BorderThickness="1"
|
||||
Classes="OutsideNavigator"
|
||||
Command="{Binding DownloadSingleplayer}"
|
||||
Opacity="1"
|
||||
FontSize="11"
|
||||
Content="{Binding SingleplayerDownloadText}"
|
||||
ZIndex="9999"
|
||||
IsEnabled="{Binding CanDownload}" />
|
||||
|
||||
<Button
|
||||
Margin="0,0,0,0"
|
||||
Width="140"
|
||||
Height="25"
|
||||
BorderBrush="{StaticResource DarkBorderBrush}"
|
||||
BorderThickness="1"
|
||||
Classes="OutsideNavigator"
|
||||
Command="{Binding LaunchSingleplayer}"
|
||||
Opacity="1"
|
||||
FontSize="11"
|
||||
Content="Start Singleplayer"
|
||||
ZIndex="9999"
|
||||
IsEnabled="{Binding CanLaunch}" />
|
||||
|
||||
<Grid Margin="0,2,0,4"
|
||||
ColumnDefinitions="*,Auto"
|
||||
RowDefinitions="Auto,Auto">
|
||||
<TextBlock Grid.Row="0"
|
||||
Grid.ColumnSpan="2"
|
||||
Margin="3,0,0,2"
|
||||
Foreground="{StaticResource DarkForegroundBrush}"
|
||||
Text="2009scape installation directory" />
|
||||
|
||||
<!--
|
||||
Don't let the user edit it directly to avoid creating a ton of directories,
|
||||
since we get a notification every time the textbox is updated.
|
||||
-->
|
||||
<TextBox Grid.Row="1"
|
||||
Grid.Column="0"
|
||||
Width="300"
|
||||
Margin="2,0,0,0"
|
||||
HorizontalAlignment="Left"
|
||||
Classes="NormalTextBox"
|
||||
IsReadOnly="True"
|
||||
Text="{Binding Launcher.InstallationDirectory, Mode=TwoWay}"
|
||||
Watermark="Enter a path to your preferred installation directory..." />
|
||||
|
||||
<Button Grid.Row="1"
|
||||
Grid.Column="1"
|
||||
Width="22"
|
||||
Height="24"
|
||||
Margin="2,0,0,0"
|
||||
Classes="OutsideNavigator"
|
||||
Command="{Binding BrowseForInstallationDirectory}"
|
||||
Content="..."
|
||||
ToolTip.Tip="Browse..." />
|
||||
</Grid>
|
||||
|
||||
</StackPanel>
|
||||
</HeaderedContentControl>
|
||||
|
||||
<HeaderedContentControl Margin="2,2,0,0"
|
||||
Classes="GroupBox"
|
||||
DockPanel.Dock="Top"
|
||||
Header="singleplayer config">
|
||||
<HeaderedContentControl.HeaderTemplate>
|
||||
<DataTemplate>
|
||||
<TextBlock HorizontalAlignment="Center"
|
||||
Text="{Binding Header}" />
|
||||
</DataTemplate>
|
||||
</HeaderedContentControl.HeaderTemplate>
|
||||
|
||||
<StackPanel>
|
||||
<TextBlock HorizontalAlignment="Center"
|
||||
Foreground="{StaticResource DarkForegroundBrush}"
|
||||
Text="Not configurable via launcher for now. Edit config file manually." />
|
||||
|
||||
<CheckBox Content="Place 'X' button on the left"
|
||||
IsEnabled="False"
|
||||
IsChecked="{Binding Launcher.PlaceCloseButtonOnLeft, Mode=TwoWay}" />
|
||||
|
||||
<CheckBox Content="Close the launcher after executing the client"
|
||||
IsEnabled="False"
|
||||
IsChecked="{Binding Launcher.ExitAfterLaunchingClient, Mode=TwoWay}" />
|
||||
|
||||
<CheckBox Content="Check for client updates on launch"
|
||||
IsEnabled="False"
|
||||
IsChecked="{Binding Launcher.CheckForClientUpdatesOnLaunch, Mode=TwoWay}" />
|
||||
|
||||
<CheckBox Content="Check for updated server profiles on launch"
|
||||
IsEnabled="False"
|
||||
IsChecked="{Binding Launcher.CheckForServerProfilesOnLaunch, Mode=TwoWay}" />
|
||||
|
||||
<CheckBox Content="Allow multiple client instances to run"
|
||||
IsEnabled="False"
|
||||
IsChecked="{Binding Launcher.AllowMultiboxing, Mode=TwoWay}" />
|
||||
</StackPanel>
|
||||
</HeaderedContentControl>
|
||||
</DockPanel>
|
||||
</Grid>
|
||||
</UserControl>
|
||||
20
Saradomin/View/Controls/SingleplayerView.axaml.cs
Normal file
20
Saradomin/View/Controls/SingleplayerView.axaml.cs
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
using Avalonia.Controls;
|
||||
using Avalonia.Markup.Xaml;
|
||||
using PropertyChanged;
|
||||
|
||||
namespace Saradomin.View.Controls
|
||||
{
|
||||
[DoNotNotify]
|
||||
public class SingleplayerView : UserControl
|
||||
{
|
||||
public SingleplayerView()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
private void InitializeComponent()
|
||||
{
|
||||
AvaloniaXamlLoader.Load(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -111,7 +111,7 @@
|
|||
|
||||
<TabItem Width="95"
|
||||
HorizontalContentAlignment="Center"
|
||||
CornerRadius="0,0,8,0"
|
||||
CornerRadius="0,0,0,0"
|
||||
Header="settings">
|
||||
<Border Margin="4,0,4,0"
|
||||
Background="{StaticResource MediumBackgroundBrush}"
|
||||
|
|
@ -125,6 +125,23 @@
|
|||
</ScrollViewer>
|
||||
</Border>
|
||||
</TabItem>
|
||||
|
||||
<TabItem Width="95"
|
||||
HorizontalContentAlignment="Center"
|
||||
CornerRadius="0,0,8,0"
|
||||
Header="singleplayer">
|
||||
<Border Margin="4,0,4,0"
|
||||
Background="{StaticResource MediumBackgroundBrush}"
|
||||
BorderBrush="{StaticResource SemiLightMediumBorderBrush}"
|
||||
BorderThickness="1,1,1,0"
|
||||
CornerRadius="6,6,0,0">
|
||||
<ScrollViewer Classes="MainViewScrollViewer"
|
||||
HorizontalScrollBarVisibility="Hidden"
|
||||
VerticalScrollBarVisibility="Visible">
|
||||
<controls:SingleplayerView VerticalAlignment="Stretch" />
|
||||
</ScrollViewer>
|
||||
</Border>
|
||||
</TabItem>
|
||||
</TabControl>
|
||||
|
||||
<Border Grid.Row="2"
|
||||
|
|
|
|||
140
Saradomin/ViewModel/Controls/SingleplayerViewModel.cs
Normal file
140
Saradomin/ViewModel/Controls/SingleplayerViewModel.cs
Normal file
|
|
@ -0,0 +1,140 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
using System.Threading.Tasks;
|
||||
using Avalonia;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Layout;
|
||||
using Avalonia.Media;
|
||||
using Avalonia.Threading;
|
||||
using Glitonea.Extensions;
|
||||
using Glitonea.Mvvm;
|
||||
using Glitonea.Mvvm.Messaging;
|
||||
using Saradomin.Infrastructure.Messaging;
|
||||
using Saradomin.Infrastructure.Services;
|
||||
using Saradomin.Model.Settings.Launcher;
|
||||
using Saradomin.Utilities;
|
||||
using Saradomin.View.Windows;
|
||||
|
||||
namespace Saradomin.ViewModel.Controls
|
||||
{
|
||||
public class SingleplayerViewModel : ViewModelBase
|
||||
{
|
||||
private readonly ISingleplayerUpdateService _singleplayerUpdateService;
|
||||
private readonly ISettingsService _settingsService;
|
||||
|
||||
public string SingleplayerDownloadText { get; private set; } = "Download Singleplayer";
|
||||
public bool CanDownload { get; private set; } = true;
|
||||
public bool CanLaunch => File.Exists(CrossPlatform.LocateSingleplayerExecutable());
|
||||
public bool IsRunning {get ; private set; }
|
||||
public TextBox SingleplayerLogsTextBox { get; private set; }
|
||||
|
||||
public LauncherSettings Launcher => _settingsService.Launcher;
|
||||
|
||||
public SingleplayerViewModel(ISettingsService settingsService, ISingleplayerUpdateService iSingleplayerUpdateService)
|
||||
{
|
||||
_settingsService = settingsService;
|
||||
Message.Subscribe<MainViewLoadedMessage>(this, OnMainViewLoaded);
|
||||
_singleplayerUpdateService = iSingleplayerUpdateService;
|
||||
_singleplayerUpdateService.SingleplayerDownloadProgressChanged += OnSingleplayerDownloadProgressChanged;
|
||||
|
||||
SingleplayerLogsTextBox = new TextBox
|
||||
{
|
||||
Foreground = new SolidColorBrush(Colors.Black),
|
||||
FontSize = 12,
|
||||
Margin = new Thickness(8, 0, 0, 0),
|
||||
IsReadOnly = true,
|
||||
BorderThickness = new Thickness(0),
|
||||
Background = Brushes.Transparent,
|
||||
AcceptsReturn = true,
|
||||
TextWrapping = TextWrapping.Wrap,
|
||||
};
|
||||
}
|
||||
|
||||
private void OnSingleplayerDownloadProgressChanged(object sender, Tuple<float, bool> e)
|
||||
{
|
||||
float progress = e.Item1;
|
||||
bool finished = e.Item2;
|
||||
CanDownload = finished;
|
||||
if (finished)
|
||||
{
|
||||
SingleplayerDownloadText = "Download Singleplayer";
|
||||
return;
|
||||
}
|
||||
|
||||
if (progress >= 1f)
|
||||
{
|
||||
SingleplayerDownloadText = "Extracting...";
|
||||
return;
|
||||
}
|
||||
SingleplayerDownloadText = $"Downloading... {progress * 100:F2}%";
|
||||
}
|
||||
|
||||
private void OnMainViewLoaded(MainViewLoadedMessage _)
|
||||
{
|
||||
Message.Subscribe<SettingsModifiedMessage>(this, OnSettingsModified);
|
||||
}
|
||||
|
||||
private void OnSettingsModified(SettingsModifiedMessage _)
|
||||
{
|
||||
Console.WriteLine("Saving settings");
|
||||
_settingsService.SaveAll();
|
||||
}
|
||||
|
||||
public void DownloadSingleplayer()
|
||||
{
|
||||
_singleplayerUpdateService.DownloadSingleplayer();
|
||||
Console.WriteLine("Download singleplayer button clicked");
|
||||
}
|
||||
|
||||
public void PrintLog(string message)
|
||||
{
|
||||
Dispatcher.UIThread.Post(() =>
|
||||
{
|
||||
SingleplayerLogsTextBox.Text += message + Environment.NewLine;
|
||||
}, DispatcherPriority.Background);
|
||||
}
|
||||
|
||||
public void LaunchSingleplayer()
|
||||
{
|
||||
IsRunning = true;
|
||||
new Task(() => CrossPlatform.RunCommandAndGetOutput(CrossPlatform.LocateSingleplayerExecutable(), PrintLog, PrintLog)).Start();
|
||||
}
|
||||
|
||||
private void LaunchFaq()
|
||||
{
|
||||
CrossPlatform.LaunchURL("https://2009scape.org/site/game_guide/singleplayer.html");
|
||||
}
|
||||
|
||||
private void LaunchForums()
|
||||
{
|
||||
CrossPlatform.LaunchURL("https://forum.2009scape.org/viewforum.php?f=8-support");
|
||||
}
|
||||
|
||||
private async Task BrowseForInstallationDirectory()
|
||||
{
|
||||
var ofd = new OpenFolderDialog
|
||||
{
|
||||
Title = "Browse for Installation Directory...",
|
||||
Directory = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile)
|
||||
};
|
||||
|
||||
var path = await ofd.ShowAsync(Application.Current.GetMainWindow());
|
||||
|
||||
if (path != null)
|
||||
{
|
||||
if (CrossPlatform.IsDirectoryWritable(path))
|
||||
{
|
||||
Launcher.InstallationDirectory = path;
|
||||
}
|
||||
else
|
||||
{
|
||||
NotificationBox.DisplayNotification(
|
||||
"Access denied",
|
||||
"The location you have selected is not writable. Select the one you have permissions for.",
|
||||
Application.Current.GetMainWindow()
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue