273 lines
13 KiB
C#
273 lines
13 KiB
C#
using AzuresPackager;
|
|
using Lentia.Core.Auth.OAuth2;
|
|
using Lentia.Core.Constants;
|
|
using Lentia.Core.Game;
|
|
using Lentia.Utils;
|
|
using Photino.NET;
|
|
using System.Reflection;
|
|
using System.Text;
|
|
using System.Text.Json;
|
|
using LentRules = Lentia.Core.Auth.Yggdrasil;
|
|
|
|
namespace Lentia;
|
|
|
|
class Program {
|
|
|
|
private static readonly string __dirname = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location)!;
|
|
private static LentRules.AuthenticateResponse? _authenticatedPlayer;
|
|
private static readonly string appData = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);
|
|
private static readonly string gameRoot = Path.Combine(appData, ".lentia2");
|
|
private static readonly LentRules.Authenticator _ygg = new();
|
|
|
|
[STAThread]
|
|
static void Main(string[] args) {
|
|
SettingsManager.InitSettings(gameRoot);
|
|
CreateLoginWindow().WaitForClose();
|
|
}
|
|
|
|
public static PhotinoWindow CreateLoginWindow() {
|
|
AzuresPackage azp = new AzuresPackage(Path.Combine(__dirname, "root.dat"), 66);
|
|
List<string> entries = azp.ListEntries();
|
|
var window = new PhotinoWindow()
|
|
.SetUseOsDefaultLocation(false)
|
|
.SetUseOsDefaultSize(false)
|
|
.SetContextMenuEnabled(false)
|
|
.SetChromeless(true)
|
|
.RegisterCustomSchemeHandler("http", (object sender, string scheme, string url, out string contentType) =>{
|
|
Uri uri = new Uri(url);
|
|
if (uri.Host == "internal") {
|
|
string internalPath = uri.AbsolutePath;
|
|
contentType = MimeHelper.GetMimeType(uri.AbsolutePath);
|
|
byte[] fileData = azp.GetFileBytes(internalPath.TrimStart('/'));
|
|
return fileData != null ? new MemoryStream(fileData) : null;
|
|
}
|
|
contentType = null!;
|
|
return null;
|
|
});
|
|
|
|
window.WindowCreated += (sender, e) => {
|
|
SetupBridge(window);
|
|
WindowHelper.MakeLoginWindow(window);
|
|
};
|
|
|
|
|
|
window.Load("http://internal/login.html");
|
|
|
|
return window;
|
|
}
|
|
|
|
public static void SetupBridge(PhotinoWindow window) {
|
|
window.RegisterWebMessageReceivedHandler(async (object? sender, string message) => {
|
|
try {
|
|
var json = JsonDocument.Parse(message);
|
|
string requestId = json.RootElement.GetProperty("requestId").GetString()!;
|
|
string method = json.RootElement.GetProperty("functionName").GetString()!;
|
|
var jsonPayload = json.RootElement.GetProperty("payload");
|
|
var pw = (PhotinoWindow)sender!;
|
|
|
|
object? payload = null;
|
|
|
|
switch (method) {
|
|
case "launcher::version":
|
|
payload = "v1.0.0-beta";
|
|
break;
|
|
|
|
case "window::close":
|
|
pw.Close();
|
|
break;
|
|
|
|
case "lentia::dynmap":
|
|
payload = "http://azures.fr:8123/";
|
|
break;
|
|
|
|
case "hardware::ram":
|
|
payload = Hardware.GetRamUsage();
|
|
break;
|
|
|
|
case "auth::lentia":
|
|
string user = jsonPayload.GetProperty("username").GetString()!;
|
|
string pass = jsonPayload.GetProperty("password").GetString()!;
|
|
var lentiaAuthResult = await _ygg.Login(user, pass);
|
|
|
|
if (lentiaAuthResult.Success) {
|
|
_authenticatedPlayer = lentiaAuthResult.Player;
|
|
WindowHelper.MakeStandardWindow(pw, 1356, 720, "http://internal/logged.html");
|
|
payload = new { success = true };
|
|
} else {
|
|
payload = new { success = false, error = lentiaAuthResult.Error };
|
|
}
|
|
break;
|
|
|
|
case "auth::logout":
|
|
_authenticatedPlayer = null;
|
|
pw.Load("http://internal/login.html");
|
|
WindowHelper.MakeLoginWindow(pw);
|
|
payload = true;
|
|
break;
|
|
|
|
case "dialog::error":
|
|
string title = jsonPayload.TryGetProperty("title", out var t) ? t.GetString()! : "Lentia";
|
|
string msg = jsonPayload.GetProperty("message").GetString()!;
|
|
pw.ShowMessage(title, msg, PhotinoDialogButtons.Ok, PhotinoDialogIcon.Error);
|
|
payload = new { success = true };
|
|
break;
|
|
|
|
case "settings::read":
|
|
payload = SettingsManager.ReadSettings();
|
|
break;
|
|
|
|
case "settings::set":
|
|
if (jsonPayload.TryGetProperty("key", out var keyElement) && jsonPayload.TryGetProperty("value", out var valueElement)) {
|
|
string key = keyElement.GetString()!;
|
|
|
|
object? valueToSet = valueElement.ValueKind switch {
|
|
JsonValueKind.String => valueElement.GetString(),
|
|
JsonValueKind.Number => valueElement.TryGetInt32(out int i) ? i : valueElement.GetDouble(),
|
|
JsonValueKind.True => true,
|
|
JsonValueKind.False => false,
|
|
JsonValueKind.Null => null,
|
|
_ => valueElement
|
|
};
|
|
|
|
if (valueToSet != null) {
|
|
SettingsManager.Set(key, valueToSet);
|
|
payload = new { success = true };
|
|
} else {
|
|
payload = new { success = false, error = "Incorrect or null value" };
|
|
}
|
|
}
|
|
break;
|
|
|
|
case "dialog::selectSkin":
|
|
var imageFilter = new (string Name, string[] Extensions)[] {
|
|
("Portable Network Graphic Image", new[] { "*.png" })
|
|
};
|
|
|
|
string[] files = window.ShowOpenFile("Choisis ton plus beau skin mon reuf", null, false, imageFilter);
|
|
|
|
payload = new {
|
|
success = files != null && files.Length > 0,
|
|
path = (files != null && files.Length > 0) ? files[0] : null
|
|
};
|
|
break;
|
|
|
|
case "network::uploadSkin":
|
|
try {
|
|
string path = jsonPayload.GetProperty("path").GetString()!;
|
|
string variant = jsonPayload.GetProperty("variant").GetString()!;
|
|
string token = _authenticatedPlayer?.AccessToken!;
|
|
|
|
string skinResult = await MojangAPI.UploadSkinAsync(path, variant, token);
|
|
|
|
payload = new { success = true };
|
|
} catch (Exception ex) {
|
|
payload = new { success = false, error = ex.Message };
|
|
}
|
|
break;
|
|
|
|
case "network::getPlayer":
|
|
try {
|
|
var profileData = await MojangAPI.GetPlayerProfileAsync(_authenticatedPlayer!.AccessToken);
|
|
payload = profileData;
|
|
} catch (Exception ex) {
|
|
payload = new { success = false, error = ex.Message };
|
|
}
|
|
break;
|
|
|
|
case "network::hideCape":
|
|
try {
|
|
var hideCapeResult = await MojangAPI.HideCapeAsync(_authenticatedPlayer!.AccessToken);
|
|
payload = new { success = true, data = hideCapeResult };
|
|
} catch (Exception ex) {
|
|
payload = new { success = false, error = ex.Message };
|
|
}
|
|
break;
|
|
|
|
case "network::showCape":
|
|
try {
|
|
string token = _authenticatedPlayer?.AccessToken!;
|
|
string capeId = jsonPayload.GetProperty("capeId").GetString()!;
|
|
|
|
var showCapeResult = await MojangAPI.ShowCapeAsync(token, capeId);
|
|
payload = new { success = true, data = showCapeResult };
|
|
} catch (Exception ex) {
|
|
payload = new { success = false, error = ex.Message };
|
|
}
|
|
break;
|
|
|
|
case "network::changeUsername":
|
|
try {
|
|
string newName = jsonPayload.GetProperty("username").GetString()!;
|
|
string token = _authenticatedPlayer?.AccessToken!;
|
|
|
|
if (string.IsNullOrEmpty(token)) throw new Exception("Session expirée ou invalide.");
|
|
|
|
var updatedProfile = await MojangAPI.ChangeUsernameAsync(newName, token);
|
|
|
|
if (_authenticatedPlayer != null) {
|
|
_authenticatedPlayer.User.Username = newName;
|
|
}
|
|
|
|
payload = new { success = true, profile = updatedProfile };
|
|
} catch (Exception ex) {
|
|
payload = new { success = false, error = ex.Message };
|
|
}
|
|
break;
|
|
|
|
case "oauth2::discord":
|
|
BashUtils.OpenUrl("https://yggdrasil.azures.fr/auth/provider/discord/login");
|
|
string? code = await Discord.ListenForCode();
|
|
var discordLoginResult = await Discord.LoginWithDiscordOAuth2(code!);
|
|
|
|
if (discordLoginResult.Success) {
|
|
_authenticatedPlayer = discordLoginResult.Player;
|
|
WindowHelper.MakeStandardWindow(pw, 1356, 720, "http://internal/logged.html");
|
|
payload = new { success = true };
|
|
} else {
|
|
Console.WriteLine(discordLoginResult);
|
|
payload = new { success = false, error = discordLoginResult.Error };
|
|
}
|
|
break;
|
|
|
|
case "launcher::game":
|
|
try {
|
|
await GenericFilesService.FetchAndSyncGenericFiles(gameRoot);
|
|
var options = new LaunchOptions {
|
|
Version = new LaunchOptions.VersionOptions {
|
|
Number = "1.12.2",
|
|
Type = "release"
|
|
},
|
|
Memory = new LaunchOptions.MemoryOptions {
|
|
Max = $"{SettingsManager.ReadSettings().Ram.Max}M",
|
|
Min = "512M"
|
|
},
|
|
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);
|
|
GameHelper.Launch(version, _authenticatedPlayer!, gameRoot, options, (logLine) => {
|
|
var logMessage = new {
|
|
requestId = "game::log",
|
|
payload = new { message = logLine.ToString() }
|
|
};
|
|
window.SendWebMessage(JsonSerializer.Serialize(logMessage, LauncherConstants._jsonOptions));
|
|
});
|
|
payload = new { success = true };
|
|
} catch (Exception) {
|
|
payload = new { success = false };
|
|
throw;
|
|
}
|
|
break;
|
|
}
|
|
|
|
var response = new { requestId, payload };
|
|
window.SendWebMessage(JsonSerializer.Serialize(response, LauncherConstants._jsonOptions));
|
|
} catch (Exception ex) {
|
|
Console.WriteLine($"Error stacktrace: {ex.StackTrace}");
|
|
Console.WriteLine($"Bridge error: {ex.Message}");
|
|
}
|
|
});
|
|
}
|
|
} |