first commit

This commit is contained in:
Max Chaev 2025-02-21 13:13:35 +03:00
commit 48220f8b23
28 changed files with 834 additions and 0 deletions

5
README.md Normal file
View File

@ -0,0 +1,5 @@
# Plombir Launcher
Small launcher for vanilla minecraft!
## WIP

6
src/Launcher/.gitignore vendored Normal file
View File

@ -0,0 +1,6 @@
/bin
/minecraft
/obj
/publish
/.vscode
*.env

140
src/Launcher/Launcher.cs Normal file
View File

@ -0,0 +1,140 @@
using System.Formats.Tar;
using System.Net;
using System.Runtime.InteropServices;
using System.Security.AccessControl;
using CmlLib.Core;
using CmlLib.Core.Auth;
using CmlLib.Core.ProcessBuilder;
namespace BlightFlame
{
/*
Basically a class to manage everything launcher related.
TODO - minecraft downloading from webserver
*/
public class Launcher
{
private readonly string _version;
private readonly string _nickname;
static private MinecraftPath _mcPath;
static private MinecraftLauncher _mcLauncher;
public int DownloadProgress;
public string DownloadStatus;
public Launcher(string userName, string version)
{
_version = version;
_nickname = userName;
_mcPath = new($"./runtime/{version}/minecraft");
_mcLauncher = new(_mcPath);
}
// Using it for forge loading because i don't know event-based async.
//static TaskCompletionSource<bool> tcs = new();
// Not used. Because launcher supports only VANILLA.
// public async Task FetchMinecraft()
// {
// string archieve = "mc-archieve.tar.xz";
// string runtimePath = "runtime";
// System.Uri download_uri = new("https://dixxe.top/static/distro/cmllibcore-minecraft-forge-1201.tar.xz");
// WebClient client = new();
// if ((!File.Exists(archieve)) && (!Directory.Exists(runtimePath)))
// {
// DownloadStatus = "Fetching deploy-minecraft from host...";
// Console.WriteLine(DownloadStatus);
// // Implement async download
// client.DownloadFileAsync(download_uri, archieve);
// client.DownloadDataCompleted += (o, e) =>
// {
// DownloadStatus = "Download completed";
// Console.WriteLine(DownloadStatus);
// };
// client.DownloadProgressChanged += (o, e) =>
// {
// // Curentlly this scope doing nothing
// Console.WriteLine($"{e.ProgressPercentage}% downloaded");
// DownloadProgress = e.ProgressPercentage;
// DownloadStatus = "Fetching modpack...";
// if (DownloadProgress == 100)
// {
// tcs.SetResult(true);
// }
// };
// // Waiting for archieve to download.
// await tcs.Task;
// }
// DownloadStatus = "Unarchiving modpack...";
// unarchiveMinecraft(archieve, runtimePath);
// }
// Not used. Because launcher supports only VANILLA.
// private void unarchiveMinecraft(string archieveName, string path)
// {
// if (Directory.Exists(path)) { return; }
// Console.WriteLine(DownloadStatus);
// Directory.CreateDirectory(path);
// Utils.UnzipTarGzFile(archieveName, path);
// if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
// {
// Utils.LinuxExec($"chmod -R +x {path}/");
// Console.WriteLine("Execute permissions added successfully.");
// }
// File.Delete(archieveName);
// }
async public Task BuildLauncher()
{
_mcLauncher.ByteProgressChanged += (_, args) =>
{
Console.WriteLine($"{(int)(args.ProgressedBytes * 0.000001)} MBytes / {(int)(args.TotalBytes * 0.000001)} MBytes");
DownloadProgress = (int)(args.ProgressedBytes * 100 / args.TotalBytes);
};
// Before installAsync I should fetch lightweight minecraft instance from webserver
// Then installAsync will download any runtime needed stuff.
// This method is FetchMinecraft()
// Currently this is only one viable option for forge installations.
// But it requires server, so forge (and all mod loaders) is disabled.
//await FetchMinecraft();
DownloadStatus = "Installing minecraft...";
Console.WriteLine(DownloadStatus);
await _mcLauncher.InstallAsync(_version);
DownloadStatus = "Finished!";
Console.WriteLine(DownloadStatus);
}
async public Task RunLauncher()
{
var process = await _mcLauncher.BuildProcessAsync(_version, new MLaunchOption{
Session = MSession.CreateOfflineSession(_nickname),
MaximumRamMb = 4096,
}) ?? throw new Exception("Failed to start minecraft process!");
var processUtil = new ProcessWrapper(process);
processUtil.OutputReceived += (s, e) => Console.WriteLine(e);
processUtil.StartWithEvents();
await processUtil.WaitForExitTaskAsync();
}
}
}

