Added a lot

-  Self contained runtime
  -  Translated french to english
  -  Fixed java path and url
This commit is contained in:
Gilles Lazures 2026-02-01 20:15:54 +01:00
parent 8444698e2a
commit b33779e77d
13 changed files with 38 additions and 22 deletions

View File

@ -8,6 +8,13 @@
<AssemblyName>LentiaLauncher</AssemblyName>
<ApplicationIcon>./src/resources/icon.ico</ApplicationIcon>
<PublishTrimmed>false</PublishTrimmed>
<RollForward>Major</RollForward>
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
<SelfContained>true</SelfContained>
<PublishTrimmed>false</PublishTrimmed>
<PublishReadyToRun>true</PublishReadyToRun>
<PublishSingleFile>true</PublishSingleFile>
<IncludeNativeLibrariesForSelfExtract>true</IncludeNativeLibrariesForSelfExtract>
</PropertyGroup>
<Target Name="PackRenderer" BeforeTargets="DispatchToInnerBuild;BeforeBuild">
<PropertyGroup>

View File

@ -29,6 +29,7 @@ class Program {
BrikPackage bpkg = new BrikPackage(Path.Combine(__dirname, "root.dat"), 66);
List<string> entries = bpkg.ListEntries();
var window = new PhotinoWindow()
.SetTitle("Lentia")
.SetUseOsDefaultLocation(false)
.SetUseOsDefaultSize(false)
.SetContextMenuEnabled(false)
@ -232,6 +233,15 @@ class Program {
case "launcher::game":
try {
await GenericFilesService.FetchAndSyncGenericFiles(gameRoot);
MinecraftVersion version = await GameHelper.PrepareGame(new LaunchOptions {
Version = new LaunchOptions.VersionOptions { Number = "1.12.2", Type = "release" },
ModLoader = LaunchOptions.ModLoaderType.Forge
}, gameRoot);
string javaPath = await JavaHelper.GetJavaExecutablePath(version, gameRoot);
SettingsManager.Set("JavaPath", javaPath);
var options = new LaunchOptions {
Version = new LaunchOptions.VersionOptions {
Number = "1.12.2",
@ -241,13 +251,13 @@ class Program {
Max = $"{SettingsManager.ReadSettings().Ram.Max}M",
Min = "512M"
},
JavaPath = javaPath,
ModLoader = LaunchOptions.ModLoaderType.Forge,
CustomArgs = new List<string> {
$"-javaagent:{Path.Combine(gameRoot, LauncherConstants.AgentsPath.AuthlibInjector)}={LauncherConstants.Urls.YggdrasilServer}"
}
};
MinecraftVersion version = await GameHelper.PrepareGame(options, gameRoot);
await JavaHelper.GetJavaExecutablePath(version, gameRoot);
GameHelper.Launch(version, _authenticatedPlayer!, gameRoot, options, (logLine) => {
var logMessage = new {
requestId = "game::log",

View File

@ -7,8 +7,8 @@ namespace Lentia.Core.Constants {
public const string MojangManifest = "https://launchermeta.mojang.com/mc/game/version_manifest_v2.json";
public const string YggdrasilServer = "https://yggdrasil.azures.fr/";
public const string MojangAuthServer = YggdrasilServer + "authserver";
public const string ApiUrl = "https://lentia-api.azures.fr";
public const string AllJavaRuntime = "https://launchermeta.mojang.com/v1/products/java-runtime/2ec0cc96c44e5a76b9c8b7c39df7210883d12871/all.json";
}
public static class AgentsPath {

View File

@ -90,9 +90,9 @@ public class Authenticator {
var data = await response.Content.ReadFromJsonAsync<AuthenticateResponse>();
return data != null ? AuthResult.Ok(data) : AuthResult.Fail("Erreur de lecture des données.");
} catch (HttpRequestException ex) {
return AuthResult.Fail($"Erreur réseau : {ex.Message}", "NETWORK_ERROR");
return AuthResult.Fail($"Network error : {ex.Message}", "NETWORK_ERROR");
} catch (Exception ex) {
return AuthResult.Fail($"Erreur interne : {ex.Message}", "INTERNAL_ERROR");
return AuthResult.Fail($"Internal error : {ex.Message}", "INTERNAL_ERROR");
}
}
}

View File

@ -40,12 +40,12 @@ public class Discord {
var response = await HttpHelper.FetchAsync(url, HttpMethod.Get);
if (response.IsSuccessStatusCode) {
var data = await response.Content.ReadFromJsonAsync<AuthenticateResponse>();
return data != null ? AuthResult.Ok(data) : AuthResult.Fail("Erreur de lecture des données.");
return data != null ? AuthResult.Ok(data) : AuthResult.Fail("Data reading error.");
} else {
var errorData = await response.Content.ReadFromJsonAsync<YggdrasilError>();
Console.WriteLine(await response.Content.ReadAsStringAsync());
return AuthResult.Fail(
errorData?.errorMessage ?? "Identifiants invalides.",
errorData?.errorMessage ?? "Invalid credentials.",
errorData?.error,
errorData?.cause
);

View File

@ -31,10 +31,10 @@ public class AssetsHelper {
string json = await response.Content.ReadAsStringAsync();
var index = JsonSerializer.Deserialize<AssetsIndex>(json, LauncherConstants._jsonOptions);
return index ?? throw new Exception("L'index des assets est vide ou invalide.");
return index ?? throw new Exception("The assets index is empty or invalid");
}
throw new Exception($"Impossible de récupérer l'index des assets : {response.StatusCode}");
throw new Exception($"Assets index unavailable : {response.StatusCode}");
}
public static async Task DownloadAssets(AssetsIndex index, string rootDir) {
@ -87,7 +87,7 @@ public class AssetsHelper {
await FileHelper.DownloadFileAsync(url, localPath);
} catch (Exception ex) {
Console.WriteLine(url);
Console.WriteLine($"Échec : {hash} - {ex.Message}");
Console.WriteLine($"Fail : {hash} - {ex.Message}");
}
});
}

View File

@ -69,15 +69,13 @@ public static class JavaHelper {
}
private static async Task DownloadJavaRuntime(string root, string platform, string component) {
string allJsonUrl = "https://piston-meta.mojang.com/v1/products/java-runtime/2ec0cc6c0dba9f635e09f3900331038590632291/all.json";
var allRuntimesResponse = await HttpHelper.FetchAsync(allJsonUrl);
var allRuntimesResponse = await HttpHelper.FetchAsync(LauncherConstants.Urls.AllJavaRuntime);
allRuntimesResponse.EnsureSuccessStatusCode();
var allRuntimes = await allRuntimesResponse.Content.ReadFromJsonAsync<JsonElement>(LauncherConstants._jsonOptions);
if (!allRuntimes.TryGetProperty(platform, out var platformData) ||
!platformData.TryGetProperty(component, out var componentVersions)) {
throw new Exception($"Le runtime {component} n'est pas disponible pour {platform}");
throw new Exception($"There is no {component} runtime for {platform}");
}
string manifestUrl = componentVersions[0].GetProperty("manifest").GetProperty("url").GetString()!;

View File

@ -212,9 +212,9 @@ public static class VersionsHelper {
string jsonResponse = await response.Content.ReadAsStringAsync();
var version = JsonSerializer.Deserialize<MinecraftVersion>(jsonResponse, LauncherConstants._jsonOptions);
return version ?? throw new Exception("Impossible de lire les détails de la version.");
return version ?? throw new Exception("Version details data are unreadable.");
} else {
throw new Exception($"Erreur lors de la récupération des détails : {response.StatusCode}");
throw new Exception($"Error when getting version details: {response.StatusCode}");
}
}

View File

@ -24,7 +24,7 @@ public static class ForgeHelper {
string promoKey = $"{mcVersion}-{(recommended ? "recommended" : "latest")}";
if (promoData?.Promos == null || !promoData.Promos.TryGetValue(promoKey, out string? buildVersion)) {
throw new Exception($"Version Forge introuvable pour {promoKey}");
throw new Exception($"No forge version found for : {promoKey}");
}
bool isModern = IsVersionModern(mcVersion);

View File

@ -2,6 +2,7 @@ namespace Lentia.Core.Utils;
public static class FileHelper {
public static async Task DownloadFileAsync(string url, string destinationPath) {
Console.WriteLine($"Downloading file from {url} to {destinationPath}");
string? directory = Path.GetDirectoryName(destinationPath);
if (!string.IsNullOrEmpty(directory)) {
Directory.CreateDirectory(directory);

View File

@ -8,6 +8,7 @@ public static class HttpHelper {
private static readonly HttpClient Http = new HttpClient();
public static async Task<HttpResponseMessage> FetchAsync(string url, HttpMethod? method = null, object? body = null, Dictionary<string, string>? headers = null) {
Console.WriteLine($"Fetching {url} using {method} method");
var request = new HttpRequestMessage(method ?? HttpMethod.Get, url);
if (headers != null) {

View File

@ -64,7 +64,7 @@ public static class SettingsManager {
foreach (var k in keys) {
var property = current.GetType().GetProperty(k);
if (property == null) throw new Exception($"Clé {k} introuvable.");
if (property == null) throw new Exception($"Key {k} not found.");
current = property.GetValue(current)!;
}
@ -85,7 +85,7 @@ public static class SettingsManager {
var prop = current.GetType().GetProperty(properties[i],
System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.IgnoreCase);
if (prop == null) throw new Exception($"Niveau '{properties[i]}' introuvable.");
if (prop == null) throw new Exception($"Level '{properties[i]}' not found.");
var next = prop.GetValue(current);
if (next == null) {
@ -99,14 +99,14 @@ public static class SettingsManager {
System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.IgnoreCase);
if (lastProp == null || !lastProp.CanWrite)
throw new Exception($"Propriété '{properties[^1]}' introuvable ou verrouillée.");
throw new Exception($"Property '{properties[^1]}' not found or locked.");
object? convertedValue = Convert.ChangeType(value.ToString(), lastProp.PropertyType);
lastProp.SetValue(current, convertedValue);
WriteSettings(settings);
} catch (Exception ex) {
Console.WriteLine($"[SettingsManager] Erreur Set sur '{path}': {ex.Message}");
Console.WriteLine($"[SettingsManager] \"set\" Error on '{path}': {ex.Message}");
}
}
}

View File

@ -69,7 +69,6 @@ public static class WindowHelper {
Size loginSize = GetScaledSize(window, 310, 420);
window
.SetTitle("Lentia")
.SetIconFile(iconPath)
.SetResizable(false)
.SetSize(loginSize)