- tweak: refactor funny
This commit is contained in:
@@ -8,6 +8,7 @@ using Avalonia.Markup.Xaml;
|
|||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using Nebula.Launcher.ViewModels;
|
using Nebula.Launcher.ViewModels;
|
||||||
using Nebula.Launcher.Views;
|
using Nebula.Launcher.Views;
|
||||||
|
using Nebula.Shared;
|
||||||
|
|
||||||
namespace Nebula.Launcher;
|
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>
|
||||||
<PackageReference Include="CommunityToolkit.Mvvm" Version="8.2.1" />
|
<PackageReference Include="CommunityToolkit.Mvvm" Version="8.2.1" />
|
||||||
<PackageReference Include="JetBrains.Annotations" Version="2024.3.0" />
|
<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="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>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
@@ -43,6 +37,6 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\Robust.LoaderApi\Robust.LoaderApi\Robust.LoaderApi.csproj" />
|
<ProjectReference Include="..\Nebula.Shared\Nebula.Shared.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
@@ -1,40 +1,11 @@
|
|||||||
using Avalonia;
|
using Avalonia;
|
||||||
using System;
|
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
|
||||||
|
|
||||||
namespace Nebula.Launcher;
|
namespace Nebula.Launcher;
|
||||||
|
|
||||||
sealed class Program
|
public static class Program
|
||||||
{
|
{
|
||||||
// Initialization code. Don't use any Avalonia, third-party APIs or any
|
public static void Main(string[] args) => BuildAvaloniaApp()
|
||||||
// SynchronizationContext-reliant code before AppMain is called: things aren't initialized
|
.StartWithClassicDesktopLifetime(args);
|
||||||
// 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);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Avalonia configuration, don't remove; also used by visual designer.
|
// Avalonia configuration, don't remove; also used by visual designer.
|
||||||
private static AppBuilder BuildAvaloniaApp()
|
private static AppBuilder BuildAvaloniaApp()
|
||||||
|
|||||||
@@ -36,58 +36,22 @@ public static class ServiceCollectionExtensions
|
|||||||
{
|
{
|
||||||
services.AddTransient<MainWindow>();
|
services.AddTransient<MainWindow>();
|
||||||
|
|
||||||
foreach (var (viewModel, view) in GetTypesWithHelpAttribute(Assembly.GetExecutingAssembly()))
|
foreach (var (viewModel, view, isSingleton) in GetTypesWithHelpAttribute(Assembly.GetExecutingAssembly()))
|
||||||
{
|
{
|
||||||
services.AddSingleton(viewModel);
|
if(isSingleton)services.AddSingleton(viewModel);
|
||||||
services.AddTransient(view);
|
else services.AddTransient(viewModel);
|
||||||
}
|
if (view != null) 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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static IEnumerable<(Type,Type)> GetTypesWithHelpAttribute(Assembly assembly) {
|
private static IEnumerable<(Type,Type?,bool)> GetTypesWithHelpAttribute(Assembly assembly) {
|
||||||
foreach(Type type in assembly.GetTypes())
|
foreach(Type type in assembly.GetTypes())
|
||||||
{
|
{
|
||||||
var attr = type.GetCustomAttribute<ViewRegisterAttribute>();
|
var attr = type.GetCustomAttribute<ViewModelRegisterAttribute>();
|
||||||
if (attr is not null) {
|
if (attr is not null) {
|
||||||
yield return (type, attr.Type);
|
yield return (type, attr.Type, attr.IsSingleton);
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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,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;
|
namespace Nebula.Launcher.ViewHelper;
|
||||||
|
|
||||||
[AttributeUsage(AttributeTargets.Class)]
|
[AttributeUsage(AttributeTargets.Class)]
|
||||||
public class ViewRegisterAttribute : Attribute
|
public class ViewModelRegisterAttribute : Attribute
|
||||||
{
|
{
|
||||||
public Type Type { get; }
|
public Type? Type { get; }
|
||||||
public bool IsSingleton { get; }
|
public bool IsSingleton { get; }
|
||||||
|
|
||||||
public ViewRegisterAttribute(Type type, bool isSingleton = true)
|
public ViewModelRegisterAttribute(Type? type = null, bool isSingleton = true)
|
||||||
{
|
{
|
||||||
Type = type;
|
Type = type;
|
||||||
IsSingleton = isSingleton;
|
IsSingleton = isSingleton;
|
||||||
@@ -14,7 +14,7 @@ public class ViewLocator : IDataTemplate
|
|||||||
if (param is null)
|
if (param is null)
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
var type = param.GetType().GetCustomAttribute<ViewRegisterAttribute>()?.Type;
|
var type = param.GetType().GetCustomAttribute<ViewModelRegisterAttribute>()?.Type;
|
||||||
|
|
||||||
if (type != null)
|
if (type != null)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -4,14 +4,15 @@ using System.Linq;
|
|||||||
using System.Windows.Input;
|
using System.Windows.Input;
|
||||||
using CommunityToolkit.Mvvm.ComponentModel;
|
using CommunityToolkit.Mvvm.ComponentModel;
|
||||||
using CommunityToolkit.Mvvm.Input;
|
using CommunityToolkit.Mvvm.Input;
|
||||||
using Nebula.Launcher.Services;
|
|
||||||
using Nebula.Launcher.Utils;
|
|
||||||
using Nebula.Launcher.ViewHelper;
|
using Nebula.Launcher.ViewHelper;
|
||||||
using Nebula.Launcher.Views.Pages;
|
using Nebula.Launcher.Views.Pages;
|
||||||
|
using Nebula.Shared;
|
||||||
|
using Nebula.Shared.Services;
|
||||||
|
using Nebula.Shared.Utils;
|
||||||
|
|
||||||
namespace Nebula.Launcher.ViewModels;
|
namespace Nebula.Launcher.ViewModels;
|
||||||
|
|
||||||
[ViewRegister(typeof(AccountInfoView))]
|
[ViewModelRegister(typeof(AccountInfoView))]
|
||||||
public partial class AccountInfoViewModel : ViewModelBase
|
public partial class AccountInfoViewModel : ViewModelBase
|
||||||
{
|
{
|
||||||
private readonly PopupMessageService _popupMessageService;
|
private readonly PopupMessageService _popupMessageService;
|
||||||
@@ -79,12 +80,12 @@ public partial class AccountInfoViewModel : ViewModelBase
|
|||||||
|
|
||||||
public async void DoAuth()
|
public async void DoAuth()
|
||||||
{
|
{
|
||||||
_popupMessageService.PopupInfo("Auth think, please wait...");
|
_popupMessageService.Popup("Auth think, please wait...");
|
||||||
|
|
||||||
if(await _authService.Auth(CurrentAlp))
|
if(await _authService.Auth(CurrentAlp))
|
||||||
{
|
{
|
||||||
_popupMessageService.ClosePopup();
|
_popupMessageService.ClosePopup();
|
||||||
_popupMessageService.PopupInfo("Hello, " + _authService.SelectedAuth!.AuthLoginPassword.Login);
|
_popupMessageService.Popup("Hello, " + _authService.SelectedAuth!.AuthLoginPassword.Login);
|
||||||
IsLogged = true;
|
IsLogged = true;
|
||||||
_configurationService.SetConfigValue(CurrentConVar.AuthCurrent, CurrentAlp);
|
_configurationService.SetConfigValue(CurrentConVar.AuthCurrent, CurrentAlp);
|
||||||
}
|
}
|
||||||
@@ -92,7 +93,7 @@ public partial class AccountInfoViewModel : ViewModelBase
|
|||||||
{
|
{
|
||||||
_popupMessageService.ClosePopup();
|
_popupMessageService.ClosePopup();
|
||||||
Logout();
|
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;
|
IsLogged = false;
|
||||||
CurrentAlp = new AuthLoginPassword("", "", "");
|
CurrentAlp = new AuthLoginPassword("", "", "");
|
||||||
_authService.SelectedAuth = null;
|
_authService.ClearAuth();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void UpdateAuthMenu()
|
private void UpdateAuthMenu()
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ using Nebula.Launcher.Views.Popup;
|
|||||||
|
|
||||||
namespace Nebula.Launcher.ViewModels;
|
namespace Nebula.Launcher.ViewModels;
|
||||||
|
|
||||||
[ViewRegister(typeof(InfoPopupView), false)]
|
[ViewModelRegister(typeof(InfoPopupView), false)]
|
||||||
public partial class InfoPopupViewModel : PopupViewModelBase
|
public partial class InfoPopupViewModel : PopupViewModelBase
|
||||||
{
|
{
|
||||||
public InfoPopupViewModel()
|
public InfoPopupViewModel()
|
||||||
|
|||||||
@@ -5,15 +5,15 @@ using System.Linq;
|
|||||||
using CommunityToolkit.Mvvm.ComponentModel;
|
using CommunityToolkit.Mvvm.ComponentModel;
|
||||||
using CommunityToolkit.Mvvm.Input;
|
using CommunityToolkit.Mvvm.Input;
|
||||||
using JetBrains.Annotations;
|
using JetBrains.Annotations;
|
||||||
using Nebula.Launcher.Models;
|
|
||||||
using Nebula.Launcher.Services;
|
|
||||||
using Nebula.Launcher.Utils;
|
|
||||||
using Nebula.Launcher.ViewHelper;
|
using Nebula.Launcher.ViewHelper;
|
||||||
using Nebula.Launcher.Views;
|
using Nebula.Launcher.Views;
|
||||||
|
using Nebula.Shared.Models;
|
||||||
|
using Nebula.Shared.Services;
|
||||||
|
using Nebula.Shared.Utils;
|
||||||
|
|
||||||
namespace Nebula.Launcher.ViewModels;
|
namespace Nebula.Launcher.ViewModels;
|
||||||
|
|
||||||
[ViewRegister(typeof(MainView))]
|
[ViewModelRegister(typeof(MainView))]
|
||||||
public partial class MainViewModel : ViewModelBase
|
public partial class MainViewModel : ViewModelBase
|
||||||
{
|
{
|
||||||
public MainViewModel()
|
public MainViewModel()
|
||||||
@@ -111,15 +111,23 @@ public partial class MainViewModel : ViewModelBase
|
|||||||
Helper.OpenBrowser("https://cinka.ru/nebula-launcher/");
|
Helper.OpenBrowser("https://cinka.ru/nebula-launcher/");
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnPopupRequired(PopupViewModelBase? viewModelBase)
|
private void OnPopupRequired(object? viewModelBase)
|
||||||
{
|
{
|
||||||
if (viewModelBase is null)
|
switch (viewModelBase)
|
||||||
{
|
{
|
||||||
ClosePopup();
|
case null:
|
||||||
}
|
ClosePopup();
|
||||||
else
|
break;
|
||||||
{
|
case string str:
|
||||||
PopupMessage(viewModelBase);
|
{
|
||||||
|
var view = GetViewModel<InfoPopupViewModel>();
|
||||||
|
view.InfoText = str;
|
||||||
|
PopupMessage(view);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case PopupViewModelBase @base:
|
||||||
|
PopupMessage(@base);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,33 +1,41 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using System.Diagnostics;
|
||||||
using CommunityToolkit.Mvvm.ComponentModel;
|
using CommunityToolkit.Mvvm.ComponentModel;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Nebula.Launcher.ViewHelper;
|
||||||
using Nebula.Launcher.Models;
|
using Nebula.Shared.Models;
|
||||||
using Nebula.Launcher.Services;
|
|
||||||
|
|
||||||
namespace Nebula.Launcher.ViewModels;
|
namespace Nebula.Launcher.ViewModels;
|
||||||
|
|
||||||
|
[ViewModelRegister(isSingleton:false)]
|
||||||
public partial class ServerEntryModelView : ViewModelBase
|
public partial class ServerEntryModelView : ViewModelBase
|
||||||
{
|
{
|
||||||
|
[ObservableProperty] private bool _runVisible = true;
|
||||||
private readonly IServiceProvider _serviceProvider;
|
|
||||||
private readonly RunnerService _runnerService;
|
|
||||||
private readonly PopupMessageService _popupMessageService;
|
|
||||||
private readonly RestService _restService;
|
|
||||||
|
|
||||||
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.Collections.ObjectModel;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using CommunityToolkit.Mvvm.ComponentModel;
|
using CommunityToolkit.Mvvm.ComponentModel;
|
||||||
using Nebula.Launcher.Models;
|
|
||||||
using Nebula.Launcher.Services;
|
|
||||||
using Nebula.Launcher.ViewHelper;
|
using Nebula.Launcher.ViewHelper;
|
||||||
using Nebula.Launcher.Views.Pages;
|
using Nebula.Launcher.Views.Pages;
|
||||||
|
using Nebula.Shared.Models;
|
||||||
|
using Nebula.Shared.Services;
|
||||||
|
|
||||||
namespace Nebula.Launcher.ViewModels;
|
namespace Nebula.Launcher.ViewModels;
|
||||||
|
|
||||||
[ViewRegister(typeof(ServerListView))]
|
[ViewModelRegister(typeof(ServerListView))]
|
||||||
public partial class ServerListViewModel : ViewModelBase
|
public partial class ServerListViewModel : ViewModelBase
|
||||||
{
|
{
|
||||||
private readonly IServiceProvider _serviceProvider;
|
private readonly IServiceProvider _serviceProvider;
|
||||||
@@ -84,7 +84,9 @@ public partial class ServerListViewModel : ViewModelBase
|
|||||||
|
|
||||||
private ServerEntryModelView CreateServerView(ServerHubInfo serverHubInfo)
|
private ServerEntryModelView CreateServerView(ServerHubInfo serverHubInfo)
|
||||||
{
|
{
|
||||||
return new ServerEntryModelView(_serviceProvider, serverHubInfo);
|
var svn = GetViewModel<ServerEntryModelView>();
|
||||||
|
svn.ServerHubInfo = serverHubInfo;
|
||||||
|
return svn;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void FilterRequired()
|
public void FilterRequired()
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
xmlns:converters="clr-namespace:Nebula.Launcher.Converters"
|
xmlns:converters="clr-namespace:Nebula.Launcher.Converters"
|
||||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
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:viewModels="clr-namespace:Nebula.Launcher.ViewModels"
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
|
||||||
<Design.DataContext>
|
<Design.DataContext>
|
||||||
|
|||||||
@@ -8,7 +8,6 @@
|
|||||||
xmlns:asyncImageLoader="clr-namespace:AsyncImageLoader;assembly=AsyncImageLoader.Avalonia"
|
xmlns:asyncImageLoader="clr-namespace:AsyncImageLoader;assembly=AsyncImageLoader.Avalonia"
|
||||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
xmlns:models="clr-namespace:Nebula.Launcher.Models"
|
|
||||||
xmlns:viewModels="clr-namespace:Nebula.Launcher.ViewModels"
|
xmlns:viewModels="clr-namespace:Nebula.Launcher.ViewModels"
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
|
||||||
|
|
||||||
@@ -25,7 +24,7 @@
|
|||||||
<ListBox.ItemTemplate>
|
<ListBox.ItemTemplate>
|
||||||
<DataTemplate DataType="{x:Type viewModels:ServerEntryModelView}">
|
<DataTemplate DataType="{x:Type viewModels:ServerEntryModelView}">
|
||||||
<Grid
|
<Grid
|
||||||
ColumnDefinitions="*,90"
|
ColumnDefinitions="*,120"
|
||||||
Margin="0,5,0,5"
|
Margin="0,5,0,5"
|
||||||
RowDefinitions="30,*">
|
RowDefinitions="30,*">
|
||||||
<Border
|
<Border
|
||||||
@@ -38,7 +37,7 @@
|
|||||||
</Label>
|
</Label>
|
||||||
</Border>
|
</Border>
|
||||||
<Border
|
<Border
|
||||||
BorderThickness="2,0,0,0"
|
BorderThickness="2,0,2,0"
|
||||||
CornerRadius="0"
|
CornerRadius="0"
|
||||||
Grid.Column="1"
|
Grid.Column="1"
|
||||||
Grid.Row="0"
|
Grid.Row="0"
|
||||||
@@ -69,9 +68,9 @@
|
|||||||
</Border.Background>
|
</Border.Background>
|
||||||
<Border
|
<Border
|
||||||
BorderThickness="0,2,2,0"
|
BorderThickness="0,2,2,0"
|
||||||
CornerRadius="0,10,10,10"
|
CornerRadius="0,0,10,10"
|
||||||
IsVisible="True"
|
IsVisible="True"
|
||||||
Margin="0,0,5,0"
|
Margin="0,0,0,0"
|
||||||
Opacity="40"
|
Opacity="40"
|
||||||
Padding="0">
|
Padding="0">
|
||||||
<UniformGrid Margin="15,5,15,0">
|
<UniformGrid Margin="15,5,15,0">
|
||||||
@@ -121,18 +120,36 @@
|
|||||||
</Border>
|
</Border>
|
||||||
|
|
||||||
<Panel Grid.Column="1" Grid.Row="1">
|
<Panel Grid.Column="1" Grid.Row="1">
|
||||||
<Border Classes="ButtonBack" CornerRadius="0,0,10,0">
|
<Button
|
||||||
<Button
|
Command="{Binding RunInstance}"
|
||||||
Command="{Binding OnConnectRequired}"
|
IsVisible="{Binding RunVisible}"
|
||||||
CornerRadius="0,0,10,0"
|
HorizontalAlignment="Stretch"
|
||||||
HorizontalAlignment="Stretch"
|
CornerRadius="10,0,10,10"
|
||||||
Padding="0"
|
VerticalAlignment="Stretch">
|
||||||
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">
|
<Label HorizontalAlignment="Center" VerticalAlignment="Center">
|
||||||
Play
|
Log
|
||||||
</Label>
|
</Label>
|
||||||
</Button>
|
</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>
|
</Panel>
|
||||||
</Grid>
|
</Grid>
|
||||||
</DataTemplate>
|
</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
|
public static class CurrentConVar
|
||||||
{
|
{
|
||||||
@@ -1,8 +1,6 @@
|
|||||||
using System.Collections.Generic;
|
using Robust.LoaderApi;
|
||||||
using System.IO;
|
|
||||||
using Robust.LoaderApi;
|
|
||||||
|
|
||||||
namespace Nebula.Launcher.FileApis;
|
namespace Nebula.Shared.FileApis;
|
||||||
|
|
||||||
public class AssemblyApi : IFileApi
|
public class AssemblyApi : IFileApi
|
||||||
{
|
{
|
||||||
@@ -12,7 +10,7 @@ public class AssemblyApi : IFileApi
|
|||||||
{
|
{
|
||||||
_root = root;
|
_root = root;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool TryOpen(string path, out Stream? stream)
|
public bool TryOpen(string path, out Stream? stream)
|
||||||
{
|
{
|
||||||
return _root.TryOpen(path, out stream);
|
return _root.TryOpen(path, out stream);
|
||||||
@@ -1,9 +1,6 @@
|
|||||||
using System;
|
using Nebula.Shared.FileApis.Interfaces;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.IO;
|
|
||||||
using Nebula.Launcher.FileApis.Interfaces;
|
|
||||||
|
|
||||||
namespace Nebula.Launcher.FileApis;
|
namespace Nebula.Shared.FileApis;
|
||||||
|
|
||||||
public class FileApi : IReadWriteFileApi
|
public class FileApi : IReadWriteFileApi
|
||||||
{
|
{
|
||||||
@@ -1,10 +1,7 @@
|
|||||||
using System.Collections.Generic;
|
using Nebula.Shared.Models;
|
||||||
using System.IO;
|
|
||||||
using Nebula.Launcher.Models;
|
|
||||||
using Nebula.Launcher.Utils;
|
|
||||||
using Robust.LoaderApi;
|
using Robust.LoaderApi;
|
||||||
|
|
||||||
namespace Nebula.Launcher.FileApis;
|
namespace Nebula.Shared.FileApis;
|
||||||
|
|
||||||
public class HashApi : IFileApi
|
public class HashApi : IFileApi
|
||||||
{
|
{
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
using Robust.LoaderApi;
|
using Robust.LoaderApi;
|
||||||
|
|
||||||
namespace Nebula.Launcher.FileApis.Interfaces;
|
namespace Nebula.Shared.FileApis.Interfaces;
|
||||||
|
|
||||||
public interface IReadWriteFileApi : IFileApi, IWriteFileApi
|
public interface IReadWriteFileApi : IFileApi, IWriteFileApi
|
||||||
{
|
{
|
||||||
@@ -1,6 +1,4 @@
|
|||||||
using System.IO;
|
namespace Nebula.Shared.FileApis.Interfaces;
|
||||||
|
|
||||||
namespace Nebula.Launcher.FileApis.Interfaces;
|
|
||||||
|
|
||||||
public interface IWriteFileApi
|
public interface IWriteFileApi
|
||||||
{
|
{
|
||||||
@@ -1,12 +1,9 @@
|
|||||||
using System.Collections.Generic;
|
|
||||||
using System.Diagnostics.CodeAnalysis;
|
using System.Diagnostics.CodeAnalysis;
|
||||||
using System.IO;
|
|
||||||
using System.IO.Compression;
|
using System.IO.Compression;
|
||||||
using System.Linq;
|
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using Robust.LoaderApi;
|
using Robust.LoaderApi;
|
||||||
|
|
||||||
namespace Nebula.Launcher.FileApis;
|
namespace Nebula.Shared.FileApis;
|
||||||
|
|
||||||
public sealed class ZipFileApi : IFileApi
|
public sealed class ZipFileApi : IFileApi
|
||||||
{
|
{
|
||||||
@@ -1,6 +1,4 @@
|
|||||||
using System;
|
namespace Nebula.Shared.Models.Auth;
|
||||||
|
|
||||||
namespace Nebula.Launcher.Models.Auth;
|
|
||||||
|
|
||||||
public sealed record AuthenticateRequest(string? Username, Guid? UserId, string Password, string? TfaCode = null)
|
public sealed record AuthenticateRequest(string? Username, Guid? UserId, string Password, string? TfaCode = null)
|
||||||
{
|
{
|
||||||
@@ -1,5 +1,3 @@
|
|||||||
using System;
|
namespace Nebula.Shared.Models.Auth;
|
||||||
|
|
||||||
namespace Nebula.Launcher.Models.Auth;
|
|
||||||
|
|
||||||
public sealed record AuthenticateResponse(string Token, string Username, Guid UserId, DateTimeOffset ExpireTime);
|
public sealed record AuthenticateResponse(string Token, string Username, Guid UserId, DateTimeOffset ExpireTime);
|
||||||
@@ -1,6 +1,4 @@
|
|||||||
using System;
|
namespace Nebula.Shared.Models.Auth;
|
||||||
|
|
||||||
namespace Nebula.Launcher.Models.Auth;
|
|
||||||
|
|
||||||
public class LoginInfo
|
public class LoginInfo
|
||||||
{
|
{
|
||||||
@@ -1,6 +1,4 @@
|
|||||||
using System;
|
namespace Nebula.Shared.Models.Auth;
|
||||||
|
|
||||||
namespace Nebula.Launcher.Models.Auth;
|
|
||||||
|
|
||||||
public readonly struct LoginToken
|
public readonly struct LoginToken
|
||||||
{
|
{
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
namespace Nebula.Launcher.Models;
|
namespace Nebula.Shared.Models;
|
||||||
|
|
||||||
public enum ContentCompressionScheme
|
public enum ContentCompressionScheme
|
||||||
{
|
{
|
||||||
@@ -1,6 +1,4 @@
|
|||||||
using System;
|
namespace Nebula.Shared.Models;
|
||||||
|
|
||||||
namespace Nebula.Launcher.Models;
|
|
||||||
|
|
||||||
[Flags]
|
[Flags]
|
||||||
public enum DownloadStreamHeaderFlags
|
public enum DownloadStreamHeaderFlags
|
||||||
@@ -1,4 +1,2 @@
|
|||||||
using System;
|
namespace Nebula.Shared.Models;
|
||||||
|
|
||||||
namespace Nebula.Launcher.Models;
|
|
||||||
public record ListItemTemplate(Type ModelType, string IconKey, string Label);
|
public record ListItemTemplate(Type ModelType, string IconKey, string Label);
|
||||||
@@ -1,7 +1,6 @@
|
|||||||
using System.Collections.Generic;
|
|
||||||
using Robust.LoaderApi;
|
using Robust.LoaderApi;
|
||||||
|
|
||||||
namespace Nebula.Launcher.Models;
|
namespace Nebula.Shared.Models;
|
||||||
|
|
||||||
public sealed class MainArgs : IMainArgs
|
public sealed class MainArgs : IMainArgs
|
||||||
{
|
{
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
namespace Nebula.Launcher.Models;
|
namespace Nebula.Shared.Models;
|
||||||
|
|
||||||
public class RobustBuildInfo
|
public class RobustBuildInfo
|
||||||
{
|
{
|
||||||
@@ -1,5 +1,3 @@
|
|||||||
using System;
|
namespace Nebula.Shared.Models;
|
||||||
|
|
||||||
namespace Nebula.Launcher.Models;
|
|
||||||
|
|
||||||
public record struct RobustManifestInfo(Uri ManifestUri, Uri DownloadUri, string Hash);
|
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);
|
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;
|
using System.Text.Json.Serialization;
|
||||||
|
|
||||||
namespace Nebula.Launcher.Models;
|
namespace Nebula.Shared.Models;
|
||||||
|
|
||||||
public sealed record AuthInfo(
|
public sealed record AuthInfo(
|
||||||
[property: JsonPropertyName("mode")] string Mode,
|
[property: JsonPropertyName("mode")] string Mode,
|
||||||
@@ -1,7 +1,6 @@
|
|||||||
using System;
|
using Nebula.Shared.Utils;
|
||||||
using Nebula.Launcher.Utils;
|
|
||||||
|
|
||||||
namespace Nebula.Launcher.Models;
|
namespace Nebula.Shared.Models;
|
||||||
|
|
||||||
public class RobustUrl
|
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.Diagnostics.CodeAnalysis;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Diagnostics.CodeAnalysis;
|
|
||||||
using System.IO;
|
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using System.Runtime.Loader;
|
using System.Runtime.Loader;
|
||||||
using Nebula.Launcher.FileApis;
|
using Nebula.Shared.FileApis;
|
||||||
using Robust.LoaderApi;
|
using Robust.LoaderApi;
|
||||||
|
|
||||||
namespace Nebula.Launcher.Services;
|
namespace Nebula.Shared.Services;
|
||||||
|
|
||||||
[ServiceRegister]
|
[ServiceRegister]
|
||||||
public class AssemblyService
|
public class AssemblyService
|
||||||
{
|
{
|
||||||
private readonly List<Assembly> _assemblies = new();
|
private readonly Dictionary<string,Assembly> _assemblies = new();
|
||||||
private readonly DebugService _debugService;
|
private readonly DebugService _debugService;
|
||||||
|
|
||||||
public AssemblyService(DebugService debugService)
|
public AssemblyService(DebugService debugService)
|
||||||
@@ -21,12 +18,12 @@ public class AssemblyService
|
|||||||
_debugService = debugService;
|
_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);
|
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;
|
AssemblyLoadContext.Default.ResolvingUnmanagedDll += LoadContextOnResolvingUnmanaged;
|
||||||
|
|
||||||
return asmApi;
|
return asmApi;
|
||||||
@@ -56,6 +53,11 @@ public class AssemblyService
|
|||||||
|
|
||||||
public bool TryOpenAssembly(string name, AssemblyApi assemblyApi, [NotNullWhen(true)] out Assembly? assembly)
|
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))
|
if (!TryOpenAssemblyStream(name, assemblyApi, out var asm, out var pdb))
|
||||||
{
|
{
|
||||||
assembly = null;
|
assembly = null;
|
||||||
@@ -64,9 +66,8 @@ public class AssemblyService
|
|||||||
|
|
||||||
assembly = AssemblyLoadContext.Default.LoadFromStream(asm, pdb);
|
assembly = AssemblyLoadContext.Default.LoadFromStream(asm, pdb);
|
||||||
_debugService.Log("LOADED ASSEMBLY " + name);
|
_debugService.Log("LOADED ASSEMBLY " + name);
|
||||||
|
|
||||||
|
_assemblies.Add(name, assembly);
|
||||||
if (!_assemblies.Contains(assembly)) _assemblies.Add(assembly);
|
|
||||||
|
|
||||||
asm.Dispose();
|
asm.Dispose();
|
||||||
pdb?.Dispose();
|
pdb?.Dispose();
|
||||||
@@ -86,9 +87,11 @@ public class AssemblyService
|
|||||||
return true;
|
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;
|
return TryOpenAssembly(name.Name!, assemblyApi, out var assembly) ? assembly : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1,45 +1,32 @@
|
|||||||
using System;
|
using System.Net.Http.Headers;
|
||||||
using System.Net.Http;
|
using Nebula.Shared.Models.Auth;
|
||||||
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;
|
|
||||||
|
|
||||||
namespace Nebula.Launcher.Services;
|
namespace Nebula.Shared.Services;
|
||||||
|
|
||||||
[ServiceRegister]
|
[ServiceRegister]
|
||||||
public partial class AuthService : ObservableObject
|
public partial class AuthService(
|
||||||
|
RestService restService,
|
||||||
|
DebugService debugService,
|
||||||
|
CancellationService cancellationService)
|
||||||
{
|
{
|
||||||
private readonly HttpClient _httpClient = new();
|
private readonly HttpClient _httpClient = new();
|
||||||
private readonly RestService _restService;
|
public CurrentAuthInfo? SelectedAuth { get; internal set; }
|
||||||
private readonly DebugService _debugService;
|
|
||||||
|
|
||||||
[ObservableProperty]
|
|
||||||
private CurrentAuthInfo? _selectedAuth;
|
|
||||||
|
|
||||||
public string Reason = "";
|
public string Reason = "";
|
||||||
|
|
||||||
public AuthService(RestService restService, DebugService debugService)
|
|
||||||
{
|
|
||||||
_restService = restService;
|
|
||||||
_debugService = debugService;
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<bool> Auth(AuthLoginPassword authLoginPassword)
|
public async Task<bool> Auth(AuthLoginPassword authLoginPassword)
|
||||||
{
|
{
|
||||||
var authServer = authLoginPassword.AuthServer;
|
var authServer = authLoginPassword.AuthServer;
|
||||||
var login = authLoginPassword.Login;
|
var login = authLoginPassword.Login;
|
||||||
var password = authLoginPassword.Password;
|
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 authUrl = new Uri($"{authServer}api/auth/authenticate");
|
||||||
|
|
||||||
var result =
|
var result =
|
||||||
await _restService.PostAsync<AuthenticateResponse, AuthenticateRequest>(
|
await restService.PostAsync<AuthenticateResponse, AuthenticateRequest>(
|
||||||
new AuthenticateRequest(login, password), authUrl, CancellationToken.None);
|
new AuthenticateRequest(login, password), authUrl, cancellationService.Token);
|
||||||
|
|
||||||
if (result.Value is null)
|
if (result.Value is null)
|
||||||
{
|
{
|
||||||
@@ -53,6 +40,11 @@ public partial class AuthService : ObservableObject
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void ClearAuth()
|
||||||
|
{
|
||||||
|
SelectedAuth = null;
|
||||||
|
}
|
||||||
|
|
||||||
public async Task<bool> EnsureToken()
|
public async Task<bool> EnsureToken()
|
||||||
{
|
{
|
||||||
if (SelectedAuth is null) return false;
|
if (SelectedAuth is null) return false;
|
||||||
@@ -61,7 +53,7 @@ public partial class AuthService : ObservableObject
|
|||||||
|
|
||||||
using var requestMessage = new HttpRequestMessage(HttpMethod.Get, authUrl);
|
using var requestMessage = new HttpRequestMessage(HttpMethod.Get, authUrl);
|
||||||
requestMessage.Headers.Authorization = new AuthenticationHeaderValue("SS14Auth", SelectedAuth.Token.Token);
|
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;
|
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.Diagnostics.CodeAnalysis;
|
||||||
using System.IO;
|
|
||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
|
|
||||||
namespace Nebula.Launcher.Services;
|
namespace Nebula.Shared.Services;
|
||||||
|
|
||||||
public class ConVar<T>
|
public class ConVar<T>
|
||||||
{
|
{
|
||||||
@@ -1,24 +1,18 @@
|
|||||||
using System;
|
using System.Buffers.Binary;
|
||||||
using System.Buffers.Binary;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using System.IO;
|
|
||||||
using System.Net.Http;
|
|
||||||
using System.Net.Http.Headers;
|
using System.Net.Http.Headers;
|
||||||
using System.Numerics;
|
using System.Numerics;
|
||||||
using System.Threading;
|
using Nebula.Shared.FileApis.Interfaces;
|
||||||
using System.Threading.Tasks;
|
using Nebula.Shared.Models;
|
||||||
using Nebula.Launcher.FileApis.Interfaces;
|
using Nebula.Shared.Utils;
|
||||||
using Nebula.Launcher.Models;
|
|
||||||
using Nebula.Launcher.Utils;
|
|
||||||
|
|
||||||
namespace Nebula.Launcher.Services;
|
namespace Nebula.Shared.Services;
|
||||||
|
|
||||||
public partial class ContentService
|
public partial class ContentService
|
||||||
{
|
{
|
||||||
public bool CheckManifestExist(RobustManifestItem item)
|
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,
|
public async Task<List<RobustManifestItem>> EnsureItems(ManifestReader manifestReader, Uri downloadUri,
|
||||||
@@ -31,7 +25,7 @@ public partial class ContentService
|
|||||||
{
|
{
|
||||||
if (cancellationToken.IsCancellationRequested)
|
if (cancellationToken.IsCancellationRequested)
|
||||||
{
|
{
|
||||||
_debugService.Log("ensuring is cancelled!");
|
debugService.Log("ensuring is cancelled!");
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -40,11 +34,11 @@ public partial class ContentService
|
|||||||
allItems.Add(item.Value);
|
allItems.Add(item.Value);
|
||||||
}
|
}
|
||||||
|
|
||||||
_debugService.Log("Download Count:" + items.Count);
|
debugService.Log("Download Count:" + items.Count);
|
||||||
|
|
||||||
await Download(downloadUri, items, cancellationToken);
|
await Download(downloadUri, items, cancellationToken);
|
||||||
|
|
||||||
_fileService.ManifestItems = allItems;
|
fileService.ManifestItems = allItems;
|
||||||
|
|
||||||
return allItems;
|
return allItems;
|
||||||
}
|
}
|
||||||
@@ -52,21 +46,21 @@ public partial class ContentService
|
|||||||
public async Task<List<RobustManifestItem>> EnsureItems(RobustManifestInfo info,
|
public async Task<List<RobustManifestItem>> EnsureItems(RobustManifestInfo info,
|
||||||
CancellationToken cancellationToken)
|
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);
|
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);
|
var response = await _http.GetAsync(info.ManifestUri, cancellationToken);
|
||||||
if (!response.IsSuccessStatusCode) throw new Exception();
|
if (!response.IsSuccessStatusCode) throw new Exception();
|
||||||
|
|
||||||
await using var streamContent = await response.Content.ReadAsStreamAsync(cancellationToken);
|
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);
|
streamContent.Seek(0, SeekOrigin.Begin);
|
||||||
using var manifestReader = new ManifestReader(streamContent);
|
using var manifestReader = new ManifestReader(streamContent);
|
||||||
return await EnsureItems(manifestReader, info.DownloadUri, cancellationToken);
|
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)
|
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);
|
var items = await EnsureItems(info, cancellationToken);
|
||||||
foreach (var item in items)
|
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);
|
otherApi.Save(item.Path, stream);
|
||||||
stream.Close();
|
stream.Close();
|
||||||
}
|
}
|
||||||
else
|
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)
|
if (toDownload.Count == 0 || cancellationToken.IsCancellationRequested)
|
||||||
{
|
{
|
||||||
_debugService.Log("Nothing to download! Fuck this!");
|
debugService.Log("Nothing to download! Fuck this!");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
_debugService.Log("Downloading from: " + contentCdn);
|
debugService.Log("Downloading from: " + contentCdn);
|
||||||
|
|
||||||
var requestBody = new byte[toDownload.Count * 4];
|
var requestBody = new byte[toDownload.Count * 4];
|
||||||
var reqI = 0;
|
var reqI = 0;
|
||||||
@@ -110,7 +104,7 @@ public partial class ContentService
|
|||||||
var request = new HttpRequestMessage(HttpMethod.Post, contentCdn);
|
var request = new HttpRequestMessage(HttpMethod.Post, contentCdn);
|
||||||
request.Headers.Add(
|
request.Headers.Add(
|
||||||
"X-Robust-Download-Protocol",
|
"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 = new ByteArrayContent(requestBody);
|
||||||
request.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
|
request.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
|
||||||
@@ -120,7 +114,7 @@ public partial class ContentService
|
|||||||
|
|
||||||
if (cancellationToken.IsCancellationRequested)
|
if (cancellationToken.IsCancellationRequested)
|
||||||
{
|
{
|
||||||
_debugService.Log("Downloading is cancelled!");
|
debugService.Log("Downloading is cancelled!");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -165,7 +159,7 @@ public partial class ContentService
|
|||||||
{
|
{
|
||||||
if (cancellationToken.IsCancellationRequested)
|
if (cancellationToken.IsCancellationRequested)
|
||||||
{
|
{
|
||||||
_debugService.Log("Downloading is cancelled!");
|
debugService.Log("Downloading is cancelled!");
|
||||||
decompressContext?.Dispose();
|
decompressContext?.Dispose();
|
||||||
compressContext?.Dispose();
|
compressContext?.Dispose();
|
||||||
return;
|
return;
|
||||||
@@ -233,9 +227,9 @@ public partial class ContentService
|
|||||||
}
|
}
|
||||||
|
|
||||||
using var fileStream = new MemoryStream(data.ToArray());
|
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;
|
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 Nebula.Shared.Services.Logging;
|
||||||
using System.IO;
|
|
||||||
using Nebula.Launcher.Services.Logging;
|
|
||||||
|
|
||||||
namespace Nebula.Launcher.Services;
|
namespace Nebula.Shared.Services;
|
||||||
|
|
||||||
[ServiceRegister]
|
[ServiceRegister]
|
||||||
public class DebugService : IDisposable
|
public class DebugService : IDisposable
|
||||||
@@ -18,14 +16,14 @@ public class DebugService : IDisposable
|
|||||||
{
|
{
|
||||||
Logger = logger;
|
Logger = logger;
|
||||||
|
|
||||||
if (!Directory.Exists(LogPath))
|
//if (!Directory.Exists(LogPath))
|
||||||
Directory.CreateDirectory(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),
|
//LogStream = File.Open(Path.Combine(LogPath, filename),
|
||||||
FileMode.Append, FileAccess.Write);
|
// FileMode.Append, FileAccess.Write);
|
||||||
LogWriter = new StreamWriter(LogStream);
|
//LogWriter = new StreamWriter(LogStream);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Debug(string message)
|
public void Debug(string message)
|
||||||
@@ -59,7 +57,7 @@ public class DebugService : IDisposable
|
|||||||
private void Log(LoggerCategory category, string message)
|
private void Log(LoggerCategory category, string message)
|
||||||
{
|
{
|
||||||
Logger.Log(category, message);
|
Logger.Log(category, message);
|
||||||
SaveToLog(category, message);
|
//SaveToLog(category, message);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void SaveToLog(LoggerCategory category, string message)
|
private void SaveToLog(LoggerCategory category, string message)
|
||||||
@@ -1,19 +1,12 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Diagnostics.CodeAnalysis;
|
using System.Diagnostics.CodeAnalysis;
|
||||||
using System.IO;
|
using Nebula.Shared.FileApis;
|
||||||
using System.Linq;
|
using Nebula.Shared.Models;
|
||||||
using System.Net.Http;
|
using Nebula.Shared.Utils;
|
||||||
using System.Threading;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using Nebula.Launcher.FileApis;
|
|
||||||
using Nebula.Launcher.Models;
|
|
||||||
using Nebula.Launcher.Utils;
|
|
||||||
|
|
||||||
namespace Nebula.Launcher.Services;
|
namespace Nebula.Shared.Services;
|
||||||
|
|
||||||
[ServiceRegister]
|
[ServiceRegister]
|
||||||
public class EngineService
|
public sealed class EngineService
|
||||||
{
|
{
|
||||||
private readonly AssemblyService _assemblyService;
|
private readonly AssemblyService _assemblyService;
|
||||||
private readonly DebugService _debugService;
|
private readonly DebugService _debugService;
|
||||||
@@ -21,9 +14,11 @@ public class EngineService
|
|||||||
private readonly RestService _restService;
|
private readonly RestService _restService;
|
||||||
private readonly IServiceProvider _serviceProvider;
|
private readonly IServiceProvider _serviceProvider;
|
||||||
private readonly ConfigurationService _varService;
|
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,
|
public EngineService(RestService restService, DebugService debugService, ConfigurationService varService,
|
||||||
FileService fileService, IServiceProvider serviceProvider, AssemblyService assemblyService)
|
FileService fileService, IServiceProvider serviceProvider, AssemblyService assemblyService)
|
||||||
@@ -35,8 +30,7 @@ public class EngineService
|
|||||||
_serviceProvider = serviceProvider;
|
_serviceProvider = serviceProvider;
|
||||||
_assemblyService = assemblyService;
|
_assemblyService = assemblyService;
|
||||||
|
|
||||||
var loadTask = Task.Run(() => LoadEngineManifest(CancellationToken.None));
|
_currInfoTask = Task.Run(() => LoadEngineManifest(CancellationToken.None));
|
||||||
loadTask.Wait();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task LoadEngineManifest(CancellationToken cancellationToken)
|
public async Task LoadEngineManifest(CancellationToken cancellationToken)
|
||||||
@@ -57,6 +51,8 @@ public class EngineService
|
|||||||
|
|
||||||
public EngineBuildInfo? GetVersionInfo(string version)
|
public EngineBuildInfo? GetVersionInfo(string version)
|
||||||
{
|
{
|
||||||
|
CheckAndWaitValidation();
|
||||||
|
|
||||||
if (!VersionInfos.TryGetValue(version, out var foundVersion))
|
if (!VersionInfos.TryGetValue(version, out var foundVersion))
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
@@ -85,7 +81,7 @@ public class EngineService
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
return _assemblyService.Mount(_fileService.OpenZip(version, _fileService.EngineFileApi));
|
return _assemblyService.Mount(_fileService.OpenZip(version, _fileService.EngineFileApi),$"Engine.Ensure-{version}");
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
@@ -120,6 +116,8 @@ public class EngineService
|
|||||||
|
|
||||||
public EngineBuildInfo? GetModuleBuildInfo(string moduleName, string version)
|
public EngineBuildInfo? GetModuleBuildInfo(string moduleName, string version)
|
||||||
{
|
{
|
||||||
|
CheckAndWaitValidation();
|
||||||
|
|
||||||
if (!ModuleInfos.TryGetValue(moduleName, out var module) ||
|
if (!ModuleInfos.TryGetValue(moduleName, out var module) ||
|
||||||
!module.Versions.TryGetValue(version, out var value))
|
!module.Versions.TryGetValue(version, out var value))
|
||||||
return null;
|
return null;
|
||||||
@@ -138,6 +136,8 @@ public class EngineService
|
|||||||
|
|
||||||
public string ResolveModuleVersion(string moduleName, string engineVersion)
|
public string ResolveModuleVersion(string moduleName, string engineVersion)
|
||||||
{
|
{
|
||||||
|
CheckAndWaitValidation();
|
||||||
|
|
||||||
var engineVersionObj = Version.Parse(engineVersion);
|
var engineVersionObj = Version.Parse(engineVersion);
|
||||||
var module = ModuleInfos[moduleName];
|
var module = ModuleInfos[moduleName];
|
||||||
var selectedVersion = module.Versions.Select(kv => new { Version = Version.Parse(kv.Key), kv.Key, kv.Value })
|
var selectedVersion = module.Versions.Select(kv => new { Version = Version.Parse(kv.Key), kv.Key, kv.Value })
|
||||||
@@ -161,7 +161,7 @@ public class EngineService
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
return _assemblyService.Mount(_fileService.OpenZip(fileName, _fileService.EngineFileApi));
|
return _assemblyService.Mount(_fileService.OpenZip(fileName, _fileService.EngineFileApi),"Engine.EnsureModule");
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
@@ -186,4 +186,13 @@ public class EngineService
|
|||||||
{
|
{
|
||||||
return moduleName + "" + moduleVersion;
|
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.IO.Compression;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using Nebula.Launcher.FileApis;
|
using Nebula.Shared.FileApis;
|
||||||
using Nebula.Launcher.FileApis.Interfaces;
|
using Nebula.Shared.FileApis.Interfaces;
|
||||||
using Nebula.Launcher.Models;
|
using Nebula.Shared.Models;
|
||||||
using Nebula.Launcher.Utils;
|
|
||||||
using Robust.LoaderApi;
|
using Robust.LoaderApi;
|
||||||
|
|
||||||
namespace Nebula.Launcher.Services;
|
namespace Nebula.Shared.Services;
|
||||||
|
|
||||||
[ServiceRegister]
|
[ServiceRegister]
|
||||||
public class FileService
|
public class FileService
|
||||||
@@ -1,9 +1,6 @@
|
|||||||
using System;
|
using Nebula.Shared.Models;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Threading;
|
|
||||||
using Nebula.Launcher.Models;
|
|
||||||
|
|
||||||
namespace Nebula.Launcher.Services;
|
namespace Nebula.Shared.Services;
|
||||||
|
|
||||||
[ServiceRegister]
|
[ServiceRegister]
|
||||||
public class HubService
|
public class HubService
|
||||||
@@ -1,6 +1,4 @@
|
|||||||
using System;
|
namespace Nebula.Shared.Services.Logging;
|
||||||
|
|
||||||
namespace Nebula.Launcher.Services.Logging;
|
|
||||||
|
|
||||||
[ServiceRegister(typeof(ILogger))]
|
[ServiceRegister(typeof(ILogger))]
|
||||||
public class ConsoleLogger : ILogger
|
public class ConsoleLogger : ILogger
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
namespace Nebula.Launcher.Services.Logging;
|
namespace Nebula.Shared.Services.Logging;
|
||||||
|
|
||||||
public interface ILogger
|
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.Globalization;
|
||||||
using System.IO;
|
|
||||||
using System.Net;
|
using System.Net;
|
||||||
using System.Net.Http;
|
|
||||||
using System.Net.Http.Json;
|
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
using System.Threading;
|
using Nebula.Shared.Utils;
|
||||||
using System.Threading.Tasks;
|
|
||||||
using Nebula.Launcher.Utils;
|
|
||||||
|
|
||||||
namespace Nebula.Launcher.Services;
|
namespace Nebula.Shared.Services;
|
||||||
|
|
||||||
[ServiceRegister]
|
[ServiceRegister]
|
||||||
public class RestService
|
public class RestService
|
||||||
@@ -1,66 +1,68 @@
|
|||||||
using System;
|
using Nebula.Shared.Models;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Threading;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using Nebula.Launcher.Models;
|
|
||||||
using Robust.LoaderApi;
|
using Robust.LoaderApi;
|
||||||
|
|
||||||
namespace Nebula.Launcher.Services;
|
namespace Nebula.Shared.Services;
|
||||||
|
|
||||||
[ServiceRegister]
|
[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;
|
public async Task PrepareRun(RobustUrl url)
|
||||||
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)
|
|
||||||
{
|
{
|
||||||
_contentService = contentService;
|
var buildInfo = await contentService.GetBuildInfo(url, cancellationService.Token);
|
||||||
_debugService = debugService;
|
await PrepareRun(buildInfo, cancellationService.Token);
|
||||||
_varService = varService;
|
}
|
||||||
_fileService = fileService;
|
|
||||||
_engineService = engineService;
|
public async Task PrepareRun(RobustBuildInfo buildInfo, CancellationToken cancellationToken)
|
||||||
_assemblyService = assemblyService;
|
{
|
||||||
_authService = authService;
|
debugService.Log("Prepare Content!");
|
||||||
_popupMessageService = popupMessageService;
|
|
||||||
|
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,
|
public async Task Run(string[] runArgs, RobustBuildInfo buildInfo, IRedialApi redialApi,
|
||||||
CancellationToken cancellationToken)
|
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)
|
if (engine is null)
|
||||||
throw new Exception("Engine version is not usable: " + buildInfo.BuildInfo.Build.EngineVersion);
|
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>
|
var extraMounts = new List<ApiMount>
|
||||||
{
|
{
|
||||||
new(_fileService.HashApi, "/")
|
new(fileService.HashApi, "/")
|
||||||
};
|
};
|
||||||
|
|
||||||
var module =
|
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)
|
if (module is not null)
|
||||||
extraMounts.Add(new ApiMount(module, "/"));
|
extraMounts.Add(new ApiMount(module, "/"));
|
||||||
|
|
||||||
var args = new MainArgs(runArgs, engine, redialApi, extraMounts);
|
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!");
|
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;
|
return;
|
||||||
|
|
||||||
await Task.Run(() => loader.Main(args), cancellationToken);
|
await Task.Run(() => loader.Main(args), cancellationToken);
|
||||||
@@ -71,12 +73,12 @@ public class RunnerService: IRedialApi
|
|||||||
var url = new RobustUrl(urlraw);
|
var url = new RobustUrl(urlraw);
|
||||||
|
|
||||||
using var cancelTokenSource = new CancellationTokenSource();
|
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)
|
if (account is null)
|
||||||
{
|
{
|
||||||
_popupMessageService.PopupInfo("Error! Auth is required!");
|
popupMessageService.Popup("Error! Auth is required!");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -112,13 +114,13 @@ public class RunnerService: IRedialApi
|
|||||||
|
|
||||||
args.Add("--ss14-address");
|
args.Add("--ss14-address");
|
||||||
args.Add(url.ToString());
|
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);
|
await Run(args.ToArray(), buildInfo, this, cancelTokenSource.Token);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async void Redial(Uri uri, string text = "")
|
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.Diagnostics;
|
||||||
using System.IO;
|
|
||||||
using System.Threading;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace Nebula.Launcher.Utils;
|
namespace Nebula.Shared.Utils;
|
||||||
|
|
||||||
public sealed class BandwidthStream : Stream
|
public sealed class BandwidthStream : Stream
|
||||||
{
|
{
|
||||||
@@ -1,8 +1,6 @@
|
|||||||
using System;
|
|
||||||
using System.Windows.Input;
|
using System.Windows.Input;
|
||||||
using Nebula.Launcher.ViewModels;
|
|
||||||
|
|
||||||
namespace Nebula.Launcher.Utils;
|
namespace Nebula.Shared.Utils;
|
||||||
|
|
||||||
public class DelegateCommand<T> : ICommand
|
public class DelegateCommand<T> : ICommand
|
||||||
{
|
{
|
||||||
@@ -1,10 +1,8 @@
|
|||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Net.Http;
|
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace Nebula.Launcher.Utils;
|
namespace Nebula.Shared.Utils;
|
||||||
|
|
||||||
public static class Helper
|
public static class Helper
|
||||||
{
|
{
|
||||||
@@ -1,9 +1,8 @@
|
|||||||
using System.Diagnostics.CodeAnalysis;
|
using System.Diagnostics.CodeAnalysis;
|
||||||
using System.IO;
|
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using Nebula.Launcher.Models;
|
using Nebula.Shared.Models;
|
||||||
|
|
||||||
namespace Nebula.Launcher.Utils;
|
namespace Nebula.Shared.Utils;
|
||||||
|
|
||||||
public class ManifestReader : StreamReader
|
public class ManifestReader : StreamReader
|
||||||
{
|
{
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
namespace Nebula.Launcher.Utils;
|
namespace Nebula.Shared.Utils;
|
||||||
|
|
||||||
public class Ref<T>
|
public class Ref<T>
|
||||||
{
|
{
|
||||||
@@ -1,11 +1,8 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.IO;
|
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
using System.Text.Json.Serialization;
|
using System.Text.Json.Serialization;
|
||||||
|
|
||||||
namespace Nebula.Launcher.Utils;
|
namespace Nebula.Shared.Utils;
|
||||||
|
|
||||||
public static class RidUtility
|
public static class RidUtility
|
||||||
{
|
{
|
||||||
@@ -1,10 +1,6 @@
|
|||||||
using System;
|
|
||||||
using System.Buffers;
|
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
|
public static class StreamHelper
|
||||||
{
|
{
|
||||||
@@ -1,9 +1,9 @@
|
|||||||
using System;
|
|
||||||
using System.Diagnostics.CodeAnalysis;
|
using System.Diagnostics.CodeAnalysis;
|
||||||
using System.Diagnostics.Contracts;
|
using System.Diagnostics.Contracts;
|
||||||
using System.Web;
|
using System.Web;
|
||||||
|
using Nebula.Shared.Models;
|
||||||
|
|
||||||
namespace Nebula.Launcher.Utils;
|
namespace Nebula.Shared.Utils;
|
||||||
|
|
||||||
public static class UriHelper
|
public static class UriHelper
|
||||||
{
|
{
|
||||||
@@ -132,4 +132,9 @@ public static class UriHelper
|
|||||||
|
|
||||||
return uriBuilder.Uri;
|
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.Buffers;
|
||||||
using System.IO;
|
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using System.Threading;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using SharpZstd.Interop;
|
using SharpZstd.Interop;
|
||||||
using static SharpZstd.Interop.Zstd;
|
using static SharpZstd.Interop.Zstd;
|
||||||
|
|
||||||
namespace Nebula.Launcher.Utils;
|
namespace Nebula.Shared.Utils;
|
||||||
|
|
||||||
public static class ZStd
|
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
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Robust.LoaderApi", "Robust.LoaderApi\Robust.LoaderApi\Robust.LoaderApi.csproj", "{8AE91631-DE96-4A97-A255-058E27A7C3EA}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Robust.LoaderApi", "Robust.LoaderApi\Robust.LoaderApi\Robust.LoaderApi.csproj", "{8AE91631-DE96-4A97-A255-058E27A7C3EA}"
|
||||||
EndProject
|
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
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
Debug|Any CPU = Debug|Any CPU
|
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}.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.ActiveCfg = Release|Any CPU
|
||||||
{8AE91631-DE96-4A97-A255-058E27A7C3EA}.Release|Any CPU.Build.0 = 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
|
EndGlobalSection
|
||||||
EndGlobal
|
EndGlobal
|
||||||
|
|||||||
Reference in New Issue
Block a user