minecraft-launcher/minecraft-launcher-client/Launcher.cs

185 lines
7.9 KiB
C#

using System;
using System.Diagnostics;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Threading;
using DTLib.Console;
using DTLib.Logging;
using DTLib.Filesystem;
namespace launcher_client;
internal static partial class Launcher
{
public static bool Debug, Offline, Updated;
private static void Main(string[] args)
{
// console arguments parsing
#if DEBUG
Debug = true;
#else
if (args.Contains("debug"))
Debug = true;
#endif
if (args.Contains("offline"))
Offline = true;
if (args.Contains("updated"))
Updated = true;
// console initialization
Console.Title = "anarx_2";
Console.OutputEncoding = Encoding.UTF8;
Console.InputEncoding = Encoding.UTF8;
using ConsoleWrapper console = new ConsoleWrapper();
console.StartUpdating();
// logger initialization
FileLogger fileLogger = new FileLogger("launcher-logs", "launcher-client");
ConsoleWrapperLogger consoleWrapperLogger = new ConsoleWrapperLogger(console);
ILogger Logger = new CompositeLogger(
fileLogger,
consoleWrapperLogger
);
Logger.DebugLogEnabled = true; // always print debug log to file
consoleWrapperLogger.DebugLogEnabled = Debug;
try
{
var config = LauncherConfig.LoadOrCreateDefault();
NetworkManager networkManager = new NetworkManager(Logger, config.ServerAddress, config.ServerPort);
Logger.LogInfo(nameof(Main), "launcher started");
if(File.Exists("minecraft-launcher.exe_old"))
File.Delete("minecraft-launcher.exe_old");
// self-update
if (!Updated && !Offline)
{
Logger.LogInfo(nameof(Main), "checking for launcher update");
networkManager.ConnectToLauncherServer();
bool updateDownloaded = networkManager.TryDownloadLauncherUpdate("minecraft-launcher.exe_new");
if(updateDownloaded)
{
System.IO.File.Move("minecraft-launcher.exe", "minecraft-launcher.exe_old");
Process.Start("cmd", "/c " +
"move minecraft-launcher.exe_new minecraft-launcher.exe && " +
"minecraft-launcher.exe updated");
return;
}
networkManager.DisconnectFromLauncherServer();
}
// если уже обновлён
console.SetHeader($"username: {config.Username} | game memory: {config.GameMemory}M");
console.SetFooter("[L] launch game | [N] change username | [H] help");
console.DrawGui();
while (true)
{
try
{
var pressedKey = Console.ReadKey(true); // Считывание ввода
switch (pressedKey.Key)
{
case ConsoleKey.UpArrow:
console.ScrollUp();
break;
case ConsoleKey.DownArrow:
console.ScrollDown();
break;
case ConsoleKey.PageUp:
console.ScrollUp(console.TextAreaH);
break;
case ConsoleKey.PageDown:
console.ScrollDown(console.TextAreaH);
break;
case ConsoleKey.N:
// todo ReadLine wrapper
Console.SetCursorPosition(0, Console.WindowHeight - 1);
Console.CursorVisible = true;
string? _username = Console.ReadLine();
if (_username == null || _username.Length < 2)
throw new Exception("too short username");
config.Username = _username;
config.Save();
console.DrawGui();
break;
case ConsoleKey.L:
if (config.Username.Length < 2)
throw new Exception("username is too short");
// обновление клиента
if (!Offline)
{
networkManager.ConnectToLauncherServer();
networkManager.UpdateGame();
}
// запуск майнкрафта
Logger.LogInfo(nameof(Main), "launching minecraft");
string gameOptions = ConstructGameLaunchArgs(config.Username,
NameUUIDFromString("OfflinePlayer:" + config.Username),
config.GameMemory,
config.GameWindowWidth,
config.GameWindowHeight,
Directory.GetCurrent());
Logger.LogDebug("LaunchGame", gameOptions);
var gameProcess = Process.Start(config.JavaPath.Str, gameOptions);
gameProcess?.WaitForExit();
Logger.LogInfo(nameof(Main), "minecraft closed");
break;
case ConsoleKey.H:
console.WriteLine("help:");
console.WriteLine(" Q: How to use this launcher?");
console.WriteLine(" A: Set username if it isn't set and launch the game.");
console.WriteLine(" Q: How to change game memory and other settings?");
console.WriteLine(" A: Edit the `minecraft-launcher.dtsod` file.");
console.WriteLine(" Q: How to disable game files update on launch?");
console.WriteLine(" A: Restart the launcher with argument 'offline'.");
console.WriteLine(" Q: What to do if launcher doesn't work?");
console.WriteLine(" A: Send latest log file from `launcher-logs/` to Timerix.");
break;
}
}
catch (Exception ex)
{
Logger.LogError(nameof(Main), ex);
}
}
}
catch (Exception ex)
{
console.StopUpdating();
Logger.LogError(nameof(Main), ex);
ColoredConsole.Write("gray", "press any key to close...");
Console.ReadKey();
}
Console.ResetColor();
}
//minecraft player uuid explanation
//https://gist.github.com/CatDany/0e71ca7cd9b42a254e49/
//java uuid generation in c#
//https://stackoverflow.com/questions/18021808/uuid-interop-with-c-sharp-code
public static string NameUUIDFromString(string input)
=> NameUUIDFromBytes(Encoding.UTF8.GetBytes(input));
public static string NameUUIDFromBytes(byte[] input)
{
var md5 = MD5.Create();
byte[] hash = md5.ComputeHash(input);
hash[6] &= 0x0f;
hash[6] |= 0x30;
hash[8] &= 0x3f;
hash[8] |= 0x80;
string hex = BitConverter.ToString(hash).Replace("-", string.Empty).ToLower();
return hex.Insert(8, "-").Insert(13, "-").Insert(18, "-").Insert(23, "-");
}
}