Compare commits
No commits in common. "f0679403d1e76c4fee47011bfe57d0b159bc054f" and "34f298c43be7d927375629464203c8386202049a" have entirely different histories.
f0679403d1
...
34f298c43b
@ -1,75 +0,0 @@
|
|||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,189 +0,0 @@
|
|||||||
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,169 +1,239 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
|
using System.Dynamic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Security.Cryptography;
|
using System.Security.Cryptography;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading;
|
|
||||||
using DTLib.Console;
|
using DTLib.Console;
|
||||||
|
using DTLib.Extensions;
|
||||||
using DTLib.Logging;
|
using DTLib.Logging;
|
||||||
|
using DTLib.Network;
|
||||||
using DTLib.Filesystem;
|
using DTLib.Filesystem;
|
||||||
|
using Directory = DTLib.Filesystem.Directory;
|
||||||
|
using File = DTLib.Filesystem.File;
|
||||||
|
using static launcher_client.Network;
|
||||||
namespace launcher_client;
|
namespace launcher_client;
|
||||||
|
|
||||||
internal static partial class Launcher
|
internal static partial class Launcher
|
||||||
{
|
{
|
||||||
public static bool Debug, Offline, Updated;
|
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();
|
||||||
|
|
||||||
private static void Main(string[] args)
|
private static void Main(string[] args)
|
||||||
{
|
{
|
||||||
// console arguments parsing
|
try
|
||||||
#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.Title = "anarx_2";
|
||||||
Console.OutputEncoding = Encoding.UTF8;
|
Console.OutputEncoding = Encoding.UTF8;
|
||||||
Console.InputEncoding = Encoding.UTF8;
|
Console.InputEncoding = Encoding.UTF8;
|
||||||
using ConsoleWrapper console = new ConsoleWrapper();
|
Console.CursorVisible = false;
|
||||||
console.StartUpdating();
|
|
||||||
|
|
||||||
// logger initialization
|
#if DEBUG
|
||||||
FileLogger fileLogger = new FileLogger("launcher-logs", "launcher-client");
|
debug = true;
|
||||||
ConsoleWrapperLogger consoleWrapperLogger = new ConsoleWrapperLogger(console);
|
#else
|
||||||
ILogger Logger = new CompositeLogger(
|
if (args.Contains("debug")) debug = true;
|
||||||
fileLogger,
|
#endif
|
||||||
consoleWrapperLogger
|
if (args.Contains("offline")) offline = true;
|
||||||
);
|
if (args.Contains("updated")) updated = true;
|
||||||
Logger.DebugLogEnabled = true; // always print debug log to file
|
|
||||||
consoleWrapperLogger.DebugLogEnabled = Debug;
|
|
||||||
|
|
||||||
try
|
Config = LauncherConfig.LoadOrCreateDefault();
|
||||||
{
|
|
||||||
var config = LauncherConfig.LoadOrCreateDefault();
|
|
||||||
NetworkManager networkManager = new NetworkManager(Logger, config.ServerAddress, config.ServerPort);
|
|
||||||
|
|
||||||
Logger.LogInfo(nameof(Main), "launcher started");
|
Logger.DebugLogEnabled = debug;
|
||||||
|
Logger.LogInfo("Main", "launcher is starting");
|
||||||
|
|
||||||
if(File.Exists("minecraft-launcher.exe_old"))
|
if(File.Exists("minecraft-launcher.exe_old"))
|
||||||
File.Delete("minecraft-launcher.exe_old");
|
File.Delete("minecraft-launcher.exe_old");
|
||||||
|
|
||||||
// self-update
|
// обновление лаунчера
|
||||||
if (!Updated && !Offline)
|
if (!updated && !offline)
|
||||||
{
|
|
||||||
Logger.LogInfo(nameof(Main), "checking for launcher update");
|
|
||||||
networkManager.ConnectToLauncherServer();
|
|
||||||
bool updateDownloaded = networkManager.TryDownloadLauncherUpdate("minecraft-launcher.exe_new");
|
|
||||||
if(updateDownloaded)
|
|
||||||
{
|
{
|
||||||
|
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");
|
System.IO.File.Move("minecraft-launcher.exe", "minecraft-launcher.exe_old");
|
||||||
Process.Start("cmd", "/c " +
|
Process.Start("cmd","/c " +
|
||||||
"move minecraft-launcher.exe_new minecraft-launcher.exe && " +
|
"move minecraft-launcher.exe_new minecraft-launcher.exe && " +
|
||||||
"minecraft-launcher.exe updated");
|
"minecraft-launcher.exe updated");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
networkManager.DisconnectFromLauncherServer();
|
|
||||||
}
|
|
||||||
|
|
||||||
// если уже обновлён
|
// если уже обновлён
|
||||||
|
tabs.Login = EmbeddedResources.ReadText("launcher_client.gui.login.gui");
|
||||||
console.SetHeader($"username: {config.Username} | game memory: {config.GameMemory}M");
|
tabs.Settings = EmbeddedResources.ReadText("launcher_client.gui.settings.gui");
|
||||||
console.SetFooter("[L] launch game | [N] change username | [H] help");
|
tabs.Exit = EmbeddedResources.ReadText("launcher_client.gui.exit.gui");
|
||||||
console.DrawGui();
|
tabs.Log = "";
|
||||||
|
tabs.Current = "";
|
||||||
while (true)
|
string username = "";
|
||||||
|
if (!Config.Username.IsNullOrEmpty())
|
||||||
{
|
{
|
||||||
try
|
tabs.Login = tabs.Login.Remove(833, Config.Username.Length).Insert(833, Config.Username);
|
||||||
|
username = Config.Username;
|
||||||
|
}
|
||||||
|
|
||||||
|
RenderTab(tabs.Login);
|
||||||
|
|
||||||
|
while (true) try
|
||||||
|
// ReSharper disable once BadChildStatementIndent
|
||||||
{
|
{
|
||||||
var pressedKey = Console.ReadKey(true); // Считывание ввода
|
var pressedKey = Console.ReadKey(true); // Считывание ввода
|
||||||
switch (pressedKey.Key)
|
switch (pressedKey.Key)
|
||||||
{
|
{
|
||||||
case ConsoleKey.UpArrow:
|
case ConsoleKey.F1:
|
||||||
console.ScrollUp();
|
RenderTab(tabs.Login);
|
||||||
break;
|
|
||||||
case ConsoleKey.DownArrow:
|
|
||||||
console.ScrollDown();
|
|
||||||
break;
|
|
||||||
case ConsoleKey.PageUp:
|
|
||||||
console.ScrollUp(console.TextAreaH);
|
|
||||||
break;
|
|
||||||
case ConsoleKey.PageDown:
|
|
||||||
console.ScrollDown(console.TextAreaH);
|
|
||||||
break;
|
break;
|
||||||
case ConsoleKey.N:
|
case ConsoleKey.N:
|
||||||
// todo ReadLine wrapper
|
if (tabs.Current == tabs.Login)
|
||||||
Console.SetCursorPosition(0, Console.WindowHeight - 1);
|
{
|
||||||
Console.CursorVisible = true;
|
tabs.Login = tabs.Login
|
||||||
string? _username = Console.ReadLine();
|
.Remove(751, 20).Insert(751, "┏━━━━━━━━━━━━━━━━━━┓")
|
||||||
|
.Remove(831, 20).Insert(831, "┃ ┃")
|
||||||
if (_username == null || _username.Length < 2)
|
.Remove(911, 20).Insert(911, "┗━━━━━━━━━━━━━━━━━━┛");
|
||||||
throw new Exception("too short username");
|
RenderTab(tabs.Login);
|
||||||
config.Username = _username;
|
var _username = ReadString(33, 10, 15);
|
||||||
config.Save();
|
tabs.Login = tabs.Login
|
||||||
|
.Remove(751, 20).Insert(751, "┌──────────────────┐")
|
||||||
console.DrawGui();
|
.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;
|
break;
|
||||||
case ConsoleKey.L:
|
case ConsoleKey.L:
|
||||||
if (config.Username.Length < 2)
|
if (tabs.Current == tabs.Login)
|
||||||
throw new Exception("username is too short");
|
{
|
||||||
|
RenderTab(tabs.Current);
|
||||||
|
if (username.Length < 2) throw new Exception("username is too short");
|
||||||
|
|
||||||
// обновление клиента
|
// обновление клиента
|
||||||
if (!Offline)
|
if (!offline)
|
||||||
{
|
{
|
||||||
networkManager.ConnectToLauncherServer();
|
ConnectToLauncherServer();
|
||||||
networkManager.UpdateGame();
|
UpdateGame();
|
||||||
}
|
}
|
||||||
|
|
||||||
// запуск майнкрафта
|
// запуск майнкрафта
|
||||||
Logger.LogInfo(nameof(Main), "launching minecraft");
|
Logger.LogInfo("Main", "launching minecraft");
|
||||||
string gameOptions = ConstructGameLaunchArgs(config.Username,
|
string gameOptions = ConstructGameLaunchArgs(Config.Username,
|
||||||
NameUUIDFromString("OfflinePlayer:" + config.Username),
|
NameUUIDFromString("OfflinePlayer:" + Config.Username),
|
||||||
config.GameMemory,
|
Config.GameMemory,
|
||||||
config.GameWindowWidth,
|
Config.GameWindowWidth,
|
||||||
config.GameWindowHeight,
|
Config.GameWindowHeight,
|
||||||
Directory.GetCurrent());
|
Directory.GetCurrent());
|
||||||
Logger.LogDebug("LaunchGame", gameOptions);
|
Logger.LogDebug("LaunchGame", gameOptions);
|
||||||
var gameProcess = Process.Start(config.JavaPath.Str, gameOptions);
|
var gameProcess = Process.Start(Config.JavaPath.Str, gameOptions);
|
||||||
gameProcess?.WaitForExit();
|
gameProcess?.WaitForExit();
|
||||||
Logger.LogInfo(nameof(Main), "minecraft closed");
|
Logger.LogInfo("Main", "minecraft closed");
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case ConsoleKey.H:
|
case ConsoleKey.F2:
|
||||||
console.WriteLine("help:");
|
tabs.Log = File.ReadAllText(_fileLogger.LogfileName);
|
||||||
console.WriteLine(" Q: How to use this launcher?");
|
RenderTab(tabs.Log, 9999);
|
||||||
console.WriteLine(" A: Set username if it isn't set and launch the game.");
|
break;
|
||||||
console.WriteLine(" Q: How to change game memory and other settings?");
|
case ConsoleKey.F3:
|
||||||
console.WriteLine(" A: Edit the `minecraft-launcher.dtsod` file.");
|
RenderTab(tabs.Settings);
|
||||||
console.WriteLine(" Q: How to disable game files update on launch?");
|
break;
|
||||||
console.WriteLine(" A: Restart the launcher with argument 'offline'.");
|
case ConsoleKey.F4:
|
||||||
console.WriteLine(" Q: What to do if launcher doesn't work?");
|
RenderTab(tabs.Exit);
|
||||||
console.WriteLine(" A: Send latest log file from `launcher-logs/` to Timerix.");
|
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;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Logger.LogError(nameof(Main), ex);
|
Logger.LogError("Main", ex);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
console.StopUpdating();
|
Logger.LogError("Main", ex);
|
||||||
Logger.LogError(nameof(Main), ex);
|
|
||||||
ColoredConsole.Write("gray", "press any key to close...");
|
ColoredConsole.Write("gray", "press any key to close...");
|
||||||
Console.ReadKey();
|
Console.ReadKey();
|
||||||
}
|
}
|
||||||
|
Console.CursorVisible = true;
|
||||||
Console.ResetColor();
|
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
|
//minecraft player uuid explanation
|
||||||
//https://gist.github.com/CatDany/0e71ca7cd9b42a254e49/
|
//https://gist.github.com/CatDany/0e71ca7cd9b42a254e49/
|
||||||
//java uuid generation in c#
|
//java uuid generation in c#
|
||||||
|
|||||||
@ -8,10 +8,10 @@ public class LauncherConfig
|
|||||||
public static IOPath ConfigFilePath = "minecraft-launcher.dtsod";
|
public static IOPath ConfigFilePath = "minecraft-launcher.dtsod";
|
||||||
|
|
||||||
public int GameMemory = 3000;
|
public int GameMemory = 3000;
|
||||||
public int GameWindowHeight = 600;
|
public int GameWindowHeight = 500;
|
||||||
public int GameWindowWidth = 900;
|
public int GameWindowWidth = 900;
|
||||||
public IOPath JavaPath = "jre/bin/javaw.exe";
|
public IOPath JavaPath = "jre/bin/java.exe";
|
||||||
public string ServerAddress = "185.117.155.226";
|
public string ServerAddress = "127.0.0.1";
|
||||||
public int ServerPort = 25000;
|
public int ServerPort = 25000;
|
||||||
public string Username = "";
|
public string Username = "";
|
||||||
|
|
||||||
|
|||||||
91
minecraft-launcher-client/Network.cs
Normal file
91
minecraft-launcher-client/Network.cs
Normal file
@ -0,0 +1,91 @@
|
|||||||
|
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 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();
|
||||||
|
var manifest = new DtsodV23(manifestContent);
|
||||||
|
var hasher = new Hasher();
|
||||||
|
foreach (var fileOnServerData in manifest)
|
||||||
|
{
|
||||||
|
IOPath fileOnClient = Path.Concat(dirOnClient, fileOnServerData.Key);
|
||||||
|
if (!File.Exists(fileOnClient) || (overwrite && hasher.HashFile(fileOnClient).HashToString() != 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('\\','/')))
|
||||||
|
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");
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,160 +0,0 @@
|
|||||||
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(28), 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");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
29
minecraft-launcher-client/gui/exit.gui
Normal file
29
minecraft-launcher-client/gui/exit.gui
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
┏━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┓
|
||||||
|
┃ [F1] login ┃ [F2] log ┃ [F3] settings ┃ [F4] EXIT ┃ [F5] refresh ┃
|
||||||
|
┣━━━━━━━━━━━━━━┻━━━━━━━━━━━━━━┻━━━━━━━━━━━━━━━━┻━━━━━━━━━━━━━━┻━━━━━━━━━━━━━━━┫
|
||||||
|
┃ ┃
|
||||||
|
┃ ┃
|
||||||
|
┃ ┃
|
||||||
|
┃ ┃
|
||||||
|
┃ ┃
|
||||||
|
┃ ┃
|
||||||
|
┃ ┃
|
||||||
|
┃ ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ ┃
|
||||||
|
┃ ┃ ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ ┃ ┃
|
||||||
|
┃ ┃ ┃ ┃ ┃ ┃
|
||||||
|
┃ ┃ ┃ press [ENTER] to exit ┃ ┃ ┃
|
||||||
|
┃ ┃ ┃ ┃ ┃ ┃
|
||||||
|
┃ ┃ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ┃ ┃
|
||||||
|
┃ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ┃
|
||||||
|
┃ ┃
|
||||||
|
┃ ┃
|
||||||
|
┃ ┃
|
||||||
|
┃ ┃
|
||||||
|
┃ ┃
|
||||||
|
┃ ┃
|
||||||
|
┃ ┃
|
||||||
|
┃ ┃
|
||||||
|
┃ ┃
|
||||||
|
┃ ┃
|
||||||
|
┃ ┃
|
||||||
|
┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
|
||||||
29
minecraft-launcher-client/gui/login.gui
Normal file
29
minecraft-launcher-client/gui/login.gui
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
┏━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┓
|
||||||
|
┃ [F1] LOGIN ┃ [F2] log ┃ [F3] settings ┃ [F4] exit ┃ [F5] refresh ┃
|
||||||
|
┣━━━━━━━━━━━━━━┻━━━━━━━━━━━━━━┻━━━━━━━━━━━━━━━━┻━━━━━━━━━━━━━━┻━━━━━━━━━━━━━━━┫
|
||||||
|
┃ ┃
|
||||||
|
┃ ┃
|
||||||
|
┃ ┃
|
||||||
|
┃ ┃
|
||||||
|
┃ ┃
|
||||||
|
┃ ┃
|
||||||
|
┃ ┌──────────────────┐ ┃
|
||||||
|
┃ [N] nickname:│ │ ┃
|
||||||
|
┃ └──────────────────┘ ┃
|
||||||
|
┃ ┃
|
||||||
|
┃ ┏━━━━━━━━━━━━━━━━┓ ┃
|
||||||
|
┃ ┃ [L] login ┃ ┃
|
||||||
|
┃ ┗━━━━━━━━━━━━━━━━┛ ┃
|
||||||
|
┃ ┃
|
||||||
|
┃ ┃
|
||||||
|
┃ ┃
|
||||||
|
┃ ┃
|
||||||
|
┃ ┃
|
||||||
|
┃ ┃
|
||||||
|
┃ ┃
|
||||||
|
┃ ┃
|
||||||
|
┃ ┃
|
||||||
|
┃ ┃
|
||||||
|
┃ ┃
|
||||||
|
┃ ┃
|
||||||
|
┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
|
||||||
29
minecraft-launcher-client/gui/settings.gui
Normal file
29
minecraft-launcher-client/gui/settings.gui
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
┏━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┓
|
||||||
|
┃ [F1] login ┃ [F2] log ┃ [F3] SETTINGS ┃ [F4] exit ┃ [F5] refresh ┃
|
||||||
|
┣━━━━━━━━━━━━━━┻━━━━━━━━━━━━━━┻━━━━━━━━━━━━━━━━┻━━━━━━━━━━━━━━┻━━━━━━━━━━━━━━━┫
|
||||||
|
┃ ┃
|
||||||
|
┃ ┃
|
||||||
|
┃ ┃
|
||||||
|
┃ ┃
|
||||||
|
┃ я ещё не добавил настройки ┃
|
||||||
|
┃ ┃
|
||||||
|
┃ приходите позже ┃
|
||||||
|
┃ ┃
|
||||||
|
┃ ┃
|
||||||
|
┃ ┃
|
||||||
|
┃ ■ ■ ■ ■ ┃
|
||||||
|
┃ ■ ■ ■ ■ ┃
|
||||||
|
┃ ■ ■ ■ ■ ■ ■ ■ ┃
|
||||||
|
┃ ■ ■ ■ ■ ■ ■ ■ ┃
|
||||||
|
┃ ■ ■ ■ ┃
|
||||||
|
┃ ┃
|
||||||
|
┃ ┃
|
||||||
|
┃ ┃
|
||||||
|
┃ ┃
|
||||||
|
┃ ┃
|
||||||
|
┃ ┃
|
||||||
|
┃ ┃
|
||||||
|
┃ ┃
|
||||||
|
┃ ┃
|
||||||
|
┃ ┃
|
||||||
|
┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
|
||||||
0
minecraft-launcher-client/gui/test_label.colormap
Normal file
0
minecraft-launcher-client/gui/test_label.colormap
Normal file
3
minecraft-launcher-client/gui/test_label.textmap
Normal file
3
minecraft-launcher-client/gui/test_label.textmap
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
┏━━━━━━━━━┓
|
||||||
|
┃ ejejeje ┃
|
||||||
|
┗━━━━━━━━━┛
|
||||||
16
minecraft-launcher-client/gui/window.dtsod
Normal file
16
minecraft-launcher-client/gui/window.dtsod
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
window:
|
||||||
|
{
|
||||||
|
type: "container";
|
||||||
|
anchor: [0us, 0us];
|
||||||
|
width: 90us;
|
||||||
|
height: 30us;
|
||||||
|
children:
|
||||||
|
{
|
||||||
|
test_label:
|
||||||
|
{
|
||||||
|
type: "label";
|
||||||
|
anchor: [0us, 0us];
|
||||||
|
resdir: "gui";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
@ -11,22 +11,20 @@
|
|||||||
<ApplicationIcon>launcher.ico</ApplicationIcon>
|
<ApplicationIcon>launcher.ico</ApplicationIcon>
|
||||||
<DebugType>embedded</DebugType>
|
<DebugType>embedded</DebugType>
|
||||||
<InvariantGlobalization>true</InvariantGlobalization>
|
<InvariantGlobalization>true</InvariantGlobalization>
|
||||||
<GenerateSupportedRuntime>false</GenerateSupportedRuntime>
|
<GenerateSupportedRuntime>False</GenerateSupportedRuntime>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<None Remove="gui\exit.gui" />
|
||||||
|
<EmbeddedResource Include="gui\**" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Costura.Fody" Version="5.7.0">
|
<PackageReference Include="Costura.Fody" Version="5.7.0">
|
||||||
<PrivateAssets>all</PrivateAssets>
|
<PrivateAssets>all</PrivateAssets>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
<PackageReference Include="DTLib.Dtsod" Version="1.3.4" />
|
<PackageReference Include="DTLib.Dtsod" Version="1.3.1" />
|
||||||
<PackageReference Include="DTLib.Logging" Version="1.3.5" />
|
<PackageReference Include="DTLib.Logging" Version="1.3.1" />
|
||||||
<PackageReference Include="DTLib.Network" Version="1.4.2" />
|
<PackageReference Include="DTLib.Network" Version="1.3.3" />
|
||||||
<PackageReference Include="DTLib.XXHash" Version="1.0.0" />
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<None Update="launcher_version.txt">
|
|
||||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
|
||||||
</None>
|
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
||||||
@ -1 +0,0 @@
|
|||||||
2.0.0
|
|
||||||
@ -1,3 +1,2 @@
|
|||||||
set /p version=<launcher_version.txt
|
dotnet publish -c Release -o bin\publish
|
||||||
dotnet publish -c Release -o bin\publish -p:Version=%version%
|
|
||||||
del /f bin\publish\minecraft-launcher.exe.config
|
del /f bin\publish\minecraft-launcher.exe.config
|
||||||
|
|||||||
@ -1,5 +1,8 @@
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using DTLib.XXHash;
|
using System.Text;
|
||||||
|
using DTLib;
|
||||||
|
using DTLib.Extensions;
|
||||||
|
using DTLib.Filesystem;
|
||||||
using static launcher_server.Server;
|
using static launcher_server.Server;
|
||||||
|
|
||||||
namespace launcher_server;
|
namespace launcher_server;
|
||||||
@ -17,6 +20,7 @@ public static class Manifests
|
|||||||
}
|
}
|
||||||
|
|
||||||
StringBuilder manifestBuilder = new();
|
StringBuilder manifestBuilder = new();
|
||||||
|
Hasher hasher = new();
|
||||||
var manifestPath = Path.Concat(dir, "manifest.dtsod");
|
var manifestPath = Path.Concat(dir, "manifest.dtsod");
|
||||||
if (Directory.GetFiles(dir).Contains(manifestPath))
|
if (Directory.GetFiles(dir).Contains(manifestPath))
|
||||||
File.Delete(manifestPath);
|
File.Delete(manifestPath);
|
||||||
@ -25,11 +29,8 @@ public static class Manifests
|
|||||||
var fileRelative = fileInDir.RemoveBase(dir);
|
var fileRelative = fileInDir.RemoveBase(dir);
|
||||||
manifestBuilder.Append(fileRelative);
|
manifestBuilder.Append(fileRelative);
|
||||||
manifestBuilder.Append(": \"");
|
manifestBuilder.Append(": \"");
|
||||||
var fileStream = File.OpenRead(fileInDir);
|
byte[] hash = hasher.HashFile(Path.Concat(fileInDir));
|
||||||
ulong hash = xxHash64.ComputeHash(fileStream);
|
manifestBuilder.Append(hash.HashToString());
|
||||||
fileStream.Close();
|
|
||||||
string hashStr = BitConverter.GetBytes(hash).HashToString();
|
|
||||||
manifestBuilder.Append(hashStr);
|
|
||||||
manifestBuilder.Append("\";\n");
|
manifestBuilder.Append("\";\n");
|
||||||
}
|
}
|
||||||
File.WriteAllText(manifestPath, manifestBuilder.ToString().Replace('\\','/'));
|
File.WriteAllText(manifestPath, manifestBuilder.ToString().Replace('\\','/'));
|
||||||
@ -58,7 +59,7 @@ public static class Manifests
|
|||||||
}
|
}
|
||||||
dirlist_content_builder
|
dirlist_content_builder
|
||||||
.Append("\t\"")
|
.Append("\t\"")
|
||||||
.Append(dirs[^1].RemoveBase(sync_and_remove_dir).Str.Replace('\\','/'))
|
.Append(dirs[dirs.Length-1].RemoveBase(sync_and_remove_dir).Str.Replace('\\','/'))
|
||||||
.Append("\"\n");
|
.Append("\"\n");
|
||||||
|
|
||||||
dirlist_content_builder.Append("];");
|
dirlist_content_builder.Append("];");
|
||||||
|
|||||||
@ -10,24 +10,25 @@ global using DTLib.Extensions;
|
|||||||
global using DTLib.Filesystem;
|
global using DTLib.Filesystem;
|
||||||
global using DTLib.Logging;
|
global using DTLib.Logging;
|
||||||
global using DTLib.Network;
|
global using DTLib.Network;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using DTLib.Ben.Demystifier;
|
||||||
using Timer = DTLib.Timer;
|
using Timer = DTLib.Timer;
|
||||||
|
|
||||||
namespace launcher_server;
|
namespace launcher_server;
|
||||||
|
|
||||||
static class Server
|
static class Server
|
||||||
{
|
{
|
||||||
public static ILogger Logger = new CompositeLogger(
|
private static ILogger logger = new CompositeLogger(
|
||||||
new FileLogger("logs","launcher-server"),
|
new FileLogger("logs","launcher-server"),
|
||||||
new ConsoleLogger());
|
new ConsoleLogger());
|
||||||
|
static readonly Socket mainSocket = new(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
|
||||||
static ServerConfig Config = null!;
|
static ServerConfig Config = null!;
|
||||||
public static readonly IOPath shared_dir = "public";
|
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)
|
static void Main(string[] args)
|
||||||
{
|
{
|
||||||
var mainSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
|
Timer? updateCheckTimer = null;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
Console.Title = "minecraft_launcher_server";
|
Console.Title = "minecraft_launcher_server";
|
||||||
@ -35,26 +36,22 @@ static class Server
|
|||||||
Console.OutputEncoding = Encoding.Unicode;
|
Console.OutputEncoding = Encoding.Unicode;
|
||||||
|
|
||||||
Config = ServerConfig.LoadOrCreateDefault();
|
Config = ServerConfig.LoadOrCreateDefault();
|
||||||
LatestLauncherVersion = File.ReadAllText(LatestLauncherVersionFile);
|
|
||||||
|
|
||||||
Updates.Check();
|
CheckUpdates();
|
||||||
Logger.LogInfo(nameof(Main), "creating manifests...");
|
|
||||||
Manifests.CreateAllManifests();
|
|
||||||
Logger.LogInfo(nameof(Main), "manifests created");
|
|
||||||
// check for updates every minute
|
// check for updates every minute
|
||||||
var updateCheckTimer = new Timer(true, 60 * 1000, Updates.Check);
|
updateCheckTimer = new Timer(true, 60 * 1000, CheckUpdates);
|
||||||
updateCheckTimer.Start();
|
updateCheckTimer.Start();
|
||||||
|
|
||||||
|
|
||||||
Logger.LogInfo("Main", $"local address: {Config.LocalIp}");
|
logger.LogInfo("Main", $"local address: {Config.LocalIp}");
|
||||||
Logger.LogInfo("Main", $"public address: {Functions.GetPublicIP()}");
|
logger.LogInfo("Main", $"public address: {Functions.GetPublicIP()}");
|
||||||
Logger.LogInfo("Main", $"port: {Config.LocalPort}");
|
logger.LogInfo("Main", $"port: {Config.LocalPort}");
|
||||||
mainSocket.Bind(new IPEndPoint(IPAddress.Parse(Config.LocalIp), Config.LocalPort));
|
mainSocket.Bind(new IPEndPoint(IPAddress.Parse(Config.LocalIp), Config.LocalPort));
|
||||||
mainSocket.Listen(1000);
|
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)
|
while (true)
|
||||||
{
|
{
|
||||||
var userSocket = mainSocket.Accept();
|
var userSocket = mainSocket.Accept();
|
||||||
@ -64,16 +61,58 @@ static class Server
|
|||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Logger.LogError("Main", ex);
|
logger.LogError("Main", ex);
|
||||||
mainSocket.Close();
|
mainSocket.Close();
|
||||||
}
|
}
|
||||||
Console.ResetColor();
|
Console.ResetColor();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void CheckUpdates()
|
||||||
|
{
|
||||||
|
logger.LogInfo(nameof(CheckUpdates), "checking for updates...");
|
||||||
|
IOPath updatesDir = "updates";
|
||||||
|
Directory.Create(updatesDir);
|
||||||
|
var updatedFiles = Directory.GetAllFiles(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.LogInfo(nameof(CheckUpdates), "update check completed");
|
||||||
|
}
|
||||||
|
|
||||||
// запускается для каждого юзера в отдельном потоке
|
// запускается для каждого юзера в отдельном потоке
|
||||||
static void HandleUser(Socket handlerSocket)
|
static void HandleUser(Socket handlerSocket)
|
||||||
{
|
{
|
||||||
Logger.LogInfo(nameof(HandleUser), "user connecting... ");
|
logger.LogInfo(nameof(HandleUser), "user connecting... ");
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
// тут запрос пароля заменён запросом заглушки
|
// тут запрос пароля заменён запросом заглушки
|
||||||
@ -84,7 +123,7 @@ static class Server
|
|||||||
// запрос от апдейтера
|
// запрос от апдейтера
|
||||||
if (connectionString == "minecraft-launcher")
|
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");
|
handlerSocket.SendPackage("minecraft-launcher OK");
|
||||||
// обработка запросов
|
// обработка запросов
|
||||||
while (true)
|
while (true)
|
||||||
@ -94,17 +133,14 @@ static class Server
|
|||||||
string request = handlerSocket.GetPackage().BytesToString();
|
string request = handlerSocket.GetPackage().BytesToString();
|
||||||
switch (request)
|
switch (request)
|
||||||
{
|
{
|
||||||
case "requesting latest launcher version":
|
|
||||||
handlerSocket.SendPackage("latest launcher version is "+LatestLauncherVersion);
|
|
||||||
break;
|
|
||||||
case "requesting launcher update":
|
case "requesting launcher update":
|
||||||
Logger.LogInfo(nameof(HandleUser), "updater requested launcher update");
|
logger.LogInfo(nameof(HandleUser), "updater requested launcher update");
|
||||||
// ReSharper disable once InconsistentlySynchronizedField
|
// ReSharper disable once InconsistentlySynchronizedField
|
||||||
fsp.UploadFile(Path.Concat(shared_dir, "minecraft-launcher.exe"));
|
fsp.UploadFile(Path.Concat(shared_dir, "minecraft-launcher.exe"));
|
||||||
break;
|
break;
|
||||||
case "requesting file download":
|
case "requesting file download":
|
||||||
var filePath = handlerSocket.GetPackage().BytesToString();
|
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"))
|
if(filePath.EndsWith("manifest.dtsod"))
|
||||||
lock (Manifests.manifestLocker)
|
lock (Manifests.manifestLocker)
|
||||||
{
|
{
|
||||||
@ -122,18 +158,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");
|
handlerSocket.SendPackage("invalid connection string");
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Logger.LogWarn(nameof(HandleUser), ex);
|
logger.LogWarn(nameof(HandleUser), ex);
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
if (handlerSocket.Connected) handlerSocket.Shutdown(SocketShutdown.Both);
|
if (handlerSocket.Connected) handlerSocket.Shutdown(SocketShutdown.Both);
|
||||||
handlerSocket.Close();
|
handlerSocket.Close();
|
||||||
Logger.LogInfo(nameof(HandleUser), "user disconnected");
|
logger.LogInfo(nameof(HandleUser), "user disconnected");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,71 +0,0 @@
|
|||||||
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 updatedFilePath in updatedFiles)
|
|
||||||
{
|
|
||||||
var relativeFilePath = updatedFilePath.RemoveBase(updatesDir);
|
|
||||||
if(relativeFilePath.Str is "minecraft-launcher-server" or "minecraft-launcher-server.exe")
|
|
||||||
SelfUpdate(updatedFilePath, relativeFilePath);
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (var updatedFilePath in updatedFiles)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var relativeFilePath = updatedFilePath.RemoveBase(updatesDir);
|
|
||||||
if (relativeFilePath == Path.Concat(Server.shared_dir, "launcher_version.txt"))
|
|
||||||
UpdateLauncherVersion(updatedFilePath);
|
|
||||||
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");
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void UpdateLauncherVersion(IOPath updatedFilePath)
|
|
||||||
{
|
|
||||||
Server.LatestLauncherVersion = File.ReadAllText(updatedFilePath);
|
|
||||||
Server.Logger.LogInfo(nameof(Check), "new launcher version: " + Server.LatestLauncherVersion);
|
|
||||||
File.Move(updatedFilePath, Server.LatestLauncherVersionFile, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void SelfUpdate(IOPath updatedFile, IOPath exeFile)
|
|
||||||
{
|
|
||||||
Server.Logger.LogWarn(nameof(SelfUpdate), "program update found, restarting...");
|
|
||||||
IOPath exeFileNew = exeFile + "_new";
|
|
||||||
File.Move(updatedFile, 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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -12,9 +12,8 @@
|
|||||||
<InvariantGlobalization>true</InvariantGlobalization>
|
<InvariantGlobalization>true</InvariantGlobalization>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="DTLib.Dtsod" Version="1.3.4" />
|
<PackageReference Include="DTLib.Dtsod" Version="1.3.1" />
|
||||||
<PackageReference Include="DTLib.Logging" Version="1.3.4" />
|
<PackageReference Include="DTLib.Logging" Version="1.3.1" />
|
||||||
<PackageReference Include="DTLib.Network" Version="1.4.2" />
|
<PackageReference Include="DTLib.Network" Version="1.3.3" />
|
||||||
<PackageReference Include="DTLib.XXHash" Version="1.0.0" />
|
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
||||||
@ -1,4 +1,3 @@
|
|||||||
#!/bin/bash
|
|
||||||
dotnet publish -c release -o bin/publish \
|
dotnet publish -c release -o bin/publish \
|
||||||
--self-contained \
|
--self-contained \
|
||||||
--use-current-runtime \
|
--use-current-runtime \
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user