10
src/Launcher/Program.cs Normal file
View File

@ -0,0 +1,10 @@
namespace BlightFlame
{
sealed class Program
{
public static void Main()
{
Console.WriteLine("init: launcher");
}
}
}

74
src/Launcher/Utils.cs Normal file
View File

@ -0,0 +1,74 @@
using System.IO.Compression;
using System;
using System.IO;
using SharpCompress.Archives;
using SharpCompress.Common;
using SharpCompress.Readers;
using System.Diagnostics;
using CmlLib.Core;
namespace BlightFlame
{
static public class Utils
{
public static void UnzipTarGzFile(string filePath, string destinationPath)
{
using (Stream stream = File.OpenRead(filePath))
{
using (var reader = ReaderFactory.Open(stream))
{
while (reader.MoveToNextEntry())
{
if (!reader.Entry.IsDirectory)
{
reader.WriteEntryToDirectory(destinationPath, new ExtractionOptions()
{
ExtractFullPath = true,
Overwrite = true
});
}
}
}
}
}
public static void LinuxExec(string cmd)
{
var escapedArgs = cmd.Replace("\"", "\\\"");
using var process = new Process
{
StartInfo = new ProcessStartInfo
{
RedirectStandardOutput = true,
UseShellExecute = false,
CreateNoWindow = true,
WindowStyle = ProcessWindowStyle.Hidden,
FileName = "/bin/bash",
Arguments = $"-c \"{escapedArgs}\""
}
};
process.Start();
process.WaitForExit();
}
public static async Task<List<string>> GetAllMcVersions()
{
return await Task.Run(async() => {
var ln = new MinecraftLauncher();
var result = new List<string>();
foreach (var x in await ln.GetAllVersionsAsync())
{
result.Add(x.Name);
}
return result;
});
}
}
}

View File

@ -0,0 +1,23 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>exe</OutputType>
<TargetFramework>net9.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<PublishSingleFile>true</PublishSingleFile>
<EnableCompressionInSingleFile>true</EnableCompressionInSingleFile>
<IsAotCompatible>false</IsAotCompatible>
</PropertyGroup>
<ItemGroup>
</ItemGroup>
<ItemGroup>
<PackageReference Include="CmlLib.Core" Version="4.0.4" />
<PackageReference Include="SharpCompress" Version="0.39.0" />
</ItemGroup>
</Project>

6
src/LauncherGUI/.gitignore vendored Normal file
View File

@ -0,0 +1,6 @@
/bin
/runtime
/obj
/publish
/.vscode
*.env

20
src/LauncherGUI/App.axaml Normal file
View File

@ -0,0 +1,20 @@
<Application xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="LauncherGUI.App"
xmlns:local="using:LauncherGUI"
RequestedThemeVariant="Default">
<!-- "Default" ThemeVariant follows system theme variant. "Dark" or "Light" are other available options. -->
<Application.DataTemplates>
<local:ViewLocator/>
</Application.DataTemplates>
<Application.Styles>
<FluentTheme />
</Application.Styles>
<Application.Resources>
<FontFamily x:Key="QuicksandFont">avares://LauncherGUI/Assets/Fonts/Quicksand-SemiBold.ttf#Quicksand</FontFamily>
</Application.Resources>
</Application>

