- tweak: refactor funny

This commit is contained in:
2025-01-05 17:05:23 +03:00
parent 5b24f915a2
commit 8619e248fd
67 changed files with 485 additions and 492 deletions

View File

@@ -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;

View File

@@ -1,11 +0,0 @@
using Nebula.Launcher.Services;
namespace Nebula.Launcher;
public class AppNoUi(RunnerService runnerService, AuthService authService)
{
public void Run(string[] args)
{
}
}

View File

@@ -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>

View File

@@ -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()

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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);
}
}

View File

@@ -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;

View File

@@ -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)
{

View File

@@ -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()

View File

@@ -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()

View File

@@ -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;
}
}

View File

@@ -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()
{
}
}

View File

@@ -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()

View File

@@ -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>

View File

@@ -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
View 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));
}
}

View 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
View 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);
}
}

View File

@@ -1,6 +1,6 @@
using Nebula.Launcher.Services;
using Nebula.Shared.Services;
namespace Nebula.Launcher;
namespace Nebula.Shared;
public static class CurrentConVar
{

View File

@@ -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);

View File

@@ -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
{

View File

@@ -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
{

View File

@@ -1,6 +1,6 @@
using Robust.LoaderApi;
namespace Nebula.Launcher.FileApis.Interfaces;
namespace Nebula.Shared.FileApis.Interfaces;
public interface IReadWriteFileApi : IFileApi, IWriteFileApi
{

View File

@@ -1,6 +1,4 @@
using System.IO;
namespace Nebula.Launcher.FileApis.Interfaces;
namespace Nebula.Shared.FileApis.Interfaces;
public interface IWriteFileApi
{

View File

@@ -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
{

View File

@@ -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)
{

View File

@@ -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);

View File

@@ -1,6 +1,4 @@
using System;
namespace Nebula.Launcher.Models.Auth;
namespace Nebula.Shared.Models.Auth;
public class LoginInfo
{

View File

@@ -1,6 +1,4 @@
using System;
namespace Nebula.Launcher.Models.Auth;
namespace Nebula.Shared.Models.Auth;
public readonly struct LoginToken
{

View File

@@ -1,4 +1,4 @@
namespace Nebula.Launcher.Models;
namespace Nebula.Shared.Models;
public enum ContentCompressionScheme
{

View File

@@ -1,6 +1,4 @@
using System;
namespace Nebula.Launcher.Models;
namespace Nebula.Shared.Models;
[Flags]
public enum DownloadStreamHeaderFlags

View File

@@ -1,4 +1,2 @@
using System;
namespace Nebula.Launcher.Models;
namespace Nebula.Shared.Models;
public record ListItemTemplate(Type ModelType, string IconKey, string Label);

View File

@@ -1,7 +1,6 @@
using System.Collections.Generic;
using Robust.LoaderApi;
namespace Nebula.Launcher.Models;
namespace Nebula.Shared.Models;
public sealed class MainArgs : IMainArgs
{

View File

@@ -1,4 +1,4 @@
namespace Nebula.Launcher.Models;
namespace Nebula.Shared.Models;
public class RobustBuildInfo
{

View File

@@ -1,5 +1,3 @@
using System;
namespace Nebula.Launcher.Models;
namespace Nebula.Shared.Models;
public record struct RobustManifestInfo(Uri ManifestUri, Uri DownloadUri, string Hash);

View File

@@ -1,3 +1,3 @@
namespace Nebula.Launcher.Models;
namespace Nebula.Shared.Models;
public record struct RobustManifestItem(string Hash, string Path, int Id);

View File

@@ -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,

View File

@@ -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
{

View 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>

View 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;
}
}

View File

@@ -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;
}

View File

@@ -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;

View 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();
}
}

View File

@@ -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>
{

View File

@@ -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;
}
}

View 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;
}
}

View File

@@ -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)

View File

@@ -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();
}
}

View File

@@ -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

View File

@@ -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

View File

@@ -1,6 +1,4 @@
using System;
namespace Nebula.Launcher.Services.Logging;
namespace Nebula.Shared.Services.Logging;
[ServiceRegister(typeof(ILogger))]
public class ConsoleLogger : ILogger

View File

@@ -1,4 +1,4 @@
namespace Nebula.Launcher.Services.Logging;
namespace Nebula.Shared.Services.Logging;
public interface ILogger
{

View 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);
}
}

View File

@@ -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

View File

@@ -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());
}
}

View File

@@ -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
{

View File

@@ -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
{

View File

@@ -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
{

View File

@@ -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
{

View File

@@ -1,4 +1,4 @@
namespace Nebula.Launcher.Utils;
namespace Nebula.Shared.Utils;
public class Ref<T>
{

View File

@@ -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
{

View File

@@ -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
{

View File

@@ -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);
}
}

View File

@@ -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
{

View File

@@ -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