- tweak: refactor funny
This commit is contained in:
@@ -8,6 +8,7 @@ using Avalonia.Markup.Xaml;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Nebula.Launcher.ViewModels;
|
||||
using Nebula.Launcher.Views;
|
||||
using Nebula.Shared;
|
||||
|
||||
namespace Nebula.Launcher;
|
||||
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
using Nebula.Launcher.Services;
|
||||
|
||||
namespace Nebula.Launcher;
|
||||
|
||||
public class AppNoUi(RunnerService runnerService, AuthService authService)
|
||||
{
|
||||
public void Run(string[] args)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
@@ -26,13 +26,7 @@
|
||||
</PackageReference>
|
||||
<PackageReference Include="CommunityToolkit.Mvvm" Version="8.2.1" />
|
||||
<PackageReference Include="JetBrains.Annotations" Version="2024.3.0" />
|
||||
<PackageReference Include="libsodium" Version="1.0.20" />
|
||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="9.0.0" />
|
||||
<PackageReference Include="Robust.Natives" Version="0.1.1" />
|
||||
<PackageReference Include="SharpZstd.Interop" Version="1.5.6" />
|
||||
<EmbeddedResource Include="Utils\runtime.json">
|
||||
<LogicalName>Utility.runtime.json</LogicalName>
|
||||
</EmbeddedResource>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
@@ -43,6 +37,6 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Robust.LoaderApi\Robust.LoaderApi\Robust.LoaderApi.csproj" />
|
||||
<ProjectReference Include="..\Nebula.Shared\Nebula.Shared.csproj" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
||||
@@ -1,40 +1,11 @@
|
||||
using Avalonia;
|
||||
using System;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace Nebula.Launcher;
|
||||
|
||||
sealed class Program
|
||||
public static class Program
|
||||
{
|
||||
// Initialization code. Don't use any Avalonia, third-party APIs or any
|
||||
// SynchronizationContext-reliant code before AppMain is called: things aren't initialized
|
||||
// yet and stuff might break.
|
||||
[STAThread]
|
||||
public static void Main(string[] args)
|
||||
{
|
||||
var uiMode = false;
|
||||
|
||||
if (uiMode)
|
||||
{
|
||||
BuildAvaloniaApp()
|
||||
.StartWithClassicDesktopLifetime(args);
|
||||
}
|
||||
else
|
||||
{
|
||||
RunNoUI(args);
|
||||
}
|
||||
}
|
||||
|
||||
private static void RunNoUI(string[] args)
|
||||
{
|
||||
var services = new ServiceCollection();
|
||||
services.AddAvaloniaServices();
|
||||
services.AddServices();
|
||||
services.AddSingleton<AppNoUi>(); //Separated because no ui
|
||||
|
||||
var serviceProvider = services.BuildServiceProvider();
|
||||
serviceProvider.GetService<AppNoUi>()!.Run(args);
|
||||
}
|
||||
public static void Main(string[] args) => BuildAvaloniaApp()
|
||||
.StartWithClassicDesktopLifetime(args);
|
||||
|
||||
// Avalonia configuration, don't remove; also used by visual designer.
|
||||
private static AppBuilder BuildAvaloniaApp()
|
||||
|
||||
@@ -36,58 +36,22 @@ public static class ServiceCollectionExtensions
|
||||
{
|
||||
services.AddTransient<MainWindow>();
|
||||
|
||||
foreach (var (viewModel, view) in GetTypesWithHelpAttribute(Assembly.GetExecutingAssembly()))
|
||||
foreach (var (viewModel, view, isSingleton) in GetTypesWithHelpAttribute(Assembly.GetExecutingAssembly()))
|
||||
{
|
||||
services.AddSingleton(viewModel);
|
||||
services.AddTransient(view);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static void AddServices(this IServiceCollection services)
|
||||
{
|
||||
foreach (var (type, inference) in GetServicesWithHelpAttribute(Assembly.GetExecutingAssembly()))
|
||||
{
|
||||
if (inference is null)
|
||||
{
|
||||
services.AddSingleton(type);
|
||||
}
|
||||
else
|
||||
{
|
||||
services.AddSingleton(inference, type);
|
||||
}
|
||||
if(isSingleton)services.AddSingleton(viewModel);
|
||||
else services.AddTransient(viewModel);
|
||||
if (view != null) services.AddTransient(view);
|
||||
}
|
||||
}
|
||||
|
||||
private static IEnumerable<(Type,Type)> GetTypesWithHelpAttribute(Assembly assembly) {
|
||||
private static IEnumerable<(Type,Type?,bool)> GetTypesWithHelpAttribute(Assembly assembly) {
|
||||
foreach(Type type in assembly.GetTypes())
|
||||
{
|
||||
var attr = type.GetCustomAttribute<ViewRegisterAttribute>();
|
||||
var attr = type.GetCustomAttribute<ViewModelRegisterAttribute>();
|
||||
if (attr is not null) {
|
||||
yield return (type, attr.Type);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static IEnumerable<(Type,Type?)> GetServicesWithHelpAttribute(Assembly assembly) {
|
||||
foreach(Type type in assembly.GetTypes())
|
||||
{
|
||||
var attr = type.GetCustomAttribute<ServiceRegisterAttribute>();
|
||||
if (attr is not null) {
|
||||
yield return (type, attr.Inference);
|
||||
yield return (type, attr.Type, attr.IsSingleton);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -1,48 +0,0 @@
|
||||
using System;
|
||||
using System.Data;
|
||||
using System.Net.Http;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Nebula.Launcher.Models;
|
||||
|
||||
namespace Nebula.Launcher.Services;
|
||||
|
||||
[ServiceRegister]
|
||||
public partial class ContentService
|
||||
{
|
||||
private readonly AssemblyService _assemblyService;
|
||||
private readonly DebugService _debugService;
|
||||
private readonly EngineService _engineService;
|
||||
private readonly FileService _fileService;
|
||||
private readonly HttpClient _http = new();
|
||||
private readonly RestService _restService;
|
||||
private readonly ConfigurationService _varService;
|
||||
|
||||
public ContentService(RestService restService, DebugService debugService, ConfigurationService varService,
|
||||
FileService fileService, EngineService engineService, AssemblyService assemblyService)
|
||||
{
|
||||
_restService = restService;
|
||||
_debugService = debugService;
|
||||
_varService = varService;
|
||||
_fileService = fileService;
|
||||
_engineService = engineService;
|
||||
_assemblyService = assemblyService;
|
||||
}
|
||||
|
||||
public async Task<RobustBuildInfo> GetBuildInfo(RobustUrl url, CancellationToken cancellationToken)
|
||||
{
|
||||
var info = new RobustBuildInfo();
|
||||
info.Url = url;
|
||||
var bi = await _restService.GetAsync<ServerInfo>(url.InfoUri, cancellationToken);
|
||||
if (bi.Value is null) throw new NoNullAllowedException();
|
||||
info.BuildInfo = bi.Value;
|
||||
Console.WriteLine(info.BuildInfo);
|
||||
info.RobustManifestInfo = info.BuildInfo.Build.Acz
|
||||
? new RobustManifestInfo(new RobustPath(info.Url, "manifest.txt"), new RobustPath(info.Url, "download"),
|
||||
bi.Value.Build.ManifestHash)
|
||||
: new RobustManifestInfo(new Uri(info.BuildInfo.Build.ManifestUrl),
|
||||
new Uri(info.BuildInfo.Build.ManifestDownloadUrl), bi.Value.Build.ManifestHash);
|
||||
|
||||
return info;
|
||||
}
|
||||
}
|
||||
@@ -1,36 +0,0 @@
|
||||
using System;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Nebula.Launcher.ViewModels;
|
||||
|
||||
namespace Nebula.Launcher.Services;
|
||||
|
||||
[ServiceRegister]
|
||||
public class PopupMessageService
|
||||
{
|
||||
private readonly IServiceProvider _serviceProvider;
|
||||
|
||||
public Action<PopupViewModelBase?>? OnPopupRequired;
|
||||
|
||||
public PopupMessageService(IServiceProvider serviceProvider)
|
||||
{
|
||||
_serviceProvider = serviceProvider;
|
||||
|
||||
}
|
||||
|
||||
public void PopupInfo(string info)
|
||||
{
|
||||
var message = _serviceProvider.GetService<InfoPopupViewModel>();
|
||||
message.InfoText = info;
|
||||
PopupMessage(message);
|
||||
}
|
||||
|
||||
public void PopupMessage(PopupViewModelBase viewModelBase)
|
||||
{
|
||||
OnPopupRequired?.Invoke(viewModelBase);
|
||||
}
|
||||
|
||||
public void ClosePopup()
|
||||
{
|
||||
OnPopupRequired?.Invoke(null);
|
||||
}
|
||||
}
|
||||
@@ -3,12 +3,12 @@ using System;
|
||||
namespace Nebula.Launcher.ViewHelper;
|
||||
|
||||
[AttributeUsage(AttributeTargets.Class)]
|
||||
public class ViewRegisterAttribute : Attribute
|
||||
public class ViewModelRegisterAttribute : Attribute
|
||||
{
|
||||
public Type Type { get; }
|
||||
public Type? Type { get; }
|
||||
public bool IsSingleton { get; }
|
||||
|
||||
public ViewRegisterAttribute(Type type, bool isSingleton = true)
|
||||
public ViewModelRegisterAttribute(Type? type = null, bool isSingleton = true)
|
||||
{
|
||||
Type = type;
|
||||
IsSingleton = isSingleton;
|
||||
@@ -14,7 +14,7 @@ public class ViewLocator : IDataTemplate
|
||||
if (param is null)
|
||||
return null;
|
||||
|
||||
var type = param.GetType().GetCustomAttribute<ViewRegisterAttribute>()?.Type;
|
||||
var type = param.GetType().GetCustomAttribute<ViewModelRegisterAttribute>()?.Type;
|
||||
|
||||
if (type != null)
|
||||
{
|
||||
|
||||
@@ -4,14 +4,15 @@ using System.Linq;
|
||||
using System.Windows.Input;
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using CommunityToolkit.Mvvm.Input;
|
||||
using Nebula.Launcher.Services;
|
||||
using Nebula.Launcher.Utils;
|
||||
using Nebula.Launcher.ViewHelper;
|
||||
using Nebula.Launcher.Views.Pages;
|
||||
using Nebula.Shared;
|
||||
using Nebula.Shared.Services;
|
||||
using Nebula.Shared.Utils;
|
||||
|
||||
namespace Nebula.Launcher.ViewModels;
|
||||
|
||||
[ViewRegister(typeof(AccountInfoView))]
|
||||
[ViewModelRegister(typeof(AccountInfoView))]
|
||||
public partial class AccountInfoViewModel : ViewModelBase
|
||||
{
|
||||
private readonly PopupMessageService _popupMessageService;
|
||||
@@ -79,12 +80,12 @@ public partial class AccountInfoViewModel : ViewModelBase
|
||||
|
||||
public async void DoAuth()
|
||||
{
|
||||
_popupMessageService.PopupInfo("Auth think, please wait...");
|
||||
_popupMessageService.Popup("Auth think, please wait...");
|
||||
|
||||
if(await _authService.Auth(CurrentAlp))
|
||||
{
|
||||
_popupMessageService.ClosePopup();
|
||||
_popupMessageService.PopupInfo("Hello, " + _authService.SelectedAuth!.AuthLoginPassword.Login);
|
||||
_popupMessageService.Popup("Hello, " + _authService.SelectedAuth!.AuthLoginPassword.Login);
|
||||
IsLogged = true;
|
||||
_configurationService.SetConfigValue(CurrentConVar.AuthCurrent, CurrentAlp);
|
||||
}
|
||||
@@ -92,7 +93,7 @@ public partial class AccountInfoViewModel : ViewModelBase
|
||||
{
|
||||
_popupMessageService.ClosePopup();
|
||||
Logout();
|
||||
_popupMessageService.PopupInfo("Well, shit is happened: " + _authService.Reason);
|
||||
_popupMessageService.Popup("Well, shit is happened: " + _authService.Reason);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -100,7 +101,7 @@ public partial class AccountInfoViewModel : ViewModelBase
|
||||
{
|
||||
IsLogged = false;
|
||||
CurrentAlp = new AuthLoginPassword("", "", "");
|
||||
_authService.SelectedAuth = null;
|
||||
_authService.ClearAuth();
|
||||
}
|
||||
|
||||
private void UpdateAuthMenu()
|
||||
|
||||
@@ -5,7 +5,7 @@ using Nebula.Launcher.Views.Popup;
|
||||
|
||||
namespace Nebula.Launcher.ViewModels;
|
||||
|
||||
[ViewRegister(typeof(InfoPopupView), false)]
|
||||
[ViewModelRegister(typeof(InfoPopupView), false)]
|
||||
public partial class InfoPopupViewModel : PopupViewModelBase
|
||||
{
|
||||
public InfoPopupViewModel()
|
||||
|
||||
@@ -5,15 +5,15 @@ using System.Linq;
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using CommunityToolkit.Mvvm.Input;
|
||||
using JetBrains.Annotations;
|
||||
using Nebula.Launcher.Models;
|
||||
using Nebula.Launcher.Services;
|
||||
using Nebula.Launcher.Utils;
|
||||
using Nebula.Launcher.ViewHelper;
|
||||
using Nebula.Launcher.Views;
|
||||
using Nebula.Shared.Models;
|
||||
using Nebula.Shared.Services;
|
||||
using Nebula.Shared.Utils;
|
||||
|
||||
namespace Nebula.Launcher.ViewModels;
|
||||
|
||||
[ViewRegister(typeof(MainView))]
|
||||
[ViewModelRegister(typeof(MainView))]
|
||||
public partial class MainViewModel : ViewModelBase
|
||||
{
|
||||
public MainViewModel()
|
||||
@@ -111,15 +111,23 @@ public partial class MainViewModel : ViewModelBase
|
||||
Helper.OpenBrowser("https://cinka.ru/nebula-launcher/");
|
||||
}
|
||||
|
||||
private void OnPopupRequired(PopupViewModelBase? viewModelBase)
|
||||
private void OnPopupRequired(object? viewModelBase)
|
||||
{
|
||||
if (viewModelBase is null)
|
||||
switch (viewModelBase)
|
||||
{
|
||||
ClosePopup();
|
||||
}
|
||||
else
|
||||
{
|
||||
PopupMessage(viewModelBase);
|
||||
case null:
|
||||
ClosePopup();
|
||||
break;
|
||||
case string str:
|
||||
{
|
||||
var view = GetViewModel<InfoPopupViewModel>();
|
||||
view.InfoText = str;
|
||||
PopupMessage(view);
|
||||
break;
|
||||
}
|
||||
case PopupViewModelBase @base:
|
||||
PopupMessage(@base);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,33 +1,41 @@
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Nebula.Launcher.Models;
|
||||
using Nebula.Launcher.Services;
|
||||
using Nebula.Launcher.ViewHelper;
|
||||
using Nebula.Shared.Models;
|
||||
|
||||
namespace Nebula.Launcher.ViewModels;
|
||||
|
||||
[ViewModelRegister(isSingleton:false)]
|
||||
public partial class ServerEntryModelView : ViewModelBase
|
||||
{
|
||||
|
||||
private readonly IServiceProvider _serviceProvider;
|
||||
private readonly RunnerService _runnerService;
|
||||
private readonly PopupMessageService _popupMessageService;
|
||||
private readonly RestService _restService;
|
||||
[ObservableProperty] private bool _runVisible = true;
|
||||
|
||||
public ServerHubInfo ServerHubInfo { get; }
|
||||
public ServerHubInfo ServerHubInfo { get; set; }
|
||||
|
||||
public ServerEntryModelView(IServiceProvider serviceProvider, ServerHubInfo serverHubInfo) : base(serviceProvider)
|
||||
public ServerEntryModelView() : base()
|
||||
{
|
||||
_serviceProvider = serviceProvider;
|
||||
_runnerService = serviceProvider.GetService<RunnerService>()!;
|
||||
_popupMessageService = serviceProvider.GetService<PopupMessageService>()!;
|
||||
_restService = serviceProvider.GetService<RestService>()!;
|
||||
ServerHubInfo = serverHubInfo;
|
||||
}
|
||||
|
||||
public async void OnConnectRequired()
|
||||
public ServerEntryModelView(IServiceProvider serviceProvider) : base(serviceProvider)
|
||||
{
|
||||
_popupMessageService.PopupInfo("Running server: " + ServerHubInfo.StatusData.Name);
|
||||
await _runnerService.RunGame(ServerHubInfo.Address);
|
||||
}
|
||||
|
||||
public void RunInstance()
|
||||
{
|
||||
var p = Process.Start("./Nebula.Runner", "a b c");
|
||||
p.BeginOutputReadLine();
|
||||
p.BeginErrorReadLine();
|
||||
}
|
||||
|
||||
|
||||
public void ReadLog()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public void StopInstance()
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
@@ -3,14 +3,14 @@ using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Linq;
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using Nebula.Launcher.Models;
|
||||
using Nebula.Launcher.Services;
|
||||
using Nebula.Launcher.ViewHelper;
|
||||
using Nebula.Launcher.Views.Pages;
|
||||
using Nebula.Shared.Models;
|
||||
using Nebula.Shared.Services;
|
||||
|
||||
namespace Nebula.Launcher.ViewModels;
|
||||
|
||||
[ViewRegister(typeof(ServerListView))]
|
||||
[ViewModelRegister(typeof(ServerListView))]
|
||||
public partial class ServerListViewModel : ViewModelBase
|
||||
{
|
||||
private readonly IServiceProvider _serviceProvider;
|
||||
@@ -84,7 +84,9 @@ public partial class ServerListViewModel : ViewModelBase
|
||||
|
||||
private ServerEntryModelView CreateServerView(ServerHubInfo serverHubInfo)
|
||||
{
|
||||
return new ServerEntryModelView(_serviceProvider, serverHubInfo);
|
||||
var svn = GetViewModel<ServerEntryModelView>();
|
||||
svn.ServerHubInfo = serverHubInfo;
|
||||
return svn;
|
||||
}
|
||||
|
||||
public void FilterRequired()
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
xmlns:converters="clr-namespace:Nebula.Launcher.Converters"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:models="clr-namespace:Nebula.Launcher.Models"
|
||||
xmlns:models="clr-namespace:Nebula.Shared.Models;assembly=Nebula.Shared"
|
||||
xmlns:viewModels="clr-namespace:Nebula.Launcher.ViewModels"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
|
||||
<Design.DataContext>
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
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:models="clr-namespace:Nebula.Launcher.Models"
|
||||
xmlns:viewModels="clr-namespace:Nebula.Launcher.ViewModels"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
|
||||
|
||||
@@ -25,7 +24,7 @@
|
||||
<ListBox.ItemTemplate>
|
||||
<DataTemplate DataType="{x:Type viewModels:ServerEntryModelView}">
|
||||
<Grid
|
||||
ColumnDefinitions="*,90"
|
||||
ColumnDefinitions="*,120"
|
||||
Margin="0,5,0,5"
|
||||
RowDefinitions="30,*">
|
||||
<Border
|
||||
@@ -38,7 +37,7 @@
|
||||
</Label>
|
||||
</Border>
|
||||
<Border
|
||||
BorderThickness="2,0,0,0"
|
||||
BorderThickness="2,0,2,0"
|
||||
CornerRadius="0"
|
||||
Grid.Column="1"
|
||||
Grid.Row="0"
|
||||
@@ -69,9 +68,9 @@
|
||||
</Border.Background>
|
||||
<Border
|
||||
BorderThickness="0,2,2,0"
|
||||
CornerRadius="0,10,10,10"
|
||||
CornerRadius="0,0,10,10"
|
||||
IsVisible="True"
|
||||
Margin="0,0,5,0"
|
||||
Margin="0,0,0,0"
|
||||
Opacity="40"
|
||||
Padding="0">
|
||||
<UniformGrid Margin="15,5,15,0">
|
||||
@@ -121,18 +120,36 @@
|
||||
</Border>
|
||||
|
||||
<Panel Grid.Column="1" Grid.Row="1">
|
||||
<Border Classes="ButtonBack" CornerRadius="0,0,10,0">
|
||||
<Button
|
||||
Command="{Binding OnConnectRequired}"
|
||||
CornerRadius="0,0,10,0"
|
||||
HorizontalAlignment="Stretch"
|
||||
Padding="0"
|
||||
VerticalAlignment="Stretch">
|
||||
<Button
|
||||
Command="{Binding RunInstance}"
|
||||
IsVisible="{Binding RunVisible}"
|
||||
HorizontalAlignment="Stretch"
|
||||
CornerRadius="10,0,10,10"
|
||||
VerticalAlignment="Stretch">
|
||||
<Label HorizontalAlignment="Center" VerticalAlignment="Center">
|
||||
Play
|
||||
</Label>
|
||||
</Button>
|
||||
<Grid Grid.ColumnDefinitions="*,*" IsVisible="{Binding !RunVisible}">
|
||||
<Button Command="{Binding ReadLog}"
|
||||
CornerRadius="10,0,0,10"
|
||||
Margin="0,0,1,0"
|
||||
VerticalAlignment="Stretch"
|
||||
HorizontalAlignment="Stretch">
|
||||
<Label HorizontalAlignment="Center" VerticalAlignment="Center">
|
||||
Play
|
||||
Log
|
||||
</Label>
|
||||
</Button>
|
||||
</Border>
|
||||
<Button Grid.Column="1" HorizontalAlignment="Stretch"
|
||||
CornerRadius="0,0,10,0"
|
||||
Margin="1,0,0,0"
|
||||
VerticalAlignment="Stretch"
|
||||
Command="{Binding StopInstance}">
|
||||
<Label HorizontalAlignment="Center" VerticalAlignment="Center">
|
||||
Stop
|
||||
</Label>
|
||||
</Button>
|
||||
</Grid>
|
||||
</Panel>
|
||||
</Grid>
|
||||
</DataTemplate>
|
||||
|
||||
14
Nebula.Runner/App.cs
Normal file
14
Nebula.Runner/App.cs
Normal file
@@ -0,0 +1,14 @@
|
||||
using Nebula.Shared;
|
||||
using Nebula.Shared.Services;
|
||||
|
||||
namespace Nebula.Runner;
|
||||
|
||||
[ServiceRegister]
|
||||
public class App(DebugService debugService)
|
||||
{
|
||||
|
||||
public void Run(string[] args)
|
||||
{
|
||||
debugService.Log("HELLO!!! " + string.Join(" ",args));
|
||||
}
|
||||
}
|
||||
17
Nebula.Runner/Nebula.Runner.csproj
Normal file
17
Nebula.Runner/Nebula.Runner.csproj
Normal file
@@ -0,0 +1,17 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Nebula.Shared\Nebula.Shared.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="9.0.0" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
16
Nebula.Runner/Program.cs
Normal file
16
Nebula.Runner/Program.cs
Normal file
@@ -0,0 +1,16 @@
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Nebula.Shared;
|
||||
|
||||
namespace Nebula.Runner;
|
||||
|
||||
public static class Program
|
||||
{
|
||||
public static void Main(string[] args)
|
||||
{
|
||||
var services = new ServiceCollection();
|
||||
services.AddServices();
|
||||
|
||||
var serviceProvider = services.BuildServiceProvider();
|
||||
serviceProvider.GetService<App>()!.Run(args);
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
using Nebula.Launcher.Services;
|
||||
using Nebula.Shared.Services;
|
||||
|
||||
namespace Nebula.Launcher;
|
||||
namespace Nebula.Shared;
|
||||
|
||||
public static class CurrentConVar
|
||||
{
|
||||
@@ -1,8 +1,6 @@
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using Robust.LoaderApi;
|
||||
using Robust.LoaderApi;
|
||||
|
||||
namespace Nebula.Launcher.FileApis;
|
||||
namespace Nebula.Shared.FileApis;
|
||||
|
||||
public class AssemblyApi : IFileApi
|
||||
{
|
||||
@@ -12,7 +10,7 @@ public class AssemblyApi : IFileApi
|
||||
{
|
||||
_root = root;
|
||||
}
|
||||
|
||||
|
||||
public bool TryOpen(string path, out Stream? stream)
|
||||
{
|
||||
return _root.TryOpen(path, out stream);
|
||||
@@ -1,9 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using Nebula.Launcher.FileApis.Interfaces;
|
||||
using Nebula.Shared.FileApis.Interfaces;
|
||||
|
||||
namespace Nebula.Launcher.FileApis;
|
||||
namespace Nebula.Shared.FileApis;
|
||||
|
||||
public class FileApi : IReadWriteFileApi
|
||||
{
|
||||
@@ -1,10 +1,7 @@
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using Nebula.Launcher.Models;
|
||||
using Nebula.Launcher.Utils;
|
||||
using Nebula.Shared.Models;
|
||||
using Robust.LoaderApi;
|
||||
|
||||
namespace Nebula.Launcher.FileApis;
|
||||
namespace Nebula.Shared.FileApis;
|
||||
|
||||
public class HashApi : IFileApi
|
||||
{
|
||||
@@ -1,6 +1,6 @@
|
||||
using Robust.LoaderApi;
|
||||
|
||||
namespace Nebula.Launcher.FileApis.Interfaces;
|
||||
namespace Nebula.Shared.FileApis.Interfaces;
|
||||
|
||||
public interface IReadWriteFileApi : IFileApi, IWriteFileApi
|
||||
{
|
||||
@@ -1,6 +1,4 @@
|
||||
using System.IO;
|
||||
|
||||
namespace Nebula.Launcher.FileApis.Interfaces;
|
||||
namespace Nebula.Shared.FileApis.Interfaces;
|
||||
|
||||
public interface IWriteFileApi
|
||||
{
|
||||
@@ -1,12 +1,9 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.IO;
|
||||
using System.IO.Compression;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using Robust.LoaderApi;
|
||||
|
||||
namespace Nebula.Launcher.FileApis;
|
||||
namespace Nebula.Shared.FileApis;
|
||||
|
||||
public sealed class ZipFileApi : IFileApi
|
||||
{
|
||||
@@ -1,6 +1,4 @@
|
||||
using System;
|
||||
|
||||
namespace Nebula.Launcher.Models.Auth;
|
||||
namespace Nebula.Shared.Models.Auth;
|
||||
|
||||
public sealed record AuthenticateRequest(string? Username, Guid? UserId, string Password, string? TfaCode = null)
|
||||
{
|
||||
@@ -1,5 +1,3 @@
|
||||
using System;
|
||||
|
||||
namespace Nebula.Launcher.Models.Auth;
|
||||
namespace Nebula.Shared.Models.Auth;
|
||||
|
||||
public sealed record AuthenticateResponse(string Token, string Username, Guid UserId, DateTimeOffset ExpireTime);
|
||||
@@ -1,6 +1,4 @@
|
||||
using System;
|
||||
|
||||
namespace Nebula.Launcher.Models.Auth;
|
||||
namespace Nebula.Shared.Models.Auth;
|
||||
|
||||
public class LoginInfo
|
||||
{
|
||||
@@ -1,6 +1,4 @@
|
||||
using System;
|
||||
|
||||
namespace Nebula.Launcher.Models.Auth;
|
||||
namespace Nebula.Shared.Models.Auth;
|
||||
|
||||
public readonly struct LoginToken
|
||||
{
|
||||
@@ -1,4 +1,4 @@
|
||||
namespace Nebula.Launcher.Models;
|
||||
namespace Nebula.Shared.Models;
|
||||
|
||||
public enum ContentCompressionScheme
|
||||
{
|
||||
@@ -1,6 +1,4 @@
|
||||
using System;
|
||||
|
||||
namespace Nebula.Launcher.Models;
|
||||
namespace Nebula.Shared.Models;
|
||||
|
||||
[Flags]
|
||||
public enum DownloadStreamHeaderFlags
|
||||
@@ -1,4 +1,2 @@
|
||||
using System;
|
||||
|
||||
namespace Nebula.Launcher.Models;
|
||||
namespace Nebula.Shared.Models;
|
||||
public record ListItemTemplate(Type ModelType, string IconKey, string Label);
|
||||
@@ -1,7 +1,6 @@
|
||||
using System.Collections.Generic;
|
||||
using Robust.LoaderApi;
|
||||
|
||||
namespace Nebula.Launcher.Models;
|
||||
namespace Nebula.Shared.Models;
|
||||
|
||||
public sealed class MainArgs : IMainArgs
|
||||
{
|
||||
@@ -1,4 +1,4 @@
|
||||
namespace Nebula.Launcher.Models;
|
||||
namespace Nebula.Shared.Models;
|
||||
|
||||
public class RobustBuildInfo
|
||||
{
|
||||
@@ -1,5 +1,3 @@
|
||||
using System;
|
||||
|
||||
namespace Nebula.Launcher.Models;
|
||||
namespace Nebula.Shared.Models;
|
||||
|
||||
public record struct RobustManifestInfo(Uri ManifestUri, Uri DownloadUri, string Hash);
|
||||
@@ -1,3 +1,3 @@
|
||||
namespace Nebula.Launcher.Models;
|
||||
namespace Nebula.Shared.Models;
|
||||
|
||||
public record struct RobustManifestItem(string Hash, string Path, int Id);
|
||||
@@ -1,8 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace Nebula.Launcher.Models;
|
||||
namespace Nebula.Shared.Models;
|
||||
|
||||
public sealed record AuthInfo(
|
||||
[property: JsonPropertyName("mode")] string Mode,
|
||||
@@ -1,7 +1,6 @@
|
||||
using System;
|
||||
using Nebula.Launcher.Utils;
|
||||
using Nebula.Shared.Utils;
|
||||
|
||||
namespace Nebula.Launcher.Models;
|
||||
namespace Nebula.Shared.Models;
|
||||
|
||||
public class RobustUrl
|
||||
{
|
||||
25
Nebula.Shared/Nebula.Shared.csproj
Normal file
25
Nebula.Shared/Nebula.Shared.csproj
Normal file
@@ -0,0 +1,25 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Include="Utils\runtime.json" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="9.0.0" />
|
||||
<PackageReference Include="libsodium" Version="1.0.20" />
|
||||
<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" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
44
Nebula.Shared/ServiceManager.cs
Normal file
44
Nebula.Shared/ServiceManager.cs
Normal file
@@ -0,0 +1,44 @@
|
||||
using System.Reflection;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace Nebula.Shared;
|
||||
|
||||
public static class ServiceExt
|
||||
{
|
||||
public static void AddServices(this IServiceCollection services)
|
||||
{
|
||||
foreach (var (type, inference) in GetServicesWithHelpAttribute(Assembly.GetExecutingAssembly()))
|
||||
{
|
||||
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())
|
||||
{
|
||||
var attr = type.GetCustomAttribute<ServiceRegisterAttribute>();
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -1,19 +1,16 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.IO;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Reflection;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Runtime.Loader;
|
||||
using Nebula.Launcher.FileApis;
|
||||
using Nebula.Shared.FileApis;
|
||||
using Robust.LoaderApi;
|
||||
|
||||
namespace Nebula.Launcher.Services;
|
||||
namespace Nebula.Shared.Services;
|
||||
|
||||
[ServiceRegister]
|
||||
public class AssemblyService
|
||||
{
|
||||
private readonly List<Assembly> _assemblies = new();
|
||||
private readonly Dictionary<string,Assembly> _assemblies = new();
|
||||
private readonly DebugService _debugService;
|
||||
|
||||
public AssemblyService(DebugService debugService)
|
||||
@@ -21,12 +18,12 @@ public class AssemblyService
|
||||
_debugService = debugService;
|
||||
}
|
||||
|
||||
public IReadOnlyList<Assembly> Assemblies => _assemblies;
|
||||
//public IReadOnlyList<Assembly> Assemblies => _assemblies;
|
||||
|
||||
public AssemblyApi Mount(IFileApi fileApi)
|
||||
public AssemblyApi Mount(IFileApi fileApi, string apiName = "")
|
||||
{
|
||||
var asmApi = new AssemblyApi(fileApi);
|
||||
AssemblyLoadContext.Default.Resolving += (context, name) => OnAssemblyResolving(context, name, asmApi);
|
||||
AssemblyLoadContext.Default.Resolving += (context, name) => OnAssemblyResolving(context, name, asmApi, apiName);
|
||||
AssemblyLoadContext.Default.ResolvingUnmanagedDll += LoadContextOnResolvingUnmanaged;
|
||||
|
||||
return asmApi;
|
||||
@@ -56,6 +53,11 @@ public class AssemblyService
|
||||
|
||||
public bool TryOpenAssembly(string name, AssemblyApi assemblyApi, [NotNullWhen(true)] out Assembly? assembly)
|
||||
{
|
||||
if (_assemblies.TryGetValue(name, out assembly))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!TryOpenAssemblyStream(name, assemblyApi, out var asm, out var pdb))
|
||||
{
|
||||
assembly = null;
|
||||
@@ -64,9 +66,8 @@ public class AssemblyService
|
||||
|
||||
assembly = AssemblyLoadContext.Default.LoadFromStream(asm, pdb);
|
||||
_debugService.Log("LOADED ASSEMBLY " + name);
|
||||
|
||||
|
||||
if (!_assemblies.Contains(assembly)) _assemblies.Add(assembly);
|
||||
|
||||
_assemblies.Add(name, assembly);
|
||||
|
||||
asm.Dispose();
|
||||
pdb?.Dispose();
|
||||
@@ -86,9 +87,11 @@ public class AssemblyService
|
||||
return true;
|
||||
}
|
||||
|
||||
private Assembly? OnAssemblyResolving(AssemblyLoadContext context, AssemblyName name, AssemblyApi assemblyApi)
|
||||
private Assembly? OnAssemblyResolving(AssemblyLoadContext context, AssemblyName name, AssemblyApi assemblyApi,
|
||||
string apiName)
|
||||
{
|
||||
_debugService.Debug("Resolving assembly from FileAPI: " + name.Name);
|
||||
|
||||
_debugService.Debug($"Resolving assembly from {apiName}: {name.Name}");
|
||||
return TryOpenAssembly(name.Name!, assemblyApi, out var assembly) ? assembly : null;
|
||||
}
|
||||
|
||||
@@ -1,45 +1,32 @@
|
||||
using System;
|
||||
using System.Net.Http;
|
||||
using System.Net.Http.Headers;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Input;
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using Nebula.Launcher.Models.Auth;
|
||||
using System.Net.Http.Headers;
|
||||
using Nebula.Shared.Models.Auth;
|
||||
|
||||
namespace Nebula.Launcher.Services;
|
||||
namespace Nebula.Shared.Services;
|
||||
|
||||
[ServiceRegister]
|
||||
public partial class AuthService : ObservableObject
|
||||
public partial class AuthService(
|
||||
RestService restService,
|
||||
DebugService debugService,
|
||||
CancellationService cancellationService)
|
||||
{
|
||||
private readonly HttpClient _httpClient = new();
|
||||
private readonly RestService _restService;
|
||||
private readonly DebugService _debugService;
|
||||
|
||||
[ObservableProperty]
|
||||
private CurrentAuthInfo? _selectedAuth;
|
||||
public CurrentAuthInfo? SelectedAuth { get; internal set; }
|
||||
|
||||
public string Reason = "";
|
||||
|
||||
public AuthService(RestService restService, DebugService debugService)
|
||||
{
|
||||
_restService = restService;
|
||||
_debugService = debugService;
|
||||
}
|
||||
|
||||
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}");
|
||||
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, CancellationToken.None);
|
||||
await restService.PostAsync<AuthenticateResponse, AuthenticateRequest>(
|
||||
new AuthenticateRequest(login, password), authUrl, cancellationService.Token);
|
||||
|
||||
if (result.Value is null)
|
||||
{
|
||||
@@ -53,6 +40,11 @@ public partial class AuthService : ObservableObject
|
||||
return true;
|
||||
}
|
||||
|
||||
public void ClearAuth()
|
||||
{
|
||||
SelectedAuth = null;
|
||||
}
|
||||
|
||||
public async Task<bool> EnsureToken()
|
||||
{
|
||||
if (SelectedAuth is null) return false;
|
||||
@@ -61,7 +53,7 @@ public partial class AuthService : ObservableObject
|
||||
|
||||
using var requestMessage = new HttpRequestMessage(HttpMethod.Get, authUrl);
|
||||
requestMessage.Headers.Authorization = new AuthenticationHeaderValue("SS14Auth", SelectedAuth.Token.Token);
|
||||
using var resp = await _httpClient.SendAsync(requestMessage);
|
||||
using var resp = await _httpClient.SendAsync(requestMessage, cancellationService.Token);
|
||||
|
||||
if (!resp.IsSuccessStatusCode) SelectedAuth = null;
|
||||
|
||||
14
Nebula.Shared/Services/CancellationService.cs
Normal file
14
Nebula.Shared/Services/CancellationService.cs
Normal file
@@ -0,0 +1,14 @@
|
||||
namespace Nebula.Shared.Services;
|
||||
|
||||
[ServiceRegister]
|
||||
public class CancellationService
|
||||
{
|
||||
private CancellationTokenSource _cancellationTokenSource = new();
|
||||
public CancellationToken Token => _cancellationTokenSource.Token;
|
||||
|
||||
public void Cancel()
|
||||
{
|
||||
_cancellationTokenSource.Cancel();
|
||||
_cancellationTokenSource = new CancellationTokenSource();
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,7 @@
|
||||
using System;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.IO;
|
||||
using System.Text.Json;
|
||||
|
||||
namespace Nebula.Launcher.Services;
|
||||
namespace Nebula.Shared.Services;
|
||||
|
||||
public class ConVar<T>
|
||||
{
|
||||
@@ -1,24 +1,18 @@
|
||||
using System;
|
||||
using System.Buffers.Binary;
|
||||
using System.Collections.Generic;
|
||||
using System.Buffers.Binary;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Net.Http;
|
||||
using System.Net.Http.Headers;
|
||||
using System.Numerics;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Nebula.Launcher.FileApis.Interfaces;
|
||||
using Nebula.Launcher.Models;
|
||||
using Nebula.Launcher.Utils;
|
||||
using Nebula.Shared.FileApis.Interfaces;
|
||||
using Nebula.Shared.Models;
|
||||
using Nebula.Shared.Utils;
|
||||
|
||||
namespace Nebula.Launcher.Services;
|
||||
namespace Nebula.Shared.Services;
|
||||
|
||||
public partial class ContentService
|
||||
{
|
||||
public bool CheckManifestExist(RobustManifestItem item)
|
||||
{
|
||||
return _fileService.ContentFileApi.Has(item.Hash);
|
||||
return fileService.ContentFileApi.Has(item.Hash);
|
||||
}
|
||||
|
||||
public async Task<List<RobustManifestItem>> EnsureItems(ManifestReader manifestReader, Uri downloadUri,
|
||||
@@ -31,7 +25,7 @@ public partial class ContentService
|
||||
{
|
||||
if (cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
_debugService.Log("ensuring is cancelled!");
|
||||
debugService.Log("ensuring is cancelled!");
|
||||
return [];
|
||||
}
|
||||
|
||||
@@ -40,11 +34,11 @@ public partial class ContentService
|
||||
allItems.Add(item.Value);
|
||||
}
|
||||
|
||||
_debugService.Log("Download Count:" + items.Count);
|
||||
debugService.Log("Download Count:" + items.Count);
|
||||
|
||||
await Download(downloadUri, items, cancellationToken);
|
||||
|
||||
_fileService.ManifestItems = allItems;
|
||||
fileService.ManifestItems = allItems;
|
||||
|
||||
return allItems;
|
||||
}
|
||||
@@ -52,21 +46,21 @@ public partial class ContentService
|
||||
public async Task<List<RobustManifestItem>> EnsureItems(RobustManifestInfo info,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
_debugService.Log("Getting manifest: " + info.Hash);
|
||||
debugService.Log("Getting manifest: " + info.Hash);
|
||||
|
||||
if (_fileService.ManifestFileApi.TryOpen(info.Hash, out var stream))
|
||||
if (fileService.ManifestFileApi.TryOpen(info.Hash, out var stream))
|
||||
{
|
||||
_debugService.Log("Loading manifest from: " + info.Hash);
|
||||
debugService.Log("Loading manifest from: " + info.Hash);
|
||||
return await EnsureItems(new ManifestReader(stream), info.DownloadUri, cancellationToken);
|
||||
}
|
||||
|
||||
_debugService.Log("Fetching manifest from: " + info.ManifestUri);
|
||||
debugService.Log("Fetching manifest from: " + info.ManifestUri);
|
||||
|
||||
var response = await _http.GetAsync(info.ManifestUri, cancellationToken);
|
||||
if (!response.IsSuccessStatusCode) throw new Exception();
|
||||
|
||||
await using var streamContent = await response.Content.ReadAsStreamAsync(cancellationToken);
|
||||
_fileService.ManifestFileApi.Save(info.Hash, streamContent);
|
||||
fileService.ManifestFileApi.Save(info.Hash, streamContent);
|
||||
streamContent.Seek(0, SeekOrigin.Begin);
|
||||
using var manifestReader = new ManifestReader(streamContent);
|
||||
return await EnsureItems(manifestReader, info.DownloadUri, cancellationToken);
|
||||
@@ -74,18 +68,18 @@ public partial class ContentService
|
||||
|
||||
public async Task Unpack(RobustManifestInfo info, IWriteFileApi otherApi, CancellationToken cancellationToken)
|
||||
{
|
||||
_debugService.Log("Unpack manifest files");
|
||||
debugService.Log("Unpack manifest files");
|
||||
var items = await EnsureItems(info, cancellationToken);
|
||||
foreach (var item in items)
|
||||
if (_fileService.ContentFileApi.TryOpen(item.Hash, out var stream))
|
||||
if (fileService.ContentFileApi.TryOpen(item.Hash, out var stream))
|
||||
{
|
||||
_debugService.Log($"Unpack {item.Hash} to: {item.Path}");
|
||||
debugService.Log($"Unpack {item.Hash} to: {item.Path}");
|
||||
otherApi.Save(item.Path, stream);
|
||||
stream.Close();
|
||||
}
|
||||
else
|
||||
{
|
||||
_debugService.Error("OH FUCK!! " + item.Path);
|
||||
debugService.Error("OH FUCK!! " + item.Path);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -93,11 +87,11 @@ public partial class ContentService
|
||||
{
|
||||
if (toDownload.Count == 0 || cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
_debugService.Log("Nothing to download! Fuck this!");
|
||||
debugService.Log("Nothing to download! Fuck this!");
|
||||
return;
|
||||
}
|
||||
|
||||
_debugService.Log("Downloading from: " + contentCdn);
|
||||
debugService.Log("Downloading from: " + contentCdn);
|
||||
|
||||
var requestBody = new byte[toDownload.Count * 4];
|
||||
var reqI = 0;
|
||||
@@ -110,7 +104,7 @@ 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");
|
||||
@@ -120,7 +114,7 @@ public partial class ContentService
|
||||
|
||||
if (cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
_debugService.Log("Downloading is cancelled!");
|
||||
debugService.Log("Downloading is cancelled!");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -165,7 +159,7 @@ public partial class ContentService
|
||||
{
|
||||
if (cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
_debugService.Log("Downloading is cancelled!");
|
||||
debugService.Log("Downloading is cancelled!");
|
||||
decompressContext?.Dispose();
|
||||
compressContext?.Dispose();
|
||||
return;
|
||||
@@ -233,9 +227,9 @@ public partial class ContentService
|
||||
}
|
||||
|
||||
using var fileStream = new MemoryStream(data.ToArray());
|
||||
_fileService.ContentFileApi.Save(item.Hash, fileStream);
|
||||
fileService.ContentFileApi.Save(item.Hash, fileStream);
|
||||
|
||||
_debugService.Log("file saved:" + item.Path);
|
||||
debugService.Log("file saved:" + item.Path);
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
30
Nebula.Shared/Services/ContentService.cs
Normal file
30
Nebula.Shared/Services/ContentService.cs
Normal file
@@ -0,0 +1,30 @@
|
||||
using System.Data;
|
||||
using Nebula.Shared.Models;
|
||||
|
||||
namespace Nebula.Shared.Services;
|
||||
|
||||
[ServiceRegister]
|
||||
public partial class ContentService(
|
||||
RestService restService,
|
||||
DebugService debugService,
|
||||
ConfigurationService varService,
|
||||
FileService fileService)
|
||||
{
|
||||
private readonly HttpClient _http = new();
|
||||
|
||||
public async Task<RobustBuildInfo> GetBuildInfo(RobustUrl url, CancellationToken cancellationToken)
|
||||
{
|
||||
var info = new RobustBuildInfo();
|
||||
info.Url = url;
|
||||
var bi = await restService.GetAsync<ServerInfo>(url.InfoUri, cancellationToken);
|
||||
if (bi.Value is null) throw new NoNullAllowedException();
|
||||
info.BuildInfo = bi.Value;
|
||||
info.RobustManifestInfo = info.BuildInfo.Build.Acz
|
||||
? new RobustManifestInfo(new RobustPath(info.Url, "manifest.txt"), new RobustPath(info.Url, "download"),
|
||||
bi.Value.Build.ManifestHash)
|
||||
: new RobustManifestInfo(new Uri(info.BuildInfo.Build.ManifestUrl),
|
||||
new Uri(info.BuildInfo.Build.ManifestDownloadUrl), bi.Value.Build.ManifestHash);
|
||||
|
||||
return info;
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,6 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using Nebula.Launcher.Services.Logging;
|
||||
using Nebula.Shared.Services.Logging;
|
||||
|
||||
namespace Nebula.Launcher.Services;
|
||||
namespace Nebula.Shared.Services;
|
||||
|
||||
[ServiceRegister]
|
||||
public class DebugService : IDisposable
|
||||
@@ -18,14 +16,14 @@ public class DebugService : IDisposable
|
||||
{
|
||||
Logger = logger;
|
||||
|
||||
if (!Directory.Exists(LogPath))
|
||||
Directory.CreateDirectory(LogPath);
|
||||
//if (!Directory.Exists(LogPath))
|
||||
// Directory.CreateDirectory(LogPath);
|
||||
|
||||
var filename = String.Format("{0:yyyy-MM-dd}.txt", DateTime.Now);
|
||||
//var filename = String.Format("{0:yyyy-MM-dd}.txt", DateTime.Now);
|
||||
|
||||
LogStream = File.Open(Path.Combine(LogPath, filename),
|
||||
FileMode.Append, FileAccess.Write);
|
||||
LogWriter = new StreamWriter(LogStream);
|
||||
//LogStream = File.Open(Path.Combine(LogPath, filename),
|
||||
// FileMode.Append, FileAccess.Write);
|
||||
//LogWriter = new StreamWriter(LogStream);
|
||||
}
|
||||
|
||||
public void Debug(string message)
|
||||
@@ -59,7 +57,7 @@ public class DebugService : IDisposable
|
||||
private void Log(LoggerCategory category, string message)
|
||||
{
|
||||
Logger.Log(category, message);
|
||||
SaveToLog(category, message);
|
||||
//SaveToLog(category, message);
|
||||
}
|
||||
|
||||
private void SaveToLog(LoggerCategory category, string message)
|
||||
@@ -1,19 +1,12 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net.Http;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Nebula.Launcher.FileApis;
|
||||
using Nebula.Launcher.Models;
|
||||
using Nebula.Launcher.Utils;
|
||||
using Nebula.Shared.FileApis;
|
||||
using Nebula.Shared.Models;
|
||||
using Nebula.Shared.Utils;
|
||||
|
||||
namespace Nebula.Launcher.Services;
|
||||
namespace Nebula.Shared.Services;
|
||||
|
||||
[ServiceRegister]
|
||||
public class EngineService
|
||||
public sealed class EngineService
|
||||
{
|
||||
private readonly AssemblyService _assemblyService;
|
||||
private readonly DebugService _debugService;
|
||||
@@ -21,9 +14,11 @@ public class EngineService
|
||||
private readonly RestService _restService;
|
||||
private readonly IServiceProvider _serviceProvider;
|
||||
private readonly ConfigurationService _varService;
|
||||
public Dictionary<string, Module> ModuleInfos;
|
||||
|
||||
public Dictionary<string, Module> ModuleInfos = default!;
|
||||
public Dictionary<string, EngineVersionInfo> VersionInfos = default!;
|
||||
|
||||
public Dictionary<string, EngineVersionInfo> VersionInfos;
|
||||
private Task _currInfoTask;
|
||||
|
||||
public EngineService(RestService restService, DebugService debugService, ConfigurationService varService,
|
||||
FileService fileService, IServiceProvider serviceProvider, AssemblyService assemblyService)
|
||||
@@ -35,8 +30,7 @@ public class EngineService
|
||||
_serviceProvider = serviceProvider;
|
||||
_assemblyService = assemblyService;
|
||||
|
||||
var loadTask = Task.Run(() => LoadEngineManifest(CancellationToken.None));
|
||||
loadTask.Wait();
|
||||
_currInfoTask = Task.Run(() => LoadEngineManifest(CancellationToken.None));
|
||||
}
|
||||
|
||||
public async Task LoadEngineManifest(CancellationToken cancellationToken)
|
||||
@@ -57,6 +51,8 @@ public class EngineService
|
||||
|
||||
public EngineBuildInfo? GetVersionInfo(string version)
|
||||
{
|
||||
CheckAndWaitValidation();
|
||||
|
||||
if (!VersionInfos.TryGetValue(version, out var foundVersion))
|
||||
return null;
|
||||
|
||||
@@ -85,7 +81,7 @@ public class EngineService
|
||||
|
||||
try
|
||||
{
|
||||
return _assemblyService.Mount(_fileService.OpenZip(version, _fileService.EngineFileApi));
|
||||
return _assemblyService.Mount(_fileService.OpenZip(version, _fileService.EngineFileApi),$"Engine.Ensure-{version}");
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
@@ -120,6 +116,8 @@ public 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;
|
||||
@@ -138,6 +136,8 @@ public 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 })
|
||||
@@ -161,7 +161,7 @@ public class EngineService
|
||||
|
||||
try
|
||||
{
|
||||
return _assemblyService.Mount(_fileService.OpenZip(fileName, _fileService.EngineFileApi));
|
||||
return _assemblyService.Mount(_fileService.OpenZip(fileName, _fileService.EngineFileApi),"Engine.EnsureModule");
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
@@ -186,4 +186,13 @@ public class EngineService
|
||||
{
|
||||
return moduleName + "" + moduleVersion;
|
||||
}
|
||||
|
||||
private void CheckAndWaitValidation()
|
||||
{
|
||||
if (_currInfoTask.IsCompleted)
|
||||
return;
|
||||
|
||||
_debugService.Debug("thinks is not done yet, please wait");
|
||||
_currInfoTask.Wait();
|
||||
}
|
||||
}
|
||||
@@ -1,15 +1,11 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.IO.Compression;
|
||||
using System.Runtime.InteropServices;
|
||||
using Nebula.Launcher.FileApis;
|
||||
using Nebula.Launcher.FileApis.Interfaces;
|
||||
using Nebula.Launcher.Models;
|
||||
using Nebula.Launcher.Utils;
|
||||
using Nebula.Shared.FileApis;
|
||||
using Nebula.Shared.FileApis.Interfaces;
|
||||
using Nebula.Shared.Models;
|
||||
using Robust.LoaderApi;
|
||||
|
||||
namespace Nebula.Launcher.Services;
|
||||
namespace Nebula.Shared.Services;
|
||||
|
||||
[ServiceRegister]
|
||||
public class FileService
|
||||
@@ -1,9 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
using Nebula.Launcher.Models;
|
||||
using Nebula.Shared.Models;
|
||||
|
||||
namespace Nebula.Launcher.Services;
|
||||
namespace Nebula.Shared.Services;
|
||||
|
||||
[ServiceRegister]
|
||||
public class HubService
|
||||
@@ -1,6 +1,4 @@
|
||||
using System;
|
||||
|
||||
namespace Nebula.Launcher.Services.Logging;
|
||||
namespace Nebula.Shared.Services.Logging;
|
||||
|
||||
[ServiceRegister(typeof(ILogger))]
|
||||
public class ConsoleLogger : ILogger
|
||||
@@ -1,4 +1,4 @@
|
||||
namespace Nebula.Launcher.Services.Logging;
|
||||
namespace Nebula.Shared.Services.Logging;
|
||||
|
||||
public interface ILogger
|
||||
{
|
||||
15
Nebula.Shared/Services/PopupMessageService.cs
Normal file
15
Nebula.Shared/Services/PopupMessageService.cs
Normal file
@@ -0,0 +1,15 @@
|
||||
namespace Nebula.Shared.Services;
|
||||
|
||||
[ServiceRegister]
|
||||
public class PopupMessageService
|
||||
{
|
||||
public Action<object?>? OnPopupRequired;
|
||||
public void Popup(object obj)
|
||||
{
|
||||
OnPopupRequired?.Invoke(obj);
|
||||
}
|
||||
public void ClosePopup()
|
||||
{
|
||||
OnPopupRequired?.Invoke(null);
|
||||
}
|
||||
}
|
||||
@@ -1,16 +1,10 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Net.Http.Json;
|
||||
using System.Text;
|
||||
using System.Text.Json;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Nebula.Launcher.Utils;
|
||||
using Nebula.Shared.Utils;
|
||||
|
||||
namespace Nebula.Launcher.Services;
|
||||
namespace Nebula.Shared.Services;
|
||||
|
||||
[ServiceRegister]
|
||||
public class RestService
|
||||
@@ -1,66 +1,68 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Nebula.Launcher.Models;
|
||||
using Nebula.Shared.Models;
|
||||
using Robust.LoaderApi;
|
||||
|
||||
namespace Nebula.Launcher.Services;
|
||||
namespace Nebula.Shared.Services;
|
||||
|
||||
[ServiceRegister]
|
||||
public class RunnerService: IRedialApi
|
||||
public sealed class RunnerService(
|
||||
ContentService contentService,
|
||||
DebugService debugService,
|
||||
ConfigurationService varService,
|
||||
FileService fileService,
|
||||
EngineService engineService,
|
||||
AssemblyService assemblyService,
|
||||
AuthService authService,
|
||||
PopupMessageService popupMessageService,
|
||||
CancellationService cancellationService)
|
||||
: IRedialApi
|
||||
{
|
||||
private readonly AssemblyService _assemblyService;
|
||||
private readonly AuthService _authService;
|
||||
private readonly PopupMessageService _popupMessageService;
|
||||
private readonly ContentService _contentService;
|
||||
private readonly DebugService _debugService;
|
||||
private readonly EngineService _engineService;
|
||||
private readonly FileService _fileService;
|
||||
private readonly ConfigurationService _varService;
|
||||
|
||||
public RunnerService(ContentService contentService, DebugService debugService, ConfigurationService varService,
|
||||
FileService fileService, EngineService engineService, AssemblyService assemblyService, AuthService authService,
|
||||
PopupMessageService popupMessageService)
|
||||
public async Task PrepareRun(RobustUrl url)
|
||||
{
|
||||
_contentService = contentService;
|
||||
_debugService = debugService;
|
||||
_varService = varService;
|
||||
_fileService = fileService;
|
||||
_engineService = engineService;
|
||||
_assemblyService = assemblyService;
|
||||
_authService = authService;
|
||||
_popupMessageService = popupMessageService;
|
||||
var buildInfo = await contentService.GetBuildInfo(url, cancellationService.Token);
|
||||
await PrepareRun(buildInfo, cancellationService.Token);
|
||||
}
|
||||
|
||||
public async Task PrepareRun(RobustBuildInfo buildInfo, CancellationToken cancellationToken)
|
||||
{
|
||||
debugService.Log("Prepare Content!");
|
||||
|
||||
var engine = await engineService.EnsureEngine(buildInfo.BuildInfo.Build.EngineVersion);
|
||||
|
||||
if (engine is null)
|
||||
throw new Exception("Engine version is not usable: " + buildInfo.BuildInfo.Build.EngineVersion);
|
||||
|
||||
await contentService.EnsureItems(buildInfo.RobustManifestInfo, cancellationToken);
|
||||
await engineService.EnsureEngineModules("Robust.Client.WebView", buildInfo.BuildInfo.Build.EngineVersion);
|
||||
}
|
||||
|
||||
public async Task Run(string[] runArgs, RobustBuildInfo buildInfo, IRedialApi redialApi,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
_debugService.Log("Start Content!");
|
||||
debugService.Log("Start Content!");
|
||||
|
||||
var engine = await _engineService.EnsureEngine(buildInfo.BuildInfo.Build.EngineVersion);
|
||||
var engine = await engineService.EnsureEngine(buildInfo.BuildInfo.Build.EngineVersion);
|
||||
|
||||
if (engine is null)
|
||||
throw new Exception("Engine version is not usable: " + buildInfo.BuildInfo.Build.EngineVersion);
|
||||
|
||||
await _contentService.EnsureItems(buildInfo.RobustManifestInfo, cancellationToken);
|
||||
await contentService.EnsureItems(buildInfo.RobustManifestInfo, cancellationToken);
|
||||
|
||||
var extraMounts = new List<ApiMount>
|
||||
{
|
||||
new(_fileService.HashApi, "/")
|
||||
new(fileService.HashApi, "/")
|
||||
};
|
||||
|
||||
var module =
|
||||
await _engineService.EnsureEngineModules("Robust.Client.WebView", buildInfo.BuildInfo.Build.EngineVersion);
|
||||
await engineService.EnsureEngineModules("Robust.Client.WebView", buildInfo.BuildInfo.Build.EngineVersion);
|
||||
if (module is not null)
|
||||
extraMounts.Add(new ApiMount(module, "/"));
|
||||
|
||||
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))
|
||||
if (!assemblyService.TryGetLoader(clientAssembly, out var loader))
|
||||
return;
|
||||
|
||||
await Task.Run(() => loader.Main(args), cancellationToken);
|
||||
@@ -71,12 +73,12 @@ public class RunnerService: IRedialApi
|
||||
var url = new RobustUrl(urlraw);
|
||||
|
||||
using var cancelTokenSource = new CancellationTokenSource();
|
||||
var buildInfo = await _contentService.GetBuildInfo(url, cancelTokenSource.Token);
|
||||
var buildInfo = await contentService.GetBuildInfo(url, cancelTokenSource.Token);
|
||||
|
||||
var account = _authService.SelectedAuth;
|
||||
var account = authService.SelectedAuth;
|
||||
if (account is null)
|
||||
{
|
||||
_popupMessageService.PopupInfo("Error! Auth is required!");
|
||||
popupMessageService.Popup("Error! Auth is required!");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -112,13 +114,13 @@ public class RunnerService: IRedialApi
|
||||
|
||||
args.Add("--ss14-address");
|
||||
args.Add(url.ToString());
|
||||
_debugService.Debug("Connect to " + url.ToString() + " " + account.AuthLoginPassword.AuthServer);
|
||||
debugService.Debug("Connect to " + url.ToString() + " " + account.AuthLoginPassword.AuthServer);
|
||||
|
||||
await Run(args.ToArray(), buildInfo, this, cancelTokenSource.Token);
|
||||
}
|
||||
|
||||
public async void Redial(Uri uri, string text = "")
|
||||
{
|
||||
await RunGame(uri.ToString());
|
||||
//await RunGame(uri.ToString());
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,6 @@
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Nebula.Launcher.Utils;
|
||||
namespace Nebula.Shared.Utils;
|
||||
|
||||
public sealed class BandwidthStream : Stream
|
||||
{
|
||||
@@ -1,8 +1,6 @@
|
||||
using System;
|
||||
using System.Windows.Input;
|
||||
using Nebula.Launcher.ViewModels;
|
||||
|
||||
namespace Nebula.Launcher.Utils;
|
||||
namespace Nebula.Shared.Utils;
|
||||
|
||||
public class DelegateCommand<T> : ICommand
|
||||
{
|
||||
@@ -1,10 +1,8 @@
|
||||
using System.Diagnostics;
|
||||
using System.Net.Http;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text.Json;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Nebula.Launcher.Utils;
|
||||
namespace Nebula.Shared.Utils;
|
||||
|
||||
public static class Helper
|
||||
{
|
||||
@@ -1,9 +1,8 @@
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using Nebula.Launcher.Models;
|
||||
using Nebula.Shared.Models;
|
||||
|
||||
namespace Nebula.Launcher.Utils;
|
||||
namespace Nebula.Shared.Utils;
|
||||
|
||||
public class ManifestReader : StreamReader
|
||||
{
|
||||
@@ -1,4 +1,4 @@
|
||||
namespace Nebula.Launcher.Utils;
|
||||
namespace Nebula.Shared.Utils;
|
||||
|
||||
public class Ref<T>
|
||||
{
|
||||
@@ -1,11 +1,8 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace Nebula.Launcher.Utils;
|
||||
namespace Nebula.Shared.Utils;
|
||||
|
||||
public static class RidUtility
|
||||
{
|
||||
@@ -1,10 +1,6 @@
|
||||
using System;
|
||||
using System.Buffers;
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Nebula.Launcher.Utils;
|
||||
namespace Nebula.Shared.Utils;
|
||||
|
||||
public static class StreamHelper
|
||||
{
|
||||
@@ -1,9 +1,9 @@
|
||||
using System;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Diagnostics.Contracts;
|
||||
using System.Web;
|
||||
using Nebula.Shared.Models;
|
||||
|
||||
namespace Nebula.Launcher.Utils;
|
||||
namespace Nebula.Shared.Utils;
|
||||
|
||||
public static class UriHelper
|
||||
{
|
||||
@@ -132,4 +132,9 @@ public static class UriHelper
|
||||
|
||||
return uriBuilder.Uri;
|
||||
}
|
||||
|
||||
public static RobustUrl ToRobustUrl(this string str)
|
||||
{
|
||||
return new RobustUrl(str);
|
||||
}
|
||||
}
|
||||
@@ -1,15 +1,11 @@
|
||||
using System;
|
||||
using System.Buffers;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using SharpZstd.Interop;
|
||||
using static SharpZstd.Interop.Zstd;
|
||||
|
||||
namespace Nebula.Launcher.Utils;
|
||||
namespace Nebula.Shared.Utils;
|
||||
|
||||
public static class ZStd
|
||||
{
|
||||
12
Nebula.sln
12
Nebula.sln
@@ -4,6 +4,10 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nebula.Launcher", "Nebula.L
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Robust.LoaderApi", "Robust.LoaderApi\Robust.LoaderApi\Robust.LoaderApi.csproj", "{8AE91631-DE96-4A97-A255-058E27A7C3EA}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nebula.Shared", "Nebula.Shared\Nebula.Shared.csproj", "{47519EA2-03C0-49D8-86CA-418F6B7267A4}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nebula.Runner", "Nebula.Runner\Nebula.Runner.csproj", "{82D96367-44B0-4F25-A094-CBE73B052B73}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
@@ -18,5 +22,13 @@ Global
|
||||
{8AE91631-DE96-4A97-A255-058E27A7C3EA}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{8AE91631-DE96-4A97-A255-058E27A7C3EA}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{8AE91631-DE96-4A97-A255-058E27A7C3EA}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{47519EA2-03C0-49D8-86CA-418F6B7267A4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{47519EA2-03C0-49D8-86CA-418F6B7267A4}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{47519EA2-03C0-49D8-86CA-418F6B7267A4}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{47519EA2-03C0-49D8-86CA-418F6B7267A4}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{82D96367-44B0-4F25-A094-CBE73B052B73}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{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
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
|
||||
Reference in New Issue
Block a user