Project structure changes

This commit is contained in:
Max Chaev 2025-02-22 12:19:42 +03:00
parent 652e918acd
commit 882548b110
49 changed files with 245 additions and 302 deletions

1
.gitignore vendored Normal file
View File

@ -0,0 +1 @@
/package/out

72
Launcher-Core/Launcher.cs Normal file
View File

@ -0,0 +1,72 @@
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 Plombir;
/*
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, string? location = null)
{
_version = version;
_nickname = userName;
_mcPath = new($"{location}/{version}/minecraft");
_mcLauncher = new(_mcPath);
}
async public Task BuildLauncher(CancellationToken token)
{
if (_mcLauncher is null)
throw new NullReferenceException("Failed to build! Launcher is null!");
_mcLauncher.ByteProgressChanged += (_, args) =>
{
Console.WriteLine($"{(int)(args.ProgressedBytes * 0.000001)} MBytes / {(int)(args.TotalBytes * 0.000001)} MBytes");
DownloadProgress = (int)(args.ProgressedBytes * 100 / args.TotalBytes);
};
DownloadStatus = "Installing minecraft...";
Console.WriteLine(DownloadStatus);
await _mcLauncher.InstallAsync(_version);
DownloadStatus = "Finished!";
Console.WriteLine(DownloadStatus);
return;
}
async public Task RunLauncher()
{
if (_mcLauncher is null)
throw new NullReferenceException("Failed to run launcher! Launcher is null!");
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();
}
}

9
Launcher-Core/Program.cs Normal file
View File

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

32
Launcher-Core/Utils.cs Normal file
View File

@ -0,0 +1,32 @@
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 Plombir;
static public class Utils
{
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;
});
}
}

24
Launcher-UI/App.axaml Normal file
View File

@ -0,0 +1,24 @@
<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://Launcher-UI/Assets/Fonts/Quicksand-SemiBold.ttf#Quicksand</FontFamily>
</Application.Resources>
</Application>

View File

Before

Width:  |  Height:  |  Size: 147 KiB

After

Width:  |  Height:  |  Size: 147 KiB

View File

Before

Width:  |  Height:  |  Size: 892 B

After

Width:  |  Height:  |  Size: 892 B

View File

Before

Width:  |  Height:  |  Size: 939 B

After

Width:  |  Height:  |  Size: 939 B

View File

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

Before

Width:  |  Height:  |  Size: 2.0 KiB

After

Width:  |  Height:  |  Size: 2.0 KiB

View File

Before

Width:  |  Height:  |  Size: 911 B

After

Width:  |  Height:  |  Size: 911 B

View File

@ -2,7 +2,7 @@ using System;
using System.IO;
using Tommy;
namespace PlombirLauncher;
namespace Plombir;
public class ConfigManager
{
@ -27,7 +27,7 @@ public class ConfigManager
["nickname"] = "slugcat"
};
using(StreamWriter writer = File.CreateText("tweaks.toml"))
using (StreamWriter writer = File.CreateText("tweaks.toml"))
{
toml.WriteTo(writer);
// Remember to flush the data if needed!
@ -41,7 +41,7 @@ public class ConfigManager
{
BuildDefault();
}
using(StreamReader reader = File.OpenText("tweaks.toml"))
using (StreamReader reader = File.OpenText("tweaks.toml"))
{
TomlTable table = TOML.Parse(reader);
@ -58,18 +58,18 @@ public class ConfigManager
TomlTable table;
using(StreamReader reader = File.OpenText("tweaks.toml"))
using (StreamReader reader = File.OpenText("tweaks.toml"))
{
table = TOML.Parse(reader);
table[key] = value;
}
using(StreamWriter writer = File.CreateText("tweaks.toml"))
using (StreamWriter writer = File.CreateText("tweaks.toml"))
{
table.WriteTo(writer);
// Remember to flush the data if needed!
writer.Flush();
}
}
}
}

View File

@ -32,6 +32,7 @@
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Launcher\cmllibLauncher.csproj" />
<ProjectReference Include="..\Launcher-Core\Launcher-Core.csproj" />
</ItemGroup>
</Project>

View File

@ -1,14 +1,18 @@
using System;
using System.Threading.Tasks;
using Avalonia.Controls;
using LauncherGUI.ViewModels;
using LauncherGUI.Views;
namespace PlombirLauncher;
namespace Plombir;
public class LauncherUtils
{
public async static Task CreateMinecraftInstance(MainWindowViewModel vm, Window windowCaller)
{
if (vm.Usernick is null) throw new NullReferenceException("Failed to create minecraft instance! Nickname is null!");
if (vm.SelectedVersion is null) throw new NullReferenceException("Failed to create minecraft instance! Selected version is null!");
System.Console.WriteLine($"Creating minecraft instance for {vm.Usernick}, {vm.SelectedVersion} in {vm.RuntimeLocation}");
LoadingWindow loading = new(vm.Usernick, vm.SelectedVersion, vm.RuntimeLocation);
ConfigManager.WriteInConfig("last-version-launched", vm.SelectedVersion);
@ -20,4 +24,4 @@ public class LauncherUtils
await loading.RunMinecraft();
return;
}
}
}

Binary file not shown.

Binary file not shown.

View File

@ -1,5 +1,5 @@
using Avalonia;
using PlombirLauncher;
using Avalonia;
using Plombir;
using System;
namespace LauncherGUI;

View File

@ -0,0 +1,18 @@
using System.Collections.Generic;
using Plombir;
namespace LauncherGUI.ViewModels;
public partial class MainWindowViewModel : ViewModelBase
{
public string Greeting { get; } = "Plombir launcher";
private string? _userNick = ConfigManager.ReadConfig("nickname");
public string? Usernick { get => _userNick; set { _userNick = value; OnPropertyChanged(nameof(Usernick)); } }
private string? _selectedVersion = ConfigManager.ReadConfig("last-version-launched");
public string? SelectedVersion { get => _selectedVersion; set { _selectedVersion = value; OnPropertyChanged(nameof(SelectedVersion)); } }
private string? _runtimeLocation = ConfigManager.ReadConfig("runtime-path");
public string? RuntimeLocation { get => _runtimeLocation; set { _runtimeLocation = value; OnPropertyChanged(nameof(RuntimeLocation)); } }
}

View File

@ -1,5 +1,5 @@
using System.Collections.Generic;
using PlombirLauncher;
using Plombir;
using LauncherGUI.ViewModels;
namespace LauncherGUI.ViewModels;
@ -7,4 +7,4 @@ namespace LauncherGUI.ViewModels;
public partial class VersionSelectorWindowViewModel : ViewModelBase
{
// I save launcher data mostly in MainWindowViewModel.
}
}

View File

@ -3,7 +3,7 @@ using System.Threading.Tasks;
using Avalonia.Controls;
using Avalonia.Interactivity;
using Avalonia.VisualTree;
using PlombirLauncher;
using Plombir;
using LauncherGUI.ViewModels;
using System.Threading;
@ -12,9 +12,9 @@ namespace LauncherGUI.Views;
public partial class LoadingWindow : Window
{
private Launcher ln;
private Task _buildingTask;
private Task? _buildingTask;
// Tokens for controlling download task.
// Tokens for controlling download task.
CancellationTokenSource tokenSource = new CancellationTokenSource();
public LoadingWindow(string nickname, string? version = null, string? location = null)
{
@ -23,7 +23,7 @@ public partial class LoadingWindow : Window
DataContext = new LoadingWindowViewModel();
}
public async Task InitLoading()
public async Task InitLoading()
{
var viewModel = DataContext as LoadingWindowViewModel;
if (viewModel == null)
@ -31,10 +31,12 @@ public partial class LoadingWindow : Window
throw new InvalidOperationException("No DataContext set");
}
Task updateGui = new Task(async () => {
while (ln.DownloadStatus != "Finished!"){
Task updateGui = new Task(async () =>
{
while (ln.DownloadStatus != "Finished!")
{
viewModel.Progress = ln.DownloadProgress;
viewModel.LoadingStatus = ln.DownloadStatus;
viewModel.LoadingStatus = ln.DownloadStatus ?? "Looking at qubits...";
await Task.Delay(1000);
}
viewModel.Progress = 100;
@ -42,12 +44,12 @@ public partial class LoadingWindow : Window
updateGui.Start();
_buildingTask = ln.BuildLauncher(tokenSource.Token);
await _buildingTask;
}
public async Task RunMinecraft()
@ -62,4 +64,4 @@ public partial class LoadingWindow : Window
System.Console.WriteLine("Loading disabled gracefully.");
Close();
}
}
}

View File

@ -4,7 +4,7 @@ using System.Linq;
using Avalonia.Controls;
using Avalonia.Interactivity;
using Avalonia.VisualTree;
using PlombirLauncher;
using Plombir;
using CmlLib.Core.VersionMetadata;
using LauncherGUI.ViewModels;
using System.Diagnostics;
@ -29,11 +29,11 @@ public partial class MainWindow : Window
var root = button.GetVisualRoot() as MainWindow;
if (root == null) return;
var vm = DataContext as MainWindowViewModel;
await LauncherUtils.CreateMinecraftInstance(vm, root);
button.Content = "Minecraft launched";
}
private void OnChooseVersionClick(object sender, RoutedEventArgs e)
@ -86,4 +86,4 @@ public partial class MainWindow : Window
}
}
}
}

View File

@ -3,7 +3,7 @@ using Avalonia.Controls;
using Avalonia.Interactivity;
using Avalonia.Platform.Storage;
using LauncherGUI.ViewModels;
using PlombirLauncher;
using Plombir;
namespace LauncherGUI.Views;
@ -21,6 +21,7 @@ public partial class SettingsWindow : Window
// Get top level from the current control. Alternatively, you can use Window reference instead.
var topLevel = TopLevel.GetTopLevel(this);
if (topLevel is null) throw new NullReferenceException("Failed to start file picker!");
// Start async operation to open the dialog.
var files = await topLevel.StorageProvider.OpenFolderPickerAsync(new FolderPickerOpenOptions
{
@ -38,4 +39,3 @@ public partial class SettingsWindow : Window
}
}
}

View File

@ -4,7 +4,7 @@ using System.Threading.Tasks;
using Avalonia.Controls;
using Avalonia.Threading;
using LauncherGUI.ViewModels;
using PlombirLauncher;
using Plombir;
namespace LauncherGUI.Views;
@ -13,14 +13,14 @@ public partial class VersionSelectorWindow : Window
private MainWindowViewModel _mainViewModel;
public VersionSelectorWindow(MainWindowViewModel mainViewModel)
{
InitializeComponent();
InitializeComponent();
_mainViewModel = mainViewModel;
//Load versions asynchronously
var versionsList = Task.Run(() => PlombirLauncher.Utils.GetAllMcVersions().GetAwaiter().GetResult());
var versionsList = Task.Run(() => Plombir.Utils.GetAllMcVersions().GetAwaiter().GetResult());
versions.ItemsSource = versionsList.Result;
}
private async void OnSelectionChanged(object sender, SelectionChangedEventArgs e)
@ -30,10 +30,10 @@ public partial class VersionSelectorWindow : Window
_mainViewModel.SelectedVersion = selectedVersion;
System.Console.WriteLine($"Selected version: {selectedVersion}");
LauncherUtils.CreateMinecraftInstance(_mainViewModel, this);
Close();
}
}
}

6
Launcher-UI/tweaks.toml Normal file
View File

@ -0,0 +1,6 @@
title = "Launcher tweaks file!"
# Path to folder that will hold all minecraft versions
runtime-path = "./runtime"
# Saving last launched version to use it after launch
last-version-launched = "1.20.1"
nickname = "slugcat"

11
package/build-targz-linux-ui.sh Executable file
View File

@ -0,0 +1,11 @@
cd ../Launcher-UI
out_dir=../package/out/build
archieve_name=PlombirLinux-v1-1-0.tar.gz
rm -r $out_dir
dotnet publish -r linux-x64 -o $out_dir -p:PublishReadyToRun=true -p:PublishSingleFile=true --self-contained true -p:IncludeNativeLibrariesForSelfExtract=true
cd ../package/out
tar -czvf $archieve_name -C build/ .

11
package/build-targz-osx-ui.sh Executable file
View File

@ -0,0 +1,11 @@
cd ../Launcher-UI
out_dir=../package/out/build
archieve_name=PlombirOSX-v1-1-0.tar.gz
rm -r $out_dir
dotnet publish -r osx-x64 -o $out_dir -p:PublishReadyToRun=true -p:PublishSingleFile=true --self-contained true -p:IncludeNativeLibrariesForSelfExtract=true
cd ../package/out
tar -czvf $archieve_name -C build/ .

11
package/build-targz-win-ui.sh Executable file
View File

@ -0,0 +1,11 @@
cd ../Launcher-UI
out_dir=../package/out/build
archieve_name=PlombirWindows-v1-1-0.tar.gz
rm -r $out_dir
dotnet publish -r win-x64 -o $out_dir -p:PublishReadyToRun=true -p:PublishSingleFile=true --self-contained true -p:IncludeNativeLibrariesForSelfExtract=true
cd ../package/out
tar -czvf $archieve_name -C build/ .

View File

@ -1,139 +0,0 @@
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 PlombirLauncher
{
/*
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, string? location = null)
{
_version = version;
_nickname = userName;
_mcPath = new($"{location}/{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(CancellationToken token)
{
_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);
return;
}
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();
}
}
}

View File

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

View File

@ -1,74 +0,0 @@
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 PlombirLauncher
{
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

@ -1,20 +0,0 @@
<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

@ -1,18 +0,0 @@
using System.Collections.Generic;
using PlombirLauncher;
namespace LauncherGUI.ViewModels;
public partial class MainWindowViewModel : ViewModelBase
{
public string Greeting { get; } = "Plombir launcher";
private string _userNick = ConfigManager.ReadConfig("nickname");
public string Usernick {get => _userNick; set {_userNick = value; OnPropertyChanged(nameof(Usernick)); }}
private string _selectedVersion = ConfigManager.ReadConfig("last-version-launched");
public string SelectedVersion {get => _selectedVersion; set {_selectedVersion = value; OnPropertyChanged(nameof(SelectedVersion)); }}
private string _runtimeLocation = ConfigManager.ReadConfig("runtime-path");
public string RuntimeLocation {get => _runtimeLocation; set {_runtimeLocation = value; OnPropertyChanged(nameof(RuntimeLocation)); }}
}

View File

@ -1,4 +0,0 @@
title = "Launcher tweaks file!"
runtime-path = "/home/nullmax17/test_folder"
last-version-launched = "1.15"
nickname = "nullmax17"

6
tweaks.toml Normal file
View File

@ -0,0 +1,6 @@
title = "Launcher tweaks file!"
# Path to folder that will hold all minecraft versions
runtime-path = "./runtime"
# Saving last launched version to use it after launch
last-version-launched = "1.20.1"
nickname = "slugcat"