View File

@ -0,0 +1,47 @@
using Avalonia;
using Avalonia.Controls.ApplicationLifetimes;
using Avalonia.Data.Core;
using Avalonia.Data.Core.Plugins;
using System.Linq;
using Avalonia.Markup.Xaml;
using LauncherGUI.ViewModels;
using LauncherGUI.Views;
namespace LauncherGUI;
public partial class App : Application
{
public override void Initialize()
{
AvaloniaXamlLoader.Load(this);
}
public override void OnFrameworkInitializationCompleted()
{
if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
{
// Avoid duplicate validations from both Avalonia and the CommunityToolkit.
// More info: https://docs.avaloniaui.net/docs/guides/development-guides/data-validation#manage-validationplugins
DisableAvaloniaDataAnnotationValidation();
desktop.MainWindow = new MainWindow
{
DataContext = new MainWindowViewModel(),
};
}
base.OnFrameworkInitializationCompleted();
}
private void DisableAvaloniaDataAnnotationValidation()
{
// Get an array of plugins to remove
var dataValidationPluginsToRemove =
BindingPlugins.DataValidators.OfType<DataAnnotationsValidationPlugin>().ToArray();
// remove each entry found
foreach (var plugin in dataValidationPluginsToRemove)
{
BindingPlugins.DataValidators.Remove(plugin);
}
}
}

Binary file not shown.

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 147 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

View File

@ -0,0 +1,36 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFramework>net9.0</TargetFramework>
<Nullable>enable</Nullable>
<BuiltInComInteropSupport>true</BuiltInComInteropSupport>
<ApplicationManifest>app.manifest</ApplicationManifest>
<AvaloniaUseCompiledBindingsByDefault>true</AvaloniaUseCompiledBindingsByDefault>
</PropertyGroup>
<ItemGroup>
<Folder Include="Models\" />
<AvaloniaResource Include="Assets\**" />
</ItemGroup>
<PropertyGroup>
<AvaloniaUseCompiledBindingsByDefault>true</AvaloniaUseCompiledBindingsByDefault>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Avalonia" Version="11.2.1" />
<PackageReference Include="Avalonia.Desktop" Version="11.2.1" />
<PackageReference Include="Avalonia.Themes.Fluent" Version="11.2.1" />
<PackageReference Include="Avalonia.Fonts.Inter" Version="11.2.1" />
<!--Condition below is needed to remove Avalonia.Diagnostics package from build output in Release configuration.-->
<PackageReference Include="Avalonia.Diagnostics" Version="11.2.1">
<IncludeAssets Condition="'$(Configuration)' != 'Debug'">None</IncludeAssets>
<PrivateAssets Condition="'$(Configuration)' != 'Debug'">All</PrivateAssets>
</PackageReference>
<PackageReference Include="CommunityToolkit.Mvvm" Version="8.2.1" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Launcher\cmllibLauncher.csproj" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,22 @@
using Avalonia;
using BlightFlame;
using System;
namespace LauncherGUI;
sealed 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) => BuildAvaloniaApp()
.StartWithClassicDesktopLifetime(args);
// Avalonia configuration, don't remove; also used by visual designer.
public static AppBuilder BuildAvaloniaApp()
=> AppBuilder.Configure<App>()
.UsePlatformDetect()
.WithInterFont()
.LogToTrace();
}

View File

@ -0,0 +1,31 @@
using System;
using Avalonia.Controls;
using Avalonia.Controls.Templates;
using LauncherGUI.ViewModels;
namespace LauncherGUI;
public class ViewLocator : IDataTemplate
{
public Control? Build(object? param)
{
if (param is null)
return null;
var name = param.GetType().FullName!.Replace("ViewModel", "View", StringComparison.Ordinal);
var type = Type.GetType(name);
if (type != null)
{
return (Control)Activator.CreateInstance(type)!;
}
return new TextBlock { Text = "Not Found: " + name };
}
public bool Match(object? data)
{
return data is ViewModelBase;
}
}

