- shit: Cleanup this mess
This commit is contained in:
@@ -1,22 +1,19 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using Avalonia;
|
||||
using Avalonia.Controls.ApplicationLifetimes;
|
||||
using Avalonia.Data.Core;
|
||||
using Avalonia.Data.Core.Plugins;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using Avalonia.Markup.Xaml;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Nebula.Launcher.ViewModels;
|
||||
using Nebula.Launcher.Views;
|
||||
using Nebula.Shared;
|
||||
|
||||
namespace Nebula.Launcher;
|
||||
|
||||
public partial class App : Application
|
||||
public class App : Application
|
||||
{
|
||||
private IServiceProvider _serviceProvider = null!;
|
||||
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
AvaloniaXamlLoader.Load(this);
|
||||
@@ -26,11 +23,11 @@ public partial class App : Application
|
||||
{
|
||||
var services = new ServiceCollection();
|
||||
services.AddAvaloniaServices();
|
||||
services.AddViews();
|
||||
services.AddServices();
|
||||
|
||||
services.AddViews();
|
||||
|
||||
_serviceProvider = services.BuildServiceProvider();
|
||||
|
||||
|
||||
switch (ApplicationLifetime)
|
||||
{
|
||||
case IClassicDesktopStyleApplicationLifetime desktop:
|
||||
@@ -52,9 +49,6 @@ public partial class App : Application
|
||||
BindingPlugins.DataValidators.OfType<DataAnnotationsValidationPlugin>().ToArray();
|
||||
|
||||
// remove each entry found
|
||||
foreach (var plugin in dataValidationPluginsToRemove)
|
||||
{
|
||||
BindingPlugins.DataValidators.Remove(plugin);
|
||||
}
|
||||
foreach (var plugin in dataValidationPluginsToRemove) BindingPlugins.DataValidators.Remove(plugin);
|
||||
}
|
||||
}
|
||||
@@ -57,7 +57,7 @@
|
||||
<Setter Property="Padding" Value="8" />
|
||||
<Setter Property="Background" Value="#00000000" />
|
||||
</Style>
|
||||
|
||||
|
||||
<Style Selector="ListBox.AccountSelector > ListBoxItem">
|
||||
<Setter Property="CornerRadius" Value="0" />
|
||||
<Setter Property="Margin" Value="0,0,0,0" />
|
||||
@@ -65,8 +65,8 @@
|
||||
<Setter Property="Background" Value="#00000000" />
|
||||
<Setter Property="Focusable" Value="False" />
|
||||
</Style>
|
||||
|
||||
|
||||
<Style Selector="ListBox.AccountSelector > ListBoxItem:selected">
|
||||
<Setter Property="Background" Value="#00000000" />
|
||||
</Style>
|
||||
</Styles>
|
||||
</Styles>
|
||||
@@ -9,7 +9,7 @@ public class TypeConverters
|
||||
{
|
||||
private const string StreamGeometryNotFound =
|
||||
"M24 4C35.0457 4 44 12.9543 44 24C44 35.0457 35.0457 44 24 44C12.9543 44 4 35.0457 4 24C4 12.9543 12.9543 4 24 4ZM24 6.5C14.335 6.5 6.5 14.335 6.5 24C6.5 33.665 14.335 41.5 24 41.5C33.665 41.5 41.5 33.665 41.5 24C41.5 14.335 33.665 6.5 24 6.5ZM24.25 32C25.0784 32 25.75 32.6716 25.75 33.5C25.75 34.3284 25.0784 35 24.25 35C23.4216 35 22.75 34.3284 22.75 33.5C22.75 32.6716 23.4216 32 24.25 32ZM24.25 13C27.6147 13 30.5 15.8821 30.5 19.2488C30.502 21.3691 29.7314 22.7192 27.8216 24.7772L26.8066 25.8638C25.7842 27.0028 25.3794 27.7252 25.3409 28.5793L25.3379 28.7411L25.3323 28.8689L25.3143 28.9932C25.2018 29.5636 24.7009 29.9957 24.0968 30.0001C23.4065 30.0049 22.8428 29.4493 22.8379 28.7589C22.8251 26.9703 23.5147 25.7467 25.1461 23.9739L26.1734 22.8762C27.5312 21.3837 28.0012 20.503 28 19.25C28 17.2634 26.2346 15.5 24.25 15.5C22.3307 15.5 20.6142 17.1536 20.5055 19.0587L20.4935 19.3778C20.4295 20.0081 19.8972 20.5 19.25 20.5C18.5596 20.5 18 19.9404 18 19.25C18 15.8846 20.8864 13 24.25 13Z";
|
||||
|
||||
|
||||
public static FuncValueConverter<string, StreamGeometry> IconConverter { get; } =
|
||||
new(iconKey =>
|
||||
{
|
||||
|
||||
2
Nebula.Launcher/GlobalUsing.cs
Normal file
2
Nebula.Launcher/GlobalUsing.cs
Normal file
@@ -0,0 +1,2 @@
|
||||
global using SourceGen;
|
||||
global using Nebula.Launcher.ViewHelper;
|
||||
@@ -10,33 +10,33 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<AvaloniaResource Include="Assets\**" />
|
||||
<AvaloniaResource Include="Assets\**"/>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="AsyncImageLoader.Avalonia" Version="3.3.0" />
|
||||
<PackageReference Include="Avalonia" Version="11.2.1" />
|
||||
<PackageReference Include="Avalonia.Desktop" Version="11.2.1" />
|
||||
<PackageReference Include="Avalonia.Themes.Fluent" Version="11.2.1" />
|
||||
<PackageReference Include="Avalonia.Fonts.Inter" Version="11.2.1" />
|
||||
<PackageReference Include="AsyncImageLoader.Avalonia" Version="3.3.0"/>
|
||||
<PackageReference Include="Avalonia" Version="11.2.1"/>
|
||||
<PackageReference Include="Avalonia.Desktop" Version="11.2.1"/>
|
||||
<PackageReference Include="Avalonia.Themes.Fluent" Version="11.2.1"/>
|
||||
<PackageReference Include="Avalonia.Fonts.Inter" Version="11.2.1"/>
|
||||
<!--Condition below is needed to remove Avalonia.Diagnostics package from build output in Release configuration.-->
|
||||
<PackageReference Include="Avalonia.Diagnostics" Version="11.2.1">
|
||||
<IncludeAssets Condition="'$(Configuration)' != 'Debug'">None</IncludeAssets>
|
||||
<PrivateAssets Condition="'$(Configuration)' != 'Debug'">All</PrivateAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="CommunityToolkit.Mvvm" Version="8.2.1" />
|
||||
<PackageReference Include="JetBrains.Annotations" Version="2024.3.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="9.0.0" />
|
||||
<PackageReference Include="libsodium" Version="1.0.20" />
|
||||
<PackageReference Include="CommunityToolkit.Mvvm" Version="8.2.1"/>
|
||||
<PackageReference Include="JetBrains.Annotations" Version="2024.3.0"/>
|
||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="9.0.0"/>
|
||||
<PackageReference Include="libsodium" Version="1.0.20"/>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Update="Views\Tabs\ServerListTab.axaml.cs">
|
||||
<DependentUpon>ServerListTab.axaml</DependentUpon>
|
||||
<SubType>Code</SubType>
|
||||
</Compile>
|
||||
<Compile Update="Views\Tabs\ServerListTab.axaml.cs">
|
||||
<DependentUpon>ServerListTab.axaml</DependentUpon>
|
||||
<SubType>Code</SubType>
|
||||
</Compile>
|
||||
</ItemGroup>
|
||||
|
||||
|
||||
<Target Name="BuildCheck" AfterTargets="AfterBuild">
|
||||
<Copy SourceFiles="..\Nebula.Runner\bin\$(Configuration)\$(TargetFramework)\Nebula.Runner.dll" DestinationFolder="$(OutDir)"/>
|
||||
<Copy SourceFiles="..\Nebula.Runner\bin\$(Configuration)\$(TargetFramework)\Nebula.Runner.pdb" DestinationFolder="$(OutDir)"/>
|
||||
@@ -45,6 +45,7 @@
|
||||
</Target>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Nebula.Shared\Nebula.Shared.csproj" />
|
||||
<ProjectReference Include="..\Nebula.Shared\Nebula.Shared.csproj"/>
|
||||
<ProjectReference Include="..\Nebula.SourceGenerators\Nebula.SourceGenerators.csproj" OutputItemType="Analyzer" ReferenceOutputAssembly="false"/>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
||||
@@ -4,13 +4,18 @@ namespace Nebula.Launcher;
|
||||
|
||||
public static class Program
|
||||
{
|
||||
public static void Main(string[] args) => BuildAvaloniaApp()
|
||||
.StartWithClassicDesktopLifetime(args);
|
||||
public static void Main(string[] args)
|
||||
{
|
||||
BuildAvaloniaApp()
|
||||
.StartWithClassicDesktopLifetime(args);
|
||||
}
|
||||
|
||||
// Avalonia configuration, don't remove; also used by visual designer.
|
||||
private static AppBuilder BuildAvaloniaApp()
|
||||
=> AppBuilder.Configure<App>()
|
||||
{
|
||||
return AppBuilder.Configure<App>()
|
||||
.UsePlatformDetect()
|
||||
.WithInterFont()
|
||||
.LogToTrace();
|
||||
}
|
||||
}
|
||||
@@ -6,10 +6,7 @@ using Avalonia.Controls;
|
||||
using Avalonia.Controls.ApplicationLifetimes;
|
||||
using Avalonia.Threading;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Nebula.Launcher.ViewHelper;
|
||||
using Nebula.Launcher.ViewModels;
|
||||
using Nebula.Launcher.Views;
|
||||
using Nebula.Launcher.Views.Pages;
|
||||
|
||||
namespace Nebula.Launcher;
|
||||
|
||||
@@ -18,14 +15,20 @@ public static class ServiceCollectionExtensions
|
||||
public static void AddAvaloniaServices(this IServiceCollection services)
|
||||
{
|
||||
services.AddSingleton<IDispatcher>(_ => Dispatcher.UIThread);
|
||||
services.AddSingleton(_ => Application.Current?.ApplicationLifetime ?? throw new InvalidOperationException("No application lifetime is set"));
|
||||
services.AddSingleton(_ =>
|
||||
Application.Current?.ApplicationLifetime ??
|
||||
throw new InvalidOperationException("No application lifetime is set"));
|
||||
|
||||
services.AddSingleton(sp =>
|
||||
sp.GetRequiredService<IApplicationLifetime>() switch
|
||||
{
|
||||
IClassicDesktopStyleApplicationLifetime desktop => desktop.MainWindow ?? throw new InvalidOperationException("No main window set"),
|
||||
ISingleViewApplicationLifetime singleViewPlatform => TopLevel.GetTopLevel(singleViewPlatform.MainView) ?? throw new InvalidOperationException("Could not find top level element for single view"),
|
||||
_ => throw new InvalidOperationException($"Could not find {nameof(TopLevel)} element"),
|
||||
IClassicDesktopStyleApplicationLifetime desktop => desktop.MainWindow ??
|
||||
throw new InvalidOperationException(
|
||||
"No main window set"),
|
||||
ISingleViewApplicationLifetime singleViewPlatform =>
|
||||
TopLevel.GetTopLevel(singleViewPlatform.MainView) ??
|
||||
throw new InvalidOperationException("Could not find top level element for single view"),
|
||||
_ => throw new InvalidOperationException($"Could not find {nameof(TopLevel)} element")
|
||||
}
|
||||
);
|
||||
|
||||
@@ -38,20 +41,18 @@ public static class ServiceCollectionExtensions
|
||||
|
||||
foreach (var (viewModel, view, isSingleton) in GetTypesWithHelpAttribute(Assembly.GetExecutingAssembly()))
|
||||
{
|
||||
if(isSingleton)services.AddSingleton(viewModel);
|
||||
if (isSingleton) services.AddSingleton(viewModel);
|
||||
else services.AddTransient(viewModel);
|
||||
if (view != null) services.AddTransient(view);
|
||||
}
|
||||
}
|
||||
|
||||
private static IEnumerable<(Type,Type?,bool)> GetTypesWithHelpAttribute(Assembly assembly) {
|
||||
foreach(Type type in assembly.GetTypes())
|
||||
|
||||
private static IEnumerable<(Type, Type?, bool)> GetTypesWithHelpAttribute(Assembly assembly)
|
||||
{
|
||||
foreach (var type in assembly.GetTypes())
|
||||
{
|
||||
var attr = type.GetCustomAttribute<ViewModelRegisterAttribute>();
|
||||
if (attr is not null) {
|
||||
yield return (type, attr.Type, attr.IsSingleton);
|
||||
}
|
||||
if (attr is not null) yield return (type, attr.Type, attr.IsSingleton);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
42
Nebula.Launcher/Services/ViewHelperService.cs
Normal file
42
Nebula.Launcher/Services/ViewHelperService.cs
Normal file
@@ -0,0 +1,42 @@
|
||||
using System;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using Avalonia.Controls;
|
||||
using Nebula.Launcher.ViewModels;
|
||||
using Nebula.Shared;
|
||||
|
||||
namespace Nebula.Launcher.Services;
|
||||
|
||||
[ServiceRegister, ConstructGenerator]
|
||||
public sealed partial class ViewHelperService
|
||||
{
|
||||
[GenerateProperty] private IServiceProvider ServiceProvider { get; } = default!;
|
||||
|
||||
public bool TryGetViewModel(Type type, [NotNullWhen(true)] out ViewModelBase? viewModelBase)
|
||||
{
|
||||
viewModelBase = null;
|
||||
var vm = Design.IsDesignMode
|
||||
? Activator.CreateInstance(type)
|
||||
: ServiceProvider.GetService(type);
|
||||
|
||||
if (vm is not ViewModelBase vmb) return false;
|
||||
|
||||
viewModelBase = vmb;
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool TryGetViewModel<T>([NotNullWhen(true)] out T? viewModelBase) where T : ViewModelBase
|
||||
{
|
||||
var success = TryGetViewModel(typeof(T), out var vmb);
|
||||
viewModelBase = (T?)vmb;
|
||||
return success;
|
||||
}
|
||||
|
||||
public T GetViewModel<T>() where T : ViewModelBase
|
||||
{
|
||||
TryGetViewModel<T>(out var viewModelBase);
|
||||
return viewModelBase!;
|
||||
}
|
||||
|
||||
private void Initialise(){}
|
||||
private void InitialiseInDesignMode(){}
|
||||
}
|
||||
@@ -5,12 +5,12 @@ namespace Nebula.Launcher.ViewHelper;
|
||||
[AttributeUsage(AttributeTargets.Class)]
|
||||
public class ViewModelRegisterAttribute : Attribute
|
||||
{
|
||||
public Type? Type { get; }
|
||||
public bool IsSingleton { get; }
|
||||
|
||||
public ViewModelRegisterAttribute(Type? type = null, bool isSingleton = true)
|
||||
{
|
||||
Type = type;
|
||||
IsSingleton = isSingleton;
|
||||
}
|
||||
|
||||
public Type? Type { get; }
|
||||
public bool IsSingleton { get; }
|
||||
}
|
||||
@@ -2,7 +2,6 @@ using System;
|
||||
using System.Reflection;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Controls.Templates;
|
||||
using Nebula.Launcher.ViewHelper;
|
||||
using Nebula.Launcher.ViewModels;
|
||||
|
||||
namespace Nebula.Launcher;
|
||||
@@ -13,15 +12,12 @@ public class ViewLocator : IDataTemplate
|
||||
{
|
||||
if (param is null)
|
||||
return null;
|
||||
|
||||
|
||||
var type = param.GetType().GetCustomAttribute<ViewModelRegisterAttribute>()?.Type;
|
||||
|
||||
if (type != null)
|
||||
{
|
||||
return (Control)Activator.CreateInstance(type)!;
|
||||
}
|
||||
if (type != null) return (Control)Activator.CreateInstance(type)!;
|
||||
|
||||
return new TextBlock { Text = "Not Found: " + param.GetType()};
|
||||
return new TextBlock { Text = "Not Found: " + param.GetType() };
|
||||
}
|
||||
|
||||
public bool Match(object? data)
|
||||
|
||||
@@ -1,24 +0,0 @@
|
||||
using System;
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using Nebula.Launcher.ViewHelper;
|
||||
using Nebula.Launcher.Views.Popup;
|
||||
|
||||
namespace Nebula.Launcher.ViewModels;
|
||||
|
||||
[ViewModelRegister(typeof(InfoPopupView), false)]
|
||||
public partial class InfoPopupViewModel : PopupViewModelBase
|
||||
{
|
||||
public InfoPopupViewModel()
|
||||
{
|
||||
}
|
||||
|
||||
public InfoPopupViewModel(IServiceProvider serviceProvider) : base(serviceProvider)
|
||||
{
|
||||
}
|
||||
|
||||
public override string Title => "Info";
|
||||
public override bool IsClosable => true;
|
||||
|
||||
[ObservableProperty]
|
||||
private string _infoText = "Test";
|
||||
}
|
||||
@@ -4,8 +4,9 @@ using System.Collections.ObjectModel;
|
||||
using System.Linq;
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using CommunityToolkit.Mvvm.Input;
|
||||
using JetBrains.Annotations;
|
||||
using Nebula.Launcher.ViewHelper;
|
||||
using Nebula.Launcher.Services;
|
||||
using Nebula.Launcher.ViewModels.Pages;
|
||||
using Nebula.Launcher.ViewModels.Popup;
|
||||
using Nebula.Launcher.Views;
|
||||
using Nebula.Shared.Models;
|
||||
using Nebula.Shared.Services;
|
||||
@@ -14,34 +15,9 @@ using Nebula.Shared.Utils;
|
||||
namespace Nebula.Launcher.ViewModels;
|
||||
|
||||
[ViewModelRegister(typeof(MainView))]
|
||||
[ConstructGenerator]
|
||||
public partial class MainViewModel : ViewModelBase
|
||||
{
|
||||
public MainViewModel()
|
||||
{
|
||||
TryGetViewModel(typeof(AccountInfoViewModel), out var model);
|
||||
_currentPage = model!;
|
||||
|
||||
Items = new ObservableCollection<ListItemTemplate>(_templates);
|
||||
|
||||
SelectedListItem = Items.First(vm => vm.ModelType == typeof(AccountInfoViewModel));
|
||||
}
|
||||
|
||||
[UsedImplicitly]
|
||||
public MainViewModel(AccountInfoViewModel accountInfoViewModel,DebugService debugService, PopupMessageService popupMessageService,
|
||||
IServiceProvider serviceProvider): base(serviceProvider)
|
||||
{
|
||||
_currentPage = accountInfoViewModel;
|
||||
_debugService = debugService;
|
||||
Items = new ObservableCollection<ListItemTemplate>(_templates);
|
||||
|
||||
popupMessageService.OnPopupRequired += OnPopupRequired;
|
||||
popupMessageService.OnCloseRequired += OnPopupCloseRequired;
|
||||
|
||||
SelectedListItem = Items.First(vm => vm.ModelType == typeof(AccountInfoViewModel));
|
||||
}
|
||||
|
||||
private readonly List<PopupViewModelBase> _viewQueue = new();
|
||||
|
||||
private readonly List<ListItemTemplate> _templates =
|
||||
[
|
||||
new ListItemTemplate(typeof(AccountInfoViewModel), "Account", "Account"),
|
||||
@@ -49,41 +25,57 @@ public partial class MainViewModel : ViewModelBase
|
||||
new ListItemTemplate(typeof(ContentBrowserViewModel), "GridRegular", "Content")
|
||||
];
|
||||
|
||||
[ObservableProperty]
|
||||
private bool _isPaneOpen;
|
||||
private readonly List<PopupViewModelBase> _viewQueue = new();
|
||||
|
||||
[ObservableProperty]
|
||||
private ViewModelBase _currentPage;
|
||||
[ObservableProperty] private ViewModelBase _currentPage;
|
||||
|
||||
private readonly DebugService _debugService;
|
||||
[ObservableProperty] private PopupViewModelBase? _currentPopup;
|
||||
|
||||
[ObservableProperty] private string _currentTitle = "Default";
|
||||
|
||||
[ObservableProperty] private bool _isEnabled = true;
|
||||
[ObservableProperty] private bool _popup;
|
||||
|
||||
[ObservableProperty]
|
||||
private PopupViewModelBase? _currentPopup;
|
||||
[ObservableProperty]
|
||||
private string _currentTitle = "Default";
|
||||
|
||||
[ObservableProperty] private bool _isPaneOpen;
|
||||
|
||||
[ObservableProperty] private bool _isPopupClosable = true;
|
||||
[ObservableProperty] private bool _popup;
|
||||
|
||||
[ObservableProperty]
|
||||
private ListItemTemplate? _selectedListItem;
|
||||
[ObservableProperty] private ListItemTemplate? _selectedListItem;
|
||||
|
||||
[GenerateProperty] private DebugService DebugService { get; } = default!;
|
||||
[GenerateProperty] private PopupMessageService PopupMessageService { get; } = default!;
|
||||
[GenerateProperty] private ViewHelperService ViewHelperService { get; } = default!;
|
||||
|
||||
public ObservableCollection<ListItemTemplate> Items { get; private set; }
|
||||
|
||||
protected override void InitialiseInDesignMode()
|
||||
{
|
||||
CurrentPage = ViewHelperService.GetViewModel<AccountInfoViewModel>();
|
||||
Items = new ObservableCollection<ListItemTemplate>(_templates);
|
||||
SelectedListItem = Items.First(vm => vm.ModelType == typeof(AccountInfoViewModel));
|
||||
}
|
||||
|
||||
protected override void Initialise()
|
||||
{
|
||||
CurrentPage = ViewHelperService.GetViewModel<AccountInfoViewModel>();
|
||||
|
||||
Items = new ObservableCollection<ListItemTemplate>(_templates);
|
||||
|
||||
PopupMessageService.OnPopupRequired += OnPopupRequired;
|
||||
PopupMessageService.OnCloseRequired += OnPopupCloseRequired;
|
||||
|
||||
SelectedListItem = Items.First(vm => vm.ModelType == typeof(AccountInfoViewModel));
|
||||
}
|
||||
|
||||
partial void OnSelectedListItemChanged(ListItemTemplate? value)
|
||||
{
|
||||
if (value is null) return;
|
||||
|
||||
if(!TryGetViewModel(value.ModelType, out var vmb))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!ViewHelperService.TryGetViewModel(value.ModelType, out var vmb)) return;
|
||||
|
||||
CurrentPage = vmb;
|
||||
}
|
||||
|
||||
public ObservableCollection<ListItemTemplate> Items { get; }
|
||||
|
||||
public void PopupMessage(PopupViewModelBase viewModelBase)
|
||||
{
|
||||
if (CurrentPopup == null)
|
||||
@@ -98,7 +90,7 @@ public partial class MainViewModel : ViewModelBase
|
||||
_viewQueue.Add(viewModelBase);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void OnCloseRequired()
|
||||
{
|
||||
IsEnabled = true;
|
||||
@@ -122,7 +114,7 @@ public partial class MainViewModel : ViewModelBase
|
||||
{
|
||||
case string str:
|
||||
{
|
||||
var view = GetViewModel<InfoPopupViewModel>();
|
||||
var view = ViewHelperService.GetViewModel<InfoPopupViewModel>();
|
||||
view.InfoText = str;
|
||||
PopupMessage(view);
|
||||
break;
|
||||
@@ -131,21 +123,18 @@ public partial class MainViewModel : ViewModelBase
|
||||
PopupMessage(@base);
|
||||
break;
|
||||
case Exception error:
|
||||
var err = GetViewModel<ExceptionViewModel>();
|
||||
_debugService.Error(error);
|
||||
var err = ViewHelperService.GetViewModel<ExceptionViewModel>();
|
||||
DebugService.Error(error);
|
||||
err.AppendError(error);
|
||||
PopupMessage(err);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void OnPopupCloseRequired(object obj)
|
||||
{
|
||||
if(obj is not PopupViewModelBase viewModelBase)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (obj is not PopupViewModelBase viewModelBase) return;
|
||||
|
||||
if (obj == CurrentPopup)
|
||||
ClosePopup();
|
||||
else
|
||||
@@ -158,20 +147,21 @@ public partial class MainViewModel : ViewModelBase
|
||||
{
|
||||
IsPaneOpen = !IsPaneOpen;
|
||||
}
|
||||
|
||||
|
||||
[RelayCommand]
|
||||
public void ClosePopup()
|
||||
{
|
||||
var viewModelBase = _viewQueue.FirstOrDefault();
|
||||
if (viewModelBase is null)
|
||||
{
|
||||
OnCloseRequired();
|
||||
}
|
||||
else
|
||||
{
|
||||
CurrentTitle = viewModelBase.Title;
|
||||
_viewQueue.RemoveAt(0);
|
||||
}
|
||||
|
||||
|
||||
CurrentPopup = viewModelBase;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,46 +1,44 @@
|
||||
using System;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Linq;
|
||||
using System.Windows.Input;
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using CommunityToolkit.Mvvm.Input;
|
||||
using Nebula.Launcher.ViewHelper;
|
||||
using Nebula.Launcher.Services;
|
||||
using Nebula.Launcher.ViewModels.Popup;
|
||||
using Nebula.Launcher.Views.Pages;
|
||||
using Nebula.Shared;
|
||||
using Nebula.Shared.Services;
|
||||
using Nebula.Shared.Utils;
|
||||
|
||||
namespace Nebula.Launcher.ViewModels;
|
||||
namespace Nebula.Launcher.ViewModels.Pages;
|
||||
|
||||
[ViewModelRegister(typeof(AccountInfoView))]
|
||||
[ConstructGenerator]
|
||||
public partial class AccountInfoViewModel : ViewModelBase
|
||||
{
|
||||
private readonly PopupMessageService _popupMessageService;
|
||||
private readonly ConfigurationService _configurationService;
|
||||
private readonly AuthService _authService;
|
||||
|
||||
public ObservableCollection<AuthLoginPasswordModel> Accounts { get; } = new();
|
||||
public ObservableCollection<string> AuthUrls { get; } = new();
|
||||
|
||||
[ObservableProperty]
|
||||
private string _currentLogin = String.Empty;
|
||||
|
||||
[ObservableProperty]
|
||||
private string _currentPassword = String.Empty;
|
||||
|
||||
[ObservableProperty]
|
||||
private string _currentAuthServer = String.Empty;
|
||||
[ObservableProperty] private bool _authMenuExpand;
|
||||
|
||||
[ObservableProperty] private bool _authUrlConfigExpand;
|
||||
|
||||
[ObservableProperty] private int _authViewSpan = 1;
|
||||
|
||||
[ObservableProperty] private bool _authMenuExpand;
|
||||
|
||||
private bool _isProfilesEmpty;
|
||||
[ObservableProperty] private string _currentAuthServer = string.Empty;
|
||||
|
||||
[ObservableProperty] private string _currentLogin = string.Empty;
|
||||
|
||||
[ObservableProperty] private string _currentPassword = string.Empty;
|
||||
|
||||
[ObservableProperty] private bool _isLogged;
|
||||
|
||||
private bool _isProfilesEmpty;
|
||||
[GenerateProperty] private PopupMessageService PopupMessageService { get; } = default!;
|
||||
[GenerateProperty] private ConfigurationService ConfigurationService { get; } = default!;
|
||||
[GenerateProperty] private AuthService AuthService { get; } = default!;
|
||||
[GenerateProperty] private ViewHelperService ViewHelperService { get; } = default!;
|
||||
|
||||
public ObservableCollection<AuthLoginPasswordModel> Accounts { get; } = new();
|
||||
public ObservableCollection<string> AuthUrls { get; } = new();
|
||||
|
||||
private AuthLoginPassword CurrentAlp
|
||||
{
|
||||
get => new(CurrentLogin, CurrentPassword, CurrentAuthServer);
|
||||
@@ -51,24 +49,23 @@ public partial class AccountInfoViewModel : ViewModelBase
|
||||
CurrentAuthServer = value.AuthServer;
|
||||
}
|
||||
}
|
||||
|
||||
//Design think
|
||||
public AccountInfoViewModel()
|
||||
|
||||
public string AuthItemSelect
|
||||
{
|
||||
AddAccount(new AuthLoginPassword("Binka","12341",""));
|
||||
set => CurrentAuthServer = value;
|
||||
}
|
||||
|
||||
//Design think
|
||||
protected override void InitialiseInDesignMode()
|
||||
{
|
||||
AddAccount(new AuthLoginPassword("Binka", "12341", ""));
|
||||
AuthUrls.Add("https://cinka.ru");
|
||||
AuthUrls.Add("https://cinka.ru");
|
||||
}
|
||||
|
||||
//Real think
|
||||
public AccountInfoViewModel(IServiceProvider serviceProvider, PopupMessageService popupMessageService,
|
||||
ConfigurationService configurationService, AuthService authService) : base(serviceProvider)
|
||||
{
|
||||
//_popupMessageService = mainViewModel;
|
||||
_popupMessageService = popupMessageService;
|
||||
_configurationService = configurationService;
|
||||
_authService = authService;
|
||||
|
||||
//Real think
|
||||
protected override void Initialise()
|
||||
{
|
||||
ReadAuthConfig();
|
||||
}
|
||||
|
||||
@@ -80,88 +77,75 @@ public partial class AccountInfoViewModel : ViewModelBase
|
||||
|
||||
public async void DoAuth()
|
||||
{
|
||||
var message = GetViewModel<InfoPopupViewModel>();
|
||||
var message = ViewHelperService.GetViewModel<InfoPopupViewModel>();
|
||||
message.InfoText = "Auth think, please wait...";
|
||||
_popupMessageService.Popup(message);
|
||||
|
||||
if(await _authService.Auth(CurrentAlp))
|
||||
PopupMessageService.Popup(message);
|
||||
|
||||
if (await AuthService.Auth(CurrentAlp))
|
||||
{
|
||||
message.Dispose();
|
||||
IsLogged = true;
|
||||
_configurationService.SetConfigValue(CurrentConVar.AuthCurrent, CurrentAlp);
|
||||
ConfigurationService.SetConfigValue(CurrentConVar.AuthCurrent, CurrentAlp);
|
||||
}
|
||||
else
|
||||
{
|
||||
message.Dispose();
|
||||
Logout();
|
||||
_popupMessageService.Popup("Well, shit is happened: " + _authService.Reason);
|
||||
PopupMessageService.Popup("Well, shit is happened: " + AuthService.Reason);
|
||||
}
|
||||
}
|
||||
|
||||
public void Logout()
|
||||
{
|
||||
IsLogged = false;
|
||||
//CurrentAlp = new AuthLoginPassword("", "", "");
|
||||
_authService.ClearAuth();
|
||||
AuthService.ClearAuth();
|
||||
}
|
||||
|
||||
private void UpdateAuthMenu()
|
||||
{
|
||||
if (AuthMenuExpand || _isProfilesEmpty)
|
||||
{
|
||||
AuthViewSpan = 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
AuthViewSpan = 1;
|
||||
}
|
||||
}
|
||||
|
||||
private void AddAccount(AuthLoginPassword authLoginPassword)
|
||||
{
|
||||
var onDelete = new DelegateCommand<AuthLoginPasswordModel>(OnDeleteProfile);
|
||||
var onSelect = new DelegateCommand<AuthLoginPasswordModel>(AuthByAlp);
|
||||
|
||||
|
||||
var alpm = new AuthLoginPasswordModel(
|
||||
authLoginPassword.Login,
|
||||
authLoginPassword.Login,
|
||||
authLoginPassword.Password,
|
||||
authLoginPassword.AuthServer,
|
||||
onSelect,
|
||||
authLoginPassword.AuthServer,
|
||||
onSelect,
|
||||
onDelete);
|
||||
|
||||
onDelete.TRef.Value = alpm;
|
||||
onSelect.TRef.Value = alpm;
|
||||
|
||||
|
||||
Accounts.Add(alpm);
|
||||
}
|
||||
|
||||
private void ReadAuthConfig()
|
||||
{
|
||||
foreach (var profile in
|
||||
_configurationService.GetConfigValue(CurrentConVar.AuthProfiles)!)
|
||||
{
|
||||
foreach (var profile in
|
||||
ConfigurationService.GetConfigValue(CurrentConVar.AuthProfiles)!)
|
||||
AddAccount(profile);
|
||||
}
|
||||
|
||||
if (Accounts.Count == 0)
|
||||
{
|
||||
UpdateAuthMenu();
|
||||
}
|
||||
if (Accounts.Count == 0) UpdateAuthMenu();
|
||||
|
||||
var currProfile = _configurationService.GetConfigValue(CurrentConVar.AuthCurrent);
|
||||
var currProfile = ConfigurationService.GetConfigValue(CurrentConVar.AuthCurrent);
|
||||
|
||||
if (currProfile != null)
|
||||
{
|
||||
CurrentAlp = currProfile;
|
||||
DoAuth();
|
||||
}
|
||||
|
||||
|
||||
AuthUrls.Clear();
|
||||
var authUrls = _configurationService.GetConfigValue(CurrentConVar.AuthServers)!;
|
||||
foreach (var url in authUrls)
|
||||
{
|
||||
AuthUrls.Add(url);
|
||||
}
|
||||
var authUrls = ConfigurationService.GetConfigValue(CurrentConVar.AuthServers)!;
|
||||
foreach (var url in authUrls) AuthUrls.Add(url);
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
@@ -172,7 +156,7 @@ public partial class AccountInfoViewModel : ViewModelBase
|
||||
UpdateAuthMenu();
|
||||
DirtyProfile();
|
||||
}
|
||||
|
||||
|
||||
private void OnDeleteProfile(AuthLoginPasswordModel account)
|
||||
{
|
||||
Accounts.Remove(account);
|
||||
@@ -196,15 +180,15 @@ public partial class AccountInfoViewModel : ViewModelBase
|
||||
|
||||
private void DirtyProfile()
|
||||
{
|
||||
_configurationService.SetConfigValue(CurrentConVar.AuthProfiles,
|
||||
Accounts.Select(a => (AuthLoginPassword) a).ToArray());
|
||||
}
|
||||
|
||||
public string AuthItemSelect
|
||||
{
|
||||
set => CurrentAuthServer = value;
|
||||
ConfigurationService.SetConfigValue(CurrentConVar.AuthProfiles,
|
||||
Accounts.Select(a => (AuthLoginPassword)a).ToArray());
|
||||
}
|
||||
}
|
||||
|
||||
public record AuthLoginPasswordModel(string Login, string Password, string AuthServer, ICommand OnSelect = default!, ICommand OnDelete = default!)
|
||||
public record AuthLoginPasswordModel(
|
||||
string Login,
|
||||
string Password,
|
||||
string AuthServer,
|
||||
ICommand OnSelect = default!,
|
||||
ICommand OnDelete = default!)
|
||||
: AuthLoginPassword(Login, Password, AuthServer);
|
||||
@@ -11,35 +11,37 @@ using Avalonia.Media;
|
||||
using Avalonia.Media.Imaging;
|
||||
using Avalonia.Platform;
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Nebula.Launcher.ViewHelper;
|
||||
using Nebula.Launcher.Services;
|
||||
using Nebula.Launcher.ViewModels.Popup;
|
||||
using Nebula.Launcher.Views.Pages;
|
||||
using Nebula.Shared;
|
||||
using Nebula.Shared.Models;
|
||||
using Nebula.Shared.Services;
|
||||
using Nebula.Shared.Utils;
|
||||
|
||||
namespace Nebula.Launcher.ViewModels;
|
||||
namespace Nebula.Launcher.ViewModels.Pages;
|
||||
|
||||
[ViewModelRegister(typeof(ContentBrowserView))]
|
||||
[ConstructGenerator]
|
||||
public sealed partial class ContentBrowserViewModel : ViewModelBase
|
||||
{
|
||||
private readonly IServiceProvider _provider;
|
||||
private readonly ContentService _contentService;
|
||||
private readonly CancellationService _cancellationService;
|
||||
private readonly FileService _fileService;
|
||||
private readonly DebugService _debugService;
|
||||
private readonly PopupMessageService _popupService;
|
||||
public ObservableCollection<ContentEntry> Entries { get; } = new();
|
||||
private readonly List<ContentEntry> _root = new();
|
||||
|
||||
private List<string> _history = new();
|
||||
|
||||
private readonly List<string> _history = new();
|
||||
|
||||
[ObservableProperty] private string _message = "";
|
||||
[ObservableProperty] private string _searchText = "";
|
||||
[ObservableProperty] private string _serverText = "";
|
||||
|
||||
private ContentEntry? _selectedEntry;
|
||||
[ObservableProperty] private string _serverText = "";
|
||||
[GenerateProperty] private ContentService ContentService { get; } = default!;
|
||||
[GenerateProperty] private CancellationService CancellationService { get; } = default!;
|
||||
[GenerateProperty] private FileService FileService { get; } = default!;
|
||||
[GenerateProperty] private DebugService DebugService { get; } = default!;
|
||||
[GenerateProperty] private PopupMessageService PopupService { get; } = default!;
|
||||
[GenerateProperty] private HubService HubService { get; } = default!;
|
||||
[GenerateProperty] private ViewHelperService ViewHelperService { get; } = default!;
|
||||
|
||||
public ObservableCollection<ContentEntry> Entries { get; } = new();
|
||||
|
||||
public ContentEntry? SelectedEntry
|
||||
{
|
||||
@@ -48,94 +50,73 @@ public sealed partial class ContentBrowserViewModel : ViewModelBase
|
||||
{
|
||||
if (value is { Item: not null })
|
||||
{
|
||||
if (_fileService.ContentFileApi.TryOpen(value.Item.Value.Hash, out var stream))
|
||||
if (FileService.ContentFileApi.TryOpen(value.Item.Value.Hash, out var stream))
|
||||
{
|
||||
var ext = Path.GetExtension(value.Item.Value.Path);
|
||||
|
||||
var myTempFile = Path.Combine(Path.GetTempPath(), "tempie"+ ext);
|
||||
|
||||
using(var sw = new FileStream(myTempFile, FileMode.Create, FileAccess.Write, FileShare.None))
|
||||
|
||||
var myTempFile = Path.Combine(Path.GetTempPath(), "tempie" + ext);
|
||||
|
||||
using (var sw = new FileStream(myTempFile, FileMode.Create, FileAccess.Write, FileShare.None))
|
||||
{
|
||||
stream.CopyTo(sw);
|
||||
}
|
||||
|
||||
stream.Dispose();
|
||||
|
||||
|
||||
var startInfo = new ProcessStartInfo(myTempFile)
|
||||
{
|
||||
UseShellExecute = true
|
||||
UseShellExecute = true
|
||||
};
|
||||
|
||||
Process.Start(startInfo);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
Entries.Clear();
|
||||
_selectedEntry = value;
|
||||
|
||||
if (value == null) return;
|
||||
|
||||
foreach (var (_, entryCh) in value.Childs)
|
||||
{
|
||||
Entries.Add(entryCh);
|
||||
}
|
||||
|
||||
foreach (var (_, entryCh) in value.Childs) Entries.Add(entryCh);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public ContentBrowserViewModel() : base()
|
||||
protected override void InitialiseInDesignMode()
|
||||
{
|
||||
var a = new ContentEntry(this, "A:","A", "");
|
||||
var b = new ContentEntry(this, "B","B", "");
|
||||
var a = new ContentEntry(this, "A:", "A", "");
|
||||
var b = new ContentEntry(this, "B", "B", "");
|
||||
a.TryAddChild(b);
|
||||
Entries.Add(a);
|
||||
Entries.Add(a);
|
||||
}
|
||||
|
||||
public ContentBrowserViewModel(IServiceProvider provider, ContentService contentService, CancellationService cancellationService,
|
||||
FileService fileService, HubService hubService, DebugService debugService, PopupMessageService popupService) : base(provider)
|
||||
protected override void Initialise()
|
||||
{
|
||||
_provider = provider;
|
||||
_contentService = contentService;
|
||||
_cancellationService = cancellationService;
|
||||
_fileService = fileService;
|
||||
_debugService = debugService;
|
||||
_popupService = popupService;
|
||||
|
||||
FillRoot(hubService.ServerList);
|
||||
FillRoot(HubService.ServerList);
|
||||
|
||||
hubService.HubServerChangedEventArgs += HubServerChangedEventArgs;
|
||||
hubService.HubServerLoaded += GoHome;
|
||||
|
||||
if (!hubService.IsUpdating)
|
||||
{
|
||||
GoHome();
|
||||
}
|
||||
HubService.HubServerChangedEventArgs += HubServerChangedEventArgs;
|
||||
HubService.HubServerLoaded += GoHome;
|
||||
|
||||
if (!HubService.IsUpdating) GoHome();
|
||||
}
|
||||
|
||||
private void GoHome()
|
||||
{
|
||||
SelectedEntry = null;
|
||||
foreach (var entry in _root)
|
||||
{
|
||||
Entries.Add(entry);
|
||||
}
|
||||
foreach (var entry in _root) Entries.Add(entry);
|
||||
}
|
||||
|
||||
private void HubServerChangedEventArgs(HubServerChangedEventArgs obj)
|
||||
{
|
||||
if(obj.Action == HubServerChangeAction.Clear) _root.Clear();
|
||||
if (obj.Action == HubServerChangeAction.Add)
|
||||
{
|
||||
FillRoot(obj.Items);
|
||||
};
|
||||
if (obj.Action == HubServerChangeAction.Clear) _root.Clear();
|
||||
if (obj.Action == HubServerChangeAction.Add) FillRoot(obj.Items);
|
||||
}
|
||||
|
||||
private void FillRoot(IEnumerable<ServerHubInfo> infos)
|
||||
{
|
||||
foreach (var info in infos)
|
||||
{
|
||||
_root.Add(new ContentEntry(this, info.StatusData.Name,info.Address,info.Address));
|
||||
}
|
||||
foreach (var info in infos) _root.Add(new ContentEntry(this, info.StatusData.Name, info.Address, info.Address));
|
||||
}
|
||||
|
||||
public async void Go(ContentPath path, bool appendHistory = true)
|
||||
@@ -145,42 +126,34 @@ public sealed partial class ContentBrowserViewModel : ViewModelBase
|
||||
ServerText = path.Pathes[0];
|
||||
path = new ContentPath("");
|
||||
}
|
||||
|
||||
|
||||
if (string.IsNullOrEmpty(ServerText))
|
||||
{
|
||||
SearchText = "";
|
||||
GoHome();
|
||||
return;
|
||||
}
|
||||
|
||||
if (ServerText != SelectedEntry?.ServerName)
|
||||
{
|
||||
SelectedEntry = await CreateEntry(ServerText);
|
||||
}
|
||||
|
||||
_debugService.Debug("Going to:" + path.Path);
|
||||
|
||||
|
||||
if (ServerText != SelectedEntry?.ServerName) SelectedEntry = await CreateEntry(ServerText);
|
||||
|
||||
DebugService.Debug("Going to:" + path.Path);
|
||||
|
||||
var oriPath = path.Clone();
|
||||
try
|
||||
{
|
||||
if (SelectedEntry == null || !SelectedEntry.GetRoot().TryGetEntry(path, out var centry))
|
||||
{
|
||||
throw new Exception("Not found! " + oriPath.Path);
|
||||
}
|
||||
|
||||
if (appendHistory)
|
||||
{
|
||||
AppendHistory(SearchText);
|
||||
}
|
||||
|
||||
if (appendHistory) AppendHistory(SearchText);
|
||||
SearchText = oriPath.Path;
|
||||
|
||||
|
||||
SelectedEntry = centry;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Console.WriteLine(e);
|
||||
SearchText = oriPath.Path;
|
||||
_popupService.Popup(e);
|
||||
PopupService.Popup(e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -189,7 +162,7 @@ public sealed partial class ContentBrowserViewModel : ViewModelBase
|
||||
{
|
||||
Go(new ContentPath(GetHistory()), false);
|
||||
}
|
||||
|
||||
|
||||
public void OnGoEnter()
|
||||
{
|
||||
Go(new ContentPath(SearchText));
|
||||
@@ -198,21 +171,21 @@ public sealed partial class ContentBrowserViewModel : ViewModelBase
|
||||
private async Task<ContentEntry> CreateEntry(string serverUrl)
|
||||
{
|
||||
var rurl = serverUrl.ToRobustUrl();
|
||||
var info = await _contentService.GetBuildInfo(rurl, _cancellationService.Token);
|
||||
var loading = _provider.GetService<LoadingContextViewModel>()!;
|
||||
var info = await ContentService.GetBuildInfo(rurl, CancellationService.Token);
|
||||
var loading = ViewHelperService.GetViewModel<LoadingContextViewModel>();
|
||||
loading.LoadingName = "Loading entry";
|
||||
_popupService.Popup(loading);
|
||||
var items = await _contentService.EnsureItems(info.RobustManifestInfo, loading,
|
||||
_cancellationService.Token);
|
||||
PopupService.Popup(loading);
|
||||
var items = await ContentService.EnsureItems(info.RobustManifestInfo, loading,
|
||||
CancellationService.Token);
|
||||
|
||||
var rootEntry = new ContentEntry(this,"","", serverUrl);
|
||||
var rootEntry = new ContentEntry(this, "", "", serverUrl);
|
||||
|
||||
foreach (var item in items)
|
||||
{
|
||||
var path = new ContentPath(item.Path);
|
||||
rootEntry.CreateItem(path, item);
|
||||
}
|
||||
|
||||
|
||||
loading.Dispose();
|
||||
|
||||
return rootEntry;
|
||||
@@ -220,7 +193,7 @@ public sealed partial class ContentBrowserViewModel : ViewModelBase
|
||||
|
||||
private void AppendHistory(string str)
|
||||
{
|
||||
if(_history.Count >= 10) _history.RemoveAt(9);
|
||||
if (_history.Count >= 10) _history.RemoveAt(9);
|
||||
_history.Insert(0, str);
|
||||
}
|
||||
|
||||
@@ -235,41 +208,13 @@ public sealed partial class ContentBrowserViewModel : ViewModelBase
|
||||
|
||||
public class ContentEntry
|
||||
{
|
||||
private readonly ContentBrowserViewModel _viewModel;
|
||||
|
||||
public static IImage DirImage = new Bitmap(AssetLoader.Open(new Uri("avares://Nebula.Launcher/Assets/dir.png")));
|
||||
public static IImage IconImage = new Bitmap(AssetLoader.Open(new Uri("avares://Nebula.Launcher/Assets/file.png")));
|
||||
|
||||
public RobustManifestItem? Item;
|
||||
public bool IsDirectory => Item == null;
|
||||
|
||||
public string Name { get; private set; }
|
||||
public string PathName { get; private set; }
|
||||
public string ServerName { get; private set; }
|
||||
public IImage IconPath { get; set; } = DirImage;
|
||||
|
||||
public ContentEntry? Parent { get; private set; }
|
||||
public bool IsRoot => Parent == null;
|
||||
|
||||
private readonly Dictionary<string, ContentEntry> _childs = new();
|
||||
private readonly ContentBrowserViewModel _viewModel;
|
||||
|
||||
public IReadOnlyDictionary<string, ContentEntry> Childs => _childs.ToFrozenDictionary();
|
||||
|
||||
public bool TryGetChild(string name,[NotNullWhen(true)] out ContentEntry? child)
|
||||
{
|
||||
return _childs.TryGetValue(name, out child);
|
||||
}
|
||||
|
||||
public bool TryAddChild(ContentEntry contentEntry)
|
||||
{
|
||||
if(_childs.TryAdd(contentEntry.PathName, contentEntry))
|
||||
{
|
||||
contentEntry.Parent = this;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
public RobustManifestItem? Item;
|
||||
|
||||
internal ContentEntry(ContentBrowserViewModel viewModel, string name, string pathName, string serverName)
|
||||
{
|
||||
@@ -279,6 +224,34 @@ public class ContentEntry
|
||||
_viewModel = viewModel;
|
||||
}
|
||||
|
||||
public bool IsDirectory => Item == null;
|
||||
|
||||
public string Name { get; private set; }
|
||||
public string PathName { get; }
|
||||
public string ServerName { get; }
|
||||
public IImage IconPath { get; set; } = DirImage;
|
||||
|
||||
public ContentEntry? Parent { get; private set; }
|
||||
public bool IsRoot => Parent == null;
|
||||
|
||||
public IReadOnlyDictionary<string, ContentEntry> Childs => _childs.ToFrozenDictionary();
|
||||
|
||||
public bool TryGetChild(string name, [NotNullWhen(true)] out ContentEntry? child)
|
||||
{
|
||||
return _childs.TryGetValue(name, out child);
|
||||
}
|
||||
|
||||
public bool TryAddChild(ContentEntry contentEntry)
|
||||
{
|
||||
if (_childs.TryAdd(contentEntry.PathName, contentEntry))
|
||||
{
|
||||
contentEntry.Parent = this;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public ContentPath GetPath()
|
||||
{
|
||||
if (Parent != null)
|
||||
@@ -287,6 +260,7 @@ public class ContentEntry
|
||||
path.Pathes.Add(PathName);
|
||||
return path;
|
||||
}
|
||||
|
||||
return new ContentPath([PathName]);
|
||||
}
|
||||
|
||||
@@ -295,8 +269,8 @@ public class ContentEntry
|
||||
if (rootPath.Pathes.Count == 0) return this;
|
||||
|
||||
var fName = rootPath.GetNext();
|
||||
|
||||
if(!TryGetChild(fName, out var child))
|
||||
|
||||
if (!TryGetChild(fName, out var child))
|
||||
{
|
||||
child = new ContentEntry(_viewModel, fName, fName, ServerName);
|
||||
TryAddChild(child);
|
||||
@@ -321,7 +295,7 @@ public class ContentEntry
|
||||
{
|
||||
Item = item
|
||||
};
|
||||
|
||||
|
||||
dirEntry.TryAddChild(entry);
|
||||
entry.IconPath = IconImage;
|
||||
return entry;
|
||||
@@ -330,7 +304,7 @@ public class ContentEntry
|
||||
public bool TryGetEntry(ContentPath path, out ContentEntry? entry)
|
||||
{
|
||||
entry = null;
|
||||
|
||||
|
||||
if (path.Pathes.Count == 0)
|
||||
{
|
||||
entry = this;
|
||||
@@ -338,11 +312,8 @@ public class ContentEntry
|
||||
}
|
||||
|
||||
var fName = path.GetNext();
|
||||
|
||||
if(!TryGetChild(fName, out var child))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!TryGetChild(fName, out var child)) return false;
|
||||
|
||||
return child.TryGetEntry(path, out entry);
|
||||
}
|
||||
@@ -353,14 +324,13 @@ public class ContentEntry
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public struct ContentPath
|
||||
{
|
||||
public List<string> Pathes { get; private set; }
|
||||
public List<string> Pathes { get; }
|
||||
|
||||
public ContentPath(List<string> pathes)
|
||||
{
|
||||
Pathes = pathes ?? new List<string>();
|
||||
Pathes = pathes;
|
||||
}
|
||||
|
||||
public ContentPath(string path)
|
||||
@@ -1,13 +1,17 @@
|
||||
using System;
|
||||
using System.Collections.ObjectModel;
|
||||
using Nebula.Shared.Models;
|
||||
|
||||
namespace Nebula.Launcher.ViewModels;
|
||||
namespace Nebula.Launcher.ViewModels.Pages;
|
||||
|
||||
public class FavoriteServerListViewModel : ViewModelBase
|
||||
{
|
||||
public FavoriteServerListViewModel() : base(){}
|
||||
public FavoriteServerListViewModel(IServiceProvider provider) : base(provider){}
|
||||
|
||||
public ObservableCollection<ServerHubInfo> Servers = new();
|
||||
|
||||
protected override void Initialise()
|
||||
{
|
||||
}
|
||||
|
||||
protected override void InitialiseInDesignMode()
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -4,50 +4,42 @@ using System.Collections.ObjectModel;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using Nebula.Launcher.ViewHelper;
|
||||
using Nebula.Launcher.Services;
|
||||
using Nebula.Launcher.Views.Pages;
|
||||
using Nebula.Shared.Models;
|
||||
using Nebula.Shared.Services;
|
||||
|
||||
namespace Nebula.Launcher.ViewModels;
|
||||
namespace Nebula.Launcher.ViewModels.Pages;
|
||||
|
||||
[ViewModelRegister(typeof(ServerListView))]
|
||||
[ConstructGenerator]
|
||||
public partial class ServerListViewModel : ViewModelBase
|
||||
{
|
||||
private readonly IServiceProvider _serviceProvider;
|
||||
private readonly HubService _hubService;
|
||||
public ObservableCollection<ServerEntryModelView> ServerInfos { get; } = new();
|
||||
[ObservableProperty] private string _searchText = string.Empty;
|
||||
|
||||
public Action? OnSearchChange;
|
||||
|
||||
[ObservableProperty] private string _searchText;
|
||||
[GenerateProperty] private HubService HubService { get; } = default!;
|
||||
[GenerateProperty] private ViewHelperService ViewHelperService { get; } = default!;
|
||||
public ObservableCollection<ServerEntryModelView> ServerInfos { get; } = new();
|
||||
private List<ServerHubInfo> UnsortedServers { get; } = new();
|
||||
|
||||
|
||||
//Design think
|
||||
public ServerListViewModel()
|
||||
protected override void InitialiseInDesignMode()
|
||||
{
|
||||
ServerInfos.Add(CreateServerView(new ServerHubInfo("ss14://localhost",new ServerStatus("Nebula","TestCraft", ["16+","RU"], "super", 12,55,1,false,DateTime.Now, 20),[])));
|
||||
ServerInfos.Add(CreateServerView(new ServerHubInfo("ss14://localhost",
|
||||
new ServerStatus("Nebula", "TestCraft", ["16+", "RU"], "super", 12, 55, 1, false, DateTime.Now, 20), [])));
|
||||
}
|
||||
|
||||
|
||||
//real think
|
||||
public ServerListViewModel(IServiceProvider serviceProvider, HubService hubService) : base(serviceProvider)
|
||||
protected override void Initialise()
|
||||
{
|
||||
_serviceProvider = serviceProvider;
|
||||
_hubService = hubService;
|
||||
|
||||
foreach (var info in _hubService.ServerList)
|
||||
{
|
||||
UnsortedServers.Add(info);
|
||||
}
|
||||
|
||||
hubService.HubServerChangedEventArgs += HubServerChangedEventArgs;
|
||||
hubService.HubServerLoaded += HubServerLoaded;
|
||||
foreach (var info in HubService.ServerList) UnsortedServers.Add(info);
|
||||
|
||||
HubService.HubServerChangedEventArgs += HubServerChangedEventArgs;
|
||||
HubService.HubServerLoaded += HubServerLoaded;
|
||||
OnSearchChange += OnChangeSearch;
|
||||
|
||||
if (!hubService.IsUpdating)
|
||||
{
|
||||
SortServers();
|
||||
}
|
||||
if (!HubService.IsUpdating) SortServers();
|
||||
}
|
||||
|
||||
private void HubServerLoaded()
|
||||
@@ -63,23 +55,12 @@ public partial class ServerListViewModel : ViewModelBase
|
||||
private void HubServerChangedEventArgs(HubServerChangedEventArgs obj)
|
||||
{
|
||||
if (obj.Action == HubServerChangeAction.Add)
|
||||
{
|
||||
foreach (var info in obj.Items)
|
||||
{
|
||||
UnsortedServers.Add(info);
|
||||
}
|
||||
}
|
||||
if(obj.Action == HubServerChangeAction.Remove)
|
||||
{
|
||||
if (obj.Action == HubServerChangeAction.Remove)
|
||||
foreach (var info in obj.Items)
|
||||
{
|
||||
UnsortedServers.Remove(info);
|
||||
}
|
||||
}
|
||||
if(obj.Action == HubServerChangeAction.Clear)
|
||||
{
|
||||
UnsortedServers.Clear();
|
||||
}
|
||||
if (obj.Action == HubServerChangeAction.Clear) UnsortedServers.Clear();
|
||||
}
|
||||
|
||||
private void SortServers()
|
||||
@@ -88,10 +69,7 @@ public partial class ServerListViewModel : ViewModelBase
|
||||
{
|
||||
ServerInfos.Clear();
|
||||
UnsortedServers.Sort(new ServerComparer());
|
||||
foreach (var server in UnsortedServers.Where(CheckServerThink))
|
||||
{
|
||||
ServerInfos.Add(CreateServerView(server));
|
||||
}
|
||||
foreach (var server in UnsortedServers.Where(CheckServerThink)) ServerInfos.Add(CreateServerView(server));
|
||||
});
|
||||
}
|
||||
|
||||
@@ -103,19 +81,18 @@ public partial class ServerListViewModel : ViewModelBase
|
||||
|
||||
private ServerEntryModelView CreateServerView(ServerHubInfo serverHubInfo)
|
||||
{
|
||||
var svn = GetViewModel<ServerEntryModelView>();
|
||||
var svn = ViewHelperService.GetViewModel<ServerEntryModelView>();
|
||||
svn.ServerHubInfo = serverHubInfo;
|
||||
return svn;
|
||||
}
|
||||
|
||||
public void FilterRequired()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public void UpdateRequired()
|
||||
{
|
||||
Task.Run(_hubService.UpdateHub);
|
||||
Task.Run(HubService.UpdateHub);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -131,6 +108,5 @@ public class ServerComparer : IComparer<ServerHubInfo>
|
||||
return -1;
|
||||
|
||||
return y.StatusData.Players.CompareTo(x.StatusData.Players);
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,31 +1,34 @@
|
||||
using System;
|
||||
using System.Collections.ObjectModel;
|
||||
using Nebula.Launcher.ViewHelper;
|
||||
using Nebula.Launcher.Views.Popup;
|
||||
using Nebula.Shared.Services;
|
||||
|
||||
namespace Nebula.Launcher.ViewModels;
|
||||
namespace Nebula.Launcher.ViewModels.Popup;
|
||||
|
||||
[ViewModelRegister(typeof(ExceptionView), false)]
|
||||
public class ExceptionViewModel : PopupViewModelBase
|
||||
[ConstructGenerator]
|
||||
public sealed partial class ExceptionViewModel : PopupViewModelBase
|
||||
{
|
||||
public ExceptionViewModel() : base()
|
||||
{
|
||||
var e = new Exception("TEST");
|
||||
|
||||
AppendError(e);
|
||||
}
|
||||
|
||||
public ExceptionViewModel(IServiceProvider serviceProvider) : base(serviceProvider){}
|
||||
|
||||
[GenerateProperty] public override PopupMessageService PopupMessageService { get; }
|
||||
public override string Title => "Oopsie! Some shit is happened now!";
|
||||
public override bool IsClosable => true;
|
||||
|
||||
public ObservableCollection<Exception> Errors { get; } = new();
|
||||
|
||||
protected override void Initialise()
|
||||
{
|
||||
}
|
||||
|
||||
protected override void InitialiseInDesignMode()
|
||||
{
|
||||
var e = new Exception("TEST");
|
||||
AppendError(e);
|
||||
}
|
||||
|
||||
public void AppendError(Exception exception)
|
||||
{
|
||||
Errors.Add(exception);
|
||||
if(exception.InnerException != null)
|
||||
if (exception.InnerException != null)
|
||||
AppendError(exception.InnerException);
|
||||
}
|
||||
}
|
||||
}
|
||||
25
Nebula.Launcher/ViewModels/Popup/InfoPopupViewModel.cs
Normal file
25
Nebula.Launcher/ViewModels/Popup/InfoPopupViewModel.cs
Normal file
@@ -0,0 +1,25 @@
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using Nebula.Launcher.Views.Popup;
|
||||
using Nebula.Shared.Services;
|
||||
|
||||
namespace Nebula.Launcher.ViewModels.Popup;
|
||||
|
||||
[ViewModelRegister(typeof(InfoPopupView), false)]
|
||||
[ConstructGenerator]
|
||||
public partial class InfoPopupViewModel : PopupViewModelBase
|
||||
{
|
||||
[GenerateProperty] public override PopupMessageService PopupMessageService { get; }
|
||||
|
||||
[ObservableProperty] private string _infoText = "Test";
|
||||
|
||||
public override string Title => "Info";
|
||||
public override bool IsClosable => true;
|
||||
|
||||
protected override void Initialise()
|
||||
{
|
||||
}
|
||||
|
||||
protected override void InitialiseInDesignMode()
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -1,27 +1,25 @@
|
||||
using System;
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using Nebula.Launcher.ViewHelper;
|
||||
using Nebula.Launcher.Views.Popup;
|
||||
using Nebula.Shared.Models;
|
||||
using Nebula.Shared.Services;
|
||||
|
||||
namespace Nebula.Launcher.ViewModels;
|
||||
namespace Nebula.Launcher.ViewModels.Popup;
|
||||
|
||||
[ViewModelRegister(typeof(LoadingContextView), false)]
|
||||
[ConstructGenerator]
|
||||
public sealed partial class LoadingContextViewModel : PopupViewModelBase, ILoadingHandler
|
||||
{
|
||||
public LoadingContextViewModel() :base(){}
|
||||
public LoadingContextViewModel(IServiceProvider provider) : base(provider){}
|
||||
[GenerateProperty] public override PopupMessageService PopupMessageService { get; }
|
||||
|
||||
[ObservableProperty] private int _currJobs;
|
||||
|
||||
[ObservableProperty] private int _resolvedJobs;
|
||||
|
||||
public string LoadingName { get; set; } = "Loading...";
|
||||
public override bool IsClosable => false;
|
||||
|
||||
public override string Title => LoadingName;
|
||||
|
||||
[ObservableProperty]
|
||||
private int _currJobs;
|
||||
[ObservableProperty]
|
||||
private int _resolvedJobs;
|
||||
|
||||
|
||||
public void SetJobsCount(int count)
|
||||
{
|
||||
CurrJobs = count;
|
||||
@@ -35,11 +33,18 @@ public sealed partial class LoadingContextViewModel : PopupViewModelBase, ILoadi
|
||||
public void SetResolvedJobsCount(int count)
|
||||
{
|
||||
ResolvedJobs = count;
|
||||
|
||||
}
|
||||
|
||||
public int GetResolvedJobsCount()
|
||||
{
|
||||
return ResolvedJobs;
|
||||
}
|
||||
|
||||
protected override void Initialise()
|
||||
{
|
||||
}
|
||||
|
||||
protected override void InitialiseInDesignMode()
|
||||
{
|
||||
}
|
||||
}
|
||||
38
Nebula.Launcher/ViewModels/Popup/LogPopupModelView.cs
Normal file
38
Nebula.Launcher/ViewModels/Popup/LogPopupModelView.cs
Normal file
@@ -0,0 +1,38 @@
|
||||
using System.Collections.ObjectModel;
|
||||
using Nebula.Launcher.Views.Popup;
|
||||
using Nebula.Shared.Services;
|
||||
|
||||
namespace Nebula.Launcher.ViewModels.Popup;
|
||||
|
||||
[ViewModelRegister(typeof(LogPopupView), false)]
|
||||
[ConstructGenerator]
|
||||
public sealed partial class LogPopupModelView : PopupViewModelBase
|
||||
{
|
||||
[GenerateProperty] public override PopupMessageService PopupMessageService { get; }
|
||||
public override string Title => "LOG";
|
||||
public override bool IsClosable => true;
|
||||
|
||||
public ObservableCollection<LogInfo> Logs { get; } = new();
|
||||
|
||||
protected override void InitialiseInDesignMode()
|
||||
{
|
||||
Logs.Add(new LogInfo
|
||||
{
|
||||
Category = "DEBG", Message = "MEOW MEOW TEST"
|
||||
});
|
||||
|
||||
Logs.Add(new LogInfo
|
||||
{
|
||||
Category = "ERRO", Message = "MEOW MEOW TEST 11\naaaaa"
|
||||
});
|
||||
}
|
||||
|
||||
protected override void Initialise()
|
||||
{
|
||||
}
|
||||
|
||||
public void Append(string str)
|
||||
{
|
||||
Logs.Add(LogInfo.FromString(str));
|
||||
}
|
||||
}
|
||||
17
Nebula.Launcher/ViewModels/Popup/PopupViewModelBase.cs
Normal file
17
Nebula.Launcher/ViewModels/Popup/PopupViewModelBase.cs
Normal file
@@ -0,0 +1,17 @@
|
||||
using System;
|
||||
using Nebula.Shared.Services;
|
||||
|
||||
namespace Nebula.Launcher.ViewModels.Popup;
|
||||
|
||||
public abstract class PopupViewModelBase : ViewModelBase, IDisposable
|
||||
{
|
||||
public abstract PopupMessageService PopupMessageService { get; }
|
||||
|
||||
public abstract string Title { get; }
|
||||
public abstract bool IsClosable { get; }
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
PopupMessageService.ClosePopup(this);
|
||||
}
|
||||
}
|
||||
@@ -1,26 +0,0 @@
|
||||
using System;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Nebula.Shared.Services;
|
||||
|
||||
namespace Nebula.Launcher.ViewModels;
|
||||
|
||||
public abstract class PopupViewModelBase : ViewModelBase, IDisposable
|
||||
{
|
||||
private readonly IServiceProvider _serviceProvider;
|
||||
public abstract string Title { get; }
|
||||
public abstract bool IsClosable { get; }
|
||||
|
||||
public PopupViewModelBase()
|
||||
{
|
||||
}
|
||||
|
||||
public PopupViewModelBase(IServiceProvider serviceProvider) : base(serviceProvider)
|
||||
{
|
||||
_serviceProvider = serviceProvider;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_serviceProvider.GetService<PopupMessageService>()?.ClosePopup(this);
|
||||
}
|
||||
}
|
||||
@@ -1,37 +1,40 @@
|
||||
using System;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading.Tasks;
|
||||
using Avalonia.Media;
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using Nebula.Launcher.ViewHelper;
|
||||
using Nebula.Launcher.Views.Popup;
|
||||
using Nebula.Launcher.Services;
|
||||
using Nebula.Launcher.ViewModels.Popup;
|
||||
using Nebula.Shared.Models;
|
||||
using Nebula.Shared.Services;
|
||||
|
||||
namespace Nebula.Launcher.ViewModels;
|
||||
|
||||
[ViewModelRegister(isSingleton:false)]
|
||||
[ViewModelRegister(isSingleton: false)]
|
||||
[ConstructGenerator]
|
||||
public partial class ServerEntryModelView : ViewModelBase
|
||||
{
|
||||
private readonly AuthService _authService = default!;
|
||||
private readonly ContentService _contentService = default!;
|
||||
private readonly CancellationService _cancellationService = default!;
|
||||
private readonly DebugService _debugService = default!;
|
||||
private readonly RunnerService _runnerService = default!;
|
||||
private readonly PopupMessageService _popupMessageService;
|
||||
private Process? _p;
|
||||
|
||||
|
||||
public LogPopupModelView CurrLog;
|
||||
[GenerateProperty] private AuthService AuthService { get; } = default!;
|
||||
[GenerateProperty] private ContentService ContentService { get; } = default!;
|
||||
[GenerateProperty] private CancellationService CancellationService { get; } = default!;
|
||||
[GenerateProperty] private DebugService DebugService { get; } = default!;
|
||||
[GenerateProperty] private RunnerService RunnerService { get; } = default!;
|
||||
[GenerateProperty] private PopupMessageService PopupMessageService { get; } = default!;
|
||||
[GenerateProperty] private ViewHelperService ViewHelperService { get; } = default!;
|
||||
|
||||
public bool RunVisible => Process == null;
|
||||
|
||||
public ServerHubInfo ServerHubInfo { get; set; } = default!;
|
||||
|
||||
|
||||
private Process? _p;
|
||||
private Process? Process
|
||||
{
|
||||
get { return _p; }
|
||||
get => _p;
|
||||
set
|
||||
{
|
||||
_p = value;
|
||||
@@ -39,32 +42,14 @@ public partial class ServerEntryModelView : ViewModelBase
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
public LogPopupModelView CurrLog;
|
||||
|
||||
public ServerEntryModelView() : base()
|
||||
protected override void InitialiseInDesignMode()
|
||||
{
|
||||
CurrLog = GetViewModel<LogPopupModelView>();
|
||||
CurrLog = ViewHelperService.GetViewModel<LogPopupModelView>();
|
||||
}
|
||||
|
||||
public ServerEntryModelView(
|
||||
IServiceProvider serviceProvider,
|
||||
AuthService authService,
|
||||
ContentService contentService,
|
||||
CancellationService cancellationService,
|
||||
DebugService debugService,
|
||||
RunnerService runnerService, PopupMessageService popupMessageService
|
||||
) : base(serviceProvider)
|
||||
protected override void Initialise()
|
||||
{
|
||||
_authService = authService;
|
||||
_contentService = contentService;
|
||||
_cancellationService = cancellationService;
|
||||
_debugService = debugService;
|
||||
_runnerService = runnerService;
|
||||
_popupMessageService = popupMessageService;
|
||||
|
||||
CurrLog = GetViewModel<LogPopupModelView>();
|
||||
CurrLog = ViewHelperService.GetViewModel<LogPopupModelView>();
|
||||
}
|
||||
|
||||
public void RunInstance()
|
||||
@@ -74,84 +59,77 @@ public partial class ServerEntryModelView : ViewModelBase
|
||||
|
||||
public async Task RunAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
var authProv = _authService.SelectedAuth;
|
||||
try
|
||||
{
|
||||
var authProv = AuthService.SelectedAuth;
|
||||
|
||||
var buildInfo =
|
||||
await _contentService.GetBuildInfo(new RobustUrl(ServerHubInfo.Address), _cancellationService.Token);
|
||||
|
||||
using (var loadingContext = GetViewModel<LoadingContextViewModel>())
|
||||
{
|
||||
loadingContext.LoadingName = "Loading instance...";
|
||||
((ILoadingHandler)loadingContext).AppendJob();
|
||||
|
||||
_popupMessageService.Popup(loadingContext);
|
||||
|
||||
|
||||
await _runnerService.PrepareRun(buildInfo, loadingContext, _cancellationService.Token);
|
||||
var buildInfo =
|
||||
await ContentService.GetBuildInfo(new RobustUrl(ServerHubInfo.Address), CancellationService.Token);
|
||||
|
||||
Process = Process.Start(new ProcessStartInfo()
|
||||
{
|
||||
FileName = "dotnet.exe",
|
||||
Arguments = "./Nebula.Runner.dll",
|
||||
Environment =
|
||||
{
|
||||
{ "ROBUST_AUTH_USERID", authProv?.UserId.ToString() },
|
||||
{ "ROBUST_AUTH_TOKEN", authProv?.Token.Token },
|
||||
{ "ROBUST_AUTH_SERVER", authProv?.AuthLoginPassword.AuthServer },
|
||||
{ "ROBUST_AUTH_PUBKEY", buildInfo.BuildInfo.Auth.PublicKey },
|
||||
{ "GAME_URL", ServerHubInfo.Address },
|
||||
{ "AUTH_LOGIN", authProv?.AuthLoginPassword.Login },
|
||||
},
|
||||
CreateNoWindow = true,
|
||||
UseShellExecute = false,
|
||||
RedirectStandardOutput = true,
|
||||
RedirectStandardError = true,
|
||||
StandardOutputEncoding = Encoding.UTF8
|
||||
});
|
||||
|
||||
((ILoadingHandler)loadingContext).AppendResolvedJob();
|
||||
}
|
||||
|
||||
if (Process is null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Process.EnableRaisingEvents = true;
|
||||
|
||||
Process.BeginOutputReadLine();
|
||||
Process.BeginErrorReadLine();
|
||||
using (var loadingContext = ViewHelperService.GetViewModel<LoadingContextViewModel>())
|
||||
{
|
||||
loadingContext.LoadingName = "Loading instance...";
|
||||
((ILoadingHandler)loadingContext).AppendJob();
|
||||
|
||||
Process.OutputDataReceived += OnOutputDataReceived;
|
||||
Process.ErrorDataReceived += OnErrorDataReceived;
|
||||
PopupMessageService.Popup(loadingContext);
|
||||
|
||||
Process.Exited += OnExited;
|
||||
}
|
||||
catch (TaskCanceledException e)
|
||||
{
|
||||
_popupMessageService.Popup("Task canceled");
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
_popupMessageService.Popup(e);
|
||||
}
|
||||
await RunnerService.PrepareRun(buildInfo, loadingContext, CancellationService.Token);
|
||||
|
||||
Process = Process.Start(new ProcessStartInfo
|
||||
{
|
||||
FileName = "dotnet.exe",
|
||||
Arguments = "./Nebula.Runner.dll",
|
||||
Environment =
|
||||
{
|
||||
{ "ROBUST_AUTH_USERID", authProv?.UserId.ToString() },
|
||||
{ "ROBUST_AUTH_TOKEN", authProv?.Token.Token },
|
||||
{ "ROBUST_AUTH_SERVER", authProv?.AuthLoginPassword.AuthServer },
|
||||
{ "ROBUST_AUTH_PUBKEY", buildInfo.BuildInfo.Auth.PublicKey },
|
||||
{ "GAME_URL", ServerHubInfo.Address },
|
||||
{ "AUTH_LOGIN", authProv?.AuthLoginPassword.Login }
|
||||
},
|
||||
CreateNoWindow = true,
|
||||
UseShellExecute = false,
|
||||
RedirectStandardOutput = true,
|
||||
RedirectStandardError = true,
|
||||
StandardOutputEncoding = Encoding.UTF8
|
||||
});
|
||||
|
||||
((ILoadingHandler)loadingContext).AppendResolvedJob();
|
||||
}
|
||||
|
||||
if (Process is null) return;
|
||||
|
||||
Process.EnableRaisingEvents = true;
|
||||
|
||||
Process.BeginOutputReadLine();
|
||||
Process.BeginErrorReadLine();
|
||||
|
||||
Process.OutputDataReceived += OnOutputDataReceived;
|
||||
Process.ErrorDataReceived += OnErrorDataReceived;
|
||||
|
||||
Process.Exited += OnExited;
|
||||
}
|
||||
catch (TaskCanceledException _)
|
||||
{
|
||||
PopupMessageService.Popup("Task canceled");
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
PopupMessageService.Popup(e);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnExited(object? sender, EventArgs e)
|
||||
{
|
||||
if (Process is null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (Process is null) return;
|
||||
|
||||
Process.OutputDataReceived -= OnOutputDataReceived;
|
||||
Process.ErrorDataReceived -= OnErrorDataReceived;
|
||||
Process.Exited -= OnExited;
|
||||
|
||||
_debugService.Log("PROCESS EXIT WITH CODE " + Process.ExitCode);
|
||||
|
||||
|
||||
DebugService.Log("PROCESS EXIT WITH CODE " + Process.ExitCode);
|
||||
|
||||
Process.Dispose();
|
||||
Process = null;
|
||||
}
|
||||
@@ -160,7 +138,7 @@ public partial class ServerEntryModelView : ViewModelBase
|
||||
{
|
||||
if (e.Data != null)
|
||||
{
|
||||
_debugService.Error(e.Data);
|
||||
DebugService.Error(e.Data);
|
||||
CurrLog.Append(e.Data);
|
||||
}
|
||||
}
|
||||
@@ -169,7 +147,7 @@ public partial class ServerEntryModelView : ViewModelBase
|
||||
{
|
||||
if (e.Data != null)
|
||||
{
|
||||
_debugService.Log(e.Data);
|
||||
DebugService.Log(e.Data);
|
||||
CurrLog.Append(e.Data);
|
||||
}
|
||||
}
|
||||
@@ -177,29 +155,24 @@ public partial class ServerEntryModelView : ViewModelBase
|
||||
|
||||
public void ReadLog()
|
||||
{
|
||||
_popupMessageService.Popup(CurrLog);
|
||||
PopupMessageService.Popup(CurrLog);
|
||||
}
|
||||
|
||||
public void StopInstance()
|
||||
{
|
||||
Process?.CloseMainWindow();
|
||||
}
|
||||
|
||||
static string FindDotnetPath()
|
||||
|
||||
private static string FindDotnetPath()
|
||||
{
|
||||
var pathEnv = Environment.GetEnvironmentVariable("PATH");
|
||||
var paths = pathEnv?.Split(System.IO.Path.PathSeparator);
|
||||
var paths = pathEnv?.Split(Path.PathSeparator);
|
||||
if (paths != null)
|
||||
{
|
||||
foreach (var path in paths)
|
||||
{
|
||||
var dotnetPath = System.IO.Path.Combine(path, "dotnet");
|
||||
if (System.IO.File.Exists(dotnetPath))
|
||||
{
|
||||
return dotnetPath;
|
||||
}
|
||||
var dotnetPath = Path.Combine(path, "dotnet");
|
||||
if (File.Exists(dotnetPath)) return dotnetPath;
|
||||
}
|
||||
}
|
||||
|
||||
throw new Exception("Dotnet not found!");
|
||||
}
|
||||
@@ -207,19 +180,16 @@ public partial class ServerEntryModelView : ViewModelBase
|
||||
|
||||
public sealed class LogInfo
|
||||
{
|
||||
public string Category { get; set; } = "LOG";
|
||||
public string Category { get; set; } = "LOG";
|
||||
public IBrush CategoryColor { get; set; } = Brush.Parse("#424242");
|
||||
public string Message { get; set; } = "";
|
||||
|
||||
public static LogInfo FromString(string input)
|
||||
{
|
||||
var matches = Regex.Matches(input, @"(\[(?<c>.*)\] (?<m>.*))|(?<m>.*)");
|
||||
string category = "All";
|
||||
var category = "All";
|
||||
|
||||
if( matches[0].Groups.TryGetValue("c", out var c))
|
||||
{
|
||||
category = c.Value;
|
||||
}
|
||||
if (matches[0].Groups.TryGetValue("c", out var c)) category = c.Value;
|
||||
|
||||
var color = Brush.Parse("#444444");
|
||||
|
||||
@@ -235,42 +205,11 @@ public sealed class LogInfo
|
||||
color = Brush.Parse("#0ab3c9");
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
var message = matches[0].Groups["m"].Value;
|
||||
return new LogInfo()
|
||||
return new LogInfo
|
||||
{
|
||||
Category = category, Message = message, CategoryColor = color
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
[ViewModelRegister(typeof(LogPopupView), false)]
|
||||
public sealed class LogPopupModelView : PopupViewModelBase
|
||||
{
|
||||
public LogPopupModelView() : base()
|
||||
{
|
||||
Logs.Add(new LogInfo()
|
||||
{
|
||||
Category = "DEBG", Message = "MEOW MEOW TEST"
|
||||
});
|
||||
|
||||
Logs.Add(new LogInfo()
|
||||
{
|
||||
Category = "ERRO", Message = "MEOW MEOW TEST 11\naaaaa"
|
||||
});
|
||||
}
|
||||
|
||||
public LogPopupModelView(IServiceProvider serviceProvider) : base(serviceProvider)
|
||||
{
|
||||
}
|
||||
|
||||
public override string Title => "LOG";
|
||||
public override bool IsClosable => true;
|
||||
|
||||
public ObservableCollection<LogInfo> Logs { get; } = new();
|
||||
|
||||
public void Append(string str)
|
||||
{
|
||||
Logs.Add(LogInfo.FromString(str));
|
||||
}
|
||||
}
|
||||
@@ -1,51 +1,9 @@
|
||||
using System;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using Avalonia.Controls;
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
|
||||
namespace Nebula.Launcher.ViewModels;
|
||||
|
||||
public abstract class ViewModelBase : ObservableObject
|
||||
{
|
||||
private readonly IServiceProvider _serviceProvider;
|
||||
public ViewModelBase()
|
||||
{
|
||||
AssertDesignMode();
|
||||
_serviceProvider = default!;
|
||||
}
|
||||
public ViewModelBase(IServiceProvider serviceProvider)
|
||||
{
|
||||
_serviceProvider = serviceProvider;
|
||||
}
|
||||
|
||||
public bool TryGetViewModel(Type type,[NotNullWhen(true)] out ViewModelBase? viewModelBase)
|
||||
{
|
||||
viewModelBase = null;
|
||||
var vm = Design.IsDesignMode
|
||||
? Activator.CreateInstance(type)
|
||||
: _serviceProvider.GetService(type);
|
||||
|
||||
if (vm is not ViewModelBase vmb) return false;
|
||||
|
||||
viewModelBase = vmb;
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool TryGetViewModel<T>([NotNullWhen(true)] out T? viewModelBase) where T: ViewModelBase
|
||||
{
|
||||
var success = TryGetViewModel(typeof(T), out var vmb);
|
||||
viewModelBase = (T?)vmb;
|
||||
return success;
|
||||
}
|
||||
|
||||
public T GetViewModel<T>() where T: ViewModelBase
|
||||
{
|
||||
TryGetViewModel<T>(out var viewModelBase);
|
||||
return viewModelBase!;
|
||||
}
|
||||
|
||||
public void AssertDesignMode()
|
||||
{
|
||||
if (!Design.IsDesignMode) throw new Exception();
|
||||
}
|
||||
protected abstract void InitialiseInDesignMode();
|
||||
protected abstract void Initialise();
|
||||
}
|
||||
@@ -85,7 +85,8 @@
|
||||
Padding="5">
|
||||
<Label FontSize="10" Foreground="#777777">
|
||||
<Panel>
|
||||
<Button Command="{Binding OpenLink}" HorizontalAlignment="Left" VerticalAlignment="Center" Margin="0" Padding="0" CornerRadius="0" Background="#00000000">
|
||||
<Button Command="{Binding OpenLink}" HorizontalAlignment="Left" VerticalAlignment="Center"
|
||||
Margin="0" Padding="0" CornerRadius="0" Background="#00000000">
|
||||
<TextBlock HorizontalAlignment="Left" VerticalAlignment="Center">https://cinka.ru/nebula-launcher/</TextBlock>
|
||||
</Button>
|
||||
<TextBlock HorizontalAlignment="Right" VerticalAlignment="Center">prototype-product-v0.01</TextBlock>
|
||||
@@ -141,4 +142,4 @@
|
||||
</Border>
|
||||
</Panel>
|
||||
</Panel>
|
||||
</UserControl>
|
||||
</UserControl>
|
||||
@@ -1,15 +1,10 @@
|
||||
using System;
|
||||
using System.Windows.Input;
|
||||
using Avalonia;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Markup.Xaml;
|
||||
using Nebula.Launcher.ViewModels;
|
||||
|
||||
namespace Nebula.Launcher.Views;
|
||||
|
||||
public partial class MainView : UserControl
|
||||
{
|
||||
|
||||
// This constructor is used when the view is created by the XAML Previewer
|
||||
public MainView()
|
||||
{
|
||||
|
||||
@@ -12,4 +12,4 @@
|
||||
xmlns="https://github.com/avaloniaui"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" />
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" />
|
||||
@@ -3,14 +3,14 @@
|
||||
d:DesignWidth="800"
|
||||
mc:Ignorable="d"
|
||||
x:Class="Nebula.Launcher.Views.Pages.AccountInfoView"
|
||||
x:DataType="viewModels:AccountInfoViewModel"
|
||||
x:DataType="pages:AccountInfoViewModel"
|
||||
xmlns="https://github.com/avaloniaui"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:viewModels="clr-namespace:Nebula.Launcher.ViewModels"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:pages="clr-namespace:Nebula.Launcher.ViewModels.Pages">
|
||||
<Design.DataContext>
|
||||
<viewModels:AccountInfoViewModel />
|
||||
<pages:AccountInfoViewModel />
|
||||
</Design.DataContext>
|
||||
<Grid
|
||||
ColumnDefinitions="*,1.5*"
|
||||
@@ -29,7 +29,7 @@
|
||||
ItemsSource="{Binding Accounts}"
|
||||
Padding="0">
|
||||
<ItemsControl.ItemTemplate>
|
||||
<DataTemplate DataType="{x:Type viewModels:AuthLoginPasswordModel}">
|
||||
<DataTemplate DataType="{x:Type pages:AuthLoginPasswordModel}">
|
||||
<Border
|
||||
CornerRadius="0,10,0,10"
|
||||
Margin="5,5,5,0"
|
||||
@@ -168,4 +168,4 @@
|
||||
</Border>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</UserControl>
|
||||
</UserControl>
|
||||
@@ -1,16 +1,17 @@
|
||||
using Avalonia.Controls;
|
||||
using Nebula.Launcher.ViewModels;
|
||||
using AccountInfoViewModel = Nebula.Launcher.ViewModels.Pages.AccountInfoViewModel;
|
||||
|
||||
namespace Nebula.Launcher.Views.Pages;
|
||||
|
||||
public interface ITab;
|
||||
|
||||
public partial class AccountInfoView : UserControl
|
||||
{
|
||||
public AccountInfoView()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
|
||||
public AccountInfoView(AccountInfoViewModel viewModel)
|
||||
: this()
|
||||
{
|
||||
|
||||
@@ -3,14 +3,14 @@
|
||||
d:DesignWidth="800"
|
||||
mc:Ignorable="d"
|
||||
x:Class="Nebula.Launcher.Views.Pages.ContentBrowserView"
|
||||
x:DataType="viewModels:ContentBrowserViewModel"
|
||||
x:DataType="pages:ContentBrowserViewModel"
|
||||
xmlns="https://github.com/avaloniaui"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:viewModels="clr-namespace:Nebula.Launcher.ViewModels"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:pages="clr-namespace:Nebula.Launcher.ViewModels.Pages">
|
||||
<Design.DataContext>
|
||||
<viewModels:ContentBrowserViewModel />
|
||||
<pages:ContentBrowserViewModel />
|
||||
</Design.DataContext>
|
||||
|
||||
<Grid
|
||||
@@ -60,7 +60,7 @@
|
||||
ItemsSource="{Binding Entries}"
|
||||
Padding="0,0,0,0">
|
||||
<ItemsControl.ItemTemplate>
|
||||
<DataTemplate DataType="{x:Type viewModels:ContentEntry}">
|
||||
<DataTemplate DataType="{x:Type pages:ContentEntry}">
|
||||
<Button
|
||||
Command="{Binding OnPathGo}"
|
||||
CornerRadius="0"
|
||||
@@ -86,4 +86,4 @@
|
||||
</ItemsControl>
|
||||
</ScrollViewer>
|
||||
</Grid>
|
||||
</UserControl>
|
||||
</UserControl>
|
||||
@@ -1,7 +1,5 @@
|
||||
using Avalonia;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Markup.Xaml;
|
||||
using Nebula.Launcher.ViewModels;
|
||||
using ContentBrowserViewModel = Nebula.Launcher.ViewModels.Pages.ContentBrowserViewModel;
|
||||
|
||||
namespace Nebula.Launcher.Views.Pages;
|
||||
|
||||
@@ -11,7 +9,7 @@ public partial class ContentBrowserView : UserControl
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
|
||||
public ContentBrowserView(ContentBrowserViewModel viewModel)
|
||||
: this()
|
||||
{
|
||||
|
||||
@@ -8,4 +8,4 @@
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
|
||||
Welcome to Avalonia!
|
||||
</UserControl>
|
||||
</UserControl>
|
||||
@@ -1,6 +1,4 @@
|
||||
using Avalonia;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Markup.Xaml;
|
||||
|
||||
namespace Nebula.Launcher.Views.Pages;
|
||||
|
||||
|
||||
@@ -3,16 +3,17 @@
|
||||
d:DesignWidth="800"
|
||||
mc:Ignorable="d"
|
||||
x:Class="Nebula.Launcher.Views.Pages.ServerListView"
|
||||
x:DataType="viewModels:ServerListViewModel"
|
||||
x:DataType="pages:ServerListViewModel"
|
||||
xmlns="https://github.com/avaloniaui"
|
||||
xmlns:asyncImageLoader="clr-namespace:AsyncImageLoader;assembly=AsyncImageLoader.Avalonia"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:viewModels="clr-namespace:Nebula.Launcher.ViewModels"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:pages="clr-namespace:Nebula.Launcher.ViewModels.Pages">
|
||||
|
||||
<Design.DataContext>
|
||||
<viewModels:ServerListViewModel />
|
||||
<pages:ServerListViewModel />
|
||||
</Design.DataContext>
|
||||
|
||||
<Grid
|
||||
@@ -67,7 +68,8 @@
|
||||
Grid.Row="1"
|
||||
MinHeight="50">
|
||||
<Border.Background>
|
||||
<ImageBrush Stretch="UniformToFill" asyncImageLoader:ImageBrushLoader.Source="https://t4.ftcdn.net/jpg/00/81/55/69/360_F_81556974_8sF8cKszJaRfBGd5sDt1RXE2QbzDtQqs.jpg" />
|
||||
<ImageBrush Stretch="UniformToFill"
|
||||
asyncImageLoader:ImageBrushLoader.Source="https://t4.ftcdn.net/jpg/00/81/55/69/360_F_81556974_8sF8cKszJaRfBGd5sDt1RXE2QbzDtQqs.jpg" />
|
||||
</Border.Background>
|
||||
<Border
|
||||
BorderThickness="0,2,2,0"
|
||||
@@ -189,4 +191,4 @@
|
||||
</Grid>
|
||||
</Border>
|
||||
</Grid>
|
||||
</UserControl>
|
||||
</UserControl>
|
||||
@@ -1,5 +1,5 @@
|
||||
using Avalonia.Controls;
|
||||
using Nebula.Launcher.ViewModels;
|
||||
using ServerListViewModel = Nebula.Launcher.ViewModels.Pages.ServerListViewModel;
|
||||
|
||||
namespace Nebula.Launcher.Views.Pages;
|
||||
|
||||
|
||||
@@ -2,13 +2,13 @@
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:viewModels="clr-namespace:Nebula.Launcher.ViewModels"
|
||||
xmlns:system="clr-namespace:System;assembly=System.Runtime"
|
||||
xmlns:popup="clr-namespace:Nebula.Launcher.ViewModels.Popup"
|
||||
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
||||
x:Class="Nebula.Launcher.Views.Popup.ExceptionView"
|
||||
x:DataType="viewModels:ExceptionViewModel">
|
||||
x:DataType="popup:ExceptionViewModel">
|
||||
<Design.DataContext>
|
||||
<viewModels:ExceptionViewModel />
|
||||
<popup:ExceptionViewModel />
|
||||
</Design.DataContext>
|
||||
<ScrollViewer Margin="10" Padding="0,0,8,0">
|
||||
<ItemsControl
|
||||
@@ -20,13 +20,17 @@
|
||||
<Border Background="#333333" CornerRadius="5" Margin="0,0,0,5">
|
||||
<StackPanel>
|
||||
<Border Background="#aa2222" CornerRadius="5,5,0,0">
|
||||
<Label Margin="4"><TextBlock Text="{Binding Message}"/></Label>
|
||||
<Label Margin="4">
|
||||
<TextBlock Text="{Binding Message}" />
|
||||
</Label>
|
||||
</Border>
|
||||
<Label Margin="4"><TextBlock Text="{Binding StackTrace}"/></Label>
|
||||
<Label Margin="4">
|
||||
<TextBlock Text="{Binding StackTrace}" />
|
||||
</Label>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
</DataTemplate>
|
||||
</ItemsControl.ItemTemplate>
|
||||
</ItemsControl>
|
||||
</ScrollViewer>
|
||||
</UserControl>
|
||||
</UserControl>
|
||||
@@ -1,8 +1,5 @@
|
||||
using System;
|
||||
using Avalonia;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Markup.Xaml;
|
||||
using Nebula.Launcher.ViewModels;
|
||||
using Nebula.Launcher.ViewModels.Popup;
|
||||
|
||||
namespace Nebula.Launcher.Views.Popup;
|
||||
|
||||
|
||||
@@ -3,14 +3,14 @@
|
||||
d:DesignWidth="800"
|
||||
mc:Ignorable="d"
|
||||
x:Class="Nebula.Launcher.Views.Popup.InfoPopupView"
|
||||
x:DataType="viewModels:InfoPopupViewModel"
|
||||
x:DataType="popup:InfoPopupViewModel"
|
||||
xmlns="https://github.com/avaloniaui"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:viewModels="clr-namespace:Nebula.Launcher.ViewModels"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:popup="clr-namespace:Nebula.Launcher.ViewModels.Popup">
|
||||
<Design.DataContext>
|
||||
<viewModels:InfoPopupViewModel />
|
||||
<popup:InfoPopupViewModel />
|
||||
</Design.DataContext>
|
||||
|
||||
<Panel HorizontalAlignment="Center" VerticalAlignment="Center">
|
||||
@@ -18,4 +18,4 @@
|
||||
<TextBlock Text="{Binding InfoText}" />
|
||||
</Label>
|
||||
</Panel>
|
||||
</UserControl>
|
||||
</UserControl>
|
||||
@@ -1,7 +1,5 @@
|
||||
using Avalonia;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Markup.Xaml;
|
||||
using Nebula.Launcher.ViewModels;
|
||||
using InfoPopupViewModel = Nebula.Launcher.ViewModels.Popup.InfoPopupViewModel;
|
||||
|
||||
namespace Nebula.Launcher.Views.Popup;
|
||||
|
||||
|
||||
@@ -2,31 +2,31 @@
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:viewModels="clr-namespace:Nebula.Launcher.ViewModels"
|
||||
xmlns:popup="clr-namespace:Nebula.Launcher.ViewModels.Popup"
|
||||
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
||||
x:Class="Nebula.Launcher.Views.Popup.LoadingContextView"
|
||||
x:DataType="viewModels:LoadingContextViewModel">
|
||||
x:DataType="popup:LoadingContextViewModel">
|
||||
<Design.DataContext>
|
||||
<viewModels:LoadingContextViewModel />
|
||||
<popup:LoadingContextViewModel />
|
||||
</Design.DataContext>
|
||||
<StackPanel Margin="25" Spacing="15">
|
||||
<ProgressBar Height="40" Maximum="{Binding CurrJobs}" Value="{Binding ResolvedJobs}"/>
|
||||
<ProgressBar Height="40" Maximum="{Binding CurrJobs}" Value="{Binding ResolvedJobs}" />
|
||||
<Panel>
|
||||
<StackPanel Orientation="Horizontal" Spacing="5" HorizontalAlignment="Left" VerticalAlignment="Center">
|
||||
<Label>
|
||||
<TextBlock Text="{Binding ResolvedJobs}"/>
|
||||
<TextBlock Text="{Binding ResolvedJobs}" />
|
||||
</Label>
|
||||
<Label>
|
||||
/
|
||||
</Label>
|
||||
<Label>
|
||||
<TextBlock Text="{Binding CurrJobs}"/>
|
||||
<TextBlock Text="{Binding CurrJobs}" />
|
||||
</Label>
|
||||
</StackPanel>
|
||||
|
||||
|
||||
<Button HorizontalAlignment="Right" VerticalAlignment="Center">
|
||||
<Label>Cancel</Label>
|
||||
</Button>
|
||||
</Panel>
|
||||
</StackPanel>
|
||||
</UserControl>
|
||||
</UserControl>
|
||||
@@ -1,5 +1,5 @@
|
||||
using Avalonia.Controls;
|
||||
using Nebula.Launcher.ViewModels;
|
||||
using LoadingContextViewModel = Nebula.Launcher.ViewModels.Popup.LoadingContextViewModel;
|
||||
|
||||
namespace Nebula.Launcher.Views.Popup;
|
||||
|
||||
@@ -9,8 +9,8 @@ public partial class LoadingContextView : UserControl
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
public LoadingContextView(LoadingContextViewModel viewModel): this()
|
||||
|
||||
public LoadingContextView(LoadingContextViewModel viewModel) : this()
|
||||
{
|
||||
DataContext = viewModel;
|
||||
}
|
||||
|
||||
@@ -3,13 +3,14 @@
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:viewModels="clr-namespace:Nebula.Launcher.ViewModels"
|
||||
xmlns:popup="clr-namespace:Nebula.Launcher.ViewModels.Popup"
|
||||
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
||||
x:Class="Nebula.Launcher.Views.Popup.LogPopupView"
|
||||
x:DataType="viewModels:LogPopupModelView">
|
||||
x:DataType="popup:LogPopupModelView">
|
||||
<Design.DataContext>
|
||||
<viewModels:LogPopupModelView />
|
||||
<popup:LogPopupModelView />
|
||||
</Design.DataContext>
|
||||
|
||||
|
||||
<ScrollViewer Margin="10" Padding="0,0,8,0">
|
||||
<ItemsControl
|
||||
Background="#00000000"
|
||||
@@ -20,20 +21,20 @@
|
||||
<Border CornerRadius="5" Margin="0,0,0,5">
|
||||
<StackPanel Orientation="Horizontal" Spacing="5" Margin="0">
|
||||
<Border MinWidth="100"
|
||||
Background="{Binding CategoryColor}"
|
||||
CornerRadius="5,0,0,5"
|
||||
Padding="10,0,12,0" BorderThickness="2,0,2,0">
|
||||
<Label FontSize="15" VerticalAlignment="Center">
|
||||
<TextBlock Text="{Binding Category }"></TextBlock>
|
||||
Background="{Binding CategoryColor}"
|
||||
CornerRadius="5,0,0,5"
|
||||
Padding="10,0,12,0" BorderThickness="2,0,2,0">
|
||||
<Label FontSize="15" VerticalAlignment="Center">
|
||||
<TextBlock Text="{Binding Category }" />
|
||||
</Label>
|
||||
</Border>
|
||||
<Label FontSize="12" VerticalAlignment="Center">
|
||||
<TextBlock Text="{Binding Message }"></TextBlock>
|
||||
<TextBlock Text="{Binding Message }" />
|
||||
</Label>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
</DataTemplate>
|
||||
</ItemsControl.ItemTemplate>
|
||||
</ItemsControl>
|
||||
</ScrollViewer>
|
||||
</UserControl>
|
||||
</ItemsControl.ItemTemplate>
|
||||
</ItemsControl>
|
||||
</ScrollViewer>
|
||||
</UserControl>
|
||||
@@ -1,7 +1,5 @@
|
||||
using Avalonia;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Markup.Xaml;
|
||||
using Nebula.Launcher.ViewModels;
|
||||
using Nebula.Launcher.ViewModels.Popup;
|
||||
|
||||
namespace Nebula.Launcher.Views.Popup;
|
||||
|
||||
|
||||
@@ -1,18 +1,18 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1">
|
||||
<!-- This manifest is used on Windows only.
|
||||
Don't remove it as it might cause problems with window transparency and embedded controls.
|
||||
For more details visit https://learn.microsoft.com/en-us/windows/win32/sbscs/application-manifests -->
|
||||
<assemblyIdentity version="1.0.0.0" name="Nebula.Launcher.Desktop"/>
|
||||
<!-- This manifest is used on Windows only.
|
||||
Don't remove it as it might cause problems with window transparency and embedded controls.
|
||||
For more details visit https://learn.microsoft.com/en-us/windows/win32/sbscs/application-manifests -->
|
||||
<assemblyIdentity version="1.0.0.0" name="Nebula.Launcher.Desktop"/>
|
||||
|
||||
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
|
||||
<application>
|
||||
<!-- A list of the Windows versions that this application has been tested on
|
||||
and is designed to work with. Uncomment the appropriate elements
|
||||
and Windows will automatically select the most compatible environment. -->
|
||||
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
|
||||
<application>
|
||||
<!-- A list of the Windows versions that this application has been tested on
|
||||
and is designed to work with. Uncomment the appropriate elements
|
||||
and Windows will automatically select the most compatible environment. -->
|
||||
|
||||
<!-- Windows 10 -->
|
||||
<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}" />
|
||||
</application>
|
||||
</compatibility>
|
||||
<!-- Windows 10 -->
|
||||
<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}"/>
|
||||
</application>
|
||||
</compatibility>
|
||||
</assembly>
|
||||
|
||||
@@ -7,12 +7,17 @@ using Robust.LoaderApi;
|
||||
namespace Nebula.Runner;
|
||||
|
||||
[ServiceRegister]
|
||||
public sealed class App(DebugService debugService, RunnerService runnerService, ContentService contentService) : IRedialApi
|
||||
public sealed class App(DebugService debugService, RunnerService runnerService, ContentService contentService)
|
||||
: IRedialApi
|
||||
{
|
||||
public void Redial(Uri uri, string text = "")
|
||||
{
|
||||
}
|
||||
|
||||
public async Task Run(string[] args1)
|
||||
{
|
||||
debugService.Log("HELLO!!! ");
|
||||
|
||||
|
||||
var login = Environment.GetEnvironmentVariable("AUTH_LOGIN") ?? "Alexandra";
|
||||
var urlraw = Environment.GetEnvironmentVariable("GAME_URL") ?? "ss14://localhost";
|
||||
|
||||
@@ -20,7 +25,7 @@ public sealed class App(DebugService debugService, RunnerService runnerService,
|
||||
|
||||
using var cancelTokenSource = new CancellationTokenSource();
|
||||
var buildInfo = await contentService.GetBuildInfo(url, cancelTokenSource.Token);
|
||||
|
||||
|
||||
|
||||
var args = new List<string>
|
||||
{
|
||||
@@ -46,27 +51,22 @@ public sealed class App(DebugService debugService, RunnerService runnerService,
|
||||
|
||||
args.Add("--ss14-address");
|
||||
args.Add(url.ToString());
|
||||
|
||||
await runnerService.Run(args.ToArray(), buildInfo, this, new ConsoleLoadingHandler(), cancelTokenSource.Token);
|
||||
}
|
||||
|
||||
public void Redial(Uri uri, string text = "")
|
||||
{
|
||||
|
||||
await runnerService.Run(args.ToArray(), buildInfo, this, new ConsoleLoadingHandler(), cancelTokenSource.Token);
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class ConsoleLoadingHandler : ILoadingHandler
|
||||
{
|
||||
private int _currJobs;
|
||||
|
||||
private float _percent;
|
||||
private int _resolvedJobs;
|
||||
|
||||
private float _percent = 0f;
|
||||
|
||||
public void SetJobsCount(int count)
|
||||
{
|
||||
_currJobs = count;
|
||||
|
||||
|
||||
UpdatePercent();
|
||||
Draw();
|
||||
}
|
||||
@@ -79,7 +79,7 @@ public sealed class ConsoleLoadingHandler : ILoadingHandler
|
||||
public void SetResolvedJobsCount(int count)
|
||||
{
|
||||
_resolvedJobs = count;
|
||||
|
||||
|
||||
UpdatePercent();
|
||||
Draw();
|
||||
}
|
||||
@@ -91,15 +91,15 @@ public sealed class ConsoleLoadingHandler : ILoadingHandler
|
||||
|
||||
private void UpdatePercent()
|
||||
{
|
||||
if(_currJobs == 0)
|
||||
if (_currJobs == 0)
|
||||
{
|
||||
_percent = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
if(_resolvedJobs > _currJobs) return;
|
||||
|
||||
_percent = _resolvedJobs /(float) _currJobs;
|
||||
|
||||
if (_resolvedJobs > _currJobs) return;
|
||||
|
||||
_percent = _resolvedJobs / (float)_currJobs;
|
||||
}
|
||||
|
||||
private void Draw()
|
||||
@@ -107,20 +107,13 @@ public sealed class ConsoleLoadingHandler : ILoadingHandler
|
||||
var barCount = 10;
|
||||
var fullCount = (int)(barCount * _percent);
|
||||
var emptyCount = barCount - fullCount;
|
||||
|
||||
|
||||
Console.Write("\r");
|
||||
|
||||
for (var i = 0; i < fullCount; i++)
|
||||
{
|
||||
Console.Write("#");
|
||||
}
|
||||
|
||||
for (var i = 0; i < emptyCount; i++)
|
||||
{
|
||||
Console.Write(" ");
|
||||
}
|
||||
|
||||
for (var i = 0; i < fullCount; i++) Console.Write("#");
|
||||
|
||||
for (var i = 0; i < emptyCount; i++) Console.Write(" ");
|
||||
|
||||
Console.Write($"\t {_resolvedJobs}/{_currJobs}");
|
||||
|
||||
}
|
||||
}
|
||||
@@ -8,11 +8,11 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Nebula.Shared\Nebula.Shared.csproj" />
|
||||
<ProjectReference Include="..\Nebula.Shared\Nebula.Shared.csproj"/>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="9.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="9.0.0"/>
|
||||
<PackageReference Include="SharpZstd.Interop" Version="1.5.6"/>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
using System.Reflection;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Nebula.Shared;
|
||||
|
||||
@@ -10,7 +9,7 @@ public static class Program
|
||||
{
|
||||
var services = new ServiceCollection();
|
||||
services.AddServices();
|
||||
|
||||
|
||||
var serviceProvider = services.BuildServiceProvider();
|
||||
var task = serviceProvider.GetService<App>()!.Run(args);
|
||||
task.Wait();
|
||||
|
||||
@@ -4,22 +4,29 @@ namespace Nebula.Shared;
|
||||
|
||||
public static class CurrentConVar
|
||||
{
|
||||
public static readonly ConVar<string> EngineManifestUrl =
|
||||
public static readonly ConVar<string> EngineManifestUrl =
|
||||
ConVarBuilder.Build("engine.manifestUrl", "https://robust-builds.cdn.spacestation14.com/manifest.json");
|
||||
public static readonly ConVar<string> EngineModuleManifestUrl =
|
||||
|
||||
public static readonly ConVar<string> EngineModuleManifestUrl =
|
||||
ConVarBuilder.Build("engine.moduleManifestUrl", "https://robust-builds.cdn.spacestation14.com/modules.json");
|
||||
|
||||
public static readonly ConVar<int> ManifestDownloadProtocolVersion =
|
||||
ConVarBuilder.Build("engine.manifestDownloadProtocolVersion", 1);
|
||||
public static readonly ConVar<string> RobustAssemblyName =
|
||||
|
||||
public static readonly ConVar<string> RobustAssemblyName =
|
||||
ConVarBuilder.Build("engine.robustAssemblyName", "Robust.Client");
|
||||
|
||||
|
||||
public static readonly ConVar<string[]> Hub = ConVarBuilder.Build<string[]>("launcher.hub", [
|
||||
"https://hub.spacestation14.com/api/servers"
|
||||
]);
|
||||
|
||||
public static readonly ConVar<string[]> AuthServers = ConVarBuilder.Build<string[]>("launcher.authServers", [
|
||||
"https://auth.spacestation14.com/"
|
||||
]);
|
||||
|
||||
public static readonly ConVar<AuthLoginPassword[]> AuthProfiles = ConVarBuilder.Build<AuthLoginPassword[]>("auth.profiles", []);
|
||||
public static readonly ConVar<AuthLoginPassword> AuthCurrent = ConVarBuilder.Build<AuthLoginPassword>("auth.current");
|
||||
public static readonly ConVar<AuthLoginPassword[]> AuthProfiles =
|
||||
ConVarBuilder.Build<AuthLoginPassword[]>("auth.profiles", []);
|
||||
|
||||
public static readonly ConVar<AuthLoginPassword> AuthCurrent =
|
||||
ConVarBuilder.Build<AuthLoginPassword>("auth.current");
|
||||
}
|
||||
@@ -10,7 +10,7 @@ public class AssemblyApi : IFileApi
|
||||
{
|
||||
_root = root;
|
||||
}
|
||||
|
||||
|
||||
public bool TryOpen(string path, out Stream? stream)
|
||||
{
|
||||
return _root.TryOpen(path, out stream);
|
||||
|
||||
@@ -15,7 +15,6 @@ public sealed class FileApi : IReadWriteFileApi
|
||||
{
|
||||
var fullPath = Path.Join(RootPath, path);
|
||||
if (File.Exists(fullPath))
|
||||
{
|
||||
try
|
||||
{
|
||||
stream = new FileStream(fullPath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
|
||||
@@ -26,7 +25,6 @@ public sealed class FileApi : IReadWriteFileApi
|
||||
stream = null;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
stream = null;
|
||||
return false;
|
||||
@@ -66,6 +64,7 @@ public sealed class FileApi : IReadWriteFileApi
|
||||
{
|
||||
// Log exception if necessary
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ public interface ILoadingHandler
|
||||
{
|
||||
public void SetJobsCount(int count);
|
||||
public int GetJobsCount();
|
||||
|
||||
|
||||
public void SetResolvedJobsCount(int count);
|
||||
public int GetResolvedJobsCount();
|
||||
|
||||
@@ -30,7 +30,7 @@ public interface ILoadingHandler
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class QueryJob: IDisposable
|
||||
public sealed class QueryJob : IDisposable
|
||||
{
|
||||
private readonly ILoadingHandler _handler;
|
||||
|
||||
@@ -39,7 +39,7 @@ public sealed class QueryJob: IDisposable
|
||||
_handler = handler;
|
||||
handler.AppendJob();
|
||||
}
|
||||
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_handler.AppendResolvedJob();
|
||||
|
||||
@@ -1,2 +1,3 @@
|
||||
namespace Nebula.Shared.Models;
|
||||
|
||||
public record ListItemTemplate(Type ModelType, string IconKey, string Label);
|
||||
@@ -4,18 +4,26 @@ namespace Nebula.Shared.Models;
|
||||
|
||||
public sealed record AuthInfo(
|
||||
[property: JsonPropertyName("mode")] string Mode,
|
||||
[property: JsonPropertyName("public_key")] string PublicKey);
|
||||
[property: JsonPropertyName("public_key")]
|
||||
string PublicKey);
|
||||
|
||||
public sealed record BuildInfo(
|
||||
[property: JsonPropertyName("engine_version")] string EngineVersion,
|
||||
[property: JsonPropertyName("fork_id")] string ForkId,
|
||||
[property: JsonPropertyName("version")] string Version,
|
||||
[property: JsonPropertyName("download_url")] string DownloadUrl,
|
||||
[property: JsonPropertyName("manifest_download_url")] string ManifestDownloadUrl,
|
||||
[property: JsonPropertyName("manifest_url")] string ManifestUrl,
|
||||
[property: JsonPropertyName("engine_version")]
|
||||
string EngineVersion,
|
||||
[property: JsonPropertyName("fork_id")]
|
||||
string ForkId,
|
||||
[property: JsonPropertyName("version")]
|
||||
string Version,
|
||||
[property: JsonPropertyName("download_url")]
|
||||
string DownloadUrl,
|
||||
[property: JsonPropertyName("manifest_download_url")]
|
||||
string ManifestDownloadUrl,
|
||||
[property: JsonPropertyName("manifest_url")]
|
||||
string ManifestUrl,
|
||||
[property: JsonPropertyName("acz")] bool Acz,
|
||||
[property: JsonPropertyName("hash")] string Hash,
|
||||
[property: JsonPropertyName("manifest_hash")] string ManifestHash);
|
||||
[property: JsonPropertyName("manifest_hash")]
|
||||
string ManifestHash);
|
||||
|
||||
public sealed record ServerLink(
|
||||
[property: JsonPropertyName("name")] string Name,
|
||||
@@ -23,16 +31,20 @@ public sealed record ServerLink(
|
||||
[property: JsonPropertyName("url")] string Url);
|
||||
|
||||
public sealed record ServerInfo(
|
||||
[property: JsonPropertyName("connect_address")] string ConnectAddress,
|
||||
[property: JsonPropertyName("connect_address")]
|
||||
string ConnectAddress,
|
||||
[property: JsonPropertyName("auth")] AuthInfo Auth,
|
||||
[property: JsonPropertyName("build")] BuildInfo Build,
|
||||
[property: JsonPropertyName("desc")] string Desc,
|
||||
[property: JsonPropertyName("links")] List<ServerLink> Links);
|
||||
|
||||
public sealed record EngineVersionInfo(
|
||||
[property: JsonPropertyName("insecure")] bool Insecure,
|
||||
[property: JsonPropertyName("redirect")] string? RedirectVersion,
|
||||
[property: JsonPropertyName("platforms")] Dictionary<string, EngineBuildInfo> Platforms);
|
||||
[property: JsonPropertyName("insecure")]
|
||||
bool Insecure,
|
||||
[property: JsonPropertyName("redirect")]
|
||||
string? RedirectVersion,
|
||||
[property: JsonPropertyName("platforms")]
|
||||
Dictionary<string, EngineBuildInfo> Platforms);
|
||||
|
||||
public sealed class EngineBuildInfo
|
||||
{
|
||||
@@ -47,27 +59,39 @@ public sealed class EngineBuildInfo
|
||||
}
|
||||
|
||||
public sealed record ServerHubInfo(
|
||||
[property: JsonPropertyName("address")] string Address,
|
||||
[property: JsonPropertyName("statusData")] ServerStatus StatusData,
|
||||
[property: JsonPropertyName("inferredTags")] List<string> InferredTags);
|
||||
[property: JsonPropertyName("address")]
|
||||
string Address,
|
||||
[property: JsonPropertyName("statusData")]
|
||||
ServerStatus StatusData,
|
||||
[property: JsonPropertyName("inferredTags")]
|
||||
List<string> InferredTags);
|
||||
|
||||
public sealed record ServerStatus(
|
||||
[property: JsonPropertyName("map")] string Map,
|
||||
[property: JsonPropertyName("name")] string Name,
|
||||
[property: JsonPropertyName("tags")] List<string> Tags,
|
||||
[property: JsonPropertyName("preset")] string Preset,
|
||||
[property: JsonPropertyName("players")] int Players,
|
||||
[property: JsonPropertyName("round_id")] int RoundId,
|
||||
[property: JsonPropertyName("run_level")] int RunLevel,
|
||||
[property: JsonPropertyName("panic_bunker")] bool PanicBunker,
|
||||
[property: JsonPropertyName("round_start_time")] DateTime? RoundStartTime,
|
||||
[property: JsonPropertyName("soft_max_players")] int SoftMaxPlayers);
|
||||
[property: JsonPropertyName("players")]
|
||||
int Players,
|
||||
[property: JsonPropertyName("round_id")]
|
||||
int RoundId,
|
||||
[property: JsonPropertyName("run_level")]
|
||||
int RunLevel,
|
||||
[property: JsonPropertyName("panic_bunker")]
|
||||
bool PanicBunker,
|
||||
[property: JsonPropertyName("round_start_time")]
|
||||
DateTime? RoundStartTime,
|
||||
[property: JsonPropertyName("soft_max_players")]
|
||||
int SoftMaxPlayers);
|
||||
|
||||
public sealed record ModulesInfo(
|
||||
[property: JsonPropertyName("modules")] Dictionary<string, Module> Modules);
|
||||
[property: JsonPropertyName("modules")]
|
||||
Dictionary<string, Module> Modules);
|
||||
|
||||
public sealed record Module(
|
||||
[property: JsonPropertyName("versions")] Dictionary<string, ModuleVersionInfo> Versions);
|
||||
[property: JsonPropertyName("versions")]
|
||||
Dictionary<string, ModuleVersionInfo> Versions);
|
||||
|
||||
public sealed record ModuleVersionInfo(
|
||||
[property: JsonPropertyName("platforms")] Dictionary<string, EngineBuildInfo> Platforms);
|
||||
[property: JsonPropertyName("platforms")]
|
||||
Dictionary<string, EngineBuildInfo> Platforms);
|
||||
@@ -11,13 +11,14 @@
|
||||
<EmbeddedResource Include="Utils\runtime.json">
|
||||
<LogicalName>Utility.runtime.json</LogicalName>
|
||||
</EmbeddedResource>
|
||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="9.0.0" />
|
||||
<PackageReference Include="Robust.Natives" Version="0.1.1" />
|
||||
<PackageReference Include="SharpZstd.Interop" Version="1.5.6" />
|
||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="9.0.0"/>
|
||||
<PackageReference Include="Robust.Natives" Version="0.1.1"/>
|
||||
<PackageReference Include="SharpZstd.Interop" Version="1.5.6"/>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Robust.LoaderApi\Robust.LoaderApi\Robust.LoaderApi.csproj" />
|
||||
<ProjectReference Include="..\Nebula.SourceGenerators\Nebula.SourceGenerators.csproj" OutputItemType="Analyzer" ReferenceOutputAssembly="false"/>
|
||||
<ProjectReference Include="..\Robust.LoaderApi\Robust.LoaderApi\Robust.LoaderApi.csproj"/>
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
@@ -7,47 +7,39 @@ public static class ServiceExt
|
||||
{
|
||||
public static void AddServices(this IServiceCollection services)
|
||||
{
|
||||
foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies())
|
||||
{
|
||||
AddServices(services, assembly);
|
||||
}
|
||||
foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies()) AddServices(services, assembly);
|
||||
}
|
||||
|
||||
|
||||
public static void AddServices(this IServiceCollection services, Assembly assembly)
|
||||
{
|
||||
foreach (var (type, inference) in GetServicesWithHelpAttribute(assembly))
|
||||
{
|
||||
Console.WriteLine("[ServiceMng] ADD SERVICE " + type);
|
||||
if (inference is null)
|
||||
{
|
||||
services.AddSingleton(type);
|
||||
}
|
||||
else
|
||||
{
|
||||
services.AddSingleton(inference, type);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static IEnumerable<(Type,Type?)> GetServicesWithHelpAttribute(Assembly assembly) {
|
||||
foreach(Type type in assembly.GetTypes())
|
||||
|
||||
private static IEnumerable<(Type, Type?)> GetServicesWithHelpAttribute(Assembly assembly)
|
||||
{
|
||||
foreach (var type in assembly.GetTypes())
|
||||
{
|
||||
var attr = type.GetCustomAttribute<ServiceRegisterAttribute>();
|
||||
if (attr is not null) {
|
||||
yield return (type, attr.Inference);
|
||||
}
|
||||
if (attr is not null) yield return (type, attr.Inference);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class ServiceRegisterAttribute : Attribute
|
||||
{
|
||||
public Type? Inference { get; }
|
||||
public bool IsSingleton { get; }
|
||||
|
||||
public ServiceRegisterAttribute(Type? inference = null, bool isSingleton = true)
|
||||
{
|
||||
IsSingleton = isSingleton;
|
||||
Inference = inference;
|
||||
}
|
||||
|
||||
public Type? Inference { get; }
|
||||
public bool IsSingleton { get; }
|
||||
}
|
||||
@@ -4,6 +4,7 @@ using System.Runtime.InteropServices;
|
||||
using System.Runtime.Loader;
|
||||
using Nebula.Shared.FileApis;
|
||||
using Robust.LoaderApi;
|
||||
using SharpZstd.Interop;
|
||||
|
||||
namespace Nebula.Shared.Services;
|
||||
|
||||
@@ -13,23 +14,23 @@ public class AssemblyService
|
||||
private readonly List<Assembly> _assemblies = new();
|
||||
private readonly DebugService _debugService;
|
||||
|
||||
private readonly HashSet<string> _resolvingAssemblies = new();
|
||||
|
||||
public AssemblyService(DebugService debugService)
|
||||
{
|
||||
_debugService = debugService;
|
||||
|
||||
SharpZstd.Interop.ZstdImportResolver.ResolveLibrary += (name, assembly1, path) =>
|
||||
|
||||
ZstdImportResolver.ResolveLibrary += (name, assembly1, path) =>
|
||||
{
|
||||
if (name.Equals("SharpZstd.Native"))
|
||||
{
|
||||
_debugService.Debug("RESOLVING SHARPZSTD THINK: " + name + " " + path);
|
||||
GetRuntimeInfo(out string platform, out string architecture, out string extension);
|
||||
string fileName = GetDllName(platform, architecture, extension);
|
||||
GetRuntimeInfo(out var platform, out var architecture, out var extension);
|
||||
var fileName = GetDllName(platform, architecture, extension);
|
||||
|
||||
if (NativeLibrary.TryLoad(fileName, assembly1, path, out var nativeLibrary))
|
||||
{
|
||||
return nativeLibrary;
|
||||
}
|
||||
if (NativeLibrary.TryLoad(fileName, assembly1, path, out var nativeLibrary)) return nativeLibrary;
|
||||
}
|
||||
|
||||
return IntPtr.Zero;
|
||||
};
|
||||
}
|
||||
@@ -98,8 +99,6 @@ public class AssemblyService
|
||||
assemblyApi.TryOpen($"{name}.pdb", out pdb);
|
||||
return true;
|
||||
}
|
||||
|
||||
private readonly HashSet<string> _resolvingAssemblies = new HashSet<string>();
|
||||
|
||||
private Assembly? OnAssemblyResolving(AssemblyLoadContext context, AssemblyName name, AssemblyApi assemblyApi)
|
||||
{
|
||||
@@ -108,7 +107,7 @@ public class AssemblyService
|
||||
_debugService.Debug($"Already resolving {name.Name}, skipping.");
|
||||
return null; // Prevent recursive resolution
|
||||
}
|
||||
|
||||
|
||||
try
|
||||
{
|
||||
_resolvingAssemblies.Add(name.FullName);
|
||||
@@ -130,18 +129,18 @@ public class AssemblyService
|
||||
|
||||
if (NativeLibrary.TryLoad(a, out var handle))
|
||||
return handle;
|
||||
|
||||
|
||||
_debugService.Error("Loading dll error! Not found");
|
||||
|
||||
return IntPtr.Zero;
|
||||
}
|
||||
|
||||
|
||||
public static string GetDllName(
|
||||
string platform,
|
||||
string architecture,
|
||||
string extension)
|
||||
{
|
||||
string name = $"SharpZstd.Native.{extension}";
|
||||
var name = $"SharpZstd.Native.{extension}";
|
||||
return name;
|
||||
}
|
||||
|
||||
@@ -172,24 +171,14 @@ public class AssemblyService
|
||||
}
|
||||
|
||||
if (RuntimeInformation.ProcessArchitecture == Architecture.X64)
|
||||
{
|
||||
architecture = "x64";
|
||||
}
|
||||
else if (RuntimeInformation.ProcessArchitecture == Architecture.X86)
|
||||
{
|
||||
architecture = "x86";
|
||||
}
|
||||
else if (RuntimeInformation.ProcessArchitecture == Architecture.Arm)
|
||||
{
|
||||
architecture = "arm";
|
||||
}
|
||||
else if (RuntimeInformation.ProcessArchitecture == Architecture.Arm64)
|
||||
{
|
||||
architecture = "arm64";
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new PlatformNotSupportedException("Unsupported process architecture.");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4,37 +4,37 @@ using Nebula.Shared.Models.Auth;
|
||||
namespace Nebula.Shared.Services;
|
||||
|
||||
[ServiceRegister]
|
||||
public partial class AuthService(
|
||||
RestService restService,
|
||||
DebugService debugService,
|
||||
public class AuthService(
|
||||
RestService restService,
|
||||
DebugService debugService,
|
||||
CancellationService cancellationService)
|
||||
{
|
||||
private readonly HttpClient _httpClient = new();
|
||||
public CurrentAuthInfo? SelectedAuth { get; internal set; }
|
||||
|
||||
public string Reason = "";
|
||||
public CurrentAuthInfo? SelectedAuth { get; internal set; }
|
||||
|
||||
public async Task<bool> Auth(AuthLoginPassword authLoginPassword)
|
||||
{
|
||||
var authServer = authLoginPassword.AuthServer;
|
||||
var login = authLoginPassword.Login;
|
||||
var password = authLoginPassword.Password;
|
||||
|
||||
|
||||
debugService.Debug($"Auth to {authServer}api/auth/authenticate {login}");
|
||||
|
||||
|
||||
var authUrl = new Uri($"{authServer}api/auth/authenticate");
|
||||
|
||||
var result =
|
||||
await restService.PostAsync<AuthenticateResponse, AuthenticateRequest>(
|
||||
new AuthenticateRequest(login, password), authUrl, cancellationService.Token);
|
||||
|
||||
|
||||
if (result.Value is null)
|
||||
{
|
||||
Reason = result.Message;
|
||||
return false;
|
||||
}
|
||||
|
||||
SelectedAuth = new CurrentAuthInfo(result.Value.UserId,
|
||||
SelectedAuth = new CurrentAuthInfo(result.Value.UserId,
|
||||
new LoginToken(result.Value.Token, result.Value.ExpireTime), authLoginPassword);
|
||||
|
||||
return true;
|
||||
@@ -68,4 +68,5 @@ public partial class AuthService(
|
||||
}
|
||||
|
||||
public sealed record CurrentAuthInfo(Guid UserId, LoginToken Token, AuthLoginPassword AuthLoginPassword);
|
||||
public record AuthLoginPassword(string Login, string Password, string AuthServer);
|
||||
|
||||
public record AuthLoginPassword(string Login, string Password, string AuthServer);
|
||||
@@ -5,15 +5,15 @@ namespace Nebula.Shared.Services;
|
||||
|
||||
public class ConVar<T>
|
||||
{
|
||||
public string Name { get; }
|
||||
public Type Type => typeof(T);
|
||||
public T? DefaultValue { get; }
|
||||
|
||||
public ConVar(string name, T? defaultValue = default)
|
||||
{
|
||||
Name = name ?? throw new ArgumentNullException(nameof(name));
|
||||
DefaultValue = defaultValue;
|
||||
}
|
||||
|
||||
public string Name { get; }
|
||||
public Type Type => typeof(T);
|
||||
public T? DefaultValue { get; }
|
||||
}
|
||||
|
||||
public static class ConVarBuilder
|
||||
@@ -30,8 +30,8 @@ public static class ConVarBuilder
|
||||
[ServiceRegister]
|
||||
public class ConfigurationService
|
||||
{
|
||||
private readonly FileService _fileService;
|
||||
private readonly DebugService _debugService;
|
||||
private readonly FileService _fileService;
|
||||
|
||||
public ConfigurationService(FileService fileService, DebugService debugService)
|
||||
{
|
||||
@@ -46,7 +46,6 @@ public class ConfigurationService
|
||||
try
|
||||
{
|
||||
if (_fileService.ConfigurationApi.TryOpen(GetFileName(conVar), out var stream))
|
||||
{
|
||||
using (stream)
|
||||
{
|
||||
var obj = JsonSerializer.Deserialize<T>(stream);
|
||||
@@ -56,7 +55,6 @@ public class ConfigurationService
|
||||
return obj;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
@@ -71,10 +69,11 @@ public class ConfigurationService
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(conVar);
|
||||
if (value == null) throw new ArgumentNullException(nameof(value));
|
||||
|
||||
|
||||
if (!conVar.Type.IsInstanceOfType(value))
|
||||
{
|
||||
_debugService.Error($"Type mismatch for config {conVar.Name}. Expected {conVar.Type}, got {value.GetType()}.");
|
||||
_debugService.Error(
|
||||
$"Type mismatch for config {conVar.Name}. Expected {conVar.Type}, got {value.GetType()}.");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -105,7 +104,8 @@ public class ConfigurationService
|
||||
|
||||
public static class ConfigExtensions
|
||||
{
|
||||
public static bool TryGetConfigValue<T>(this ConfigurationService configurationService, ConVar<T> conVar, [NotNullWhen(true)] out T? value)
|
||||
public static bool TryGetConfigValue<T>(this ConfigurationService configurationService, ConVar<T> conVar,
|
||||
[NotNullWhen(true)] out T? value)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(configurationService);
|
||||
ArgumentNullException.ThrowIfNull(conVar);
|
||||
|
||||
@@ -15,7 +15,8 @@ public partial class ContentService
|
||||
return fileService.ContentFileApi.Has(item.Hash);
|
||||
}
|
||||
|
||||
public async Task<List<RobustManifestItem>> EnsureItems(ManifestReader manifestReader, Uri downloadUri, ILoadingHandler loadingHandler,
|
||||
public async Task<List<RobustManifestItem>> EnsureItems(ManifestReader manifestReader, Uri downloadUri,
|
||||
ILoadingHandler loadingHandler,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
List<RobustManifestItem> allItems = [];
|
||||
@@ -66,7 +67,8 @@ public partial class ContentService
|
||||
return await EnsureItems(manifestReader, info.DownloadUri, loadingHandler, cancellationToken);
|
||||
}
|
||||
|
||||
public async Task Unpack(RobustManifestInfo info, IWriteFileApi otherApi, ILoadingHandler loadingHandler, CancellationToken cancellationToken)
|
||||
public async Task Unpack(RobustManifestInfo info, IWriteFileApi otherApi, ILoadingHandler loadingHandler,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
debugService.Log("Unpack manifest files");
|
||||
var items = await EnsureItems(info, loadingHandler, cancellationToken);
|
||||
@@ -83,11 +85,13 @@ public partial class ContentService
|
||||
{
|
||||
debugService.Error("OH FUCK!! " + item.Path);
|
||||
}
|
||||
|
||||
loadingHandler.AppendResolvedJob();
|
||||
}
|
||||
}
|
||||
|
||||
public async Task Download(Uri contentCdn, List<RobustManifestItem> toDownload, ILoadingHandler loadingHandler, CancellationToken cancellationToken)
|
||||
public async Task Download(Uri contentCdn, List<RobustManifestItem> toDownload, ILoadingHandler loadingHandler,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
if (toDownload.Count == 0 || cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
@@ -110,7 +114,8 @@ public partial class ContentService
|
||||
var request = new HttpRequestMessage(HttpMethod.Post, contentCdn);
|
||||
request.Headers.Add(
|
||||
"X-Robust-Download-Protocol",
|
||||
varService.GetConfigValue(CurrentConVar.ManifestDownloadProtocolVersion).ToString(CultureInfo.InvariantCulture));
|
||||
varService.GetConfigValue(CurrentConVar.ManifestDownloadProtocolVersion)
|
||||
.ToString(CultureInfo.InvariantCulture));
|
||||
|
||||
request.Content = new ByteArrayContent(requestBody);
|
||||
request.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
|
||||
@@ -123,7 +128,7 @@ public partial class ContentService
|
||||
debugService.Log("Downloading is cancelled!");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
downloadJobWatch.Dispose();
|
||||
|
||||
response.EnsureSuccessStatusCode();
|
||||
@@ -163,9 +168,9 @@ public partial class ContentService
|
||||
var readBuffer = new byte[1024];
|
||||
|
||||
var i = 0;
|
||||
|
||||
|
||||
loadingHandler.AppendJob(toDownload.Count);
|
||||
|
||||
|
||||
foreach (var item in toDownload)
|
||||
{
|
||||
if (cancellationToken.IsCancellationRequested)
|
||||
|
||||
@@ -5,20 +5,19 @@ namespace Nebula.Shared.Services;
|
||||
[ServiceRegister]
|
||||
public class DebugService : IDisposable
|
||||
{
|
||||
public ILogger Logger;
|
||||
|
||||
private static string LogPath = Path.Combine(FileService.RootPath, "log");
|
||||
public DateTime LogDate = DateTime.Now;
|
||||
public ILogger Logger;
|
||||
private FileStream LogStream;
|
||||
private StreamWriter LogWriter;
|
||||
|
||||
public DebugService(ILogger logger)
|
||||
{
|
||||
Logger = logger;
|
||||
|
||||
|
||||
//if (!Directory.Exists(LogPath))
|
||||
// Directory.CreateDirectory(LogPath);
|
||||
|
||||
// Directory.CreateDirectory(LogPath);
|
||||
|
||||
//var filename = String.Format("{0:yyyy-MM-dd}.txt", DateTime.Now);
|
||||
|
||||
//LogStream = File.Open(Path.Combine(LogPath, filename),
|
||||
@@ -26,6 +25,12 @@ public class DebugService : IDisposable
|
||||
//LogWriter = new StreamWriter(LogStream);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
LogWriter.Dispose();
|
||||
LogStream.Dispose();
|
||||
}
|
||||
|
||||
public void Debug(string message)
|
||||
{
|
||||
Log(LoggerCategory.Debug, message);
|
||||
@@ -44,16 +49,10 @@ public class DebugService : IDisposable
|
||||
public void Error(Exception e)
|
||||
{
|
||||
Error(e.Message + "\r\n" + e.StackTrace);
|
||||
if(e.InnerException != null)
|
||||
if (e.InnerException != null)
|
||||
Error(e.InnerException);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
LogWriter.Dispose();
|
||||
LogStream.Dispose();
|
||||
}
|
||||
|
||||
private void Log(LoggerCategory category, string message)
|
||||
{
|
||||
Logger.Log(category, message);
|
||||
|
||||
@@ -14,12 +14,12 @@ public sealed class EngineService
|
||||
private readonly RestService _restService;
|
||||
private readonly IServiceProvider _serviceProvider;
|
||||
private readonly ConfigurationService _varService;
|
||||
|
||||
|
||||
private readonly Task _currInfoTask;
|
||||
|
||||
public Dictionary<string, Module> ModuleInfos = default!;
|
||||
public Dictionary<string, EngineVersionInfo> VersionInfos = default!;
|
||||
|
||||
private Task _currInfoTask;
|
||||
|
||||
public EngineService(RestService restService, DebugService debugService, ConfigurationService varService,
|
||||
FileService fileService, IServiceProvider serviceProvider, AssemblyService assemblyService)
|
||||
{
|
||||
@@ -52,7 +52,7 @@ public sealed class EngineService
|
||||
public EngineBuildInfo? GetVersionInfo(string version)
|
||||
{
|
||||
CheckAndWaitValidation();
|
||||
|
||||
|
||||
if (!VersionInfos.TryGetValue(version, out var foundVersion))
|
||||
return null;
|
||||
|
||||
@@ -120,7 +120,7 @@ public sealed class EngineService
|
||||
public EngineBuildInfo? GetModuleBuildInfo(string moduleName, string version)
|
||||
{
|
||||
CheckAndWaitValidation();
|
||||
|
||||
|
||||
if (!ModuleInfos.TryGetValue(moduleName, out var module) ||
|
||||
!module.Versions.TryGetValue(version, out var value))
|
||||
return null;
|
||||
@@ -140,7 +140,7 @@ public sealed class EngineService
|
||||
public string ResolveModuleVersion(string moduleName, string engineVersion)
|
||||
{
|
||||
CheckAndWaitValidation();
|
||||
|
||||
|
||||
var engineVersionObj = Version.Parse(engineVersion);
|
||||
var module = ModuleInfos[moduleName];
|
||||
var selectedVersion = module.Versions.Select(kv => new { Version = Version.Parse(kv.Key), kv.Key, kv.Value })
|
||||
@@ -192,9 +192,9 @@ public sealed class EngineService
|
||||
|
||||
private void CheckAndWaitValidation()
|
||||
{
|
||||
if (_currInfoTask.IsCompleted)
|
||||
if (_currInfoTask.IsCompleted)
|
||||
return;
|
||||
|
||||
|
||||
_debugService.Debug("thinks is not done yet, please wait");
|
||||
_currInfoTask.Wait();
|
||||
}
|
||||
|
||||
@@ -14,12 +14,12 @@ public class FileService
|
||||
Environment.SpecialFolder.ApplicationData), "Datum");
|
||||
|
||||
private readonly DebugService _debugService;
|
||||
|
||||
public readonly IReadWriteFileApi ConfigurationApi;
|
||||
|
||||
public readonly IReadWriteFileApi ContentFileApi;
|
||||
public readonly IReadWriteFileApi EngineFileApi;
|
||||
public readonly IReadWriteFileApi ManifestFileApi;
|
||||
public readonly IReadWriteFileApi ConfigurationApi;
|
||||
|
||||
|
||||
private HashApi? _hashApi;
|
||||
|
||||
public FileService(DebugService debugService)
|
||||
|
||||
@@ -8,43 +8,43 @@ public class HubService
|
||||
private readonly ConfigurationService _configurationService;
|
||||
private readonly RestService _restService;
|
||||
|
||||
private readonly List<ServerHubInfo> _serverList = new();
|
||||
|
||||
public Action<HubServerChangedEventArgs>? HubServerChangedEventArgs;
|
||||
public Action? HubServerLoaded;
|
||||
|
||||
private readonly List<ServerHubInfo> _serverList = new();
|
||||
public IReadOnlyList<ServerHubInfo> ServerList => _serverList;
|
||||
|
||||
private bool _isUpdating = false;
|
||||
public bool IsUpdating => _isUpdating;
|
||||
public HubService(ConfigurationService configurationService, RestService restService)
|
||||
{
|
||||
_configurationService = configurationService;
|
||||
_restService = restService;
|
||||
|
||||
|
||||
UpdateHub();
|
||||
}
|
||||
|
||||
public IReadOnlyList<ServerHubInfo> ServerList => _serverList;
|
||||
public bool IsUpdating { get; private set; }
|
||||
|
||||
public async void UpdateHub()
|
||||
{
|
||||
if(_isUpdating) return;
|
||||
|
||||
if (IsUpdating) return;
|
||||
|
||||
_serverList.Clear();
|
||||
|
||||
_isUpdating = true;
|
||||
|
||||
IsUpdating = true;
|
||||
|
||||
HubServerChangedEventArgs?.Invoke(new HubServerChangedEventArgs([], HubServerChangeAction.Clear));
|
||||
|
||||
|
||||
foreach (var urlStr in _configurationService.GetConfigValue(CurrentConVar.Hub)!)
|
||||
{
|
||||
var servers = await _restService.GetAsyncDefault<List<ServerHubInfo>>(new Uri(urlStr), [], CancellationToken.None);
|
||||
var servers =
|
||||
await _restService.GetAsyncDefault<List<ServerHubInfo>>(new Uri(urlStr), [], CancellationToken.None);
|
||||
_serverList.AddRange(servers);
|
||||
HubServerChangedEventArgs?.Invoke(new HubServerChangedEventArgs(servers, HubServerChangeAction.Add));
|
||||
}
|
||||
|
||||
_isUpdating = false;
|
||||
|
||||
IsUpdating = false;
|
||||
HubServerLoaded?.Invoke();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public class HubServerChangedEventArgs : EventArgs
|
||||
@@ -61,5 +61,7 @@ public class HubServerChangedEventArgs : EventArgs
|
||||
|
||||
public enum HubServerChangeAction
|
||||
{
|
||||
Add, Remove, Clear,
|
||||
Add,
|
||||
Remove,
|
||||
Clear
|
||||
}
|
||||
@@ -3,12 +3,14 @@ namespace Nebula.Shared.Services;
|
||||
[ServiceRegister]
|
||||
public class PopupMessageService
|
||||
{
|
||||
public Action<object>? OnPopupRequired;
|
||||
public Action<object>? OnCloseRequired;
|
||||
public Action<object>? OnPopupRequired;
|
||||
|
||||
public void Popup(object obj)
|
||||
{
|
||||
OnPopupRequired?.Invoke(obj);
|
||||
}
|
||||
|
||||
public void ClosePopup(object obj)
|
||||
{
|
||||
OnCloseRequired?.Invoke(obj);
|
||||
|
||||
@@ -12,7 +12,8 @@ public sealed class RunnerService(
|
||||
EngineService engineService,
|
||||
AssemblyService assemblyService)
|
||||
{
|
||||
public async Task PrepareRun(RobustBuildInfo buildInfo, ILoadingHandler loadingHandler, CancellationToken cancellationToken)
|
||||
public async Task PrepareRun(RobustBuildInfo buildInfo, ILoadingHandler loadingHandler,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
debugService.Log("Prepare Content!");
|
||||
|
||||
@@ -20,12 +21,13 @@ public sealed class RunnerService(
|
||||
|
||||
if (engine is null)
|
||||
throw new Exception("Engine version is not usable: " + buildInfo.BuildInfo.Build.EngineVersion);
|
||||
|
||||
|
||||
await contentService.EnsureItems(buildInfo.RobustManifestInfo, loadingHandler, cancellationToken);
|
||||
await engineService.EnsureEngineModules("Robust.Client.WebView", buildInfo.BuildInfo.Build.EngineVersion);
|
||||
}
|
||||
|
||||
public async Task Run(string[] runArgs, RobustBuildInfo buildInfo, IRedialApi redialApi, ILoadingHandler loadingHandler,
|
||||
public async Task Run(string[] runArgs, RobustBuildInfo buildInfo, IRedialApi redialApi,
|
||||
ILoadingHandler loadingHandler,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
debugService.Log("Start Content!");
|
||||
@@ -49,7 +51,8 @@ public sealed class RunnerService(
|
||||
|
||||
var args = new MainArgs(runArgs, engine, redialApi, extraMounts);
|
||||
|
||||
if (!assemblyService.TryOpenAssembly(varService.GetConfigValue(CurrentConVar.RobustAssemblyName)!, engine, out var clientAssembly))
|
||||
if (!assemblyService.TryOpenAssembly(varService.GetConfigValue(CurrentConVar.RobustAssemblyName)!, engine,
|
||||
out var clientAssembly))
|
||||
throw new Exception("Unable to locate Robust.Client.dll in engine build!");
|
||||
|
||||
if (!assemblyService.TryGetLoader(clientAssembly, out var loader))
|
||||
|
||||
@@ -7,7 +7,7 @@ namespace Nebula.Shared.Utils;
|
||||
public static class Helper
|
||||
{
|
||||
public static readonly JsonSerializerOptions JsonWebOptions = new(JsonSerializerDefaults.Web);
|
||||
|
||||
|
||||
public static void OpenBrowser(string url)
|
||||
{
|
||||
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
|
||||
@@ -22,12 +22,8 @@ public static class Helper
|
||||
{
|
||||
Process.Start("open", url);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static async Task<T> AsJson<T>(this HttpContent content) where T : notnull
|
||||
{
|
||||
var str = await content.ReadAsStringAsync();
|
||||
|
||||
@@ -121,7 +121,7 @@ public static class UriHelper
|
||||
{
|
||||
return new Uri(GetServerApiAddress(serverAddress), "client.zip");
|
||||
}
|
||||
|
||||
|
||||
[Pure]
|
||||
public static Uri AddParameter(this Uri url, string paramName, string paramValue)
|
||||
{
|
||||
|
||||
132
Nebula.SourceGenerators/DependencyAutoGenerator.cs
Normal file
132
Nebula.SourceGenerators/DependencyAutoGenerator.cs
Normal file
@@ -0,0 +1,132 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Microsoft.CodeAnalysis;
|
||||
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
||||
using Microsoft.CodeAnalysis.Text;
|
||||
|
||||
namespace Nebula.SourceGenerators;
|
||||
|
||||
[Generator]
|
||||
public class DependencyAutoGenerator : IIncrementalGenerator
|
||||
{
|
||||
private static readonly string ConstructGeneratorAttributeName = "ConstructGeneratorAttribute";
|
||||
private static readonly string GeneratePropertyAttributeName = "GeneratePropertyAttribute";
|
||||
|
||||
public void Initialize(IncrementalGeneratorInitializationContext context)
|
||||
{
|
||||
GenerateAttribute(ConstructGeneratorAttributeName, "Class", context);
|
||||
GenerateAttribute(GeneratePropertyAttributeName, "Property", context);
|
||||
|
||||
var provider = context.SyntaxProvider
|
||||
.CreateSyntaxProvider(
|
||||
(s, _) => s is ClassDeclarationSyntax,
|
||||
(ctx, _) => GetClassDeclarationForSourceGen(ctx))
|
||||
.Where(t => t.reportAttributeFound)
|
||||
.Select((t, _) => t.Item1);
|
||||
|
||||
context.RegisterSourceOutput(context.CompilationProvider.Combine(provider.Collect()),
|
||||
(ctx, t) => GenerateCode(ctx, t.Left, t.Right));
|
||||
}
|
||||
|
||||
private static void GenerateAttribute(string attributeName, string usage,
|
||||
IncrementalGeneratorInitializationContext context)
|
||||
{
|
||||
var attributeSourceCode = $@"// <auto-generated/>
|
||||
|
||||
namespace SourceGen
|
||||
{{
|
||||
[System.AttributeUsage(System.AttributeTargets.{usage})]
|
||||
public class {attributeName} : System.Attribute
|
||||
{{
|
||||
}}
|
||||
}}";
|
||||
|
||||
context.RegisterPostInitializationOutput(ctx => ctx.AddSource(
|
||||
$"{attributeName}.g.cs",
|
||||
SourceText.From(attributeSourceCode, Encoding.UTF8)));
|
||||
}
|
||||
|
||||
private static (ClassDeclarationSyntax, bool reportAttributeFound) GetClassDeclarationForSourceGen(
|
||||
GeneratorSyntaxContext context)
|
||||
{
|
||||
var classDeclarationSyntax = (ClassDeclarationSyntax)context.Node;
|
||||
|
||||
foreach (var attributeListSyntax in classDeclarationSyntax.AttributeLists)
|
||||
foreach (var attributeSyntax in attributeListSyntax.Attributes)
|
||||
{
|
||||
if (context.SemanticModel.GetSymbolInfo(attributeSyntax).Symbol is not IMethodSymbol attributeSymbol)
|
||||
continue;
|
||||
|
||||
var attributeName = attributeSymbol.ContainingType.ToDisplayString();
|
||||
|
||||
if (attributeName == $"SourceGen.{ConstructGeneratorAttributeName}")
|
||||
return (classDeclarationSyntax, true);
|
||||
}
|
||||
|
||||
return (classDeclarationSyntax, false);
|
||||
}
|
||||
|
||||
private void GenerateCode(SourceProductionContext context, Compilation compilation,
|
||||
ImmutableArray<ClassDeclarationSyntax> classDeclarations)
|
||||
{
|
||||
foreach (var classDeclarationSyntax in classDeclarations)
|
||||
{
|
||||
var semanticModel = compilation.GetSemanticModel(classDeclarationSyntax.SyntaxTree);
|
||||
if (semanticModel.GetDeclaredSymbol(classDeclarationSyntax) is not INamedTypeSymbol classSymbol)
|
||||
continue;
|
||||
|
||||
var namespaceName = classSymbol.ContainingNamespace.ToDisplayString();
|
||||
var className = classDeclarationSyntax.Identifier.Text;
|
||||
|
||||
var defaultConstruct = $@"public {className}(){{}}";
|
||||
|
||||
var propertiesGenerated = GetProperties(classSymbol).ToList();
|
||||
|
||||
var constr = propertiesGenerated.Select(a => $"{a.Type.ToDisplayString()} g{a.Name}");
|
||||
var body = propertiesGenerated.Select(a => $"this.{a.Name} = g{a.Name};");
|
||||
|
||||
if (!constr.Any()) defaultConstruct = "";
|
||||
|
||||
var code = $@"// <auto-generated/>
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace {namespaceName};
|
||||
|
||||
partial class {className}
|
||||
{{
|
||||
|
||||
{defaultConstruct}
|
||||
public {className}(
|
||||
{string.Join(",\n\t\t", constr)}
|
||||
) : base(){{
|
||||
{string.Join("\n\t\t", body)}
|
||||
if (Avalonia.Controls.Design.IsDesignMode) InitialiseInDesignMode();
|
||||
else Initialise();
|
||||
}}
|
||||
}}
|
||||
";
|
||||
|
||||
// Add the source code to the compilation.
|
||||
context.AddSource($"{className}.g.cs", SourceText.From(code, Encoding.UTF8));
|
||||
}
|
||||
}
|
||||
|
||||
private static IEnumerable<IPropertySymbol> GetProperties(INamedTypeSymbol classSymbol)
|
||||
{
|
||||
return classSymbol.GetMembers().OfType<IPropertySymbol>().Where(a =>
|
||||
HasAttribute(a, $"SourceGen.{GeneratePropertyAttributeName}"));
|
||||
}
|
||||
|
||||
private static bool HasAttribute(ISymbol type, string attributeName)
|
||||
{
|
||||
foreach (var attribute in type.GetAttributes())
|
||||
if (attribute.AttributeClass?.ToDisplayString() == attributeName)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
26
Nebula.SourceGenerators/Nebula.SourceGenerators.csproj
Normal file
26
Nebula.SourceGenerators/Nebula.SourceGenerators.csproj
Normal file
@@ -0,0 +1,26 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netstandard2.0</TargetFramework>
|
||||
<IsPackable>false</IsPackable>
|
||||
<Nullable>enable</Nullable>
|
||||
<LangVersion>latest</LangVersion>
|
||||
|
||||
<EnforceExtendedAnalyzerRules>true</EnforceExtendedAnalyzerRules>
|
||||
<IsRoslynComponent>true</IsRoslynComponent>
|
||||
|
||||
<RootNamespace>Nebula.SourceGenerators</RootNamespace>
|
||||
<PackageId>Nebula.SourceGenerators</PackageId>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.CodeAnalysis.Analyzers" Version="3.3.4">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.3.0"/>
|
||||
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.Workspaces" Version="4.3.0"/>
|
||||
</ItemGroup>
|
||||
|
||||
|
||||
</Project>
|
||||
9
Nebula.SourceGenerators/Properties/launchSettings.json
Normal file
9
Nebula.SourceGenerators/Properties/launchSettings.json
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"$schema": "http://json.schemastore.org/launchsettings.json",
|
||||
"profiles": {
|
||||
"DebugRoslynSourceGenerator": {
|
||||
"commandName": "DebugRoslynComponent",
|
||||
"targetProject": "../Nebula.Shared/Nebula.Shared.csproj"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -8,6 +8,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nebula.Shared", "Nebula.Sha
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nebula.Runner", "Nebula.Runner\Nebula.Runner.csproj", "{82D96367-44B0-4F25-A094-CBE73B052B73}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nebula.SourceGenerators", "Nebula.SourceGenerators\Nebula.SourceGenerators.csproj", "{985A8F36-AFEB-4E85-8EDB-7C9DDEC698DC}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
@@ -30,5 +32,9 @@ Global
|
||||
{82D96367-44B0-4F25-A094-CBE73B052B73}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{82D96367-44B0-4F25-A094-CBE73B052B73}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{82D96367-44B0-4F25-A094-CBE73B052B73}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{985A8F36-AFEB-4E85-8EDB-7C9DDEC698DC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{985A8F36-AFEB-4E85-8EDB-7C9DDEC698DC}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{985A8F36-AFEB-4E85-8EDB-7C9DDEC698DC}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{985A8F36-AFEB-4E85-8EDB-7C9DDEC698DC}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
|
||||
Reference in New Issue
Block a user