new gui and update logic
This commit is contained in:
parent
e1f851384a
commit
96d0490338
75
minecraft-launcher-client/ConsoleBuffer.cs
Normal file
75
minecraft-launcher-client/ConsoleBuffer.cs
Normal file
@ -0,0 +1,75 @@
|
||||
using System;
|
||||
|
||||
namespace launcher_client;
|
||||
|
||||
public class ConsoleBuffer
|
||||
{
|
||||
public int Width;
|
||||
public int Height;
|
||||
|
||||
private int _x, _y;
|
||||
private char[][] _buffer;
|
||||
|
||||
public ConsoleBuffer()
|
||||
{
|
||||
Width = Console.WindowWidth;
|
||||
Height = Console.WindowHeight - 1;
|
||||
|
||||
_buffer = new char[Height][];
|
||||
for(int y = 0; y < Height; y++)
|
||||
{
|
||||
_buffer[y] = new char[Width];
|
||||
for (int x = 0; x < Width; x++)
|
||||
_buffer[y][x] = ' ';
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void SetCursorPosition(int x, int y)
|
||||
{
|
||||
if (x < 0 || y < 0 || x >= Width || y >= Height)
|
||||
throw new Exception($"invalid cursor position ({x}, {y}) (width: {Width}, height: {Height})");
|
||||
_x = x;
|
||||
_y = y;
|
||||
}
|
||||
|
||||
public void Write(char c)
|
||||
{
|
||||
_buffer[_y][_x] = c;
|
||||
_x++;
|
||||
if (_x == Width)
|
||||
{
|
||||
_x = 0;
|
||||
_y++;
|
||||
}
|
||||
}
|
||||
|
||||
public void Write(string s)
|
||||
{
|
||||
for(int i = 0; i < s.Length; i++)
|
||||
{
|
||||
char c = s[i];
|
||||
switch (c)
|
||||
{
|
||||
case '\r':
|
||||
throw new Exception("restricted character: '\\r'");
|
||||
case '\n':
|
||||
throw new Exception("restricted character: '\\n'");
|
||||
case '\t':
|
||||
Write(" ");
|
||||
break;
|
||||
default:
|
||||
Write(c);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Print()
|
||||
{
|
||||
Console.SetCursorPosition(0, 0);
|
||||
for (int y = 0; y < Height; y++)
|
||||
Console.Write(new string(_buffer[y]));
|
||||
Console.SetCursorPosition(0, 0);
|
||||
}
|
||||
}
|
||||
189
minecraft-launcher-client/ConsoleWrapper.cs
Normal file
189
minecraft-launcher-client/ConsoleWrapper.cs
Normal file
@ -0,0 +1,189 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using DTLib;
|
||||
using DTLib.Extensions;
|
||||
|
||||
namespace launcher_client;
|
||||
|
||||
public class ConsoleWrapper : IConsoleWrapper
|
||||
{
|
||||
private List<string> _textLines = new();
|
||||
private int _linesUp;
|
||||
private string _headerText = "";
|
||||
private string _footerText = "";
|
||||
|
||||
private Timer _consoleSizeCheckTimer;
|
||||
|
||||
public int TextAreaW;
|
||||
public int TextAreaH;
|
||||
|
||||
|
||||
public ConsoleWrapper()
|
||||
{
|
||||
int lastW = Console.WindowWidth;
|
||||
int lastH = Console.WindowHeight;
|
||||
_consoleSizeCheckTimer = new Timer(true, 50, () =>
|
||||
{
|
||||
if(Console.WindowWidth != lastW || Console.WindowHeight != lastH)
|
||||
{
|
||||
lastW = Console.WindowWidth;
|
||||
lastH = Console.WindowHeight;
|
||||
Console.Clear();
|
||||
DrawGui();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// starts automatig gui redraw on console size change
|
||||
/// </summary>
|
||||
public void StartUpdating()
|
||||
{
|
||||
_consoleSizeCheckTimer.Start();
|
||||
}
|
||||
|
||||
public void StopUpdating()
|
||||
{
|
||||
_consoleSizeCheckTimer.Stop();
|
||||
}
|
||||
|
||||
public void WriteLine(string msg)
|
||||
{
|
||||
_textLines.Add(msg);
|
||||
DrawGui();
|
||||
}
|
||||
|
||||
public void SetHeader(string s) => _headerText = s;
|
||||
|
||||
public void SetFooter(string s) => _footerText = s;
|
||||
|
||||
public void ScrollDown(int lines = 1)
|
||||
{
|
||||
_linesUp -= lines;
|
||||
if (_linesUp < 0)
|
||||
_linesUp = 0;
|
||||
DrawGui();
|
||||
}
|
||||
|
||||
public void ScrollUp(int lines = 1)
|
||||
{
|
||||
_linesUp += lines;
|
||||
DrawGui();
|
||||
}
|
||||
|
||||
public void DrawGui()
|
||||
{
|
||||
var b = new ConsoleBuffer();
|
||||
TextAreaW = b.Width - 6;
|
||||
TextAreaH = b.Height - 6;
|
||||
Console.ForegroundColor = ConsoleColor.White;
|
||||
Console.CursorVisible = false;
|
||||
DrawBorders(b);
|
||||
DrawText(b);
|
||||
DrawScrollBar(b);
|
||||
DrawHeader(b);
|
||||
DrawFooter(b);
|
||||
b.Print();
|
||||
}
|
||||
|
||||
private void DrawBorders(ConsoleBuffer b)
|
||||
{
|
||||
b.Write( '┏' + '━'.Multiply(b.Width - 2) + '┓');
|
||||
b.Write( '┃' + ' '.Multiply(b.Width - 2) + '┃');
|
||||
b.Write( '┣' + '━'.Multiply(b.Width - 4) + "┳━┫");
|
||||
for (int y = 0; y < b.Height - 6; y++)
|
||||
b.Write('┃' + ' '.Multiply(b.Width - 4) + "┃ ┃");
|
||||
b.Write( '┣' + '━'.Multiply(b.Width - 4) + "┻━┫");
|
||||
b.Write( '┃' + ' '.Multiply(b.Width - 2) + '┃');
|
||||
b.Write( '┗' + '━'.Multiply(b.Width - 2) + '┛');
|
||||
}
|
||||
|
||||
private void DrawScrollBar(ConsoleBuffer b)
|
||||
{
|
||||
int scrollBarX = b.Width - 2;
|
||||
int scrollBarY = 3;
|
||||
|
||||
int slideH = 0;
|
||||
if (_textLines.Count >= TextAreaH)
|
||||
slideH = (int)Math.Ceiling((double)TextAreaH * TextAreaH / _textLines.Count);
|
||||
int slidePos = (int)Math.Ceiling((double) _linesUp / TextAreaH) + 1;
|
||||
for(int y = 0; y < slideH; y++)
|
||||
{
|
||||
b.SetCursorPosition(scrollBarX, scrollBarY + TextAreaH - y - slidePos);
|
||||
b.Write('▒');
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawHeader(ConsoleBuffer b)
|
||||
{
|
||||
b.SetCursorPosition(2, 1);
|
||||
b.Write(ChopLongLine(_headerText, b.Width - 4));
|
||||
}
|
||||
|
||||
private void DrawFooter(ConsoleBuffer b)
|
||||
{
|
||||
b.SetCursorPosition(2, b.Height - 2);
|
||||
b.Write(ChopLongLine(_footerText, b.Width - 4));
|
||||
}
|
||||
|
||||
private static string ChopLongLine(string s, int maxLength)
|
||||
{
|
||||
if (s.Length <= maxLength)
|
||||
return s;
|
||||
|
||||
return s.Remove(maxLength - 3) + "...";
|
||||
}
|
||||
|
||||
private void DrawText(ConsoleBuffer b)
|
||||
{
|
||||
int textAreaX = 2;
|
||||
int textAreaY = 3;
|
||||
|
||||
var realLines = _textLines
|
||||
.SelectMany(s => SplitStringToLines(s, TextAreaW))
|
||||
.ToArray();
|
||||
|
||||
int linesUp = _linesUp + TextAreaH;
|
||||
if (linesUp > realLines.Length)
|
||||
{
|
||||
linesUp = realLines.Length;
|
||||
_linesUp = Math.Max(0, realLines.Length - TextAreaH);
|
||||
}
|
||||
|
||||
for (int y = 0; y < TextAreaH; y++)
|
||||
{
|
||||
b.SetCursorPosition(textAreaX, textAreaY + y);
|
||||
int li = realLines.Length - linesUp + y;
|
||||
if (li >= realLines.Length)
|
||||
break;
|
||||
b.Write(realLines[li]);
|
||||
}
|
||||
}
|
||||
|
||||
private static ICollection<string> SplitStringToLines(string _s, int lineW)
|
||||
{
|
||||
var split = _s.Replace("\r", "").Split('\n');
|
||||
if (_s.Length <= lineW)
|
||||
return split;
|
||||
|
||||
List<string> lines = new();
|
||||
for (int spi = 0; spi < split.Length; spi++)
|
||||
{
|
||||
string s = split[spi];
|
||||
int linesCount = s.Length / lineW;
|
||||
if (s.Length % lineW != 0)
|
||||
linesCount++;
|
||||
|
||||
for (int i = 0; i < linesCount; i++)
|
||||
lines.Add(s.Substring(i * lineW, Math.Min(lineW, s.Length - i * lineW)));
|
||||
}
|
||||
|
||||
return lines;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
StopUpdating();
|
||||
}
|
||||
}
|
||||
@ -1,239 +1,169 @@
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Dynamic;
|
||||
using System.Linq;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using DTLib.Console;
|
||||
using DTLib.Extensions;
|
||||
using DTLib.Logging;
|
||||
using DTLib.Network;
|
||||
using DTLib.Filesystem;
|
||||
using Directory = DTLib.Filesystem.Directory;
|
||||
using File = DTLib.Filesystem.File;
|
||||
using static launcher_client.Network;
|
||||
|
||||
namespace launcher_client;
|
||||
|
||||
internal static partial class Launcher
|
||||
{
|
||||
private static FileLogger _fileLogger = new("launcher-logs", "launcher-client");
|
||||
public static ILogger Logger = new CompositeLogger(
|
||||
_fileLogger,
|
||||
new ConsoleLogger());
|
||||
public static LauncherConfig Config = null!;
|
||||
public static bool debug, offline, updated;
|
||||
private static dynamic tabs = new ExpandoObject();
|
||||
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
|
||||
{
|
||||
Console.Title = "anarx_2";
|
||||
Console.OutputEncoding = Encoding.UTF8;
|
||||
Console.InputEncoding = Encoding.UTF8;
|
||||
Console.CursorVisible = false;
|
||||
var config = LauncherConfig.LoadOrCreateDefault();
|
||||
NetworkManager networkManager = new NetworkManager(Logger, config.ServerAddress, config.ServerPort);
|
||||
|
||||
#if DEBUG
|
||||
debug = true;
|
||||
#else
|
||||
if (args.Contains("debug")) debug = true;
|
||||
#endif
|
||||
if (args.Contains("offline")) offline = true;
|
||||
if (args.Contains("updated")) updated = true;
|
||||
|
||||
Config = LauncherConfig.LoadOrCreateDefault();
|
||||
|
||||
Logger.DebugLogEnabled = debug;
|
||||
Logger.LogInfo("Main", "launcher is starting");
|
||||
Logger.LogInfo(nameof(Main), "launcher started");
|
||||
|
||||
if(File.Exists("minecraft-launcher.exe_old"))
|
||||
File.Delete("minecraft-launcher.exe_old");
|
||||
|
||||
// обновление лаунчера
|
||||
if (!updated && !offline)
|
||||
// self-update
|
||||
if (!Updated && !Offline)
|
||||
{
|
||||
ConnectToLauncherServer();
|
||||
mainSocket.SendPackage("requesting launcher update");
|
||||
Fsp.DownloadFile("minecraft-launcher.exe_new");
|
||||
Logger.LogInfo("Main", "minecraft-launcher.exe_new downloaded");
|
||||
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;
|
||||
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();
|
||||
}
|
||||
|
||||
// если уже обновлён
|
||||
tabs.Login = EmbeddedResources.ReadText("launcher_client.gui.login.gui");
|
||||
tabs.Settings = EmbeddedResources.ReadText("launcher_client.gui.settings.gui");
|
||||
tabs.Exit = EmbeddedResources.ReadText("launcher_client.gui.exit.gui");
|
||||
tabs.Log = "";
|
||||
tabs.Current = "";
|
||||
string username = "";
|
||||
if (!Config.Username.IsNullOrEmpty())
|
||||
{
|
||||
tabs.Login = tabs.Login.Remove(833, Config.Username.Length).Insert(833, Config.Username);
|
||||
username = Config.Username;
|
||||
}
|
||||
|
||||
RenderTab(tabs.Login);
|
||||
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
|
||||
// ReSharper disable once BadChildStatementIndent
|
||||
while (true)
|
||||
{
|
||||
var pressedKey = Console.ReadKey(true); // Считывание ввода
|
||||
switch (pressedKey.Key)
|
||||
try
|
||||
{
|
||||
case ConsoleKey.F1:
|
||||
RenderTab(tabs.Login);
|
||||
break;
|
||||
case ConsoleKey.N:
|
||||
if (tabs.Current == tabs.Login)
|
||||
{
|
||||
tabs.Login = tabs.Login
|
||||
.Remove(751, 20).Insert(751, "┏━━━━━━━━━━━━━━━━━━┓")
|
||||
.Remove(831, 20).Insert(831, "┃ ┃")
|
||||
.Remove(911, 20).Insert(911, "┗━━━━━━━━━━━━━━━━━━┛");
|
||||
RenderTab(tabs.Login);
|
||||
var _username = ReadString(33, 10, 15);
|
||||
tabs.Login = tabs.Login
|
||||
.Remove(751, 20).Insert(751, "┌──────────────────┐")
|
||||
.Remove(831, 20).Insert(831, "│ │")
|
||||
.Remove(911, 20).Insert(911, "└──────────────────┘");
|
||||
RenderTab(tabs.Login);
|
||||
if (_username.Length < 5)
|
||||
throw new Exception("username length should be > 4 and < 17");
|
||||
Config.Username = _username;
|
||||
Config.Save();
|
||||
username = _username;
|
||||
tabs.Login = tabs.Login.Remove(833, _username.Length).Insert(833, _username);
|
||||
RenderTab(tabs.Login);
|
||||
}
|
||||
break;
|
||||
case ConsoleKey.L:
|
||||
if (tabs.Current == tabs.Login)
|
||||
{
|
||||
RenderTab(tabs.Current);
|
||||
if (username.Length < 2) throw new Exception("username is too short");
|
||||
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)
|
||||
if (!Offline)
|
||||
{
|
||||
ConnectToLauncherServer();
|
||||
UpdateGame();
|
||||
networkManager.ConnectToLauncherServer();
|
||||
networkManager.UpdateGame();
|
||||
}
|
||||
|
||||
// запуск майнкрафта
|
||||
Logger.LogInfo("Main", "launching minecraft");
|
||||
string gameOptions = ConstructGameLaunchArgs(Config.Username,
|
||||
NameUUIDFromString("OfflinePlayer:" + Config.Username),
|
||||
Config.GameMemory,
|
||||
Config.GameWindowWidth,
|
||||
Config.GameWindowHeight,
|
||||
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);
|
||||
var gameProcess = Process.Start(config.JavaPath.Str, gameOptions);
|
||||
gameProcess?.WaitForExit();
|
||||
Logger.LogInfo("Main", "minecraft closed");
|
||||
}
|
||||
break;
|
||||
case ConsoleKey.F2:
|
||||
tabs.Log = File.ReadAllText(_fileLogger.LogfileName);
|
||||
RenderTab(tabs.Log, 9999);
|
||||
break;
|
||||
case ConsoleKey.F3:
|
||||
RenderTab(tabs.Settings);
|
||||
break;
|
||||
case ConsoleKey.F4:
|
||||
RenderTab(tabs.Exit);
|
||||
break;
|
||||
case ConsoleKey.Enter:
|
||||
if (tabs.Current == tabs.Exit)
|
||||
{
|
||||
Console.Clear();
|
||||
// Console.BufferHeight = 9999;
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case ConsoleKey.F5:
|
||||
if (tabs.Current == tabs.Log) goto case ConsoleKey.F2;
|
||||
RenderTab(tabs.Current);
|
||||
Console.CursorVisible = false;
|
||||
break;
|
||||
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)
|
||||
{
|
||||
Logger.LogError("Main", ex);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.LogError("Main", ex);
|
||||
console.StopUpdating();
|
||||
Logger.LogError(nameof(Main), ex);
|
||||
ColoredConsole.Write("gray", "press any key to close...");
|
||||
Console.ReadKey();
|
||||
}
|
||||
Console.CursorVisible = true;
|
||||
|
||||
Console.ResetColor();
|
||||
}
|
||||
|
||||
private static void RenderTab(string tab, ushort bufferHeight = 30)
|
||||
{
|
||||
tabs.Current = tab;
|
||||
Console.Clear();
|
||||
Console.SetWindowSize(80, 30);
|
||||
// Console.SetBufferSize(80, bufferHeight);
|
||||
ColoredConsole.Write("w", tab);
|
||||
}
|
||||
|
||||
private static string ReadString(ushort x, ushort y, ushort maxlength)
|
||||
{
|
||||
var output = "";
|
||||
tabs.Current = tabs.Current.Remove(y * 80 + x, maxlength).Insert(y * 80 + x, " ".Multiply(maxlength));
|
||||
while (true)
|
||||
{
|
||||
var pressedKey = Console.ReadKey(false);
|
||||
switch (pressedKey.Key)
|
||||
{
|
||||
case ConsoleKey.Enter:
|
||||
return output;
|
||||
case ConsoleKey.Backspace:
|
||||
if (output.Length > 0)
|
||||
{
|
||||
output = output.Remove(output.Length - 1);
|
||||
RenderTab(tabs.Current);
|
||||
Console.SetCursorPosition(x, y);
|
||||
ColoredConsole.Write("c", output);
|
||||
}
|
||||
|
||||
break;
|
||||
case ConsoleKey.Escape:
|
||||
tabs.Current = tabs.Current.Remove(y * 80 + x, maxlength)
|
||||
.Insert(y * 80 + x, " ".Multiply(maxlength));
|
||||
RenderTab(tabs.Current);
|
||||
return "";
|
||||
//case ConsoleKey.Spacebar:
|
||||
case ConsoleKey.UpArrow:
|
||||
case ConsoleKey.DownArrow:
|
||||
case ConsoleKey.LeftArrow:
|
||||
case ConsoleKey.RightArrow:
|
||||
break;
|
||||
default:
|
||||
if (output.Length <= maxlength)
|
||||
{
|
||||
string keyC = pressedKey.KeyChar.ToString();
|
||||
string thisChar = pressedKey.Modifiers.HasFlag(ConsoleModifiers.Shift) ? keyC.ToUpper() : keyC;
|
||||
output += thisChar;
|
||||
}
|
||||
|
||||
RenderTab(tabs.Current);
|
||||
Console.SetCursorPosition(x, y);
|
||||
ColoredConsole.Write("c", output);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//minecraft player uuid explanation
|
||||
//https://gist.github.com/CatDany/0e71ca7cd9b42a254e49/
|
||||
//java uuid generation in c#
|
||||
|
||||
@ -1,111 +0,0 @@
|
||||
using System;
|
||||
using System.Net;
|
||||
using System.Net.Sockets;
|
||||
using System.Threading;
|
||||
using DTLib;
|
||||
using DTLib.Dtsod;
|
||||
using DTLib.Extensions;
|
||||
using DTLib.Filesystem;
|
||||
using DTLib.Logging;
|
||||
using DTLib.Network;
|
||||
using DTLib.XXHash;
|
||||
using static launcher_client.Launcher;
|
||||
|
||||
namespace launcher_client;
|
||||
|
||||
public class Network
|
||||
{
|
||||
public static Socket mainSocket = new(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
|
||||
public static FSP Fsp = new(mainSocket);
|
||||
|
||||
// подключение серверу
|
||||
public static void ConnectToLauncherServer()
|
||||
{
|
||||
if (mainSocket.Connected)
|
||||
{
|
||||
Logger.LogInfo(nameof(Network), "socket is connected already. disconnecting...");
|
||||
mainSocket.Shutdown(SocketShutdown.Both);
|
||||
mainSocket.Close();
|
||||
mainSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
|
||||
Fsp = new(mainSocket);
|
||||
}
|
||||
|
||||
while (true)
|
||||
try
|
||||
{
|
||||
Logger.LogInfo(nameof(Network), $"connecting to server {Config.ServerAddress}:{Config.ServerPort}");
|
||||
var ip = Dns.GetHostAddresses(Config.ServerAddress)[0];
|
||||
mainSocket.Connect(new IPEndPoint(ip, Config.ServerPort));
|
||||
Logger.LogInfo(nameof(Network), $"connected to server {ip}");
|
||||
break;
|
||||
}
|
||||
catch (SocketException ex)
|
||||
{
|
||||
Logger.LogError(nameof(Network), ex);
|
||||
Thread.Sleep(2000);
|
||||
}
|
||||
|
||||
mainSocket.ReceiveTimeout = 2500;
|
||||
mainSocket.SendTimeout = 2500;
|
||||
mainSocket.GetAnswer("requesting user name");
|
||||
mainSocket.SendPackage("minecraft-launcher");
|
||||
mainSocket.GetAnswer("minecraft-launcher OK");
|
||||
}
|
||||
|
||||
public static void DownloadByManifest(IOPath dirOnServer, IOPath dirOnClient, bool overwrite = false, bool delete_excess = false)
|
||||
{
|
||||
var manifestPath = Path.Concat(dirOnServer, "manifest.dtsod");
|
||||
Logger.LogDebug(nameof(Network), manifestPath);
|
||||
string manifestContent = Fsp.DownloadFileToMemory(manifestPath).BytesToString();
|
||||
Logger.LogDebug(nameof(Network), manifestContent);
|
||||
var manifest = new DtsodV23(manifestContent);
|
||||
foreach (var fileOnServerData in manifest)
|
||||
{
|
||||
IOPath fileOnClient = Path.Concat(dirOnClient, fileOnServerData.Key);
|
||||
if (!File.Exists(fileOnClient))
|
||||
{
|
||||
Logger.LogDebug(nameof(Network), $"downloading {fileOnClient}");
|
||||
Fsp.DownloadFile(Path.Concat(dirOnServer, fileOnServerData.Key), fileOnClient);
|
||||
}
|
||||
else if (overwrite)
|
||||
{
|
||||
var fileStream = File.OpenRead(fileOnClient);
|
||||
ulong hash = xxHash64.ComputeHash(fileStream);
|
||||
fileStream.Close();
|
||||
string hashStr = BitConverter.GetBytes(hash).HashToString();
|
||||
if (hashStr != fileOnServerData.Value)
|
||||
{
|
||||
Logger.LogDebug(nameof(Network), $"downloading {fileOnClient} (hash {hashStr} != {fileOnServerData.Value})");
|
||||
Fsp.DownloadFile(Path.Concat(dirOnServer, fileOnServerData.Key), fileOnClient);
|
||||
}
|
||||
}
|
||||
}
|
||||
// удаление лишних файлов
|
||||
if (delete_excess)
|
||||
{
|
||||
foreach (var file in Directory.GetAllFiles(dirOnClient))
|
||||
{
|
||||
if (!manifest.ContainsKey(file.RemoveBase(dirOnClient).Str.Replace('\\','/')))
|
||||
{
|
||||
Logger.LogDebug(nameof(Network), $"deleting {file}");
|
||||
File.Delete(file);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void UpdateGame()
|
||||
{
|
||||
//обновление файлов клиента
|
||||
Logger.LogInfo(nameof(Network), "updating client...");
|
||||
DownloadByManifest("download_if_not_exist", Directory.GetCurrent());
|
||||
DownloadByManifest("sync_always", Directory.GetCurrent(), true);
|
||||
var dirlistDtsod = new DtsodV23(Fsp
|
||||
.DownloadFileToMemory(Path.Concat("sync_and_remove","dirlist.dtsod"))
|
||||
.BytesToString());
|
||||
foreach (string dir in dirlistDtsod["dirs"])
|
||||
DownloadByManifest(Path.Concat("sync_and_remove", dir),
|
||||
Path.Concat(Directory.GetCurrent(), dir), true, true);
|
||||
Logger.LogInfo(nameof(Network), "client updated");
|
||||
}
|
||||
}
|
||||
160
minecraft-launcher-client/NetworkManager.cs
Normal file
160
minecraft-launcher-client/NetworkManager.cs
Normal file
@ -0,0 +1,160 @@
|
||||
using System;
|
||||
using System.Net;
|
||||
using System.Net.Sockets;
|
||||
using System.Reflection;
|
||||
using System.Threading;
|
||||
using DTLib.Dtsod;
|
||||
using DTLib.Extensions;
|
||||
using DTLib.Filesystem;
|
||||
using DTLib.Logging;
|
||||
using DTLib.Network;
|
||||
using DTLib.XXHash;
|
||||
|
||||
namespace launcher_client;
|
||||
|
||||
public class NetworkManager
|
||||
{
|
||||
public Socket mainSocket = new(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
|
||||
public FSP Fsp;
|
||||
private ILogger Logger;
|
||||
private IPEndPoint ServerEndpoint;
|
||||
|
||||
public NetworkManager(ILogger logger, IPEndPoint serverEndpoint)
|
||||
{
|
||||
Fsp = new FSP(mainSocket);
|
||||
Logger = logger;
|
||||
ServerEndpoint = serverEndpoint;
|
||||
}
|
||||
public NetworkManager(ILogger logger, string serverAddress, int serverPort)
|
||||
: this(logger, new IPEndPoint(IPAddress.Parse(serverAddress), serverPort))
|
||||
{}
|
||||
|
||||
// подключение серверу
|
||||
public void ConnectToLauncherServer()
|
||||
{
|
||||
if (mainSocket.Connected)
|
||||
{
|
||||
Logger.LogInfo(nameof(NetworkManager), "socket is connected already. disconnecting...");
|
||||
DisconnectFromLauncherServer();
|
||||
}
|
||||
|
||||
while (true)
|
||||
try
|
||||
{
|
||||
Logger.LogInfo(nameof(NetworkManager), $"connecting to server {ServerEndpoint.Address}:{ServerEndpoint.Port}");
|
||||
mainSocket.Connect(ServerEndpoint);
|
||||
Logger.LogInfo(nameof(NetworkManager), "connection established");
|
||||
break;
|
||||
}
|
||||
catch (SocketException ex)
|
||||
{
|
||||
Logger.LogError(nameof(NetworkManager), ex);
|
||||
Thread.Sleep(2000);
|
||||
}
|
||||
|
||||
mainSocket.ReceiveTimeout = 2500;
|
||||
mainSocket.SendTimeout = 2500;
|
||||
mainSocket.GetAnswer("requesting user name");
|
||||
mainSocket.SendPackage("minecraft-launcher");
|
||||
mainSocket.GetAnswer("minecraft-launcher OK");
|
||||
}
|
||||
|
||||
public void DisconnectFromLauncherServer()
|
||||
{
|
||||
mainSocket.Shutdown(SocketShutdown.Both);
|
||||
mainSocket.Close();
|
||||
mainSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
|
||||
Fsp = new(mainSocket);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// returns true if new update was downloaded
|
||||
/// </summary>
|
||||
public bool TryDownloadLauncherUpdate(IOPath localFilePath)
|
||||
{
|
||||
try
|
||||
{
|
||||
Logger.LogDebug(nameof(NetworkManager), "requesting latest launcher version");
|
||||
mainSocket.SendPackage("requesting latest launcher version");
|
||||
var answer = mainSocket.GetPackage().BytesToString();
|
||||
if (!answer.StartsWith("latest launcher version is ") ||
|
||||
Version.TryParse(answer.Substring(27), out Version latestVersion))
|
||||
throw new Exception($"unexpected server answer: {answer}");
|
||||
|
||||
Version currentVersion = Assembly.GetExecutingAssembly().GetName().Version;
|
||||
Logger.LogDebug(nameof(NetworkManager),
|
||||
$"current version: {currentVersion}; latest version: {latestVersion}");
|
||||
if (currentVersion < latestVersion)
|
||||
{
|
||||
Logger.LogInfo(nameof(NetworkManager), $"downloading launcher update to {localFilePath}");
|
||||
mainSocket.SendPackage("requesting launcher update");
|
||||
Fsp.DownloadFile(localFilePath);
|
||||
Logger.LogInfo(nameof(NetworkManager), "launcher update downloaded");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.LogError(nameof(NetworkManager), ex);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public void DownloadByManifest(IOPath dirOnServer, IOPath dirOnClient, bool overwrite, bool delete_excess)
|
||||
{
|
||||
var manifestPath = Path.Concat(dirOnServer, "manifest.dtsod");
|
||||
Logger.LogDebug(nameof(NetworkManager), manifestPath);
|
||||
string manifestContent = Fsp.DownloadFileToMemory(manifestPath).BytesToString();
|
||||
Logger.LogDebug(nameof(NetworkManager), manifestContent);
|
||||
var manifest = new DtsodV23(manifestContent);
|
||||
foreach (var fileOnServerData in manifest)
|
||||
{
|
||||
IOPath fileOnClient = Path.Concat(dirOnClient, fileOnServerData.Key);
|
||||
if (!File.Exists(fileOnClient))
|
||||
{
|
||||
Logger.LogDebug(nameof(NetworkManager), $"downloading {fileOnClient}");
|
||||
Fsp.DownloadFile(Path.Concat(dirOnServer, fileOnServerData.Key), fileOnClient);
|
||||
}
|
||||
else if (overwrite)
|
||||
{
|
||||
var fileStream = File.OpenRead(fileOnClient);
|
||||
ulong hash = xxHash64.ComputeHash(fileStream);
|
||||
fileStream.Close();
|
||||
string hashStr = BitConverter.GetBytes(hash).HashToString();
|
||||
if (hashStr != fileOnServerData.Value)
|
||||
{
|
||||
Logger.LogDebug(nameof(NetworkManager), $"downloading {fileOnClient} (hash {hashStr} != {fileOnServerData.Value})");
|
||||
Fsp.DownloadFile(Path.Concat(dirOnServer, fileOnServerData.Key), fileOnClient);
|
||||
}
|
||||
}
|
||||
}
|
||||
// удаление лишних файлов
|
||||
if (delete_excess)
|
||||
{
|
||||
foreach (var file in Directory.GetAllFiles(dirOnClient))
|
||||
{
|
||||
if (!manifest.ContainsKey(file.RemoveBase(dirOnClient).Str.Replace('\\','/')))
|
||||
{
|
||||
Logger.LogDebug(nameof(NetworkManager), $"deleting {file}");
|
||||
File.Delete(file);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void UpdateGame()
|
||||
{
|
||||
//обновление файлов клиента
|
||||
Logger.LogInfo(nameof(NetworkManager), "updating client...");
|
||||
DownloadByManifest("download_if_not_exist", Directory.GetCurrent(), false, false);
|
||||
DownloadByManifest("sync_always", Directory.GetCurrent(), true, false);
|
||||
var dirlistDtsod = new DtsodV23(Fsp
|
||||
.DownloadFileToMemory(Path.Concat("sync_and_remove","dirlist.dtsod"))
|
||||
.BytesToString());
|
||||
foreach (string dir in dirlistDtsod["dirs"])
|
||||
DownloadByManifest(Path.Concat("sync_and_remove", dir),
|
||||
Path.Concat(Directory.GetCurrent(), dir), true, true);
|
||||
Logger.LogInfo(nameof(NetworkManager), "client updated");
|
||||
}
|
||||
}
|
||||
@ -1,29 +0,0 @@
|
||||
┏━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┓
|
||||
┃ [F1] login ┃ [F2] log ┃ [F3] settings ┃ [F4] EXIT ┃ [F5] refresh ┃
|
||||
┣━━━━━━━━━━━━━━┻━━━━━━━━━━━━━━┻━━━━━━━━━━━━━━━━┻━━━━━━━━━━━━━━┻━━━━━━━━━━━━━━━┫
|
||||
┃ ┃
|
||||
┃ ┃
|
||||
┃ ┃
|
||||
┃ ┃
|
||||
┃ ┃
|
||||
┃ ┃
|
||||
┃ ┃
|
||||
┃ ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ ┃
|
||||
┃ ┃ ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ ┃ ┃
|
||||
┃ ┃ ┃ ┃ ┃ ┃
|
||||
┃ ┃ ┃ press [ENTER] to exit ┃ ┃ ┃
|
||||
┃ ┃ ┃ ┃ ┃ ┃
|
||||
┃ ┃ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ┃ ┃
|
||||
┃ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ┃
|
||||
┃ ┃
|
||||
┃ ┃
|
||||
┃ ┃
|
||||
┃ ┃
|
||||
┃ ┃
|
||||
┃ ┃
|
||||
┃ ┃
|
||||
┃ ┃
|
||||
┃ ┃
|
||||
┃ ┃
|
||||
┃ ┃
|
||||
┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
|
||||
@ -1,29 +0,0 @@
|
||||
┏━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┓
|
||||
┃ [F1] LOGIN ┃ [F2] log ┃ [F3] settings ┃ [F4] exit ┃ [F5] refresh ┃
|
||||
┣━━━━━━━━━━━━━━┻━━━━━━━━━━━━━━┻━━━━━━━━━━━━━━━━┻━━━━━━━━━━━━━━┻━━━━━━━━━━━━━━━┫
|
||||
┃ ┃
|
||||
┃ ┃
|
||||
┃ ┃
|
||||
┃ ┃
|
||||
┃ ┃
|
||||
┃ ┃
|
||||
┃ ┌──────────────────┐ ┃
|
||||
┃ [N] nickname:│ │ ┃
|
||||
┃ └──────────────────┘ ┃
|
||||
┃ ┃
|
||||
┃ ┏━━━━━━━━━━━━━━━━┓ ┃
|
||||
┃ ┃ [L] login ┃ ┃
|
||||
┃ ┗━━━━━━━━━━━━━━━━┛ ┃
|
||||
┃ ┃
|
||||
┃ ┃
|
||||
┃ ┃
|
||||
┃ ┃
|
||||
┃ ┃
|
||||
┃ ┃
|
||||
┃ ┃
|
||||
┃ ┃
|
||||
┃ ┃
|
||||
┃ ┃
|
||||
┃ ┃
|
||||
┃ ┃
|
||||
┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
|
||||
@ -1,29 +0,0 @@
|
||||
┏━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┓
|
||||
┃ [F1] login ┃ [F2] log ┃ [F3] SETTINGS ┃ [F4] exit ┃ [F5] refresh ┃
|
||||
┣━━━━━━━━━━━━━━┻━━━━━━━━━━━━━━┻━━━━━━━━━━━━━━━━┻━━━━━━━━━━━━━━┻━━━━━━━━━━━━━━━┫
|
||||
┃ ┃
|
||||
┃ ┃
|
||||
┃ ┃
|
||||
┃ ┃
|
||||
┃ я ещё не добавил настройки ┃
|
||||
┃ ┃
|
||||
┃ приходите позже ┃
|
||||
┃ ┃
|
||||
┃ ┃
|
||||
┃ ┃
|
||||
┃ ■ ■ ■ ■ ┃
|
||||
┃ ■ ■ ■ ■ ┃
|
||||
┃ ■ ■ ■ ■ ■ ■ ■ ┃
|
||||
┃ ■ ■ ■ ■ ■ ■ ■ ┃
|
||||
┃ ■ ■ ■ ┃
|
||||
┃ ┃
|
||||
┃ ┃
|
||||
┃ ┃
|
||||
┃ ┃
|
||||
┃ ┃
|
||||
┃ ┃
|
||||
┃ ┃
|
||||
┃ ┃
|
||||
┃ ┃
|
||||
┃ ┃
|
||||
┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
|
||||
@ -1,3 +0,0 @@
|
||||
┏━━━━━━━━━┓
|
||||
┃ ejejeje ┃
|
||||
┗━━━━━━━━━┛
|
||||
@ -1,16 +0,0 @@
|
||||
window:
|
||||
{
|
||||
type: "container";
|
||||
anchor: [0us, 0us];
|
||||
width: 90us;
|
||||
height: 30us;
|
||||
children:
|
||||
{
|
||||
test_label:
|
||||
{
|
||||
type: "label";
|
||||
anchor: [0us, 0us];
|
||||
resdir: "gui";
|
||||
};
|
||||
};
|
||||
};
|
||||
@ -11,21 +11,22 @@
|
||||
<ApplicationIcon>launcher.ico</ApplicationIcon>
|
||||
<DebugType>embedded</DebugType>
|
||||
<InvariantGlobalization>true</InvariantGlobalization>
|
||||
<GenerateSupportedRuntime>False</GenerateSupportedRuntime>
|
||||
<GenerateSupportedRuntime>false</GenerateSupportedRuntime>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Remove="gui\exit.gui" />
|
||||
<EmbeddedResource Include="gui\**" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Costura.Fody" Version="5.7.0">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="DTLib.Dtsod" Version="1.3.4" />
|
||||
<PackageReference Include="DTLib.Logging" Version="1.3.4" />
|
||||
<PackageReference Include="DTLib.Logging" Version="1.3.5" />
|
||||
<PackageReference Include="DTLib.Network" Version="1.4.2" />
|
||||
<PackageReference Include="DTLib.XXHash" Version="1.0.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Update="launcher_version.txt">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
1
minecraft-launcher-client/launcher_version.txt
Normal file
1
minecraft-launcher-client/launcher_version.txt
Normal file
@ -0,0 +1 @@
|
||||
2.0.0
|
||||
@ -1,2 +1,3 @@
|
||||
dotnet publish -c Release -o bin\publish
|
||||
set /p version=<launcher_version.txt
|
||||
dotnet publish -c Release -o bin\publish -p:Version=%version%
|
||||
del /f bin\publish\minecraft-launcher.exe.config
|
||||
|
||||
@ -10,23 +10,24 @@ global using DTLib.Extensions;
|
||||
global using DTLib.Filesystem;
|
||||
global using DTLib.Logging;
|
||||
global using DTLib.Network;
|
||||
using System.Diagnostics;
|
||||
using DTLib.Ben.Demystifier;
|
||||
using Timer = DTLib.Timer;
|
||||
|
||||
namespace launcher_server;
|
||||
|
||||
static class Server
|
||||
{
|
||||
private static ILogger logger = new CompositeLogger(
|
||||
public static ILogger Logger = new CompositeLogger(
|
||||
new FileLogger("logs","launcher-server"),
|
||||
new ConsoleLogger());
|
||||
static readonly Socket mainSocket = new(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
|
||||
static ServerConfig Config = null!;
|
||||
public static readonly IOPath shared_dir = "public";
|
||||
|
||||
public static readonly IOPath LatestLauncherVersionFile = "launcher_version.txt";
|
||||
public static string LatestLauncherVersion = "0.0.1";
|
||||
|
||||
static void Main(string[] args)
|
||||
{
|
||||
var mainSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
|
||||
try
|
||||
{
|
||||
Console.Title = "minecraft_launcher_server";
|
||||
@ -34,23 +35,26 @@ static class Server
|
||||
Console.OutputEncoding = Encoding.Unicode;
|
||||
|
||||
Config = ServerConfig.LoadOrCreateDefault();
|
||||
LatestLauncherVersion = File.ReadAllText(LatestLauncherVersionFile);
|
||||
|
||||
Logger.LogInfo(nameof(Main), "creating manifests...");
|
||||
Manifests.CreateAllManifests();
|
||||
CheckUpdates();
|
||||
// check for updates every 5 minutes
|
||||
var updateCheckTimer = new Timer(true, 5*60 * 1000, CheckUpdates);
|
||||
Logger.LogInfo(nameof(Main), "manifests created");
|
||||
Updates.Check();
|
||||
// check for updates every minute
|
||||
var updateCheckTimer = new Timer(true, 60 * 1000, Updates.Check);
|
||||
updateCheckTimer.Start();
|
||||
|
||||
|
||||
logger.LogInfo("Main", $"local address: {Config.LocalIp}");
|
||||
logger.LogInfo("Main", $"public address: {Functions.GetPublicIP()}");
|
||||
logger.LogInfo("Main", $"port: {Config.LocalPort}");
|
||||
Logger.LogInfo("Main", $"local address: {Config.LocalIp}");
|
||||
Logger.LogInfo("Main", $"public address: {Functions.GetPublicIP()}");
|
||||
Logger.LogInfo("Main", $"port: {Config.LocalPort}");
|
||||
mainSocket.Bind(new IPEndPoint(IPAddress.Parse(Config.LocalIp), Config.LocalPort));
|
||||
mainSocket.Listen(1000);
|
||||
|
||||
logger.LogInfo("Main", "server started succesfully");
|
||||
Logger.LogInfo("Main", "server started succesfully");
|
||||
// запуск отдельного потока для каждого юзера
|
||||
logger.LogInfo("Main", "waiting for users");
|
||||
Logger.LogInfo("Main", "waiting for users");
|
||||
while (true)
|
||||
{
|
||||
var userSocket = mainSocket.Accept();
|
||||
@ -60,60 +64,16 @@ static class Server
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
logger.LogError("Main", ex);
|
||||
Logger.LogError("Main", ex);
|
||||
mainSocket.Close();
|
||||
}
|
||||
Console.ResetColor();
|
||||
}
|
||||
|
||||
static void CheckUpdates()
|
||||
{
|
||||
logger.LogDebug(nameof(CheckUpdates), "checking for updates...");
|
||||
IOPath updatesDir = "updates";
|
||||
Directory.Create(updatesDir);
|
||||
var updatedFiles = Directory.GetAllFiles(updatesDir);
|
||||
if(updatedFiles.Count != 0)
|
||||
logger.LogInfo(nameof(CheckUpdates), $"updated files found in '{updatesDir}'");
|
||||
foreach (var updatedFilePath in updatedFiles)
|
||||
{
|
||||
try
|
||||
{
|
||||
var relativeFilePath = updatedFilePath.RemoveBase(updatesDir);
|
||||
if (relativeFilePath.Str is "minecraft-launcher-server" or "minecraft-launcher-server.exe")
|
||||
{
|
||||
logger.LogWarn(nameof(CheckUpdates), "program update found, restarting...");
|
||||
string exeFile = relativeFilePath.Str;
|
||||
string exeFileNew = exeFile + "_new";
|
||||
File.Move(updatedFilePath, exeFileNew, true);
|
||||
if(Environment.OSVersion.Platform == PlatformID.Win32NT)
|
||||
Process.Start("cmd",$"/c move {exeFileNew} {exeFile} && {exeFile}");
|
||||
else
|
||||
File.Move(exeFileNew, exeFile, true);
|
||||
Environment.Exit(0);
|
||||
}
|
||||
|
||||
logger.LogDebug(nameof(CheckUpdates), "updating file "+relativeFilePath);
|
||||
File.Move(updatedFilePath, relativeFilePath, true);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
logger.LogError(nameof(CheckUpdates), $"failed update of file '{updatedFilePath}'\n"
|
||||
+ e.ToStringDemystified());
|
||||
}
|
||||
}
|
||||
if(updatedFiles.Count != 0)
|
||||
{
|
||||
logger.LogInfo(nameof(CheckUpdates), "creating manifests...");
|
||||
Manifests.CreateAllManifests();
|
||||
logger.LogInfo(nameof(CheckUpdates), "manifests created");
|
||||
}
|
||||
logger.LogDebug(nameof(CheckUpdates), "update check completed");
|
||||
}
|
||||
|
||||
// запускается для каждого юзера в отдельном потоке
|
||||
static void HandleUser(Socket handlerSocket)
|
||||
{
|
||||
logger.LogInfo(nameof(HandleUser), "user connecting... ");
|
||||
Logger.LogInfo(nameof(HandleUser), "user connecting... ");
|
||||
try
|
||||
{
|
||||
// тут запрос пароля заменён запросом заглушки
|
||||
@ -124,7 +84,7 @@ static class Server
|
||||
// запрос от апдейтера
|
||||
if (connectionString == "minecraft-launcher")
|
||||
{
|
||||
logger.LogInfo(nameof(HandleUser), "incoming connection from minecraft-launcher");
|
||||
Logger.LogInfo(nameof(HandleUser), "incoming connection from minecraft-launcher");
|
||||
handlerSocket.SendPackage("minecraft-launcher OK");
|
||||
// обработка запросов
|
||||
while (true)
|
||||
@ -134,14 +94,17 @@ static class Server
|
||||
string request = handlerSocket.GetPackage().BytesToString();
|
||||
switch (request)
|
||||
{
|
||||
case "requesting latest launcher version":
|
||||
handlerSocket.SendPackage("latest launcher version is "+LatestLauncherVersion);
|
||||
break;
|
||||
case "requesting launcher update":
|
||||
logger.LogInfo(nameof(HandleUser), "updater requested launcher update");
|
||||
Logger.LogInfo(nameof(HandleUser), "updater requested launcher update");
|
||||
// ReSharper disable once InconsistentlySynchronizedField
|
||||
fsp.UploadFile(Path.Concat(shared_dir, "minecraft-launcher.exe"));
|
||||
break;
|
||||
case "requesting file download":
|
||||
var filePath = handlerSocket.GetPackage().BytesToString();
|
||||
logger.LogInfo(nameof(HandleUser), $"updater requested file {filePath}");
|
||||
Logger.LogInfo(nameof(HandleUser), $"updater requested file {filePath}");
|
||||
if(filePath.EndsWith("manifest.dtsod"))
|
||||
lock (Manifests.manifestLocker)
|
||||
{
|
||||
@ -159,18 +122,18 @@ static class Server
|
||||
}
|
||||
// неизвестный юзер
|
||||
|
||||
logger.LogWarn(nameof(HandleUser),$"invalid connection string: '{connectionString}'");
|
||||
Logger.LogWarn(nameof(HandleUser),$"invalid connection string: '{connectionString}'");
|
||||
handlerSocket.SendPackage("invalid connection string");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
logger.LogWarn(nameof(HandleUser), ex);
|
||||
Logger.LogWarn(nameof(HandleUser), ex);
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (handlerSocket.Connected) handlerSocket.Shutdown(SocketShutdown.Both);
|
||||
handlerSocket.Close();
|
||||
logger.LogInfo(nameof(HandleUser), "user disconnected");
|
||||
Logger.LogInfo(nameof(HandleUser), "user disconnected");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
68
minecraft-launcher-server/Updates.cs
Normal file
68
minecraft-launcher-server/Updates.cs
Normal file
@ -0,0 +1,68 @@
|
||||
using System.Diagnostics;
|
||||
using DTLib.Ben.Demystifier;
|
||||
|
||||
namespace launcher_server;
|
||||
|
||||
static class Updates
|
||||
{
|
||||
public static void Check()
|
||||
{
|
||||
Server.Logger.LogDebug(nameof(Check), "checking for updates...");
|
||||
IOPath updatesDir = "updates";
|
||||
Directory.Create(updatesDir);
|
||||
var updatedFiles = Directory.GetAllFiles(updatesDir);
|
||||
if(updatedFiles.Count != 0) Server.Logger.LogInfo(nameof(Check), $"updated files found in '{updatesDir}'");
|
||||
|
||||
foreach (var f in updatedFiles)
|
||||
{
|
||||
if(f.Str is "minecraft-launcher-server" or "minecraft-launcher-server.exe")
|
||||
SelfUpdate(updatesDir, f);
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (var updatedFilePath in updatedFiles)
|
||||
{
|
||||
try
|
||||
{
|
||||
var relativeFilePath = updatedFilePath.RemoveBase(updatesDir);
|
||||
if (relativeFilePath.Str == "launcher_version.txt")
|
||||
{
|
||||
Server.LatestLauncherVersion = File.ReadAllText(updatedFilePath);
|
||||
Server.Logger.LogInfo(nameof(Check), "new launcher version: " + Server.LatestLauncherVersion);
|
||||
File.Move(updatedFilePath, Server.LatestLauncherVersionFile, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
Server.Logger.LogInfo(nameof(Check), "updating file " + relativeFilePath);
|
||||
File.Move(updatedFilePath, relativeFilePath, true);
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Server.Logger.LogError(nameof(Check), $"failed update of file '{updatedFilePath}'\n"
|
||||
+ e.ToStringDemystified());
|
||||
}
|
||||
}
|
||||
|
||||
if(updatedFiles.Count != 0)
|
||||
{
|
||||
Server.Logger.LogInfo(nameof(Check), "creating manifests...");
|
||||
Manifests.CreateAllManifests();
|
||||
Server.Logger.LogInfo(nameof(Check), "manifests created");
|
||||
}
|
||||
|
||||
Server.Logger.LogDebug(nameof(Check), "update check completed");
|
||||
}
|
||||
|
||||
public static void SelfUpdate(IOPath updatesDir, IOPath exeFile)
|
||||
{
|
||||
Server.Logger.LogWarn(nameof(SelfUpdate), "program update found, restarting...");
|
||||
IOPath exeFileNew = exeFile + "_new";
|
||||
File.Move(Path.Concat(updatesDir, exeFile), exeFileNew, true);
|
||||
if(Environment.OSVersion.Platform == PlatformID.Win32NT)
|
||||
Process.Start("cmd",$"/c move {exeFileNew} {exeFile} && {exeFile}");
|
||||
else
|
||||
File.Move(exeFileNew, exeFile, true);
|
||||
Environment.Exit(0);
|
||||
}
|
||||
}
|
||||
@ -1,3 +1,4 @@
|
||||
#!/bin/bash
|
||||
dotnet publish -c release -o bin/publish \
|
||||
--self-contained \
|
||||
--use-current-runtime \
|
||||
|
||||
Loading…
Reference in New Issue
Block a user