View File

@ -0,0 +1,10 @@
namespace LauncherGUI.ViewModels;
public partial class LoadingWindowViewModel : ViewModelBase
{
private long _loadingProgress;
public long Progress {get => _loadingProgress; set {_loadingProgress = value; OnPropertyChanged(nameof(Progress)); }}
private string _loadingStatus = "Rotating transistors..";
public string LoadingStatus {get => _loadingStatus; set {_loadingStatus = value; OnPropertyChanged(nameof(LoadingStatus)); }}
}

View File

@ -0,0 +1,15 @@
using System.Collections.Generic;
using BlightFlame;
namespace LauncherGUI.ViewModels;
public partial class MainWindowViewModel : ViewModelBase
{
public string Greeting { get; } = "Plombir launcher";
private string _userNick = "slugcat";
public string Usernick {get => _userNick; set {_userNick = value; OnPropertyChanged(nameof(Usernick)); }}
private string _selectedVersion = "1.20.1";
public string SelectedVersion {get => _selectedVersion; set {_selectedVersion = value; OnPropertyChanged(nameof(SelectedVersion)); }}
}

View File

@ -0,0 +1,10 @@
using System.Collections.Generic;
using BlightFlame;
using LauncherGUI.ViewModels;
namespace LauncherGUI.ViewModels;
public partial class VersionSelectorWindowViewModel : ViewModelBase
{
}

View File

@ -0,0 +1,7 @@
using CommunityToolkit.Mvvm.ComponentModel;
namespace LauncherGUI.ViewModels;
public class ViewModelBase : ObservableObject
{
}

View File

@ -0,0 +1,58 @@
<Window xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:vm="using:LauncherGUI.ViewModels"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" d:DesignWidth="400" d:DesignHeight="200"
x:Class="LauncherGUI.Views.LoadingWindow"
x:DataType="vm:LoadingWindowViewModel"
Icon="/Assets/icon.png"
Title="loading"
RequestedThemeVariant="Dark"
Width="400" Height="200"
MinWidth="400" MinHeight="200"
MaxWidth="400" MaxHeight="200"
Background="#353535">
<Design.DataContext>
<!-- This only sets the DataContext for the previewer in an IDE,
to set the actual DataContext for runtime, set the DataContext property in code (look at App.axaml.cs) -->
<vm:LoadingWindowViewModel/>
</Design.DataContext>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="50"/>
<RowDefinition Height="*"/>
<RowDefinition Height="50"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<TextBlock Text="Loading minecraft..."
FontFamily="{StaticResource QuicksandFont}"
HorizontalAlignment="Center"
Grid.Row="0" Grid.ColumnSpan="2"/>
<Border
Grid.Row="1" Grid.Column="1"
HorizontalAlignment="Center"
VerticalAlignment="Center">
<TextBlock Text="{Binding LoadingStatus}"/>
</Border>
<Border
Margin="10"
Grid.Row="2" Grid.ColumnSpan="2">
<ProgressBar
Minimum="0"
Value="{Binding Progress}"
Maximum="100"/>
</Border>
</Grid>
</Window>

View File

@ -0,0 +1,48 @@
using System;
using System.Threading.Tasks;
using Avalonia.Controls;
using Avalonia.Interactivity;
using Avalonia.VisualTree;
using BlightFlame;
using LauncherGUI.ViewModels;
namespace LauncherGUI.Views;
public partial class LoadingWindow : Window
{
private Launcher ln;
public LoadingWindow(string nickname, string? version = null)
{
ln = new Launcher(nickname, version ?? "1.20.1");
InitializeComponent();
DataContext = new LoadingWindowViewModel();
}
public async Task InitLoading()
{
var viewModel = DataContext as LoadingWindowViewModel;
if (viewModel == null)
{
throw new InvalidOperationException("No DataContext set");
}
Task updateGui = new Task(async () => {
while (ln.DownloadStatus != "Finished!"){
viewModel.Progress = ln.DownloadProgress;
viewModel.LoadingStatus = ln.DownloadStatus;
await Task.Delay(1000);
}
viewModel.Progress = 100;
});
updateGui.Start();
await ln.BuildLauncher();
}
public async Task RunMinecraft()
{
await ln.RunLauncher();
}
}

