mirror of
https://gitlab.com/2009scape/Saradomin-Launcher.git
synced 2026-08-01 14:19:14 -06:00
Merge branch 'ava11' into 'master'
Update the entire project to Avalonia 11 See merge request 2009scape/Saradomin-Launcher!54
This commit is contained in:
commit
27daeff0ed
45 changed files with 752 additions and 1095 deletions
2
Glitonea
2
Glitonea
|
|
@ -1 +1 @@
|
|||
Subproject commit 132a10de55d6ef4f16abc5daab6179d2e9cad5ee
|
||||
Subproject commit 9fb6de8da53dbdde9d782ce4ab1c36c61d98ff71
|
||||
|
|
@ -4,8 +4,6 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Saradomin", "Saradomin\Sara
|
|||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Glitonea", "Glitonea\Glitonea.csproj", "{D2884654-2246-4AC0-B53B-5F1DF33DEDD7}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UnitTests", "UnitTests\UnitTests.csproj", "{6A66E5A7-9297-410F-B061-EB386679E430}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
|
|
@ -20,9 +18,5 @@ Global
|
|||
{D2884654-2246-4AC0-B53B-5F1DF33DEDD7}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{D2884654-2246-4AC0-B53B-5F1DF33DEDD7}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{D2884654-2246-4AC0-B53B-5F1DF33DEDD7}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{6A66E5A7-9297-410F-B061-EB386679E430}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{6A66E5A7-9297-410F-B061-EB386679E430}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{6A66E5A7-9297-410F-B061-EB386679E430}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{6A66E5A7-9297-410F-B061-EB386679E430}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
|
|
|
|||
|
|
@ -1,8 +1,6 @@
|
|||
<Application x:Class="Saradomin.App"
|
||||
xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:controls="clr-namespace:Saradomin.View.Controls"
|
||||
xmlns:default="clr-namespace:Avalonia.Themes.Default;assembly=Avalonia.Themes.Default">
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
|
||||
<Application.Resources>
|
||||
<Color x:Key="DarkBackgroundColor">#3E3529</Color>
|
||||
<Color x:Key="DarkTranslucentBackgroundColor">#CC3E3529</Color>
|
||||
|
|
@ -93,8 +91,7 @@
|
|||
</Application.Resources>
|
||||
|
||||
<Application.Styles>
|
||||
<StyleInclude Source="avares://Avalonia.Themes.Default/Accents/BaseDark.xaml" />
|
||||
<StyleInclude Source="avares://Avalonia.Themes.Default/DefaultTheme.xaml" />
|
||||
<SimpleTheme />
|
||||
|
||||
<StyleInclude Source="avares://Saradomin/Resources/Styles/TopBarNavigation.axaml" />
|
||||
<StyleInclude Source="avares://Saradomin/Resources/Styles/CloseButton.axaml" />
|
||||
|
|
@ -102,7 +99,9 @@
|
|||
<StyleInclude Source="avares://Saradomin/Resources/Styles/GroupBox.axaml" />
|
||||
<StyleInclude Source="avares://Saradomin/Resources/Styles/CheckBox.axaml" />
|
||||
<StyleInclude Source="avares://Saradomin/Resources/Styles/ComboBox.axaml" />
|
||||
<StyleInclude Source="avares://Saradomin/Resources/Styles/Expander.axaml" />
|
||||
<StyleInclude Source="avares://Saradomin/Resources/Styles/TextBox.axaml" />
|
||||
<StyleInclude Source="avares://Saradomin/Resources/Styles/TextBlock.axaml" />
|
||||
<StyleInclude Source="avares://Saradomin/Resources/Styles/ScrollBar.axaml" />
|
||||
<StyleInclude Source="avares://Saradomin/Resources/Styles/NumericUpDown.axaml" />
|
||||
<StyleInclude Source="avares://Saradomin/Resources/Styles/Hyperlink.axaml" />
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@ using Avalonia;
|
|||
using Avalonia.Controls.ApplicationLifetimes;
|
||||
using Avalonia.Markup.Xaml;
|
||||
using Glitonea;
|
||||
using Glitonea.Mvvm;
|
||||
using PropertyChanged;
|
||||
using Saradomin.View.Windows;
|
||||
|
||||
|
|
|
|||
10
Saradomin/Infrastructure/Messages.cs
Normal file
10
Saradomin/Infrastructure/Messages.cs
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
using Glitonea.Mvvm.Messaging;
|
||||
|
||||
namespace Saradomin.Infrastructure
|
||||
{
|
||||
public record MainViewLoadedMessage : Message;
|
||||
public record NotificationBoxStateChangedMessage(bool WasOpened) : Message;
|
||||
public record SettingsModifiedMessage(string SettingName) : Message;
|
||||
public record ClientClosedMessage : Message;
|
||||
public record ClientLaunchRequestedMessage : Message;
|
||||
}
|
||||
|
|
@ -1,8 +0,0 @@
|
|||
using Glitonea.Mvvm.Messaging;
|
||||
|
||||
namespace Saradomin.Infrastructure.Messaging;
|
||||
|
||||
public class ClientClosedMessage : Message
|
||||
{
|
||||
|
||||
}
|
||||
|
|
@ -1,8 +0,0 @@
|
|||
using Glitonea.Mvvm.Messaging;
|
||||
|
||||
namespace Saradomin.Infrastructure.Messaging;
|
||||
|
||||
public class ClientLaunchRequestedMessage : Message
|
||||
{
|
||||
|
||||
}
|
||||
|
|
@ -1,8 +0,0 @@
|
|||
using Glitonea.Mvvm.Messaging;
|
||||
|
||||
namespace Saradomin.Infrastructure.Messaging
|
||||
{
|
||||
public class MainViewLoadedMessage : Message
|
||||
{
|
||||
}
|
||||
}
|
||||
|
|
@ -1,14 +0,0 @@
|
|||
using Glitonea.Mvvm.Messaging;
|
||||
|
||||
namespace Saradomin.Infrastructure.Messaging
|
||||
{
|
||||
public class NotificationBoxStateChangedMessage : Message
|
||||
{
|
||||
public bool WasOpened { get; }
|
||||
|
||||
public NotificationBoxStateChangedMessage(bool wasOpened)
|
||||
{
|
||||
WasOpened = wasOpened;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,14 +0,0 @@
|
|||
using Glitonea.Mvvm.Messaging;
|
||||
|
||||
namespace Saradomin.Infrastructure.Messaging
|
||||
{
|
||||
public class SettingsModifiedMessage : Message
|
||||
{
|
||||
public string SettingName { get; }
|
||||
|
||||
public SettingsModifiedMessage(string settingName)
|
||||
{
|
||||
SettingName = settingName;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,7 +1,6 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Drawing.Drawing2D;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net.Http;
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
using System.ComponentModel;
|
||||
using Saradomin.Infrastructure.Messaging;
|
||||
using Saradomin.Infrastructure;
|
||||
|
||||
namespace Saradomin.Model.Settings
|
||||
{
|
||||
|
|
|
|||
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
Before Width: | Height: | Size: 632 B |
Binary file not shown.
|
Before Width: | Height: | Size: 40 KiB |
|
|
@ -16,8 +16,8 @@
|
|||
</Canvas>
|
||||
|
||||
<ContentPresenter Grid.Column="1"
|
||||
TextBlock.Foreground="{TemplateBinding Foreground}"
|
||||
TextBlock.FontSize="13"
|
||||
TextElement.Foreground="{TemplateBinding Foreground}"
|
||||
TextElement.FontSize="13"
|
||||
Margin="2,0,0,0"
|
||||
ContentTemplate="{TemplateBinding ContentTemplate}"
|
||||
Content="{TemplateBinding Content}"
|
||||
|
|
@ -45,8 +45,8 @@
|
|||
</Canvas>
|
||||
|
||||
<ContentPresenter Grid.Column="1"
|
||||
TextBlock.Foreground="{TemplateBinding Foreground}"
|
||||
TextBlock.FontSize="13"
|
||||
TextElement.Foreground="{TemplateBinding Foreground}"
|
||||
TextElement.FontSize="13"
|
||||
Margin="2,0,0,0"
|
||||
ContentTemplate="{TemplateBinding ContentTemplate}"
|
||||
Content="{TemplateBinding Content}"
|
||||
|
|
|
|||
34
Saradomin/Resources/Styles/Expander.axaml
Normal file
34
Saradomin/Resources/Styles/Expander.axaml
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
<Styles xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
|
||||
<Style Selector="ListBox.PluginList Expander">
|
||||
<Setter Property="ContentTransition" Value="{x:Null}" />
|
||||
</Style>
|
||||
|
||||
<Style Selector="ListBox.PluginList Expander /template/ ToggleButton#PART_toggle /template/ Border">
|
||||
<Setter Property="BorderBrush" Value="Transparent" />
|
||||
</Style>
|
||||
|
||||
<Style Selector="ListBox.PluginList Expander /template/ ToggleButton#PART_toggle">
|
||||
<Setter Property="Foreground" Value="{StaticResource LightForegroundBrush}" />
|
||||
</Style>
|
||||
|
||||
<Style Selector="ListBox.PluginList Expander /template/ Path">
|
||||
<Setter Property="Fill" Value="{StaticResource DarkForegroundBrush}" />
|
||||
</Style>
|
||||
|
||||
<Style Selector="ListBox.PluginList Expander:pointerover /template/ ToggleButton#PART_toggle /template/ Border">
|
||||
<Setter Property="BorderBrush" Value="Transparent" />
|
||||
</Style>
|
||||
|
||||
<Style Selector="ListBox.PluginList Expander:pointerover /template/ ToggleButton#PART_toggle /template/ Path">
|
||||
<Setter Property="Fill" Value="{StaticResource AccentBrush}" />
|
||||
</Style>
|
||||
|
||||
<Style Selector="ListBox.PluginList Expander:expanded /template/ ToggleButton#PART_toggle /template/ Path">
|
||||
<Setter Property="Fill" Value="{StaticResource AccentBrush}" />
|
||||
</Style>
|
||||
|
||||
<Style Selector="ListBox.PluginList Expander:expanded /template/ ToggleButton#PART_toggle">
|
||||
<Setter Property="Foreground" Value="{StaticResource AccentBrush}" />
|
||||
</Style>
|
||||
</Styles>
|
||||
|
|
@ -1,34 +1,38 @@
|
|||
<Styles xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
|
||||
<Style Selector="ListBox.PluginList > ListBoxItem">
|
||||
<Style Selector="ListBox.PluginList > ListBoxItem">
|
||||
<Setter Property="Background" Value="{StaticResource DarkMediumBackgroundBrush}" />
|
||||
<Setter Property="Foreground" Value="{StaticResource LightForegroundBrush}" />
|
||||
<Setter Property="Padding" Value="0" />
|
||||
<Setter Property="HorizontalContentAlignment" Value="Stretch" />
|
||||
<Setter Property="HorizontalAlignment" Value="Stretch" />
|
||||
</Style>
|
||||
|
||||
<Style Selector="ListBox.PluginList > ListBoxItem:selected /template/ ContentPresenter">
|
||||
<Setter Property="Background" Value="{StaticResource DarkMediumBackgroundBrush}" />
|
||||
</Style>
|
||||
|
||||
<Style Selector="ListBox.PluginList > ListBoxItem:selected /template/ ContentPresenter">
|
||||
<Style Selector="ListBox.PluginList > ListBoxItem:pointerover /template/ ContentPresenter">
|
||||
<Setter Property="Background" Value="{StaticResource DarkMediumBackgroundBrush}" />
|
||||
</Style>
|
||||
|
||||
<Style Selector="ListBox.PluginList > ListBoxItem:pointerover /template/ ContentPresenter">
|
||||
<Style Selector="ListBox.PluginList > ListBoxItem:pressed /template/ ContentPresenter">
|
||||
<Setter Property="Background" Value="{StaticResource DarkMediumBackgroundBrush}" />
|
||||
</Style>
|
||||
|
||||
<Style Selector="ListBox.PluginList > ListBoxItem:pressed /template/ ContentPresenter">
|
||||
<Setter Property="Background" Value="{StaticResource DarkMediumBackgroundBrush}" />
|
||||
</Style>
|
||||
|
||||
<Style Selector="ListBox.PluginList > ListBoxItem:nth-child(2n) /template/ ContentPresenter">
|
||||
<Style Selector="ListBox.PluginList > ListBoxItem:nth-child(2n) /template/ ContentPresenter">
|
||||
<Setter Property="Background" Value="{StaticResource SemiLightMediumBackgroundBrush}" />
|
||||
</Style>
|
||||
|
||||
<Style Selector="ListBox.PluginList > ListBoxItem:nth-child(2n):selected /template/ ContentPresenter">
|
||||
<Style Selector="ListBox.PluginList > ListBoxItem:nth-child(2n):selected /template/ ContentPresenter">
|
||||
<Setter Property="Background" Value="{StaticResource SemiLightMediumBackgroundBrush}" />
|
||||
</Style>
|
||||
|
||||
<Style Selector="ListBox.PluginList > ListBoxItem:nth-child(2n):pressed /template/ ContentPresenter">
|
||||
<Style Selector="ListBox.PluginList > ListBoxItem:nth-child(2n):pressed /template/ ContentPresenter">
|
||||
<Setter Property="Background" Value="{StaticResource SemiLightMediumBackgroundBrush}" />
|
||||
</Style>
|
||||
|
||||
<Style Selector="ListBox.PluginList > ListBoxItem:nth-child(2n):pointerover /template/ ContentPresenter">
|
||||
<Style Selector="ListBox.PluginList > ListBoxItem:nth-child(2n):pointerover /template/ ContentPresenter">
|
||||
<Setter Property="Background" Value="{StaticResource SemiLightMediumBackgroundBrush}" />
|
||||
</Style>
|
||||
</Styles>
|
||||
|
|
@ -9,6 +9,10 @@
|
|||
<Setter Property="Padding" Value="1" />
|
||||
<Setter Property="ClipValueToMinMax" Value="True" />
|
||||
</Style>
|
||||
|
||||
<Style Selector="NumericUpDown.NormalNumericUpDown /template/ TextBox#PART_TextBox /template/ ScrollViewer#PART_ScrollViewer /template/ ScrollBar">
|
||||
<Setter Property="Visibility" Value="Hidden" />
|
||||
</Style>
|
||||
|
||||
<!-- https://github.com/AvaloniaUI/Avalonia/issues/2098
|
||||
https://github.com/AvaloniaUI/Avalonia/issues/1635 -->
|
||||
|
|
|
|||
|
|
@ -21,8 +21,8 @@
|
|||
Content="{TemplateBinding Content}"
|
||||
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
|
||||
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
|
||||
TextBlock.FontSize="13"
|
||||
TextBlock.Foreground="{TemplateBinding Foreground}" />
|
||||
TextElement.FontSize="13"
|
||||
TextElement.Foreground="{TemplateBinding Foreground}" />
|
||||
</Grid>
|
||||
</ControlTemplate>
|
||||
</Setter>
|
||||
|
|
@ -49,8 +49,8 @@
|
|||
Content="{TemplateBinding Content}"
|
||||
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
|
||||
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
|
||||
TextBlock.FontSize="13"
|
||||
TextBlock.Foreground="{TemplateBinding Foreground}" />
|
||||
TextElement.FontSize="13"
|
||||
TextElement.Foreground="{TemplateBinding Foreground}" />
|
||||
</Grid>
|
||||
</ControlTemplate>
|
||||
</Setter>
|
||||
|
|
|
|||
|
|
@ -1,51 +1,46 @@
|
|||
<Styles xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
|
||||
<Style Selector="ScrollBar:vertical">
|
||||
<Setter Property="Width" Value="10" />
|
||||
<Setter Property="Width" Value="9" />
|
||||
<Setter Property="Template">
|
||||
<ControlTemplate>
|
||||
<Border Background="{StaticResource MediumBackgroundBrush}"
|
||||
ClipToBounds="True">
|
||||
<Grid RowDefinitions="Auto,*,Auto"
|
||||
Background="{StaticResource DarkBackgroundBrush}">
|
||||
<Track Grid.Row="1"
|
||||
Grid.Column="1"
|
||||
Minimum="{TemplateBinding Minimum}"
|
||||
Maximum="{TemplateBinding Maximum}"
|
||||
Value="{TemplateBinding Value, Mode=TwoWay}"
|
||||
ViewportSize="{TemplateBinding ViewportSize}"
|
||||
Orientation="{TemplateBinding Orientation}"
|
||||
IsDirectionReversed="True">
|
||||
<Border Background="{StaticResource DarkBackgroundBrush}"
|
||||
Padding="1,0,0,0">
|
||||
<Track Minimum="{TemplateBinding Minimum}"
|
||||
Maximum="{TemplateBinding Maximum}"
|
||||
Value="{TemplateBinding Value, Mode=TwoWay}"
|
||||
ViewportSize="{TemplateBinding ViewportSize}"
|
||||
Orientation="{TemplateBinding Orientation}"
|
||||
DeferThumbDrag="{TemplateBinding ScrollViewer.IsDeferredScrollingEnabled}"
|
||||
IsDirectionReversed="True">
|
||||
<Track.Thumb>
|
||||
<Thumb Name="thumb"
|
||||
Width="4"
|
||||
Margin="0,10,0,10" />
|
||||
</Track>
|
||||
</Grid>
|
||||
HorizontalAlignment="Stretch" />
|
||||
</Track.Thumb>
|
||||
</Track>
|
||||
</Border>
|
||||
</ControlTemplate>
|
||||
</Setter>
|
||||
</Style>
|
||||
|
||||
|
||||
<Style Selector="ScrollViewer.MainViewScrollViewer /template/ ScrollBar:vertical">
|
||||
<Setter Property="Width" Value="10" />
|
||||
<Setter Property="Template">
|
||||
<ControlTemplate>
|
||||
<Border Background="{StaticResource MediumBackgroundBrush}"
|
||||
ClipToBounds="True"
|
||||
CornerRadius="0,6,0,0">
|
||||
<Grid RowDefinitions="Auto,*,Auto"
|
||||
Background="{StaticResource DarkBackgroundBrush}">
|
||||
<Track Grid.Row="1"
|
||||
Grid.Column="1"
|
||||
Minimum="{TemplateBinding Minimum}"
|
||||
<Border CornerRadius="0,4,0,0"
|
||||
Background="{StaticResource DarkBackgroundBrush}">
|
||||
<Grid>
|
||||
<Track Minimum="{TemplateBinding Minimum}"
|
||||
Maximum="{TemplateBinding Maximum}"
|
||||
Value="{TemplateBinding Value, Mode=TwoWay}"
|
||||
ViewportSize="{TemplateBinding ViewportSize}"
|
||||
Orientation="{TemplateBinding Orientation}"
|
||||
DeferThumbDrag="{TemplateBinding ScrollViewer.IsDeferredScrollingEnabled}"
|
||||
IsDirectionReversed="True">
|
||||
<Thumb Name="thumb"
|
||||
Width="4"
|
||||
Margin="0,10,0,10" />
|
||||
<Track.Thumb>
|
||||
<Thumb Name="thumb"
|
||||
HorizontalAlignment="Stretch" />
|
||||
</Track.Thumb>
|
||||
</Track>
|
||||
</Grid>
|
||||
</Border>
|
||||
|
|
@ -57,6 +52,11 @@
|
|||
<Setter Property="Background" Value="{StaticResource DarkMediumBackgroundBrush}" />
|
||||
</Style>
|
||||
|
||||
<Style Selector="Thumb#thumb /template/ Border">
|
||||
<Setter Property="Margin" Value="0,6" />
|
||||
</Style>
|
||||
|
||||
|
||||
<Style Selector="Thumb#thumb:pointerover">
|
||||
<Setter Property="Background" Value="{StaticResource MouseOverBrush}" />
|
||||
</Style>
|
||||
|
|
|
|||
6
Saradomin/Resources/Styles/TextBlock.axaml
Normal file
6
Saradomin/Resources/Styles/TextBlock.axaml
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
<Styles xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
|
||||
<Style Selector="TextBlock.NewsRenderView">
|
||||
<Setter Property="Foreground" Value="Black" />
|
||||
</Style>
|
||||
</Styles>
|
||||
|
|
@ -10,7 +10,7 @@
|
|||
<Setter Property="Margin" Value="4,0,0,0" />
|
||||
</Style>
|
||||
|
||||
<Style Selector="TabControl.PageSelector > TabItem">
|
||||
<Style Selector="TabControl.PageSelector > TabItem">
|
||||
<Setter Property="FontSize" Value="13" />
|
||||
<Setter Property="FontWeight" Value="Light" />
|
||||
<Setter Property="Height" Value="20" />
|
||||
|
|
@ -22,19 +22,23 @@
|
|||
<Setter Property="Margin" Value="0,0,0,0" />
|
||||
<Setter Property="Padding" Value="6,0,6,1" />
|
||||
</Style>
|
||||
|
||||
<Style Selector="TabControl.PageSelector > TabItem:pointerover /template/ ContentPresenter#PART_ContentPresenter">
|
||||
|
||||
<Style Selector="TabControl.PageSelector /template/ Border">
|
||||
<Setter Property="Padding" Value="0" />
|
||||
</Style>
|
||||
|
||||
<Style Selector="TabControl.PageSelector > TabItem:pointerover /template/ ContentPresenter#PART_ContentPresenter">
|
||||
<Setter Property="Background" Value="{StaticResource DarkMediumBackgroundBrush}" />
|
||||
</Style>
|
||||
<Style Selector="TabControl.PageSelector > TabItem:focus /template/ ContentPresenter#PART_ContentPresenter">
|
||||
<Style Selector="TabControl.PageSelector > TabItem:focus /template/ ContentPresenter#PART_ContentPresenter">
|
||||
<Setter Property="Background" Value="{StaticResource DarkBackgroundBrush}" />
|
||||
</Style>
|
||||
|
||||
<Style Selector="TabControl.PageSelector > TabItem:selected">
|
||||
<Style Selector="TabControl.PageSelector > TabItem:selected">
|
||||
<Setter Property="Foreground" Value="{StaticResource AccentBrush}" />
|
||||
</Style>
|
||||
|
||||
<Style Selector="TabControl.PageSelector > TabItem:selected /template/ ContentPresenter#PART_ContentPresenter">
|
||||
<Style Selector="TabControl.PageSelector > TabItem:selected /template/ ContentPresenter#PART_ContentPresenter">
|
||||
<Setter Property="Background" Value="{StaticResource DarkBackgroundBrush}" />
|
||||
</Style>
|
||||
</Styles>
|
||||
|
|
@ -2,7 +2,7 @@
|
|||
<PropertyGroup>
|
||||
<OutputType>WinExe</OutputType>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<Version>1.6.0</Version>
|
||||
<Version>1.6.1</Version>
|
||||
<NoWarn>IL2026;CS0067</NoWarn>
|
||||
<ApplicationIcon>Resources\Icons\saradomin.ico</ApplicationIcon>
|
||||
<IncludeNativeLibrariesForSelfExtract>true</IncludeNativeLibrariesForSelfExtract>
|
||||
|
|
@ -24,12 +24,13 @@
|
|||
</Target>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Avalonia" Version="0.10.18" />
|
||||
<PackageReference Include="Avalonia.Desktop" Version="0.10.18" />
|
||||
<PackageReference Include="Avalonia" Version="11.0.10" />
|
||||
<PackageReference Include="Avalonia.Desktop" Version="11.0.10" />
|
||||
<!--Condition below is needed to remove Avalonia.Diagnostics package from build output in Release configuration.-->
|
||||
<PackageReference Condition="'$(Configuration)' == 'Debug'" Include="Avalonia.Diagnostics" Version="0.10.18" />
|
||||
<PackageReference Condition="'$(Configuration)' == 'Debug'" Include="Avalonia.Diagnostics" Version="11.0.10" />
|
||||
<PackageReference Include="Avalonia.Themes.Simple" Version="11.0.10" />
|
||||
<PackageReference Include="GitLabApiClient" Version="1.8.0" />
|
||||
<PackageReference Include="HtmlAgilityPack" Version="1.11.46" />
|
||||
<PackageReference Include="HtmlAgilityPack" Version="1.11.60" />
|
||||
<PackageReference Include="Mono.Posix.NETStandard" Version="1.0.0" />
|
||||
<PackageReference Include="NSubsys" Version="1.0.0">
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
|
|
@ -42,13 +43,6 @@
|
|||
<ProjectReference Include="..\Glitonea\Glitonea.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<AvaloniaResource Include="Resources\Fonts\runescape_uf.ttf" />
|
||||
<AvaloniaResource Include="Resources\Images\previewbg.png" />
|
||||
<AvaloniaResource Include="Resources\Images\club.png" />
|
||||
<AvaloniaResource Include="Resources\Fonts\runescape_plain.ttf" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Update="Views\Windows\MainWindow.axaml.cs">
|
||||
<DependentUpon>MainWindow.axaml</DependentUpon>
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@ using System.Diagnostics;
|
|||
using System.IO;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using Microsoft.CodeAnalysis.Text;
|
||||
using Microsoft.Win32;
|
||||
using Mono.Unix;
|
||||
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ using System.Collections.Generic;
|
|||
using System.Web;
|
||||
using Avalonia;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Controls.Documents;
|
||||
using Avalonia.Layout;
|
||||
using Avalonia.Media;
|
||||
using HtmlAgilityPack;
|
||||
|
|
@ -12,54 +13,40 @@ namespace Saradomin.Utilities
|
|||
public class HtmlRenderer
|
||||
{
|
||||
private int _listDescent = 0;
|
||||
private bool seenNonWhiteSpace = false;
|
||||
|
||||
private Stack<StackPanel> _panels = new();
|
||||
private StackPanel _container;
|
||||
private string _prefix;
|
||||
private InlineCollection _inlines;
|
||||
private HtmlNode _rootNode;
|
||||
|
||||
public StackPanel CurrentLine => _panels.Peek();
|
||||
|
||||
public HtmlRenderer(StackPanel container, HtmlNode rootNode)
|
||||
public HtmlRenderer(HtmlNode rootNode)
|
||||
{
|
||||
_container = container;
|
||||
_rootNode = rootNode;
|
||||
}
|
||||
|
||||
public void RenderToContainer()
|
||||
public InlineCollection Render()
|
||||
{
|
||||
_panels.Push(_container);
|
||||
Visit(_rootNode);
|
||||
_panels.Pop();
|
||||
_inlines = new();
|
||||
{
|
||||
Visit(_rootNode);
|
||||
}
|
||||
return _inlines;
|
||||
}
|
||||
|
||||
private void InNewBlockDo(Action<StackPanel> action)
|
||||
private void InNewBlockDo(Action action)
|
||||
{
|
||||
var line = new StackPanel
|
||||
{
|
||||
Orientation = Orientation.Vertical,
|
||||
HorizontalAlignment = HorizontalAlignment.Left
|
||||
};
|
||||
_panels.Push(line);
|
||||
action(line);
|
||||
|
||||
_container.Children.Add(_panels.Pop());
|
||||
action();
|
||||
_inlines.Add(new LineBreak());
|
||||
}
|
||||
|
||||
private void CreateNewInlineTextElement(
|
||||
string text,
|
||||
FontWeight weight = FontWeight.Normal,
|
||||
double fontSize = 12,
|
||||
TextWrapping wrapping = TextWrapping.Wrap)
|
||||
double fontSize = 12
|
||||
)
|
||||
{
|
||||
CurrentLine.Children.Add(new TextBlock
|
||||
_inlines.Add(new Run(text)
|
||||
{
|
||||
Foreground = new SolidColorBrush(Colors.Black),
|
||||
FontSize = fontSize,
|
||||
FontWeight = weight,
|
||||
TextWrapping = wrapping,
|
||||
Text = text,
|
||||
Margin = new Thickness(_listDescent * 8, 0, 0, 0)
|
||||
FontSize = fontSize,
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -77,7 +64,7 @@ namespace Saradomin.Utilities
|
|||
{
|
||||
_listDescent++;
|
||||
{
|
||||
InNewBlockDo((_) =>
|
||||
InNewBlockDo(() =>
|
||||
{
|
||||
foreach (var child in htmlNode.ChildNodes)
|
||||
{
|
||||
|
|
@ -90,15 +77,29 @@ namespace Saradomin.Utilities
|
|||
|
||||
private void VisitListEntry(HtmlNode htmlNode)
|
||||
{
|
||||
foreach (var child in htmlNode.ChildNodes)
|
||||
_inlines.Add(new Run("• "));
|
||||
|
||||
for (var i = 0; i < htmlNode.ChildNodes.Count; i++)
|
||||
{
|
||||
var child = htmlNode.ChildNodes[i];
|
||||
|
||||
if (i != 0)
|
||||
{
|
||||
_prefix = " ";
|
||||
}
|
||||
|
||||
Visit(child);
|
||||
|
||||
_prefix = null;
|
||||
}
|
||||
|
||||
_prefix = null;
|
||||
_inlines.Add(new LineBreak());
|
||||
}
|
||||
|
||||
private void VisitParagraph(HtmlNode htmlNode)
|
||||
{
|
||||
InNewBlockDo((_) =>
|
||||
InNewBlockDo(() =>
|
||||
{
|
||||
foreach (var child in htmlNode.ChildNodes)
|
||||
{
|
||||
|
|
@ -115,21 +116,14 @@ namespace Saradomin.Utilities
|
|||
var text = HttpUtility.HtmlDecode(
|
||||
htmlNode.GetDirectInnerText().Trim(' ').Trim('\n')
|
||||
);
|
||||
if (!seenNonWhiteSpace && string.IsNullOrWhiteSpace(htmlNode.InnerText)) break;
|
||||
seenNonWhiteSpace = true;
|
||||
|
||||
if (htmlNode.ParentNode.Name == "li")
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(text))
|
||||
{
|
||||
text = $"• {text}";
|
||||
}
|
||||
}
|
||||
|
||||
CreateNewInlineTextElement(text);
|
||||
|
||||
CreateNewInlineTextElement($"{_prefix}{text}");
|
||||
break;
|
||||
|
||||
case "br":
|
||||
_inlines.Add(new LineBreak());
|
||||
break;
|
||||
|
||||
case "strong":
|
||||
case "b":
|
||||
VisitBold(htmlNode);
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -2,159 +2,159 @@ using System;
|
|||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net.NetworkInformation;
|
||||
|
||||
namespace Saradomin.Utilities;
|
||||
|
||||
public static class SingleplayerManagement
|
||||
namespace Saradomin.Utilities
|
||||
{
|
||||
private static readonly string[] DirsToBackup =
|
||||
public static class SingleplayerManagement
|
||||
{
|
||||
"game/data/players",
|
||||
"game/data/serverstore",
|
||||
"game/worldprops"
|
||||
};
|
||||
|
||||
private static readonly string[] FilesToBackup =
|
||||
{
|
||||
"game/data/eco/grandexchange.db"
|
||||
};
|
||||
|
||||
public static void MakeBackup(Action<string> log)
|
||||
{
|
||||
string timestamp = DateTime.Now.ToString("yyyyMMdd_HHmmss");
|
||||
string newBackupDir = Path.Combine(
|
||||
CrossPlatform.GetSingleplayerBackupsHome(),
|
||||
timestamp
|
||||
);
|
||||
|
||||
foreach (string dir in DirsToBackup)
|
||||
private static readonly string[] DirsToBackup =
|
||||
{
|
||||
string sourcePath = Path.Combine(CrossPlatform.GetSingleplayerHome(), dir);
|
||||
if (!Directory.Exists(sourcePath))
|
||||
"game/data/players",
|
||||
"game/data/serverstore",
|
||||
"game/worldprops"
|
||||
};
|
||||
|
||||
private static readonly string[] FilesToBackup =
|
||||
{
|
||||
"game/data/eco/grandexchange.db"
|
||||
};
|
||||
|
||||
public static void MakeBackup(Action<string> log)
|
||||
{
|
||||
string timestamp = DateTime.Now.ToString("yyyyMMdd_HHmmss");
|
||||
string newBackupDir = Path.Combine(
|
||||
CrossPlatform.GetSingleplayerBackupsHome(),
|
||||
timestamp
|
||||
);
|
||||
|
||||
foreach (string dir in DirsToBackup)
|
||||
{
|
||||
log($" Skipping backup of {dir} because it doesn't exist (Full path attempted: {sourcePath})");
|
||||
continue;
|
||||
string sourcePath = Path.Combine(CrossPlatform.GetSingleplayerHome(), dir);
|
||||
if (!Directory.Exists(sourcePath))
|
||||
{
|
||||
log($" Skipping backup of {dir} because it doesn't exist (Full path attempted: {sourcePath})");
|
||||
continue;
|
||||
}
|
||||
|
||||
string destPath = Path.Combine(newBackupDir, dir);
|
||||
CopyDirectory(sourcePath, destPath);
|
||||
}
|
||||
|
||||
string destPath = Path.Combine(newBackupDir, dir);
|
||||
CopyDirectory(sourcePath, destPath);
|
||||
foreach (string file in FilesToBackup)
|
||||
{
|
||||
string sourceFilePath = Path.Combine(CrossPlatform.GetSingleplayerHome(), file);
|
||||
if (!File.Exists(sourceFilePath))
|
||||
{
|
||||
log($" Skipping backup of {file} because it doesn't exist (Full path attempted: {sourceFilePath})");
|
||||
continue;
|
||||
}
|
||||
|
||||
string destFilePath = Path.Combine(newBackupDir, file);
|
||||
string directoryForFile = Path.GetDirectoryName(destFilePath);
|
||||
if (!Directory.Exists(directoryForFile))
|
||||
Directory.CreateDirectory(directoryForFile);
|
||||
File.Copy(sourceFilePath, destFilePath, true);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (string file in FilesToBackup)
|
||||
private static void CopyDirectory(string sourceDir, string destinationDir)
|
||||
{
|
||||
string sourceFilePath = Path.Combine(CrossPlatform.GetSingleplayerHome(), file);
|
||||
if (!File.Exists(sourceFilePath))
|
||||
if (!Directory.Exists(destinationDir))
|
||||
Directory.CreateDirectory(destinationDir);
|
||||
|
||||
foreach (string filePath in Directory.GetFiles(sourceDir))
|
||||
{
|
||||
log($" Skipping backup of {file} because it doesn't exist (Full path attempted: {sourceFilePath})");
|
||||
continue;
|
||||
string fileName = Path.GetFileName(filePath);
|
||||
string destFilePath = Path.Combine(destinationDir, fileName);
|
||||
File.Copy(filePath, destFilePath, true);
|
||||
}
|
||||
|
||||
string destFilePath = Path.Combine(newBackupDir, file);
|
||||
string directoryForFile = Path.GetDirectoryName(destFilePath);
|
||||
if (!Directory.Exists(directoryForFile))
|
||||
Directory.CreateDirectory(directoryForFile);
|
||||
File.Copy(sourceFilePath, destFilePath, true);
|
||||
}
|
||||
}
|
||||
|
||||
private static void CopyDirectory(string sourceDir, string destinationDir)
|
||||
{
|
||||
if (!Directory.Exists(destinationDir))
|
||||
Directory.CreateDirectory(destinationDir);
|
||||
|
||||
foreach (string filePath in Directory.GetFiles(sourceDir))
|
||||
{
|
||||
string fileName = Path.GetFileName(filePath);
|
||||
string destFilePath = Path.Combine(destinationDir, fileName);
|
||||
File.Copy(filePath, destFilePath, true);
|
||||
}
|
||||
|
||||
foreach (string subDirPath in Directory.GetDirectories(sourceDir))
|
||||
{
|
||||
string subDirName = Path.GetFileName(subDirPath);
|
||||
string destSubDirPath = Path.Combine(destinationDir, subDirName);
|
||||
// Recurse!
|
||||
CopyDirectory(subDirPath, destSubDirPath);
|
||||
}
|
||||
}
|
||||
|
||||
public static string FindMostRecentBackupDirectory(IEnumerable<string> directories)
|
||||
{
|
||||
return directories.Select(Path.GetFileName).MaxBy(name => name);
|
||||
}
|
||||
|
||||
public static void ApplyLatestBackup(Action<string> log)
|
||||
{
|
||||
var backupHome = CrossPlatform.GetSingleplayerBackupsHome();
|
||||
var singleplayerHome = CrossPlatform.GetSingleplayerHome();
|
||||
|
||||
// Get all backup directories
|
||||
string[] backupDirectories = Directory.Exists(backupHome) ? Directory.GetDirectories(backupHome) : Array.Empty<string>();
|
||||
|
||||
string mostRecentBackupDirName = FindMostRecentBackupDirectory(backupDirectories);
|
||||
|
||||
if (mostRecentBackupDirName == null)
|
||||
{
|
||||
log(" No backups found.");
|
||||
return;
|
||||
}
|
||||
|
||||
string mostRecentBackupFullPath = Path.Combine(backupHome, mostRecentBackupDirName);
|
||||
|
||||
// Get the list of files in the most recent backup
|
||||
var filesInBackup = Directory.GetFiles(
|
||||
mostRecentBackupFullPath,
|
||||
"*",
|
||||
SearchOption.AllDirectories
|
||||
);
|
||||
|
||||
foreach (var file in filesInBackup)
|
||||
{
|
||||
// Calculate the file's destination path in the singleplayer home directory
|
||||
var relativePath = file.Substring(mostRecentBackupFullPath.Length)
|
||||
.TrimStart(Path.DirectorySeparatorChar);
|
||||
var destFilePath = Path.Combine(singleplayerHome, relativePath);
|
||||
|
||||
// Ensure the destination directory exists
|
||||
var destDirectory = Path.GetDirectoryName(destFilePath);
|
||||
if (!Directory.Exists(destDirectory))
|
||||
foreach (string subDirPath in Directory.GetDirectories(sourceDir))
|
||||
{
|
||||
Directory.CreateDirectory(destDirectory);
|
||||
string subDirName = Path.GetFileName(subDirPath);
|
||||
string destSubDirPath = Path.Combine(destinationDir, subDirName);
|
||||
// Recurse!
|
||||
CopyDirectory(subDirPath, destSubDirPath);
|
||||
}
|
||||
}
|
||||
|
||||
public static string FindMostRecentBackupDirectory(IEnumerable<string> directories)
|
||||
{
|
||||
return directories.Select(Path.GetFileName).MaxBy(name => name);
|
||||
}
|
||||
|
||||
public static void ApplyLatestBackup(Action<string> log)
|
||||
{
|
||||
var backupHome = CrossPlatform.GetSingleplayerBackupsHome();
|
||||
var singleplayerHome = CrossPlatform.GetSingleplayerHome();
|
||||
|
||||
// Get all backup directories
|
||||
string[] backupDirectories = Directory.Exists(backupHome) ? Directory.GetDirectories(backupHome) : Array.Empty<string>();
|
||||
|
||||
string mostRecentBackupDirName = FindMostRecentBackupDirectory(backupDirectories);
|
||||
|
||||
if (mostRecentBackupDirName == null)
|
||||
{
|
||||
log(" No backups found.");
|
||||
return;
|
||||
}
|
||||
|
||||
// Copy the file to the destination, overwriting any existing file
|
||||
File.Copy(file, destFilePath, true);
|
||||
string mostRecentBackupFullPath = Path.Combine(backupHome, mostRecentBackupDirName);
|
||||
|
||||
// Get the list of files in the most recent backup
|
||||
var filesInBackup = Directory.GetFiles(
|
||||
mostRecentBackupFullPath,
|
||||
"*",
|
||||
SearchOption.AllDirectories
|
||||
);
|
||||
|
||||
foreach (var file in filesInBackup)
|
||||
{
|
||||
// Calculate the file's destination path in the singleplayer home directory
|
||||
var relativePath = file.Substring(mostRecentBackupFullPath.Length)
|
||||
.TrimStart(Path.DirectorySeparatorChar);
|
||||
var destFilePath = Path.Combine(singleplayerHome, relativePath);
|
||||
|
||||
// Ensure the destination directory exists
|
||||
var destDirectory = Path.GetDirectoryName(destFilePath);
|
||||
if (!Directory.Exists(destDirectory))
|
||||
{
|
||||
Directory.CreateDirectory(destDirectory);
|
||||
}
|
||||
|
||||
// Copy the file to the destination, overwriting any existing file
|
||||
File.Copy(file, destFilePath, true);
|
||||
}
|
||||
|
||||
log($" Backup from {mostRecentBackupDirName} has been successfully applied.");
|
||||
}
|
||||
|
||||
log($" Backup from {mostRecentBackupDirName} has been successfully applied.");
|
||||
}
|
||||
|
||||
private static Dictionary<string, string> _confCache;
|
||||
private static string ConfPath => Path.Combine(CrossPlatform.GetSingleplayerHome(), "game", "worldprops", "default.conf");
|
||||
public static Dictionary<string, string> GrabConfCache()
|
||||
{
|
||||
return File.ReadLines(ConfPath)
|
||||
.Where(line => line.Contains('=') && !line.TrimStart().StartsWith("#"))
|
||||
.Select(l => l.Split(new[] { '#', '=' }, 3))
|
||||
.ToDictionary(parts => parts[0].Trim(), parts => parts[1].Trim());
|
||||
}
|
||||
private static Dictionary<string, string> _confCache;
|
||||
private static string ConfPath => Path.Combine(CrossPlatform.GetSingleplayerHome(), "game", "worldprops", "default.conf");
|
||||
public static Dictionary<string, string> GrabConfCache()
|
||||
{
|
||||
return File.ReadLines(ConfPath)
|
||||
.Where(line => line.Contains('=') && !line.TrimStart().StartsWith("#"))
|
||||
.Select(l => l.Split(new[] { '#', '=' }, 3))
|
||||
.ToDictionary(parts => parts[0].Trim(), parts => parts[1].Trim());
|
||||
}
|
||||
|
||||
public static T ParseConf<T>(string key, T defaultValue = default)
|
||||
{
|
||||
if (!File.Exists(ConfPath)) return defaultValue;
|
||||
_confCache ??= GrabConfCache();
|
||||
if (!_confCache.TryGetValue(key, out var value)) return defaultValue;
|
||||
return (T)Convert.ChangeType(value, typeof(T));
|
||||
}
|
||||
public static T ParseConf<T>(string key, T defaultValue = default)
|
||||
{
|
||||
if (!File.Exists(ConfPath)) return defaultValue;
|
||||
_confCache ??= GrabConfCache();
|
||||
if (!_confCache.TryGetValue(key, out var value)) return defaultValue;
|
||||
return (T)Convert.ChangeType(value, typeof(T));
|
||||
}
|
||||
|
||||
public static void WriteConf(string key, object value)
|
||||
{
|
||||
_confCache[key] = value.ToString().ToLowerInvariant(); // Update cache
|
||||
var lines = File.ReadAllLines(ConfPath).Select(l =>
|
||||
l.StartsWith(key + " =")
|
||||
? $"{key} = {_confCache[key]}" + (l.Contains("#") ? " " + l.Substring(l.IndexOf('#')) : "")
|
||||
: l);
|
||||
File.WriteAllLines(ConfPath, lines);
|
||||
public static void WriteConf(string key, object value)
|
||||
{
|
||||
_confCache[key] = value.ToString().ToLowerInvariant(); // Update cache
|
||||
var lines = File.ReadAllLines(ConfPath).Select(l =>
|
||||
l.StartsWith(key + " =")
|
||||
? $"{key} = {_confCache[key]}" + (l.Contains("#") ? " " + l.Substring(l.IndexOf('#')) : "")
|
||||
: l);
|
||||
File.WriteAllLines(ConfPath, lines);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -6,102 +6,127 @@
|
|||
xmlns:mvvm="clr-namespace:Glitonea.Mvvm;assembly=Glitonea"
|
||||
xmlns:vm="clr-namespace:Saradomin.ViewModel.Controls"
|
||||
DataContext="{mvvm:DataContextSource vm:PluginManagerViewModel}">
|
||||
<Grid RowDefinitions="*,Auto">
|
||||
<Border Grid.Row="1"
|
||||
Height="2"
|
||||
Margin="1,2"
|
||||
BorderBrush="{StaticResource DarkMediumBorderBrush}"
|
||||
BorderThickness="0,1,0,0" />
|
||||
<Border Grid.Row="0">
|
||||
<Grid RowDefinitions="Auto,*">
|
||||
<Border Grid.Row="0"
|
||||
Height="350"
|
||||
Margin="0,2,0,0"
|
||||
BorderBrush="{StaticResource DarkBorderBrush}"
|
||||
BorderThickness="1,1,0,1"
|
||||
ClipToBounds="True">
|
||||
<Grid>
|
||||
<TextBlock HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center"
|
||||
Foreground="#BBFFFFFF"
|
||||
IsVisible="{Binding !!!PluginList.Count}"
|
||||
Text="Fetching plugin metadata..."
|
||||
ZIndex="9999"
|
||||
Width="425" />
|
||||
<ListBox Classes="PluginList"
|
||||
Items="{Binding PluginList}"
|
||||
SelectionMode="Single"
|
||||
ClipToBounds="True"
|
||||
IsVisible="{Binding PluginList.Count}"
|
||||
VirtualizationMode="Simple">
|
||||
<ListBox.ItemTemplate>
|
||||
<DataTemplate DataType="{x:Type model:PluginInfo}">
|
||||
<Grid ColumnDefinitions="250,50,100" RowDefinitions="*" >
|
||||
<TextBlock Grid.Column="1"
|
||||
Margin="2,5,2,0"
|
||||
VerticalAlignment="Top"
|
||||
HorizontalAlignment="Right"
|
||||
Foreground="#BBFFFFFF"
|
||||
FontSize="11"
|
||||
Text="{Binding Version}" />
|
||||
<Button Grid.Row="0" Grid.Column="2"
|
||||
Margin="-125,0,2,2"
|
||||
BorderBrush="{StaticResource DarkBorderBrush}"
|
||||
BorderThickness="1"
|
||||
Classes="OutsideNavigator"
|
||||
Command="{Binding $parent[local:PluginManagerView].DataContext.UpdateLocalPlugin}"
|
||||
VerticalAlignment="Top"
|
||||
Content="Update"
|
||||
IsVisible="{Binding CanUpdate}"
|
||||
IsEnabled="{Binding !$parent[local:PluginManagerView].DataContext.IsTransactionInProgress}" />
|
||||
<Button Grid.Row="0" Grid.Column="2"
|
||||
Margin="0,0,2,2"
|
||||
BorderBrush="{StaticResource DarkBorderBrush}"
|
||||
BorderThickness="1"
|
||||
Classes="OutsideNavigator"
|
||||
Command="{Binding $parent[local:PluginManagerView].DataContext.InstallRemotePlugin}"
|
||||
CommandParameter="{Binding}"
|
||||
VerticalAlignment="Top"
|
||||
Content="Install"
|
||||
IsVisible="{Binding !Installed}"
|
||||
IsEnabled="{Binding !$parent[local:PluginManagerView].DataContext.IsTransactionInProgress}" />
|
||||
<Button Grid.Row="0" Grid.Column="2"
|
||||
Margin="0,0,2,2"
|
||||
BorderBrush="{StaticResource DarkBorderBrush}"
|
||||
BorderThickness="1"
|
||||
Classes="OutsideNavigator"
|
||||
Command="{Binding $parent[local:PluginManagerView].DataContext.UninstallLocalPlugin}"
|
||||
CommandParameter="{Binding}"
|
||||
VerticalAlignment="Top"
|
||||
Content="Uninstall"
|
||||
IsVisible="{Binding Installed}"
|
||||
IsEnabled="{Binding !$parent[local:PluginManagerView].DataContext.IsTransactionInProgress}" />
|
||||
<Expander Grid.Column="0" Grid.Row="0" Header="{Binding Name}">
|
||||
<StackPanel>
|
||||
<TextBlock
|
||||
Margin="2,0,0,0"
|
||||
VerticalAlignment="Center"
|
||||
Foreground="#BBFFFFFF"
|
||||
FontSize="11"
|
||||
FontStyle="Oblique"
|
||||
Text="{Binding Author}" />
|
||||
<Grid Margin="0,0,0,4"
|
||||
RowDefinitions="Auto,*">
|
||||
<Grid Grid.Row="0"
|
||||
Margin="0,0,0,4">
|
||||
<TextBlock HorizontalAlignment="Left"
|
||||
VerticalAlignment="Center"
|
||||
Foreground="{StaticResource DarkBackgroundBrush}">
|
||||
<Run Text="Status:" />
|
||||
<Run Text="{Binding CurrentStatusMessage}" />
|
||||
</TextBlock>
|
||||
|
||||
<TextBlock
|
||||
Margin="2,5,0,4"
|
||||
VerticalAlignment="Bottom"
|
||||
Foreground="#BBFFFFFF"
|
||||
TextWrapping="Wrap"
|
||||
FontSize="11"
|
||||
Text="{Binding Description}" />
|
||||
</StackPanel>
|
||||
</Expander>
|
||||
<Button Classes="Hyperlink"
|
||||
Content="check for updates"
|
||||
HorizontalAlignment="Right"
|
||||
VerticalAlignment="Center"
|
||||
Command="{Binding CheckForUpdates}"
|
||||
IsEnabled="{Binding !IsTransactionInProgress}" />
|
||||
</Grid>
|
||||
|
||||
<TextBlock Grid.Row="1"
|
||||
HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center"
|
||||
Foreground="{StaticResource DarkForegroundBrush}"
|
||||
IsVisible="{Binding !!!PluginList.Count}"
|
||||
Text="Reloading plugin registry..." />
|
||||
|
||||
<ListBox Grid.Row="1"
|
||||
Classes="PluginList"
|
||||
ItemsSource="{Binding PluginList}"
|
||||
SelectionMode="Single"
|
||||
ClipToBounds="True"
|
||||
BorderThickness="1"
|
||||
BorderBrush="{StaticResource DarkBorderBrush}"
|
||||
IsVisible="{Binding PluginList.Count}">
|
||||
<ListBox.ItemsPanel>
|
||||
<ItemsPanelTemplate>
|
||||
<!-- There won't be too many plugins and virtualization hides any
|
||||
expanded items, so by using this instead of VirtualizingStackPanel
|
||||
helps avoid UI inconsistency. -->
|
||||
<StackPanel />
|
||||
</ItemsPanelTemplate>
|
||||
</ListBox.ItemsPanel>
|
||||
|
||||
<ListBox.ItemTemplate>
|
||||
<DataTemplate DataType="{x:Type model:PluginInfo}">
|
||||
<Grid ColumnDefinitions="*,Auto,Auto">
|
||||
<Expander Grid.Column="0"
|
||||
HorizontalAlignment="Stretch"
|
||||
HorizontalContentAlignment="Stretch"
|
||||
Header="{Binding}">
|
||||
<Expander.HeaderTemplate>
|
||||
<DataTemplate>
|
||||
<Grid ColumnDefinitions="*,Auto">
|
||||
<Grid Grid.Column="0"
|
||||
HorizontalAlignment="Stretch"
|
||||
ColumnDefinitions="Auto, Auto">
|
||||
<TextBlock Grid.Column="0"
|
||||
VerticalAlignment="Center"
|
||||
HorizontalAlignment="Left"
|
||||
Text="{Binding Name}" />
|
||||
|
||||
<TextBlock Grid.Column="1"
|
||||
HorizontalAlignment="Left"
|
||||
VerticalAlignment="Center"
|
||||
Foreground="#BBFFFFFF"
|
||||
FontSize="11"
|
||||
Text="{Binding Version, StringFormat='{} [v{0}]'}" />
|
||||
</Grid>
|
||||
|
||||
<Grid Grid.Column="1"
|
||||
IsEnabled="{Binding !$parent[local:PluginManagerView].DataContext.IsTransactionInProgress}"
|
||||
VerticalAlignment="Center"
|
||||
Margin="0,2,4,2">
|
||||
<Button BorderBrush="{StaticResource DarkBorderBrush}"
|
||||
BorderThickness="1"
|
||||
Classes="OutsideNavigator"
|
||||
Command="{Binding $parent[local:PluginManagerView].DataContext.UpdateLocalPlugin}"
|
||||
VerticalAlignment="Top"
|
||||
Content="Update"
|
||||
IsVisible="{Binding CanUpdate}" />
|
||||
<Button BorderBrush="{StaticResource DarkBorderBrush}"
|
||||
BorderThickness="1"
|
||||
Classes="OutsideNavigator"
|
||||
Command="{Binding $parent[local:PluginManagerView].DataContext.InstallRemotePlugin}"
|
||||
CommandParameter="{Binding}"
|
||||
VerticalAlignment="Top"
|
||||
Content="Install"
|
||||
IsVisible="{Binding !Installed}" />
|
||||
<Button BorderBrush="{StaticResource DarkBorderBrush}"
|
||||
BorderThickness="1"
|
||||
Classes="OutsideNavigator"
|
||||
Command="{Binding $parent[local:PluginManagerView].DataContext.UninstallLocalPlugin}"
|
||||
CommandParameter="{Binding}"
|
||||
VerticalAlignment="Top"
|
||||
Content="Uninstall"
|
||||
IsVisible="{Binding Installed}" />
|
||||
</Grid>
|
||||
</Grid>
|
||||
</DataTemplate>
|
||||
</ListBox.ItemTemplate>
|
||||
</ListBox>
|
||||
</Expander.HeaderTemplate>
|
||||
|
||||
<StackPanel>
|
||||
<TextBlock Margin="4,0,0,0"
|
||||
Foreground="#BBFFFFFF"
|
||||
FontSize="11"
|
||||
FontStyle="Oblique"
|
||||
Text="{Binding Author}" />
|
||||
|
||||
<TextBlock Margin="4,0,0,4"
|
||||
MaxWidth="400"
|
||||
FontSize="11"
|
||||
HorizontalAlignment="Left"
|
||||
Foreground="#BBFFFFFF"
|
||||
TextWrapping="Wrap"
|
||||
TextAlignment="DetectFromContent"
|
||||
Text="{Binding Description}" />
|
||||
</StackPanel>
|
||||
</Expander>
|
||||
</Grid>
|
||||
</Border>
|
||||
</Grid>
|
||||
</Border>
|
||||
</DataTemplate>
|
||||
</ListBox.ItemTemplate>
|
||||
</ListBox>
|
||||
</Grid>
|
||||
</UserControl>
|
||||
|
|
@ -1,21 +1,14 @@
|
|||
using Avalonia;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Markup.Xaml;
|
||||
using PropertyChanged;
|
||||
|
||||
namespace Saradomin.View.Controls
|
||||
{
|
||||
[DoNotNotify]
|
||||
public class PluginManagerView : UserControl
|
||||
public partial class PluginManagerView : UserControl
|
||||
{
|
||||
public PluginManagerView()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
private void InitializeComponent()
|
||||
{
|
||||
AvaloniaXamlLoader.Load(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -2,8 +2,6 @@
|
|||
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:SettingsViewModel}">
|
||||
|
|
@ -70,7 +68,7 @@
|
|||
|
||||
<ComboBox Grid.Row="1"
|
||||
Margin="2,0,0,2"
|
||||
Items="{Binding ServerProfiles}"
|
||||
ItemsSource="{Binding ServerProfiles}"
|
||||
SelectedItem="{Binding ServerProfile, Converter={StaticResource EnumDescriptionConverter}, Mode=TwoWay}">
|
||||
<ComboBox.Styles>
|
||||
<Style Selector="ComboBoxItem">
|
||||
|
|
@ -119,11 +117,13 @@
|
|||
</HeaderedContentControl>
|
||||
</DockPanel>
|
||||
|
||||
<DockPanel Grid.Column="1">
|
||||
<DockPanel Grid.Column="1"
|
||||
DockPanel.Dock="Top">
|
||||
<HeaderedContentControl Classes="GroupBox"
|
||||
DockPanel.Dock="Top"
|
||||
Header="client settings">
|
||||
<Grid RowDefinitions="Auto,*">
|
||||
<Grid RowDefinitions="Auto,*"
|
||||
Margin="0,0,0,4">
|
||||
<Grid Grid.Row="0" ColumnDefinitions="Auto, *">
|
||||
<Grid Grid.Column="0"
|
||||
RowDefinitions="Auto, Auto">
|
||||
|
|
@ -177,33 +177,15 @@
|
|||
Value="{Binding Client.Fps, Mode=TwoWay}" />
|
||||
</Grid>
|
||||
</Grid>
|
||||
|
||||
<HeaderedContentControl Grid.Row="1"
|
||||
Margin="0,4,0,4"
|
||||
Padding="3,0,7,0"
|
||||
BorderThickness="0"
|
||||
Classes="GroupBox"
|
||||
Header="plugin management">
|
||||
<DockPanel>
|
||||
<controls:PluginManagerView Margin="-2,2" Name="PmView"/>
|
||||
<Button
|
||||
Margin="-141,-17,0,2"
|
||||
Width="140"
|
||||
Height="17"
|
||||
BorderBrush="{StaticResource DarkBorderBrush}"
|
||||
BorderThickness="1"
|
||||
Classes="OutsideNavigator"
|
||||
Command="{Binding #PmView.DataContext.CheckForUpdates}"
|
||||
VerticalAlignment="Top"
|
||||
Opacity="1"
|
||||
FontSize="11"
|
||||
Content="check for updates"
|
||||
ZIndex="9999"
|
||||
IsEnabled="{Binding !#PmView.DataContext.IsTransactionInProgress}" />
|
||||
</DockPanel>
|
||||
</HeaderedContentControl>
|
||||
</Grid>
|
||||
</HeaderedContentControl>
|
||||
|
||||
<HeaderedContentControl Classes="GroupBox"
|
||||
Header="plugin management"
|
||||
DockPanel.Dock="Top">
|
||||
<controls:PluginManagerView MaxHeight="346"/>
|
||||
</HeaderedContentControl>
|
||||
</DockPanel>
|
||||
|
||||
</Grid>
|
||||
</UserControl>
|
||||
|
|
|
|||
|
|
@ -5,16 +5,11 @@ using PropertyChanged;
|
|||
namespace Saradomin.View.Controls
|
||||
{
|
||||
[DoNotNotify]
|
||||
public class SettingsView : UserControl
|
||||
public partial class SettingsView : UserControl
|
||||
{
|
||||
public SettingsView()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
private void InitializeComponent()
|
||||
{
|
||||
AvaloniaXamlLoader.Load(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -5,16 +5,11 @@ using PropertyChanged;
|
|||
namespace Saradomin.View.Controls
|
||||
{
|
||||
[DoNotNotify]
|
||||
public class SingleplayerView : UserControl
|
||||
public partial class SingleplayerView : UserControl
|
||||
{
|
||||
public SingleplayerView()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
private void InitializeComponent()
|
||||
{
|
||||
AvaloniaXamlLoader.Load(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -2,16 +2,15 @@
|
|||
xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:controls="clr-namespace:Saradomin.View.Controls"
|
||||
xmlns:glitonea="clr-namespace:Glitonea;assembly=Glitonea"
|
||||
xmlns:glitonea="clr-namespace:Glitonea.Controls;assembly=Glitonea"
|
||||
xmlns:mvvm="clr-namespace:Glitonea.Mvvm;assembly=Glitonea"
|
||||
xmlns:vm="clr-namespace:Saradomin.ViewModel.Windows"
|
||||
Name="MainWindow"
|
||||
Title="{Binding Title}"
|
||||
DataContext="{mvvm:DataContextSource vm:MainWindowViewModel}"
|
||||
Title="{Binding Title, Mode=TwoWay}"
|
||||
Width="800"
|
||||
Height="550"
|
||||
Background="{StaticResource WindowBackgroundBrush}"
|
||||
CanResize="False"
|
||||
DataContext="{mvvm:DataContextSource vm:MainWindowViewModel}"
|
||||
Icon="avares://Saradomin/Resources/Icons/saradomin.ico"
|
||||
SystemDecorations="None"
|
||||
WindowStartupLocation="CenterScreen">
|
||||
|
|
@ -43,7 +42,7 @@
|
|||
FontSize="14"
|
||||
FontWeight="Light"
|
||||
Foreground="{StaticResource AccentBrush}"
|
||||
Text="{Binding #MainWindow.Title}"
|
||||
Text="{Binding Title, Mode=TwoWay}"
|
||||
TextAlignment="Center" />
|
||||
|
||||
<Button Grid.Column="2"
|
||||
|
|
@ -86,15 +85,15 @@
|
|||
</Grid>
|
||||
|
||||
<TabControl Grid.Row="1"
|
||||
Grid.RowSpan="1"
|
||||
Background="Transparent"
|
||||
BorderBrush="{StaticResource DarkBorderBrush}"
|
||||
Padding="0"
|
||||
Classes="PageSelector">
|
||||
<TabItem Width="95"
|
||||
HorizontalContentAlignment="Center"
|
||||
CornerRadius="0,0,0,8"
|
||||
Header="what's new">
|
||||
<Border Margin="4,0,4,0"
|
||||
<Border Margin="4,4,4,0"
|
||||
Background="{StaticResource MediumBackgroundBrush}"
|
||||
BorderBrush="{StaticResource SemiLightMediumBorderBrush}"
|
||||
BorderThickness="1,1,1,0"
|
||||
|
|
@ -103,9 +102,15 @@
|
|||
<ScrollViewer HorizontalAlignment="Stretch"
|
||||
Classes="MainViewScrollViewer"
|
||||
ClipToBounds="True"
|
||||
Content="{Binding ContentContainer}"
|
||||
HorizontalScrollBarVisibility="Hidden"
|
||||
VerticalScrollBarVisibility="Visible" />
|
||||
VerticalScrollBarVisibility="Visible">
|
||||
<TextBlock Classes="NewsRenderView"
|
||||
MaxWidth="768"
|
||||
Inlines="{Binding HtmlInlines}"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Stretch"
|
||||
TextWrapping="Wrap"/>
|
||||
</ScrollViewer>
|
||||
</Border>
|
||||
</TabItem>
|
||||
|
||||
|
|
@ -113,7 +118,7 @@
|
|||
HorizontalContentAlignment="Center"
|
||||
CornerRadius="0,0,0,0"
|
||||
Header="settings">
|
||||
<Border Margin="4,0,4,0"
|
||||
<Border Margin="4,4,4,0"
|
||||
Background="{StaticResource MediumBackgroundBrush}"
|
||||
BorderBrush="{StaticResource SemiLightMediumBorderBrush}"
|
||||
BorderThickness="1,1,1,0"
|
||||
|
|
@ -121,7 +126,8 @@
|
|||
<ScrollViewer Classes="MainViewScrollViewer"
|
||||
HorizontalScrollBarVisibility="Hidden"
|
||||
VerticalScrollBarVisibility="Visible">
|
||||
<controls:SettingsView VerticalAlignment="Stretch" />
|
||||
<controls:SettingsView VerticalAlignment="Stretch"
|
||||
MaxHeight="500"/>
|
||||
</ScrollViewer>
|
||||
</Border>
|
||||
</TabItem>
|
||||
|
|
@ -130,7 +136,7 @@
|
|||
HorizontalContentAlignment="Center"
|
||||
CornerRadius="0,0,8,0"
|
||||
Header="singleplayer">
|
||||
<Border Margin="4,0,4,0"
|
||||
<Border Margin="4,4,4,0"
|
||||
Background="{StaticResource MediumBackgroundBrush}"
|
||||
BorderBrush="{StaticResource SemiLightMediumBorderBrush}"
|
||||
BorderThickness="1,1,1,0"
|
||||
|
|
|
|||
|
|
@ -1,23 +1,17 @@
|
|||
using System;
|
||||
using Avalonia;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Input;
|
||||
using Avalonia.Markup.Xaml;
|
||||
using Glitonea.Mvvm.Messaging;
|
||||
using PropertyChanged;
|
||||
using Saradomin.Infrastructure.Messaging;
|
||||
using Saradomin.Infrastructure;
|
||||
|
||||
namespace Saradomin.View.Windows
|
||||
{
|
||||
[DoNotNotify]
|
||||
public class MainWindow : Window
|
||||
public partial class MainWindow : Window
|
||||
{
|
||||
public MainWindow()
|
||||
{
|
||||
InitializeComponent();
|
||||
#if DEBUG
|
||||
this.AttachDevTools();
|
||||
#endif
|
||||
}
|
||||
|
||||
protected override void OnOpened(EventArgs e)
|
||||
|
|
@ -26,11 +20,6 @@ namespace Saradomin.View.Windows
|
|||
.Broadcast();
|
||||
}
|
||||
|
||||
private void InitializeComponent()
|
||||
{
|
||||
AvaloniaXamlLoader.Load(this);
|
||||
}
|
||||
|
||||
private void TitleBar_MouseDown(object _, PointerPressedEventArgs e)
|
||||
{
|
||||
if (e.GetCurrentPoint(this).Properties.IsLeftButtonPressed)
|
||||
|
|
|
|||
|
|
@ -1,10 +1,9 @@
|
|||
<glitonea:WindowEx x:Class="Saradomin.View.Windows.NotificationBox"
|
||||
xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:glitonea="clr-namespace:Glitonea;assembly=Glitonea"
|
||||
xmlns:glitonea="clr-namespace:Glitonea.Controls;assembly=Glitonea"
|
||||
xmlns:mvvm="clr-namespace:Glitonea.Mvvm;assembly=Glitonea"
|
||||
xmlns:windows="clr-namespace:Saradomin.ViewModel.Windows"
|
||||
Name="NotificationBox"
|
||||
Title="{Binding Title}"
|
||||
Height="120"
|
||||
MaxWidth="400"
|
||||
|
|
|
|||
|
|
@ -2,28 +2,24 @@ using System.Collections.Generic;
|
|||
using System.Linq;
|
||||
using Avalonia;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Markup.Xaml;
|
||||
using Glitonea;
|
||||
using Glitonea.Controls;
|
||||
using Glitonea.Extensions;
|
||||
using PropertyChanged;
|
||||
using Saradomin.Infrastructure.Messaging;
|
||||
using Saradomin.Infrastructure;
|
||||
|
||||
namespace Saradomin.View.Windows
|
||||
{
|
||||
[DoNotNotify]
|
||||
public class NotificationBox : WindowEx
|
||||
public partial class NotificationBox : WindowEx
|
||||
{
|
||||
private static Queue<NotificationBox> _notificationQueue = new();
|
||||
|
||||
public static NotificationBox Current { get; private set; }
|
||||
|
||||
public static readonly StyledProperty<string> MessageProperty = new(
|
||||
public static readonly StyledProperty<string> MessageProperty = AvaloniaProperty.Register<NotificationBox, string>(
|
||||
nameof(Message),
|
||||
typeof(NotificationBox),
|
||||
new StyledPropertyMetadata<string>(
|
||||
"This is supposed to be a message.\n" +
|
||||
"Someone messed up, though, so have this placeholder instead."
|
||||
)
|
||||
"This is supposed to be a message.\n" +
|
||||
"Someone messed up, though, so have this placeholder instead."
|
||||
);
|
||||
|
||||
public string Message
|
||||
|
|
@ -87,10 +83,5 @@ namespace Saradomin.View.Windows
|
|||
.Broadcast();
|
||||
}
|
||||
}
|
||||
|
||||
private void InitializeComponent()
|
||||
{
|
||||
AvaloniaXamlLoader.Load(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,10 +1,11 @@
|
|||
using System;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.ComponentModel;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Glitonea.Mvvm;
|
||||
using Glitonea.Mvvm.Messaging;
|
||||
using Saradomin.Infrastructure.Messaging;
|
||||
using Saradomin.Infrastructure;
|
||||
using Saradomin.Infrastructure.Services;
|
||||
using Saradomin.Model;
|
||||
using Saradomin.View.Windows;
|
||||
|
|
@ -18,6 +19,7 @@ namespace Saradomin.ViewModel.Controls
|
|||
|
||||
public bool IsTransactionInProgress { get; private set; }
|
||||
public ObservableCollection<PluginInfo> PluginList { get; private set; } = new();
|
||||
public string CurrentStatusMessage { get; set; } = "Idle...";
|
||||
|
||||
public PluginManagerViewModel(
|
||||
IPluginManagementService pluginManagementService,
|
||||
|
|
@ -27,26 +29,36 @@ namespace Saradomin.ViewModel.Controls
|
|||
_pluginDownloadService = pluginDownloadService;
|
||||
|
||||
Message.Subscribe<MainViewLoadedMessage>(this, MainViewLoaded);
|
||||
|
||||
PropertyChanged += ViewModelPropertyChanged;
|
||||
}
|
||||
|
||||
public async Task RefreshPluginCollections()
|
||||
{
|
||||
PluginList.Clear();
|
||||
|
||||
var remotePlugins =
|
||||
await _pluginDownloadService
|
||||
.GetAllMetadata(_pluginManagementService.PluginRepositoryPath, false, false);
|
||||
var remotePlugins =await _pluginDownloadService.GetAllMetadata(
|
||||
_pluginManagementService.PluginRepositoryPath,
|
||||
false,
|
||||
false
|
||||
);
|
||||
|
||||
PluginList = new ObservableCollection<PluginInfo>(remotePlugins.OrderByDescending(x => x.Installed));
|
||||
}
|
||||
|
||||
public async Task InstallRemotePlugin(PluginInfo pluginInfo)
|
||||
public async Task InstallRemotePlugin(object parameter)
|
||||
{
|
||||
if (parameter is not PluginInfo pluginInfo)
|
||||
return;
|
||||
|
||||
if (IsTransactionInProgress)
|
||||
return;
|
||||
|
||||
try
|
||||
{
|
||||
IsTransactionInProgress = true;
|
||||
|
||||
UpdateStatusMessage($"Installing {pluginInfo.Name}...");
|
||||
|
||||
await _pluginDownloadService.DownloadPluginFiles(
|
||||
pluginInfo.Name,
|
||||
|
|
@ -68,8 +80,11 @@ namespace Saradomin.ViewModel.Controls
|
|||
}
|
||||
}
|
||||
|
||||
public async Task UninstallLocalPlugin(PluginInfo pluginInfo)
|
||||
public async Task UninstallLocalPlugin(object parameter)
|
||||
{
|
||||
if (parameter is not PluginInfo pluginInfo)
|
||||
return;
|
||||
|
||||
if (IsTransactionInProgress)
|
||||
return;
|
||||
|
||||
|
|
@ -77,10 +92,11 @@ namespace Saradomin.ViewModel.Controls
|
|||
{
|
||||
IsTransactionInProgress = true;
|
||||
|
||||
await _pluginManagementService.UninstallPlugin(pluginInfo.Name);
|
||||
UpdateStatusMessage($"Uninstalling {pluginInfo.Name}...");
|
||||
|
||||
await _pluginManagementService.UninstallPlugin(pluginInfo.Name);
|
||||
pluginInfo.Installed = false;
|
||||
|
||||
PluginList.Add(pluginInfo);
|
||||
|
||||
PluginList = new(PluginList.OrderByDescending(x => x.Installed));
|
||||
}
|
||||
catch (Exception e)
|
||||
|
|
@ -100,16 +116,19 @@ namespace Saradomin.ViewModel.Controls
|
|||
{
|
||||
if (IsTransactionInProgress)
|
||||
return;
|
||||
IsTransactionInProgress = true;
|
||||
|
||||
|
||||
try
|
||||
{
|
||||
var updatablePlugins =
|
||||
await _pluginDownloadService.GetAllMetadata(
|
||||
_pluginManagementService.PluginRepositoryPath,
|
||||
true,
|
||||
true
|
||||
);
|
||||
IsTransactionInProgress = true;
|
||||
|
||||
UpdateStatusMessage($"Checking for updates...");
|
||||
|
||||
var updatablePlugins = await _pluginDownloadService.GetAllMetadata(
|
||||
_pluginManagementService.PluginRepositoryPath,
|
||||
true,
|
||||
true
|
||||
);
|
||||
|
||||
foreach (var plugin in updatablePlugins)
|
||||
{
|
||||
|
|
@ -125,8 +144,11 @@ namespace Saradomin.ViewModel.Controls
|
|||
}
|
||||
}
|
||||
|
||||
public async Task UpdateLocalPlugin (PluginInfo info)
|
||||
public async Task UpdateLocalPlugin(object parameter)
|
||||
{
|
||||
if (parameter is not PluginInfo pluginInfo)
|
||||
return;
|
||||
|
||||
if (IsTransactionInProgress)
|
||||
return;
|
||||
|
||||
|
|
@ -134,15 +156,17 @@ namespace Saradomin.ViewModel.Controls
|
|||
{
|
||||
IsTransactionInProgress = true;
|
||||
|
||||
await _pluginDownloadService.DownloadPluginFiles(info.Name, _pluginManagementService.PluginRepositoryPath);
|
||||
UpdateStatusMessage($"Updating {pluginInfo.Name}...");
|
||||
|
||||
await _pluginDownloadService.DownloadPluginFiles(pluginInfo.Name, _pluginManagementService.PluginRepositoryPath);
|
||||
await RefreshPluginCollections();
|
||||
|
||||
var newInfo = PluginList.First(x => x.Name == info.Name);
|
||||
if (newInfo.Version != info.Version)
|
||||
var newInfo = PluginList.First(x => x.Name == pluginInfo.Name);
|
||||
if (newInfo.Version != pluginInfo.Version)
|
||||
{
|
||||
NotificationBox.DisplayNotification(
|
||||
"Success!",
|
||||
$"Successfully updated {info.Name} to version {newInfo.Version}!"
|
||||
$"Successfully updated {pluginInfo.Name} to version {newInfo.Version}!"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -159,9 +183,30 @@ namespace Saradomin.ViewModel.Controls
|
|||
}
|
||||
}
|
||||
|
||||
private void UpdateStatusMessage(string message)
|
||||
{
|
||||
CurrentStatusMessage = message;
|
||||
}
|
||||
|
||||
private async void MainViewLoaded(MainViewLoadedMessage _)
|
||||
{
|
||||
await RefreshPluginCollections();
|
||||
}
|
||||
|
||||
private void ViewModelPropertyChanged(object sender, PropertyChangedEventArgs e)
|
||||
{
|
||||
switch (e.PropertyName)
|
||||
{
|
||||
case nameof(IsTransactionInProgress):
|
||||
{
|
||||
if (!IsTransactionInProgress)
|
||||
{
|
||||
UpdateStatusMessage("Idle...");
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,22 +1,18 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Reflection;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text.Json;
|
||||
using System.Threading.Tasks;
|
||||
using Avalonia;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Platform.Storage;
|
||||
using Glitonea.Extensions;
|
||||
using Glitonea.Mvvm;
|
||||
using Glitonea.Mvvm.Messaging;
|
||||
using Glitonea.Utilities;
|
||||
using Saradomin.Infrastructure.Messaging;
|
||||
using Saradomin.Infrastructure;
|
||||
using Saradomin.Infrastructure.Services;
|
||||
using Saradomin.Model.Settings.Client;
|
||||
using Saradomin.Model.Settings.Launcher;
|
||||
using Saradomin.Utilities;
|
||||
using Saradomin.View.Windows;
|
||||
|
||||
namespace Saradomin.ViewModel.Controls
|
||||
{
|
||||
|
|
@ -78,20 +74,34 @@ namespace Saradomin.ViewModel.Controls
|
|||
|
||||
Message.Subscribe<MainViewLoadedMessage>(this, OnMainViewLoaded);
|
||||
}
|
||||
|
||||
public void LaunchScapeWebsite()
|
||||
=> CrossPlatform.LaunchURL("https://2009scape.org");
|
||||
|
||||
private void LaunchScapeWebsite()
|
||||
{
|
||||
CrossPlatform.LaunchURL("https://2009scape.org");
|
||||
}
|
||||
public void OpenPluginTutorial()
|
||||
=> CrossPlatform.LaunchURL("https://gitlab.com/2009scape/tools/client-plugins");
|
||||
|
||||
private void OpenPluginTutorial()
|
||||
{
|
||||
CrossPlatform.LaunchURL("https://gitlab.com/2009scape/tools/client-plugins");
|
||||
}
|
||||
public void LaunchProjectWebsite()
|
||||
=> CrossPlatform.LaunchURL("https://gitlab.com/2009scape/Saradomin-Launcher");
|
||||
|
||||
private void LaunchProjectWebsite()
|
||||
public async Task BrowseForJavaExecutable()
|
||||
{
|
||||
CrossPlatform.LaunchURL("https://gitlab.com/2009scape/Saradomin-Launcher");
|
||||
var window = Application.Current!.GetMainWindow();
|
||||
var pickerOptions = new FilePickerOpenOptions
|
||||
{
|
||||
Title = "Browse for Java...",
|
||||
AllowMultiple = false,
|
||||
SuggestedStartLocation =await window!.StorageProvider.TryGetFolderFromPathAsync(
|
||||
Environment.GetFolderPath(Environment.SpecialFolder.UserProfile)
|
||||
)
|
||||
};
|
||||
|
||||
var storageFiles = await window.StorageProvider.OpenFilePickerAsync(pickerOptions);
|
||||
|
||||
if (storageFiles.Count > 0)
|
||||
{
|
||||
Launcher.JavaExecutableLocation = storageFiles[0].Path.AbsolutePath;
|
||||
}
|
||||
}
|
||||
|
||||
private void OnMainViewLoaded(MainViewLoadedMessage _)
|
||||
|
|
@ -103,22 +113,5 @@ namespace Saradomin.ViewModel.Controls
|
|||
{
|
||||
_settingsService.SaveAll();
|
||||
}
|
||||
|
||||
private async Task BrowseForJavaExecutable()
|
||||
{
|
||||
var ofd = new OpenFileDialog
|
||||
{
|
||||
Title = "Browse for Java...",
|
||||
AllowMultiple = false,
|
||||
Directory = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile)
|
||||
};
|
||||
|
||||
var paths = await ofd.ShowAsync(Application.Current.GetMainWindow());
|
||||
|
||||
if (paths != null && paths.Length > 0)
|
||||
{
|
||||
Launcher.JavaExecutableLocation = paths[0];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -15,226 +15,226 @@ using Avalonia.Media;
|
|||
using Avalonia.Threading;
|
||||
using Glitonea.Mvvm;
|
||||
using Glitonea.Mvvm.Messaging;
|
||||
using Saradomin.Infrastructure.Messaging;
|
||||
using Saradomin.Infrastructure;
|
||||
using Saradomin.Infrastructure.Services;
|
||||
using Saradomin.Model.Settings.Launcher;
|
||||
using Saradomin.Utilities;
|
||||
using Saradomin.View.Windows;
|
||||
using static Saradomin.Utilities.SingleplayerManagement;
|
||||
|
||||
namespace Saradomin.ViewModel.Controls;
|
||||
|
||||
public class SingleplayerViewModel : ViewModelBase
|
||||
namespace Saradomin.ViewModel.Controls
|
||||
{
|
||||
private readonly ISingleplayerUpdateService _singleplayerUpdateService;
|
||||
private readonly ISettingsService _settingsService;
|
||||
private readonly IJavaUpdateService _javaUpdateService;
|
||||
|
||||
public string SingleplayerDownloadText { get; private set; } =
|
||||
Directory.Exists(CrossPlatform.GetSingleplayerHome()) ? "Update Singleplayer" : "Download Singleplayer";
|
||||
public bool CanLaunch { get; private set; } = File.Exists(CrossPlatform.LocateSingleplayerExecutable());
|
||||
public TextBox SingleplayerLogsTextBox { get; }
|
||||
public bool ShowLogPanel { get; private set; }
|
||||
public LauncherSettings Launcher => _settingsService.Launcher;
|
||||
|
||||
private string _oldServerAddress, _oldManagementAddress;
|
||||
private Process _serverProcess;
|
||||
|
||||
public SingleplayerViewModel(ISettingsService settingsService,
|
||||
IJavaUpdateService javaUpdateService,
|
||||
ISingleplayerUpdateService iSingleplayerUpdateService)
|
||||
public class SingleplayerViewModel : ViewModelBase
|
||||
{
|
||||
_settingsService = settingsService;
|
||||
_javaUpdateService = javaUpdateService;
|
||||
_singleplayerUpdateService = iSingleplayerUpdateService;
|
||||
_singleplayerUpdateService.SingleplayerDownloadProgressChanged += OnSingleplayerDownloadProgressChanged;
|
||||
private readonly ISingleplayerUpdateService _singleplayerUpdateService;
|
||||
private readonly ISettingsService _settingsService;
|
||||
private readonly IJavaUpdateService _javaUpdateService;
|
||||
|
||||
SingleplayerLogsTextBox = new TextBox
|
||||
public string SingleplayerDownloadText { get; private set; } =
|
||||
Directory.Exists(CrossPlatform.GetSingleplayerHome()) ? "Update Singleplayer" : "Download Singleplayer";
|
||||
public bool CanLaunch { get; private set; } = File.Exists(CrossPlatform.LocateSingleplayerExecutable());
|
||||
public TextBox SingleplayerLogsTextBox { get; }
|
||||
public bool ShowLogPanel { get; private set; }
|
||||
public LauncherSettings Launcher => _settingsService.Launcher;
|
||||
|
||||
private string _oldServerAddress, _oldManagementAddress;
|
||||
private Process _serverProcess;
|
||||
|
||||
public SingleplayerViewModel(ISettingsService settingsService,
|
||||
IJavaUpdateService javaUpdateService,
|
||||
ISingleplayerUpdateService iSingleplayerUpdateService)
|
||||
{
|
||||
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,
|
||||
};
|
||||
_settingsService = settingsService;
|
||||
_javaUpdateService = javaUpdateService;
|
||||
_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,
|
||||
};
|
||||
|
||||
Message.Subscribe<ClientClosedMessage>(this, OnClientClosed);
|
||||
}
|
||||
Message.Subscribe<ClientClosedMessage>(this, OnClientClosed);
|
||||
}
|
||||
|
||||
private void OnClientClosed(ClientClosedMessage _)
|
||||
{
|
||||
if (_serverProcess == null) return;
|
||||
_serverProcess.Kill();
|
||||
_serverProcess = null;
|
||||
CanLaunch = true;
|
||||
_settingsService.Client.GameServerAddress = _oldServerAddress;
|
||||
_settingsService.Client.ManagementServerAddress = _oldManagementAddress;
|
||||
}
|
||||
|
||||
private void OnSingleplayerDownloadProgressChanged(object sender, Tuple<float, bool> e)
|
||||
{
|
||||
float progress = e.Item1;
|
||||
bool finished = e.Item2;
|
||||
if (finished)
|
||||
private void OnClientClosed(ClientClosedMessage _)
|
||||
{
|
||||
SingleplayerDownloadText = "Update Singleplayer";
|
||||
ApplyLatestBackup(PrintLog);
|
||||
PrintLog($"Singleplayer Download complete");
|
||||
PrintLog($"");
|
||||
if (_serverProcess == null) return;
|
||||
_serverProcess.Kill();
|
||||
_serverProcess = null;
|
||||
CanLaunch = true;
|
||||
return;
|
||||
_settingsService.Client.GameServerAddress = _oldServerAddress;
|
||||
_settingsService.Client.ManagementServerAddress = _oldManagementAddress;
|
||||
}
|
||||
|
||||
if (progress >= 1f)
|
||||
private void OnSingleplayerDownloadProgressChanged(object sender, Tuple<float, bool> e)
|
||||
{
|
||||
SingleplayerDownloadText = "Extracting...";
|
||||
return;
|
||||
float progress = e.Item1;
|
||||
bool finished = e.Item2;
|
||||
if (finished)
|
||||
{
|
||||
SingleplayerDownloadText = "Update Singleplayer";
|
||||
ApplyLatestBackup(PrintLog);
|
||||
PrintLog($"Singleplayer Download complete");
|
||||
PrintLog($"");
|
||||
CanLaunch = true;
|
||||
return;
|
||||
}
|
||||
|
||||
if (progress >= 1f)
|
||||
{
|
||||
SingleplayerDownloadText = "Extracting...";
|
||||
return;
|
||||
}
|
||||
|
||||
SingleplayerDownloadText = $"Downloading... {progress * 100:F2}%";
|
||||
}
|
||||
|
||||
SingleplayerDownloadText = $"Downloading... {progress * 100:F2}%";
|
||||
}
|
||||
public void DownloadSingleplayer()
|
||||
{
|
||||
if (File.Exists(CrossPlatform.LocateSingleplayerExecutable()) && !CanLaunch) return; // While the button could be disabled, this looks nicer visually (since we update the download progress in the button text)
|
||||
CanLaunch = false;
|
||||
MakeBackup();
|
||||
PrintLog($"Starting singleplayer download...");
|
||||
_singleplayerUpdateService.DownloadSingleplayer();
|
||||
}
|
||||
|
||||
public void DownloadSingleplayer()
|
||||
{
|
||||
if (File.Exists(CrossPlatform.LocateSingleplayerExecutable()) && !CanLaunch) return; // While the button could be disabled, this looks nicer visually (since we update the download progress in the button text)
|
||||
CanLaunch = false;
|
||||
MakeBackup();
|
||||
PrintLog($"Starting singleplayer download...");
|
||||
_singleplayerUpdateService.DownloadSingleplayer();
|
||||
}
|
||||
private void MakeBackup()
|
||||
{
|
||||
PrintLog("Starting backup of player saves and economy files..");
|
||||
SingleplayerManagement.MakeBackup(PrintLog);
|
||||
PrintLog($"Done backing up player saves and economy files");
|
||||
PrintLog($"");
|
||||
}
|
||||
|
||||
private void MakeBackup()
|
||||
{
|
||||
PrintLog("Starting backup of player saves and economy files..");
|
||||
SingleplayerManagement.MakeBackup(PrintLog);
|
||||
PrintLog($"Done backing up player saves and economy files");
|
||||
PrintLog($"");
|
||||
}
|
||||
public void OpenBackupFolder()
|
||||
{
|
||||
if (!Directory.Exists(CrossPlatform.GetSingleplayerBackupsHome()))
|
||||
Directory.CreateDirectory(CrossPlatform.GetSingleplayerBackupsHome());
|
||||
CrossPlatform.OpenFolder(CrossPlatform.GetSingleplayerBackupsHome());
|
||||
}
|
||||
|
||||
public void OpenBackupFolder()
|
||||
{
|
||||
if (!Directory.Exists(CrossPlatform.GetSingleplayerBackupsHome()))
|
||||
Directory.CreateDirectory(CrossPlatform.GetSingleplayerBackupsHome());
|
||||
CrossPlatform.OpenFolder(CrossPlatform.GetSingleplayerBackupsHome());
|
||||
}
|
||||
|
||||
[Pure]
|
||||
public static bool IsServerTerminationLog(string log)
|
||||
{
|
||||
return Regex.IsMatch(log, @"^\[\d{2}:\d{2}:\d{2}\]: \[SystemTermination\] Server successfully terminated!\s*$");
|
||||
}
|
||||
[Pure]
|
||||
public static bool IsServerTerminationLog(string log)
|
||||
{
|
||||
return Regex.IsMatch(log, @"^\[\d{2}:\d{2}:\d{2}\]: \[SystemTermination\] Server successfully terminated!\s*$");
|
||||
}
|
||||
|
||||
private void PrintLog(string message)
|
||||
{
|
||||
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) message = Regex.Replace(message, @"\e\[[0-9;]*m", string.Empty);
|
||||
private void PrintLog(string message)
|
||||
{
|
||||
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) message = Regex.Replace(message, @"\e\[[0-9;]*m", string.Empty);
|
||||
|
||||
ShowLogPanel = true;
|
||||
Dispatcher.UIThread.Post(() => { SingleplayerLogsTextBox.Text += message + Environment.NewLine; },
|
||||
DispatcherPriority.Background);
|
||||
ShowLogPanel = true;
|
||||
Dispatcher.UIThread.Post(() => { SingleplayerLogsTextBox.Text += message + Environment.NewLine; },
|
||||
DispatcherPriority.Background);
|
||||
|
||||
if (IsServerTerminationLog(message)) CanLaunch = true;
|
||||
}
|
||||
|
||||
public async void LaunchSingleplayer()
|
||||
{
|
||||
string javaVersionOutput = CrossPlatform.RunCommandAndGetOutput(
|
||||
$"\"{Launcher.JavaExecutableLocation}\" -version"
|
||||
);
|
||||
if (!javaVersionOutput.Contains("11"))
|
||||
{
|
||||
PrintLog("You don't have Java 11 set! Saradomin will grab it's own copy..");
|
||||
await _javaUpdateService.DownloadAndSetJava11(_settingsService);
|
||||
}
|
||||
CanLaunch = false;
|
||||
PrintLog("Starting Singleplayer.. The Singleplayer client will launch when 2009scape is ready. Sit tight!");
|
||||
|
||||
_oldServerAddress = _settingsService.Client.GameServerAddress;
|
||||
_oldManagementAddress = _settingsService.Client.ManagementServerAddress;
|
||||
_settingsService.Client.GameServerAddress = _settingsService.Client.ManagementServerAddress = "localhost";
|
||||
new Task(() => LaunchServerAndClient(Launcher.JavaExecutableLocation, PrintLog)).Start();
|
||||
}
|
||||
|
||||
private void LaunchServerAndClient (string javaExecutableLocation, Action<string> log)
|
||||
{
|
||||
var serverJar = CrossPlatform.GetSingleplayerHome() + @"/game/server.jar";
|
||||
|
||||
if (IsPortInUse(43595))
|
||||
{
|
||||
log("Port 43595 is in use. Cannot start the server again.");
|
||||
return;
|
||||
if (IsServerTerminationLog(message)) CanLaunch = true;
|
||||
}
|
||||
|
||||
_serverProcess = CrossPlatform.StartJavaProcess(javaExecutableLocation, serverJar, "2G", log, null);
|
||||
while (!IsPortInUse(43595)) Thread.Sleep(1000);
|
||||
Message.Broadcast<ClientLaunchRequestedMessage>();
|
||||
}
|
||||
public async void LaunchSingleplayer()
|
||||
{
|
||||
string javaVersionOutput = CrossPlatform.RunCommandAndGetOutput(
|
||||
$"\"{Launcher.JavaExecutableLocation}\" -version"
|
||||
);
|
||||
if (!javaVersionOutput.Contains("11"))
|
||||
{
|
||||
PrintLog("You don't have Java 11 set! Saradomin will grab it's own copy..");
|
||||
await _javaUpdateService.DownloadAndSetJava11(_settingsService);
|
||||
}
|
||||
CanLaunch = false;
|
||||
PrintLog("Starting Singleplayer.. The Singleplayer client will launch when 2009scape is ready. Sit tight!");
|
||||
|
||||
_oldServerAddress = _settingsService.Client.GameServerAddress;
|
||||
_oldManagementAddress = _settingsService.Client.ManagementServerAddress;
|
||||
_settingsService.Client.GameServerAddress = _settingsService.Client.ManagementServerAddress = "localhost";
|
||||
new Task(() => LaunchServerAndClient(Launcher.JavaExecutableLocation, PrintLog)).Start();
|
||||
}
|
||||
|
||||
private void LaunchServerAndClient (string javaExecutableLocation, Action<string> log)
|
||||
{
|
||||
var serverJar = CrossPlatform.GetSingleplayerHome() + @"/game/server.jar";
|
||||
|
||||
if (IsPortInUse(43595))
|
||||
{
|
||||
log("Port 43595 is in use. Cannot start the server again.");
|
||||
return;
|
||||
}
|
||||
|
||||
_serverProcess = CrossPlatform.StartJavaProcess(javaExecutableLocation, serverJar, "2G", log, null);
|
||||
while (!IsPortInUse(43595)) Thread.Sleep(1000);
|
||||
Message.Broadcast<ClientLaunchRequestedMessage>();
|
||||
}
|
||||
|
||||
private static bool IsPortInUse(int port)
|
||||
{
|
||||
var ipGlobalProperties = IPGlobalProperties.GetIPGlobalProperties();
|
||||
var tcpConnInfoArray = ipGlobalProperties.GetActiveTcpListeners();
|
||||
|
||||
return tcpConnInfoArray.Any(endpoint => endpoint.Port == port);
|
||||
}
|
||||
|
||||
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");
|
||||
}
|
||||
|
||||
public bool Cheats
|
||||
{
|
||||
get => ParseConf<bool>("noauth_default_admin");
|
||||
set => WriteConf("noauth_default_admin", value);
|
||||
}
|
||||
|
||||
public bool FakePlayers
|
||||
{
|
||||
get => ParseConf<bool>("enable_bots", true);
|
||||
set => WriteConf("enable_bots", value);
|
||||
}
|
||||
|
||||
public bool GEAutoBuySell
|
||||
{
|
||||
get => ParseConf<bool>("i_want_to_cheat");
|
||||
set => WriteConf("i_want_to_cheat", value);
|
||||
}
|
||||
|
||||
public bool Debug
|
||||
{
|
||||
get => ParseConf<bool>("debug");
|
||||
set => WriteConf("debug", value);
|
||||
}
|
||||
|
||||
public async void ResetToDefaults()
|
||||
{
|
||||
using var httpClient = new HttpClient();
|
||||
httpClient.Timeout = TimeSpan.FromSeconds(5);
|
||||
MakeBackup();
|
||||
PrintLog("Grabbing the default config from the latest singleplayer codebase..");
|
||||
try
|
||||
private static bool IsPortInUse(int port)
|
||||
{
|
||||
string defaultConf = await httpClient.GetStringAsync("https://gitlab.com/2009scape/singleplayer/windows/-/raw/master/game/worldprops/default.conf");
|
||||
await File.WriteAllTextAsync(CrossPlatform.GetSingleplayerHome() + "/game/worldprops/default.conf",
|
||||
defaultConf);
|
||||
}
|
||||
catch (Exception ex)
|
||||
var ipGlobalProperties = IPGlobalProperties.GetIPGlobalProperties();
|
||||
var tcpConnInfoArray = ipGlobalProperties.GetActiveTcpListeners();
|
||||
|
||||
return tcpConnInfoArray.Any(endpoint => endpoint.Port == port);
|
||||
}
|
||||
|
||||
private void LaunchFaq()
|
||||
{
|
||||
PrintLog($"Couldn't reset game properties");
|
||||
PrintLog(ex.Message);
|
||||
return;
|
||||
CrossPlatform.LaunchURL("https://2009scape.org/site/game_guide/singleplayer.html");
|
||||
}
|
||||
|
||||
private void LaunchForums()
|
||||
{
|
||||
CrossPlatform.LaunchURL("https://forum.2009scape.org/viewforum.php?f=8-support");
|
||||
}
|
||||
|
||||
public bool Cheats
|
||||
{
|
||||
get => ParseConf<bool>("noauth_default_admin");
|
||||
set => WriteConf("noauth_default_admin", value);
|
||||
}
|
||||
|
||||
public bool FakePlayers
|
||||
{
|
||||
get => ParseConf<bool>("enable_bots", true);
|
||||
set => WriteConf("enable_bots", value);
|
||||
}
|
||||
|
||||
public bool GEAutoBuySell
|
||||
{
|
||||
get => ParseConf<bool>("i_want_to_cheat");
|
||||
set => WriteConf("i_want_to_cheat", value);
|
||||
}
|
||||
|
||||
public bool Debug
|
||||
{
|
||||
get => ParseConf<bool>("debug");
|
||||
set => WriteConf("debug", value);
|
||||
}
|
||||
|
||||
public async void ResetToDefaults()
|
||||
{
|
||||
using var httpClient = new HttpClient();
|
||||
httpClient.Timeout = TimeSpan.FromSeconds(5);
|
||||
MakeBackup();
|
||||
PrintLog("Grabbing the default config from the latest singleplayer codebase..");
|
||||
try
|
||||
{
|
||||
string defaultConf = await httpClient.GetStringAsync("https://gitlab.com/2009scape/singleplayer/windows/-/raw/master/game/worldprops/default.conf");
|
||||
await File.WriteAllTextAsync(CrossPlatform.GetSingleplayerHome() + "/game/worldprops/default.conf",
|
||||
defaultConf);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
PrintLog($"Couldn't reset game properties");
|
||||
PrintLog(ex.Message);
|
||||
return;
|
||||
}
|
||||
Cheats = GEAutoBuySell = Debug = false; // Force update UI
|
||||
FakePlayers = true;
|
||||
PrintLog("Saved new config.");
|
||||
PrintLog("");
|
||||
}
|
||||
Cheats = GEAutoBuySell = Debug = false; // Force update UI
|
||||
FakePlayers = true;
|
||||
PrintLog("Saved new config.");
|
||||
PrintLog("");
|
||||
}
|
||||
}
|
||||
|
|
@ -5,11 +5,12 @@ using System.Net.Http;
|
|||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Controls.Documents;
|
||||
using Avalonia.Metadata;
|
||||
using Glitonea.Mvvm;
|
||||
using Glitonea.Mvvm.Messaging;
|
||||
using HtmlAgilityPack;
|
||||
using Saradomin.Infrastructure.Messaging;
|
||||
using Saradomin.Infrastructure;
|
||||
using Saradomin.Infrastructure.Services;
|
||||
using Saradomin.Model.Settings.Launcher;
|
||||
using Saradomin.Utilities;
|
||||
|
|
@ -33,7 +34,7 @@ namespace Saradomin.ViewModel.Windows
|
|||
public string LaunchText { get; private set; } = "Play!";
|
||||
|
||||
public bool DimContent { get; private set; }
|
||||
public StackPanel ContentContainer { get; private set; }
|
||||
public InlineCollection HtmlInlines { get; private set; }
|
||||
|
||||
public MainWindowViewModel(IClientLaunchService launchService,
|
||||
IClientUpdateService updateService,
|
||||
|
|
@ -51,11 +52,6 @@ namespace Saradomin.ViewModel.Windows
|
|||
_settingsService = settingsService;
|
||||
Launcher = _settingsService.Launcher;
|
||||
|
||||
ContentContainer = new StackPanel
|
||||
{
|
||||
Margin = new(4)
|
||||
};
|
||||
|
||||
Message.Subscribe<MainViewLoadedMessage>(this, MainViewLoaded);
|
||||
Message.Subscribe<NotificationBoxStateChangedMessage>(this, NotificatationBoxStateChanged);
|
||||
Message.Subscribe<ClientLaunchRequestedMessage>(this, ClientLaunchRequested);
|
||||
|
|
@ -94,9 +90,8 @@ namespace Saradomin.ViewModel.Windows
|
|||
node = doc.DocumentNode;
|
||||
}
|
||||
|
||||
ContentContainer.MaxWidth = 760;
|
||||
var renderer = new HtmlRenderer(ContentContainer, node);
|
||||
renderer.RenderToContainer();
|
||||
var renderer = new HtmlRenderer(node);
|
||||
HtmlInlines = renderer.Render();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -105,7 +100,7 @@ namespace Saradomin.ViewModel.Windows
|
|||
DimContent = msg.WasOpened;
|
||||
}
|
||||
|
||||
public void LaunchPage(string parameter)
|
||||
public void LaunchPage(object parameter)
|
||||
{
|
||||
var url = parameter switch
|
||||
{
|
||||
|
|
@ -121,7 +116,7 @@ namespace Saradomin.ViewModel.Windows
|
|||
}
|
||||
|
||||
[DependsOn(nameof(CanLaunch))]
|
||||
public bool CanExecuteLaunchSequence(object param)
|
||||
public bool CanExecuteLaunchSequence(object parameter)
|
||||
=> CanLaunch;
|
||||
|
||||
//Stub to maintain compatibility with AXAML
|
||||
|
|
|
|||
|
|
@ -1,295 +0,0 @@
|
|||
namespace UnitTests.Saradomin.Utilities.SingleplayerManagement;
|
||||
|
||||
[TestFixture]
|
||||
public class BackupManagerTests
|
||||
{
|
||||
[Test]
|
||||
public void WithValidDirectories_ReturnsMostRecent()
|
||||
{
|
||||
// Arrange
|
||||
var directories = new List<string>
|
||||
{
|
||||
"/backups/20230101_120000",
|
||||
"/backups/20230102_120000",
|
||||
"/backups/20230103_120000"
|
||||
};
|
||||
|
||||
// Act
|
||||
var mostRecent =
|
||||
global::Saradomin.Utilities.SingleplayerManagement.FindMostRecentBackupDirectory(
|
||||
directories
|
||||
);
|
||||
|
||||
// Assert
|
||||
Assert.That("20230103_120000".Equals(mostRecent));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void WithDifferentYears_ReturnsMostRecent()
|
||||
{
|
||||
// Arrange
|
||||
var directories = new List<string>
|
||||
{
|
||||
"/backups/20210101_120000",
|
||||
"/backups/20220101_120000",
|
||||
"/backups/20230101_120000"
|
||||
};
|
||||
|
||||
// Act
|
||||
var mostRecent =
|
||||
global::Saradomin.Utilities.SingleplayerManagement.FindMostRecentBackupDirectory(
|
||||
directories
|
||||
);
|
||||
|
||||
// Assert
|
||||
Assert.That("20230101_120000".Equals(mostRecent));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void WithDifferentMonths_ReturnsMostRecent()
|
||||
{
|
||||
// Arrange
|
||||
var directories = new List<string>
|
||||
{
|
||||
"/backups/20230101_120000",
|
||||
"/backups/20230201_120000",
|
||||
"/backups/20230301_120000"
|
||||
};
|
||||
|
||||
// Act
|
||||
var mostRecent =
|
||||
global::Saradomin.Utilities.SingleplayerManagement.FindMostRecentBackupDirectory(
|
||||
directories
|
||||
);
|
||||
|
||||
// Assert
|
||||
Assert.That("20230301_120000".Equals(mostRecent));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void WithDifferentDays_ReturnsMostRecent()
|
||||
{
|
||||
// Arrange
|
||||
var directories = new List<string>
|
||||
{
|
||||
"/backups/20230301_120000",
|
||||
"/backups/20230302_120000",
|
||||
"/backups/20230303_120000"
|
||||
};
|
||||
|
||||
// Act
|
||||
var mostRecent =
|
||||
global::Saradomin.Utilities.SingleplayerManagement.FindMostRecentBackupDirectory(
|
||||
directories
|
||||
);
|
||||
|
||||
// Assert
|
||||
Assert.That("20230303_120000".Equals(mostRecent));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void WithDifferentHours_ReturnsMostRecent()
|
||||
{
|
||||
// Arrange
|
||||
var directories = new List<string>
|
||||
{
|
||||
"/backups/20230301_110000",
|
||||
"/backups/20230301_120000",
|
||||
"/backups/20230301_130000"
|
||||
};
|
||||
|
||||
// Act
|
||||
var mostRecent =
|
||||
global::Saradomin.Utilities.SingleplayerManagement.FindMostRecentBackupDirectory(
|
||||
directories
|
||||
);
|
||||
|
||||
// Assert
|
||||
Assert.That("20230301_130000".Equals(mostRecent));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void WithDifferentMinutes_ReturnsMostRecent()
|
||||
{
|
||||
// Arrange
|
||||
var directories = new List<string>
|
||||
{
|
||||
"/backups/20230301_120100",
|
||||
"/backups/20230301_120200",
|
||||
"/backups/20230301_120300"
|
||||
};
|
||||
|
||||
// Act
|
||||
var mostRecent =
|
||||
global::Saradomin.Utilities.SingleplayerManagement.FindMostRecentBackupDirectory(
|
||||
directories
|
||||
);
|
||||
|
||||
// Assert
|
||||
Assert.That("20230301_120300".Equals(mostRecent));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void WithDifferentSeconds_ReturnsMostRecent()
|
||||
{
|
||||
// Arrange
|
||||
var directories = new List<string>
|
||||
{
|
||||
"/backups/20230301_120000",
|
||||
"/backups/20230301_120015",
|
||||
"/backups/20230301_120030"
|
||||
};
|
||||
|
||||
// Act
|
||||
var mostRecent =
|
||||
global::Saradomin.Utilities.SingleplayerManagement.FindMostRecentBackupDirectory(
|
||||
directories
|
||||
);
|
||||
|
||||
// Assert
|
||||
Assert.That("20230301_120030".Equals(mostRecent));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void WithMixedDateTimes_ReturnsMostRecent_Case1()
|
||||
{
|
||||
// Arrange
|
||||
var directories = new List<string>
|
||||
{
|
||||
"/backups/20210101_235959",
|
||||
"/backups/20201231_235959",
|
||||
"/backups/20220228_235959"
|
||||
};
|
||||
|
||||
// Act
|
||||
var mostRecent =
|
||||
global::Saradomin.Utilities.SingleplayerManagement.FindMostRecentBackupDirectory(
|
||||
directories
|
||||
);
|
||||
|
||||
// Assert
|
||||
Assert.That("20220228_235959".Equals(mostRecent));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void WithMixedDateTimes_ReturnsMostRecent_Case2()
|
||||
{
|
||||
// Arrange
|
||||
var directories = new List<string>
|
||||
{
|
||||
"/backups/20211001_000001",
|
||||
"/backups/20211001_000002",
|
||||
"/backups/20210930_235959"
|
||||
};
|
||||
|
||||
// Act
|
||||
var mostRecent =
|
||||
global::Saradomin.Utilities.SingleplayerManagement.FindMostRecentBackupDirectory(
|
||||
directories
|
||||
);
|
||||
|
||||
// Assert
|
||||
Assert.That("20211001_000002".Equals(mostRecent));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void WithMixedDateTimes_ReturnsMostRecent_Case3()
|
||||
{
|
||||
// Arrange
|
||||
var directories = new List<string>
|
||||
{
|
||||
"/backups/20211231_235959",
|
||||
"/backups/20220101_000000",
|
||||
"/backups/20211231_235958"
|
||||
};
|
||||
|
||||
// Act
|
||||
var mostRecent =
|
||||
global::Saradomin.Utilities.SingleplayerManagement.FindMostRecentBackupDirectory(
|
||||
directories
|
||||
);
|
||||
|
||||
// Assert
|
||||
Assert.That("20220101_000000".Equals(mostRecent));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void WithMixedDateTimes_ReturnsMostRecent_Case4()
|
||||
{
|
||||
// Arrange
|
||||
var directories = new List<string>
|
||||
{
|
||||
"/backups/20230530_123456",
|
||||
"/backups/20230529_123456",
|
||||
"/backups/20220530_123457"
|
||||
};
|
||||
|
||||
// Act
|
||||
var mostRecent =
|
||||
global::Saradomin.Utilities.SingleplayerManagement.FindMostRecentBackupDirectory(
|
||||
directories
|
||||
);
|
||||
|
||||
// Assert
|
||||
Assert.That("20230530_123456".Equals(mostRecent));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void WithMixedDateTimes_ReturnsMostRecent_Case5()
|
||||
{
|
||||
// Arrange
|
||||
var directories = new List<string>
|
||||
{
|
||||
"/backups/20230102_010101",
|
||||
"/backups/20230101_222222",
|
||||
"/backups/20221231_235959"
|
||||
};
|
||||
|
||||
// Act
|
||||
var mostRecent =
|
||||
global::Saradomin.Utilities.SingleplayerManagement.FindMostRecentBackupDirectory(
|
||||
directories
|
||||
);
|
||||
|
||||
// Assert
|
||||
Assert.That("20230102_010101".Equals(mostRecent));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void WithMixedDateTimes_ReturnsMostRecent_Case6()
|
||||
{
|
||||
// Arrange
|
||||
var directories = new List<string>
|
||||
{
|
||||
"/backups/20240101_120000",
|
||||
"/backups/20231231_235959",
|
||||
"/backups/20231231_235958"
|
||||
};
|
||||
|
||||
// Act
|
||||
var mostRecent =
|
||||
global::Saradomin.Utilities.SingleplayerManagement.FindMostRecentBackupDirectory(
|
||||
directories
|
||||
);
|
||||
|
||||
// Assert
|
||||
Assert.That("20240101_120000".Equals(mostRecent));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void WithNoDirectories_ReturnsNull()
|
||||
{
|
||||
// Arrange
|
||||
// ReSharper disable once CollectionNeverUpdated.Local
|
||||
var directories = new List<string>();
|
||||
|
||||
// Act
|
||||
var mostRecent =
|
||||
global::Saradomin.Utilities.SingleplayerManagement.FindMostRecentBackupDirectory(
|
||||
directories
|
||||
);
|
||||
|
||||
// Assert
|
||||
Assert.That(mostRecent, Is.EqualTo(null));
|
||||
}
|
||||
}
|
||||
|
|
@ -1,20 +0,0 @@
|
|||
namespace UnitTests.Saradomin.ViewModel.Controls.SingleplayerViewModel;
|
||||
|
||||
[TestFixture]
|
||||
public class IsServerTerminationLogTests
|
||||
{
|
||||
[Test]
|
||||
[TestCase("[23:43:26]: [SystemTermination] Server successfully terminated!", true)]
|
||||
[TestCase("[23:00:26]: [SystemTermination] Server successfully terminated!", true)]
|
||||
[TestCase("[23:43:26]: lol said [SystemTermination] Server successfully terminated!", false)]
|
||||
[TestCase("[23:00:26]: [SystemTermination] Server successfully terminated! weee exploit", false)]
|
||||
[TestCase("Gotcha [23:00:26]: [SystemTermination] Server successfully terminated!", false)]
|
||||
public void ServerTerminationLogTests(string log, bool expectedOutcome)
|
||||
{
|
||||
// Act
|
||||
var result = global::Saradomin.ViewModel.Controls.SingleplayerViewModel.IsServerTerminationLog(log);
|
||||
|
||||
// Assert
|
||||
Assert.That(result, Is.EqualTo(expectedOutcome), $"Failed for log: {log}");
|
||||
}
|
||||
}
|
||||
|
|
@ -1,23 +0,0 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
|
||||
<IsPackable>false</IsPackable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.3.2"/>
|
||||
<PackageReference Include="NUnit" Version="3.13.3"/>
|
||||
<PackageReference Include="NUnit3TestAdapter" Version="4.2.1"/>
|
||||
<PackageReference Include="NUnit.Analyzers" Version="3.3.0"/>
|
||||
<PackageReference Include="coverlet.collector" Version="3.1.2"/>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Saradomin\Saradomin.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
|
@ -1 +0,0 @@
|
|||
global using NUnit.Framework;
|
||||
Loading…
Add table
Add a link
Reference in a new issue