View File

@ -0,0 +1,123 @@
<Window xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:vm="using:LauncherGUI.ViewModels"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" d:DesignWidth="750" d:DesignHeight="500"
x:Class="LauncherGUI.Views.MainWindow"
x:DataType="vm:MainWindowViewModel"
Icon="/Assets/icon.png"
Title="PlombirLauncher"
RequestedThemeVariant="Dark"
Width="750" Height="500"
MinWidth="750" MinHeight="500"
MaxWidth="750" MaxHeight="500">
<Window.Background>
<ImageBrush Source="/Assets/background.jpg" Stretch="UniformToFill"/>
</Window.Background>
<Design.DataContext>
<!-- This only sets the DataContext for the previewer in an IDE,
to set the actual DataContext for runtime, set the DataContext property in code (look at App.axaml.cs) -->
<vm:MainWindowViewModel/>
</Design.DataContext>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="50"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<StackPanel
HorizontalAlignment="Center"
Grid.Row="0" Grid.ColumnSpan="3" >
<Border
Width="500"
Background="#353535"
Padding="10" Margin="3"
CornerRadius="10">
<Image Source="/Assets/title.png"
Stretch="Uniform"/>
</Border>
<TextBlock FontFamily="{StaticResource QuicksandFont}"
HorizontalAlignment="Right" Text="v1.0.0 - nullmax17"/>
</StackPanel>
<StackPanel
VerticalAlignment="Center"
HorizontalAlignment="Center"
Grid.Row="1" Grid.Column="0">
<Border
Background="#353535"
HorizontalAlignment="Center"
Width="150"
CornerRadius="10"
Padding="15">
<Button FontFamily="{StaticResource QuicksandFont}" Content="Launch MC" Click="OnLaunchMinecraftClick" HorizontalAlignment="Center"/>
</Border>
<Border
Background="#353535"
HorizontalAlignment="Center"
Width="250"
CornerRadius="10"
Padding="15" Margin="15">
<StackPanel>
<TextBlock
HorizontalAlignment="Center"
Text="Insert username:"
FontFamily="{StaticResource QuicksandFont}"/>
<TextBox Margin="5" Text="{Binding Usernick, Mode=TwoWay}" Width="200" />
</StackPanel>
</Border>
<Border
Background="#353535"
HorizontalAlignment="Center"
Width="150"
CornerRadius="10"
Padding="10">
<Button
FontFamily="{StaticResource QuicksandFont}"
Content="Choose version"
Click="OnChooseVersionClick"
HorizontalAlignment="Center"/>
</Border>
</StackPanel>
<Border
Background="#353535"
HorizontalAlignment="Center"
Width="305"
Height="300"
CornerRadius="10"
Padding="15" Margin="15"
Grid.Row="1" Grid.Column="2">
<StackPanel>
<TextBlock FontFamily="{StaticResource QuicksandFont}" Text="> Cross-platform minecraft launcher!"/>
<TextBlock FontFamily="{StaticResource QuicksandFont}" Height="50" Text="> Fully open-source and privacy focused!"/>
<TextBlock FontFamily="{StaticResource QuicksandFont}" Text="To use it:"/>
<TextBlock FontFamily="{StaticResource QuicksandFont}" Text="1. Choose desired nickname."/>
<TextBlock FontFamily="{StaticResource QuicksandFont}" Text="2. Choose desired minecraft version."/>
<TextBlock FontFamily="{StaticResource QuicksandFont}" Height="50" Text="3. Launch minecraft!"/>
</StackPanel>
</Border>
</Grid>
</Window>

View File

@ -0,0 +1,54 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Avalonia.Controls;
using Avalonia.Interactivity;
using Avalonia.VisualTree;
using BlightFlame;
using CmlLib.Core.VersionMetadata;
using LauncherGUI.ViewModels;
namespace LauncherGUI.Views;
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
DataContext = new MainWindowViewModel();
if (DataContext == null) throw new NullReferenceException("Cant load MainWindow DataContext");
}
private async void OnLaunchMinecraftClick(object sender, RoutedEventArgs e)
{
var button = sender as Button;
if (button == null) return;
var root = button.GetVisualRoot() as MainWindow;
if (root == null) return;
var vm = DataContext as MainWindowViewModel;
LoadingWindow loading = new(vm.Usernick, vm.SelectedVersion);
loading.Show(root);
await loading.InitLoading();
loading.Close();
button.Content = "Minecraft launched";
await loading.RunMinecraft();
}
private void OnChooseVersionClick(object sender, RoutedEventArgs e)
{
var button = sender as Button;
if (button == null) return;
var root = button.GetVisualRoot() as MainWindow;
if (root == null) return;
VersionSelectorWindow selector = new(DataContext as MainWindowViewModel);
selector.Show(root);
}
}

View File

@ -0,0 +1,28 @@
<Window xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:vm="using:LauncherGUI.ViewModels"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" d:DesignWidth="400" d:DesignHeight="200"
x:Class="LauncherGUI.Views.VersionSelectorWindow"
x:DataType="vm:VersionSelectorWindowViewModel"
Icon="/Assets/icon.png"
Title="Select version"
RequestedThemeVariant="Dark"
Width="600" Height="500"
MinWidth="600" MinHeight="500"
MaxWidth="600" MaxHeight="500"
Background="#353535">
<StackPanel>
<ListBox x:Name="versions" Height="499" SelectionChanged="OnSelectionChanged">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding}"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</StackPanel>
</Window>

View File

@ -0,0 +1,43 @@
using System;
using System.Linq;
using System.Threading.Tasks;
using Avalonia.Controls;
using Avalonia.Threading;
using LauncherGUI.ViewModels;
namespace LauncherGUI.Views;
public partial class VersionSelectorWindow : Window
{
private MainWindowViewModel _mainViewModel;
public VersionSelectorWindow(MainWindowViewModel mainViewModel)
{
InitializeComponent();
_mainViewModel = mainViewModel;
//Load versions asynchronously
var versionsList = Task.Run(() => BlightFlame.Utils.GetAllMcVersions().GetAwaiter().GetResult());
versions.ItemsSource = versionsList.Result;
}
private async void OnSelectionChanged(object sender, SelectionChangedEventArgs e)
{
var selectedVersion = versions.SelectedItem as string ?? throw new NullReferenceException("Null version selected!");
_mainViewModel.SelectedVersion = selectedVersion;
System.Console.WriteLine($"Selected version: {selectedVersion}");
LoadingWindow loading = new(_mainViewModel.Usernick, _mainViewModel.SelectedVersion);
loading.Show(this);
await loading.InitLoading();
loading.Close();
this.Close();
await loading.RunMinecraft();;
}
}

View File

@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1">
<!-- This manifest is used on Windows only.
Don't remove it as it might cause problems with window transparency and embedded controls.
For more details visit https://learn.microsoft.com/en-us/windows/win32/sbscs/application-manifests -->
<assemblyIdentity version="1.0.0.0" name="LauncherGUI.Desktop"/>
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
<application>
<!-- A list of the Windows versions that this application has been tested on
and is designed to work with. Uncomment the appropriate elements
and Windows will automatically select the most compatible environment. -->
<!-- Windows 10 -->
<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}" />
</application>
</compatibility>
</assembly>