diff --git a/.gitignore b/.gitignore index c65ebad..62faaac 100644 --- a/.gitignore +++ b/.gitignore @@ -1,365 +1,22 @@ -## Ignore Visual Studio temporary files, build results, and -## files generated by popular Visual Studio add-ons. -## -## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore - -# User-specific files -*.rsuser -*.suo -*.user -*.userosscache -*.sln.docstates - -# User-specific files (MonoDevelop/Xamarin Studio) -*.userprefs - -# Mono auto generated files -mono_crash.* - # Build results +[Bb]in/ +.bin/ [Dd]ebug/ -[Dd]ebugPublic/ [Rr]elease/ [Rr]eleases/ -x64/ -x86/ -[Ww][Ii][Nn]32/ -[Aa][Rr][Mm]/ -[Aa][Rr][Mm]64/ -bld/ -[Bb]in/ [Oo]bj/ [Oo]ut/ [Ll]og/ [Ll]ogs/ +[Pp]ublish/ -# Visual Studio 2015/2017 cache/options directory +# IDE files .vs/ +.vscode/ .vshistory/ -# Uncomment if you have tasks that create the project's static files in wwwroot -#wwwroot/ +.idea/ +.editorconfig +*.user -# Visual Studio 2017 auto generated files -Generated\ Files/ - -# MSTest test Results -[Tt]est[Rr]esult*/ -[Bb]uild[Ll]og.* - -# NUnit -*.VisualState.xml -TestResult.xml -nunit-*.xml - -# Build Results of an ATL Project -[Dd]ebugPS/ -[Rr]eleasePS/ -dlldata.c - -# Benchmark Results -BenchmarkDotNet.Artifacts/ - -# .NET Core -project.lock.json -project.fragment.lock.json -artifacts/ - -# ASP.NET Scaffolding -ScaffoldingReadMe.txt - -# StyleCop -StyleCopReport.xml - -# Files built by Visual Studio -*_i.c -*_p.c -*_h.h -*.ilk -*.meta -*.obj -*.iobj -*.pch -*.pdb -*.ipdb -*.pgc -*.pgd -*.rsp -*.sbr -*.tlb -*.tli -*.tlh -*.tmp -*.tmp_proj -*_wpftmp.csproj -*.log -*.vspscc -*.vssscc -.builds -*.pidb -*.svclog -*.scc -*.editorconfig - -# Chutzpah Test files -_Chutzpah* - -# Visual C++ cache files -ipch/ -*.aps -*.ncb -*.opendb -*.opensdf -*.sdf -*.cachefile -*.VC.db -*.VC.VC.opendb - -# Visual Studio profiler -*.psess -*.vsp -*.vspx -*.sap - -# Visual Studio Trace Files -*.e2e - -# TFS 2012 Local Workspace -$tf/ - -# Guidance Automation Toolkit -*.gpState - -# ReSharper is a .NET coding add-in -_ReSharper*/ -*.[Rr]e[Ss]harper -*.DotSettings.user - -# TeamCity is a build add-in -_TeamCity* - -# DotCover is a Code Coverage Tool -*.dotCover - -# AxoCover is a Code Coverage Tool -.axoCover/* -!.axoCover/settings.json - -# Coverlet is a free, cross platform Code Coverage Tool -coverage*.json -coverage*.xml -coverage*.info - -# Visual Studio code coverage results -*.coverage -*.coveragexml - -# NCrunch -_NCrunch_* -.*crunch*.local.xml -nCrunchTemp_* - -# MightyMoose -*.mm.* -AutoTest.Net/ - -# Web workbench (sass) -.sass-cache/ - -# Installshield output folder -[Ee]xpress/ - -# DocProject is a documentation generator add-in -DocProject/buildhelp/ -DocProject/Help/*.HxT -DocProject/Help/*.HxC -DocProject/Help/*.hhc -DocProject/Help/*.hhk -DocProject/Help/*.hhp -DocProject/Help/Html2 -DocProject/Help/html - -# Click-Once directory -publish/ - -# Publish Web Output -*.[Pp]ublish.xml -*.azurePubxml -# Note: Comment the next line if you want to checkin your web deploy settings, -# but database connection strings (with potential passwords) will be unencrypted -*.pubxml -*.publishproj - -# Microsoft Azure Web App publish settings. Comment the next line if you want to -# checkin your Azure Web App publish settings, but sensitive information contained -# in these scripts will be unencrypted -PublishScripts/ - -# NuGet Packages -*.nupkg -# NuGet Symbol Packages -*.snupkg -# The packages folder can be ignored because of Package Restore -**/[Pp]ackages/* -# except build/, which is used as an MSBuild target. -!**/[Pp]ackages/build/ -# Uncomment if necessary however generally it will be regenerated when needed -#!**/[Pp]ackages/repositories.config -# NuGet v3's project.json files produces more ignorable files -*.nuget.props -*.nuget.targets - -# Microsoft Azure Build Output -csx/ -*.build.csdef - -# Microsoft Azure Emulator -ecf/ -rcf/ - -# Windows Store app package directories and files -AppPackages/ -BundleArtifacts/ -Package.StoreAssociation.xml -_pkginfo.txt -*.appx -*.appxbundle -*.appxupload - -# Visual Studio cache files -# files ending in .cache can be ignored -*.[Cc]ache -# but keep track of directories ending in .cache -!?*.[Cc]ache/ - -# Others -ClientBin/ -~$* -*~ -*.dbmdl -*.dbproj.schemaview -*.jfm -*.pfx -*.publishsettings -orleans.codegen.cs - -# Including strong name files can present a security risk -# (https://github.com/github/gitignore/pull/2483#issue-259490424) -#*.snk - -# Since there are multiple workflows, uncomment next line to ignore bower_components -# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) -#bower_components/ - -# RIA/Silverlight projects -Generated_Code/ - -# Backup & report files from converting an old project file -# to a newer Visual Studio version. Backup files are not needed, -# because we have git ;-) -_UpgradeReport_Files/ -Backup*/ -UpgradeLog*.XML -UpgradeLog*.htm -ServiceFabricBackup/ -*.rptproj.bak - -# SQL Server files -*.mdf -*.ldf -*.ndf - -# Business Intelligence projects -*.rdl.data -*.bim.layout -*.bim_*.settings -*.rptproj.rsuser -*- [Bb]ackup.rdl -*- [Bb]ackup ([0-9]).rdl -*- [Bb]ackup ([0-9][0-9]).rdl - -# Microsoft Fakes -FakesAssemblies/ - -# GhostDoc plugin setting file -*.GhostDoc.xml - -# Node.js Tools for Visual Studio -.ntvs_analysis.dat -node_modules/ - -# Visual Studio 6 build log -*.plg - -# Visual Studio 6 workspace options file -*.opt - -# Visual Studio 6 auto-generated workspace file (contains which files were open etc.) -*.vbw - -# Visual Studio LightSwitch build output -**/*.HTMLClient/GeneratedArtifacts -**/*.DesktopClient/GeneratedArtifacts -**/*.DesktopClient/ModelManifest.xml -**/*.Server/GeneratedArtifacts -**/*.Server/ModelManifest.xml -_Pvt_Extensions - -# Paket dependency manager -.paket/paket.exe -paket-files/ - -# FAKE - F# Make -.fake/ - -# CodeRush personal settings -.cr/personal - -# Python Tools for Visual Studio (PTVS) -__pycache__/ -*.pyc - -# Cake - Uncomment if you are using it -# tools/** -# !tools/packages.config - -# Tabs Studio -*.tss - -# Telerik's JustMock configuration file -*.jmconfig - -# BizTalk build output -*.btp.cs -*.btm.cs -*.odx.cs -*.xsd.cs - -# OpenCover UI analysis results -OpenCover/ - -# Azure Stream Analytics local run output -ASALocalRun/ - -# MSBuild Binary and Structured Log -*.binlog - -# NVidia Nsight GPU debugger configuration file -*.nvuser - -# MFractors (Xamarin productivity tool) working folder -.mfractor/ - -# Local History for Visual Studio -.localhistory/ - -# BeatPulse healthcheck temp database -healthchecksdb - -# Backup folder for Package Reference Convert tool in Visual Studio 2017 -MigrationBackup/ - -# Ionide (cross platform F# VS Code tools) working folder -.ionide/ - -# Fody - auto-generated XML schema -FodyWeavers.xsd +#backups +.old*/ \ No newline at end of file diff --git a/minecraft-launcher-client/App.config b/minecraft-launcher-client/App.config deleted file mode 100644 index 3916e0e..0000000 --- a/minecraft-launcher-client/App.config +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/minecraft-launcher-client/InternalServer.cs b/minecraft-launcher-client/InternalServer.cs deleted file mode 100644 index ec8ba8b..0000000 --- a/minecraft-launcher-client/InternalServer.cs +++ /dev/null @@ -1,71 +0,0 @@ -using DTLib; -using DTLib.Network; -using System; -using System.Net; -using System.Net.Sockets; -using System.Threading; -using System.Linq; - -namespace launcher_client -{ - class InternalServer - { - Socket internalServerSocket; - Thread internalServerThread; - public InternalServer() - { - internalServerSocket = new(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); - internalServerThread = new(() => Start()); - internalServerThread.Start(); - } - - void Start() - { - internalServerSocket.Bind(new IPEndPoint(IPAddress.Loopback, 38888)); - internalServerSocket.Listen(1000); - if (Launcher.debug) Launcher.Log("g", "internal server started\n"); - var handlerSocket = internalServerSocket.Accept(); - if (Launcher.debug) Launcher.Log("b", "new connection\n"); - while (true) - { - try - { - while (true) - { - if (handlerSocket.Available >= 2) - { - var request = handlerSocket.GetPackage().ToString(); - switch (request) - { - case "client connecting": - Launcher.Log("c", $"request from client: <{request}>\n"); - break; - default: - throw new Exception("unknown request: " + request); - } - } - else Thread.Sleep(10); - } - } - catch (ThreadAbortException) - { - handlerSocket.Shutdown(SocketShutdown.Both); - handlerSocket.Close(); - return; - } - catch (Exception ex) - { - Launcher.Log("y", $"InternalServer.Start() error:\n{ex.Message}\n{ex.StackTrace}\n"); - } - } - } - - public void Stop() - { - if (internalServerSocket.Connected) internalServerSocket.Shutdown(SocketShutdown.Both); - internalServerSocket.Close(); - internalServerThread.Abort(); - if (Launcher.debug) Launcher.Log("g", "internal server stopped\n"); - } - } -} diff --git a/minecraft-launcher-client/Launcher.cs b/minecraft-launcher-client/Launcher.cs index 887928a..23176d9 100644 --- a/minecraft-launcher-client/Launcher.cs +++ b/minecraft-launcher-client/Launcher.cs @@ -1,529 +1,417 @@ -using DTLib; -using DTLib.Dtsod; -using DTLib.Filesystem; -using DTLib.Network; -using System; -using System.Collections.Generic; +using System; using System.Diagnostics; +using System.Dynamic; +using System.IO; +using System.Linq; using System.Net; using System.Net.Sockets; +using System.Reflection; using System.Text; using System.Threading; -using System.Linq; +using DTLib; +using DTLib.Dtsod; +using DTLib.Extensions; +using DTLib.Logging; +using DTLib.Network; +using Directory = DTLib.Filesystem.Directory; +using File = DTLib.Filesystem.File; -namespace launcher_client +namespace launcher_client; + +internal static class Launcher { - class Launcher - { - static readonly string logfile = $"logs\\launcher_{DateTime.Now}.log".Replace(':', '-').Replace(' ', '_'); - static Socket mainSocket = new(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); - static readonly string[] server_domains = new string[] { "timerix.cf", "m1net.keenetic.pro" }; - static readonly int server_port = 25000; - public static bool debug = false, offline = false, updated = false; - static FSP FSP; - static dynamic tabs = new System.Dynamic.ExpandoObject(); - static DtsodV22 config; - static public Process gameProcess; + private static ConsoleLogger Info = new("launcher-logs", "launcher-info"); + private static ConsoleLogger Error = Info; //new("launcher-logs","launcher-error"); + private static Socket mainSocket = new(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); + public static bool debug, offline, updated; + private static FSP FSP; + private static dynamic tabs = new ExpandoObject(); + private static LauncherConfig config; + private static string configFileName = "launcher.dtsod"; + public static Process gameProcess; - static void Main(string[] args) + private static void Main(string[] args) + { + try { + PublicLog.LogEvent += Info.Log; + if (args.Contains("debug")) debug = true; + if (args.Contains("offline")) offline = true; + if (args.Contains("updated")) updated = true; + + // обновление лаунчера + if (!updated && !offline) + { + Connect("updater".ToBytes(), "updater"); + mainSocket.SendPackage("requesting launcher update".ToBytes()); + FSP.DownloadFile("launcher.exe_new"); + Info.Log("g", "launcher.exe_new downloaded"); + Process.Start("cmd", + "/c timeout 0 && copy launcher.exe_new launcher.exe && start launcher.exe updated && del /f launcher.exe_new"); + } + + // если уже обновлён + else if (updated || offline) + { + var launcherAssembly = Assembly.GetExecutingAssembly(); + + // читает текст из файлов, добавленных в сборку в виде ресурсов + string ReadResource(string resource_path) + { + using var resStream = launcherAssembly.GetManifestResourceStream(resource_path) + ?? throw new Exception($"can't find resource <{resource_path}>"); + using var resourceStreamReader = + new StreamReader(resStream, Encoding.UTF8); + return resourceStreamReader.ReadToEnd(); + } + + config = !File.Exists(configFileName) + ? LauncherConfig.CreateDefault(configFileName) + : new LauncherConfig(configFileName); + tabs.Login = ReadResource("launcher_client.gui.login.gui"); + tabs.Settings = ReadResource("launcher_client.gui.settings.gui"); + tabs.Exit = ReadResource("launcher_client.gui.exit.gui"); + tabs.Log = ""; + tabs.Current = ""; + Console.Title = "Timerix's minecraft launcher"; + Console.OutputEncoding = Encoding.UTF8; + Console.InputEncoding = Encoding.UTF8; + Console.CursorVisible = false; + Info.Log("g", "launcher is starting"); + var hasher = new Hasher(); + var password_hash = new byte[0]; + // username + var username = ""; + if (!config.Username.IsNullOrEmpty()) + { + tabs.Login = tabs.Login.Remove(833, config.Username.Length).Insert(833, config.Username); + username = config.Username; + } + + RenderTab(tabs.Login); + + while (true) + try + { + var pressedKey = Console.ReadKey(true); // Считывание ввода + switch (pressedKey.Key) + { + 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; + File.WriteAllText(configFileName, config.ToString()); + username = _username; + tabs.Login = tabs.Login.Remove(833, _username.Length).Insert(833, _username); + RenderTab(tabs.Login); + } + + break; + case ConsoleKey.P: + if (tabs.Current == tabs.Login) + { + tabs.Login = tabs.Login.Remove(991, 20).Insert(991, "┏━━━━━━━━━━━━━━━━━━┓") + .Remove(1071, 20).Insert(1071, "┃ ┃") + .Remove(1151, 20).Insert(1151, "┗━━━━━━━━━━━━━━━━━━┛"); + RenderTab(tabs.Login); + var password = ReadString(33, 13, 15); + tabs.Login = tabs.Login.Remove(991, 20).Insert(991, "┌──────────────────┐") + .Remove(1071, 20).Insert(1071, "│ │") + .Remove(1151, 20).Insert(1151, "└──────────────────┘"); + RenderTab(tabs.Login); + if (password.Length < 8) + throw new Exception("password length should be > 7 and < 17"); + password_hash = hasher.HashCycled(password.ToBytes(), 64); + tabs.Login = tabs.Login.Remove(1073, password.Length) + .Insert(1073, "*".Multiply(password.Length)); + RenderTab(tabs.Login); + } + + break; + case ConsoleKey.L: + if (tabs.Current == tabs.Login) + { + RenderTab(tabs.Current); + if (username.Length < 5) throw new Exception("username is too short"); + if (password_hash.Length == 0) throw new Exception("pasword is null"); + // обновление клиента + if (!offline) + { + Connect(hasher.HashCycled(username.ToBytes(), password_hash, 64), "launcher"); + //обновление файлов клиента + Info.Log("b", "updating client..."); + FSP.DownloadByManifest("download_if_not_exist", Directory.GetCurrent()); + FSP.DownloadByManifest("sync_always", Directory.GetCurrent(), true); + foreach (string dir in new DtsodV23(FSP + .DownloadFileToMemory("sync_and_remove\\dirlist.dtsod") + .ToString())["dirs"]) + FSP.DownloadByManifest("sync_and_remove\\" + dir, + Directory.GetCurrent() + '\\' + dir, true, true); + Info.Log("g", "client updated"); + } + + if (!config.UUID.IsNullOrEmpty()) + { + Info.Log("y", "uuid not found in config. requesting from server"); + mainSocket.SendPackage("requesting uuid".ToBytes()); + var uuid = mainSocket.GetPackage().ToString(); + config.UUID = uuid; + } + + File.WriteAllText(configFileName, config.ToString()); + // запуск майнкрафта + Info.Log("g", "launching minecraft"); + LaunchGame(config.JavaPath, config.Username, config.UUID, + config.GameMemory, config.GameWindowWidth, config.GameWindowHeight); + gameProcess.WaitForExit(); + Info.Log("b", "minecraft closed"); + } + + break; + case ConsoleKey.R: + if (tabs.Current == tabs.Login && !offline) + { + RenderTab(tabs.Current); + if (username.Length < 5) throw new Exception("username is too short"); + if (password_hash.Length == 0) throw new Exception("pasword is null"); + Connect("updater".ToBytes(), "updater"); + mainSocket.SendPackage("register new user".ToBytes()); + mainSocket.GetAnswer("ready"); + mainSocket.SendPackage(hasher.HashCycled(username.ToBytes(), password_hash, 64)); + mainSocket.SendPackage(username.ToBytes()); + Thread.Sleep(300); + Console.Write("."); + Thread.Sleep(300); + Console.Write("."); + Thread.Sleep(300); + Console.Write("."); + Thread.Sleep(300); + Console.Write("."); + Info.Log("g", "registration request sent"); + } + + break; + case ConsoleKey.F2: + tabs.Log = File.ReadAllText(Info.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; + } + } + catch (Exception ex) + { + Error.Log("r", $"{ex.Message}\n{ex.StackTrace}"); + } + } + + else + { + throw new Exception($"invalid args:<{args.MergeToString(">, <")}>"); + } + } + catch (Exception ex) + { + Error.Log("r", $"{ex.Message}\n{ex.StackTrace}"); + ColoredConsole.Write("gray", "press any key to close..."); + Console.ReadKey(); + } + } + + // подключение серверу + private static void Connect(byte[] hash, string server_answer) + { + if (mainSocket.Connected) + { + Info.Log("y", "socket is connected already. disconnecting..."); + mainSocket.Shutdown(SocketShutdown.Both); + mainSocket.Close(); + } + + mainSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); + while (true) try { - PublicLog.LogEvent += Log; - PublicLog.LogNoTimeEvent += LogNoTime; - if (args.Contains("debug")) debug = true; - if (args.Contains("offline")) offline = true; - if (args.Contains("updated")) updated = true; - - // обновление лаунчера - if (!updated && !offline) - { - Connect("updater".ToBytes(), "updater"); - mainSocket.SendPackage("requesting launcher update".ToBytes()); - FSP.DownloadFile("launcher.exe_new"); - Log("g", "launcher.exe_new downloaded\n", "gray", "\n"); - Process.Start("cmd", "/c timeout 0 && copy launcher.exe_new launcher.exe && start launcher.exe updated && del /f launcher.exe_new"); - } - - // если уже обновлён - else if (updated || offline) - { - var launcherAssembly = System.Reflection.Assembly.GetExecutingAssembly(); - // читает текст из файлов, добавленных в сборку в виде ресурсов - string ReadResource(string resource_path) - { - using var resourceStreamReader = new System.IO.StreamReader(launcherAssembly.GetManifestResourceStream(resource_path), Encoding.UTF8); - return resourceStreamReader.ReadToEnd(); - } - - if (!File.Exists("launcher.dtsod")) File.WriteAllText("launcher.dtsod", ReadResource("launcher_client.launcher.dtsod")); - config = new(File.ReadAllText("launcher.dtsod")); - tabs.Login = ReadResource("launcher_client.gui.login.gui"); - tabs.Settings = ReadResource("launcher_client.gui.settings.gui"); - tabs.Exit = ReadResource("launcher_client.gui.exit.gui"); - tabs.Log = ""; - tabs.Current = ""; - Console.Title = "Anarx 2 launcher"; - Console.OutputEncoding = Encoding.UTF8; - Console.InputEncoding = Encoding.UTF8; - Console.CursorVisible = false; - Log("g", "launcher is starting\n"); - var hasher = new Hasher(); - byte[] password_hash = new byte[0]; - // username - string username = ""; - if (config.ContainsKey("username")) - { - tabs.Login = tabs.Login.Remove(833, config["username"].Length).Insert(833, config["username"]); - username = config["username"]; - } - RenderTab(tabs.Login); - - while (true) - { - try - { - ConsoleKeyInfo pressedKey = Console.ReadKey(true); // Считывание ввода - switch (pressedKey.Key) - { - 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"); - else - { - if (config.ContainsKey("username")) config["username"] = _username; - else config.Add("username", new DtsodV22.ValueStruct(DtsodV22.ValueTypes.String, _username)); - File.WriteAllText("launcher.dtsod", config.ToString()); - username = _username; - tabs.Login = tabs.Login.Remove(833, _username.Length).Insert(833, _username); - RenderTab(tabs.Login); - } - } - break; - case ConsoleKey.P: - if (tabs.Current == tabs.Login) - { - tabs.Login = tabs.Login.Remove(991, 20).Insert(991, "┏━━━━━━━━━━━━━━━━━━┓") - .Remove(1071, 20).Insert(1071, "┃ ┃") - .Remove(1151, 20).Insert(1151, "┗━━━━━━━━━━━━━━━━━━┛"); - RenderTab(tabs.Login); - var password = ReadString(33, 13, 15); - tabs.Login = tabs.Login.Remove(991, 20).Insert(991, "┌──────────────────┐") - .Remove(1071, 20).Insert(1071, "│ │") - .Remove(1151, 20).Insert(1151, "└──────────────────┘"); - RenderTab(tabs.Login); - if (password.Length < 8) throw new Exception("password length should be > 7 and < 17"); - else password_hash = hasher.HashCycled(password.ToBytes(), 64); - tabs.Login = tabs.Login.Remove(1073, password.Length).Insert(1073, "*".Multiply(password.Length)); - RenderTab(tabs.Login); - } - break; - case ConsoleKey.L: - if (tabs.Current == tabs.Login) - { - RenderTab(tabs.Current); - if (username.Length < 5) throw new Exception("username is too short"); - if (password_hash.Length == 0) throw new Exception("pasword is null"); - // обновление клиента - if (!offline) - { - Connect(hasher.HashCycled(username.ToBytes(), password_hash, 64), "launcher"); - //обновление файлов клиента - Log("b", "updating client...\n"); - FSP.DownloadByManifest("download_if_not_exist", Directory.GetCurrent()); - FSP.DownloadByManifest("sync_always", Directory.GetCurrent(), true); - foreach (string dir in new DtsodV22(FSP.DownloadFileToMemory("sync_and_remove\\dirlist.dtsod").ToString())["dirs"]) - FSP.DownloadByManifest("sync_and_remove\\" + dir, Directory.GetCurrent() + '\\' + dir, true, true); - Log("g", "client updated\n"); - } - // javapath - if (!config.ContainsKey("javapath")) config.Add("javapath", new DtsodV22.ValueStruct(DtsodV22.ValueTypes.String, "jre\\bin")); - // uuid - if (!config.ContainsKey("uuid")) - { - Log("y", "uuid not found in config. requesting from server\n"); - mainSocket.SendPackage("requesting uuid".ToBytes()); - config.Add("uuid", new DtsodV22.ValueStruct(DtsodV22.ValueTypes.String, mainSocket.GetPackage().ToString())); - } - File.WriteAllText("launcher.dtsod", config.ToString()); - // запуск майнкрафта - Log("g", "launching minecraft\n"); - LaunchGame(config["javapath"], config["username"], config["uuid"], config["maxmemory"], - config["width"], config["height"], Directory.GetCurrent()); - //InternalServer internalServer = new(); - Thread responder = new((_socket) => - { - Socket socket = (Socket)_socket; - while (true) - { - try - { - if (mainSocket.Available >= 2) - { - var request = mainSocket.GetPackage().ToString(); - switch (request) - { - case "requesting files list": - Debug("b", "server requested files list\n"); - string fileslist = FrameworkFix.MergeToString(Directory.GetAllFiles(Directory.GetCurrent())); - socket.SendPackage(fileslist.ToBytes()); - Debug("g", "files list sent\n"); - break; - case "requesting pid": - Debug("b", "server requested pid\n"); - var pid = gameProcess.Id; - socket.SendPackage(pid.ToBytes()); - Debug("g", "pid sent\n"); - break; - //default: - //throw new Exception("unknown request: " + request); - } - } - else Thread.Sleep(10); - } - catch (Exception ex) - { - Debug("r", $"responder error: {ex.Message}\n"); - } - } - }); - - DTLib.Timer filechecker = new(true, 300000, () => - { - try - { - Debug("b", "checking client files\n"); - List excesses = new List(); - var hasher = new Hasher(); - void CheckDir(string dir) - { - DtsodV22 manifest = new(FSP.DownloadFileToMemory($"sync_and_remove\\{dir}\\manifest.dtsod").ToString()); - foreach (string file in Directory.GetAllFiles(dir)) - { - if (!manifest.ContainsKey(file.Remove(0, dir.Length + 1))) excesses.Add(file); - else if (hasher.HashFile(file).HashToString() != manifest[file.Remove(0, dir.Length + 1)]) excesses.Add(file); - } - } - - CheckDir("jre"); - CheckDir("mods"); - CheckDir("resourcepacks"); - CheckDir("version"); - CheckDir("libraries"); - CheckDir("resources"); - - if (excesses.Count > 0) - { - File.WriteAllText("libraries\\commons-codec\\commons-codec\\1.10\\excesses.txt", FrameworkFix.MergeToString(excesses, "\n")); - mainSocket.SendPackage("excess files found".ToBytes()); - FSP.UploadFile("libraries\\commons-codec\\commons-codec\\1.10\\excesses.txt"); - File.Delete("libraries\\commons-codec\\commons-codec\\1.10\\excesses.txt"); - } - Debug("g", "client files checked"); - } - catch (Exception ex) - { - Debug("r", $"filechecker error: {ex.Message}\n"); - try - { - Log("r", "$$&7$&&??2A%0%A%2\n"); - mainSocket.SendPackage("sending launcher error".ToBytes()); - mainSocket.SendPackage(ex.Message.ToBytes()); - } - catch (Exception ex1) - { - Debug("r", $"filechecker error: {ex1.Message}\n"); - Log("r", "D0&??/FF\n"); - } - } - }); - - if (!offline) - { - filechecker.Start(); - //responder.Start(mainSocket); - //internalServer.Start(); - } - gameProcess.WaitForExit(); - Log("b", "minecraft closed\n"); - if (!offline) - { - filechecker.Stop(); - //responder.Abort(); - //internalServer.Stop(); - } - } - break; - case ConsoleKey.R: - if (tabs.Current == tabs.Login && !offline) - { - RenderTab(tabs.Current); - if (username.Length < 5) throw new Exception("username is too short"); - if (password_hash.Length == 0) throw new Exception("pasword is null"); - Connect("updater".ToBytes(), "updater"); - mainSocket.SendPackage("register new user".ToBytes()); - mainSocket.GetAnswer("ready"); - mainSocket.SendPackage(hasher.HashCycled(username.ToBytes(), password_hash, 64)); - mainSocket.SendPackage(username.ToBytes()); - Thread.Sleep(300); - LogNoTime("c", "."); - Thread.Sleep(300); - LogNoTime("c", "."); - Thread.Sleep(300); - LogNoTime("c", "."); - Thread.Sleep(300); - LogNoTime("c", ". "); - Log("g", "registration request sent\n"); - } - break; - case ConsoleKey.F2: - tabs.Log = File.ReadAllText(logfile); - 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; - else RenderTab(tabs.Current); - Console.CursorVisible = false; - break; - } - } - catch (Exception ex) - { - Log("r", $"Client.Main() error:\n{ex.Message}\n{ex.StackTrace}\n"); - } - } - } - - else throw new Exception($"invalid args:<{args.MergeToString(">, <")}>\n"); + Info.Log("b", "connecting to server address: <", "c", config.ServerAddress, "b", + ">\nserver port: <", "c", config.ServerPort.ToString(), "b", ">"); + var ip = Dns.GetHostAddresses(config.ServerAddress)[0]; + mainSocket.Connect(new IPEndPoint(ip, config.ServerPort)); + Info.Log("g", $"connected to server {ip}"); + break; } - catch (Exception ex) + catch (SocketException ex) { - Log("r", $"Client.Main() error:\n{ex.Message}\n{ex.StackTrace}\n"); - ColoredConsole.Write("gray", "press any key to close..."); - Console.ReadKey(); + Error.Log("r", $"{ex.Message}\n{ex.StackTrace}"); + Thread.Sleep(2000); } - } - // подключение серверу - static void Connect(byte[] hash, string server_answer) + FSP = new FSP(mainSocket); + FSP.debug = debug; + /*FSP.PackageRecieved += (size) => { - if (mainSocket.Connected) - { - Log("b", "socket is connected already. disconnecting...\n"); - mainSocket.Shutdown(SocketShutdown.Both); - mainSocket.Close(); - } - mainSocket = new(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); - byte domain_num = 0; - while (true) - { - try - { - if (domain_num >= server_domains.Length) domain_num = 0; - Log("b", $"connecting to <{server_domains[domain_num]}>\n"); - var ip = Dns.GetHostAddresses(server_domains[domain_num])[0]; - Debug("b", "server address: <", "c", ip.ToString(), "b", - ">\nserver port: <", "c", server_port.ToString(), "b", ">\n"); - mainSocket.Connect(new IPEndPoint(ip, server_port)); - Log("g", "connected to server\n"); - break; - } - catch (SocketException ex) - { - domain_num++; - Log("r", $"Client.Main() error:\n{ex.Message}\n{ex.StackTrace}\n"); - ColoredConsole.Write("r", $"Client.Main() error:\n{ex.Message}\n{ex.StackTrace}\n"); - } - } - FSP = new(mainSocket); - FSP.debug = debug; - /*FSP.PackageRecieved += (size) => - { - Console.SetCursorPosition(0, 30); - Log("b", "downloading file... [", "c", size.ToString(), "b","/", "c", FSP.Filesize = ) - };*/ - mainSocket.ReceiveTimeout = 2500; - mainSocket.SendTimeout = 2500; - mainSocket.GetAnswer("requesting hash"); - mainSocket.SendPackage(hash); - mainSocket.GetAnswer(server_answer); - } + Console.SetCursorPosition(0, 30); + Info.Log("b", "downloading file... [", "c", size.ToString(), "b","/", "c", FSP.Filesize = ) + };*/ + mainSocket.ReceiveTimeout = 2500; + mainSocket.SendTimeout = 2500; + mainSocket.GetAnswer("requesting hash"); + mainSocket.SendPackage(hash); + mainSocket.GetAnswer(server_answer); + } - 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 void RenderTab(string tab, ushort bufferHeight = 30) + { + tabs.Current = tab; + Console.Clear(); + Console.SetWindowSize(80, 30); + Console.SetBufferSize(80, bufferHeight); + ColoredConsole.Write("w", tab); + } - static string ReadString(ushort x, ushort y, ushort maxlength) + 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) { - string 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) { - ConsoleKeyInfo 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 thisChar; - if (pressedKey.Modifiers.HasFlag(ConsoleModifiers.Shift)) thisChar = pressedKey.KeyChar.ToString().ToUpper(); - else thisChar = pressedKey.KeyChar.ToString(); - output += thisChar; - } + 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; - } + } + + 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 thisChar; + if (pressedKey.Modifiers.HasFlag(ConsoleModifiers.Shift)) + thisChar = pressedKey.KeyChar.ToString().ToUpper(); + else thisChar = pressedKey.KeyChar.ToString(); + output += thisChar; + } + + RenderTab(tabs.Current); + Console.SetCursorPosition(x, y); + ColoredConsole.Write("c", output); + break; } } - - static void LaunchGame(string javapath, string username, string uuid, string maxmemory, string width, string height, string gamedir) - => gameProcess = Process.Start($"{javapath}\\javaw.exe ", - $"-Djava.net.preferIPv4Stack=true \"-Dos.name=Windows 10\" -Dos.version=10.0 " + - $"-Xmn256M -Xmx{maxmemory}M -Djava.library.path=version\\natives -cp " + - $"libraries\\net\\minecraftforge\\forge\\1.12.2-14.23.5.2855\\forge-1.12.2-14.23.5.2855.jar;" + - $"libraries\\org\\ow2\\asm\\asm-debug-all\\5.2\\asm-debug-all-5.2.jar;" + - $"libraries\\net\\minecraft\\launchwrapper\\1.12\\launchwrapper-1.12.jar;" + - $"libraries\\org\\jline\\jline\\3.5.1\\jline-3.5.1.jar;" + - $"libraries\\com\\typesafe\\akka\\akka-actor_2.11\\2.3.3\\akka-actor_2.11-2.3.3.jar;" + - $"libraries\\com\\typesafe\\config\\1.2.1\\config-1.2.1.jar;" + - $"libraries\\org\\scala-lang\\scala-actors-migration_2.11\\1.1.0\\scala-actors-migration_2.11-1.1.0.jar;" + - $"libraries\\org\\scala-lang\\scala-compiler\\2.11.1\\scala-compiler-2.11.1.jar;" + - $"libraries\\org\\scala-lang\\plugins\\scala-continuations-library_2.11\\1.0.2_mc\\scala-continuations-library_2.11-1.0.2_mc.jar;l" + - $"ibraries\\org\\scala-lang\\plugins\\scala-continuations-plugin_2.11.1\\1.0.2_mc\\scala-continuations-plugin_2.11.1-1.0.2_mc.jar;" + - $"libraries\\org\\scala-lang\\scala-library\\2.11.1\\scala-library-2.11.1.jar;" + - $"libraries\\org\\scala-lang\\scala-parser-combinators_2.11\\1.0.1\\scala-parser-combinators_2.11-1.0.1.jar;" + - $"libraries\\org\\scala-lang\\scala-reflect\\2.11.1\\scala-reflect-2.11.1.jar;" + - $"libraries\\org\\scala-lang\\scala-swing_2.11\\1.0.1\\scala-swing_2.11-1.0.1.jar;" + - $"libraries\\org\\scala-lang\\scala-xml_2.11\\1.0.2\\scala-xml_2.11-1.0.2.jar;" + - $"libraries\\lzma\\lzma\\0.0.1\\lzma-0.0.1.jar;" + - $"libraries\\java3d\\vecmath\\1.5.2\\vecmath-1.5.2.jar;" + - $"libraries\\net\\sf\\trove4j\\trove4j\\3.0.3\\trove4j-3.0.3.jar;" + - $"libraries\\org\\apache\\maven\\maven-artifact\\3.5.3\\maven-artifact-3.5.3.jar;" + - $"libraries\\net\\sf\\jopt-simple\\jopt-simple\\5.0.3\\jopt-simple-5.0.3.jar;" + - $"libraries\\oshi-project\\oshi-core\\1.1\\oshi-core-1.1.jar;" + - $"libraries\\net\\java\\dev\\jna\\jna\\4.4.0\\jna-4.4.0.jar;" + - $"libraries\\net\\java\\dev\\jna\\platform\\3.4.0\\platform-3.4.0.jar;" + - $"libraries\\com\\ibm\\icu\\icu4j-core-mojang\\51.2\\icu4j-core-mojang-51.2.jar;" + - $"libraries\\net\\sf\\jopt-simple\\jopt-simple\\5.0.3\\jopt-simple-5.0.3.jar;" + - $"libraries\\com\\paulscode\\codecjorbis\\20101023\\codecjorbis-20101023.jar;" + - $"libraries\\com\\paulscode\\codecwav\\20101023\\codecwav-20101023.jar;" + - $"libraries\\com\\paulscode\\libraryjavasound\\20101123\\libraryjavasound-20101123.jar;" + - $"libraries\\com\\paulscode\\librarylwjglopenal\\20100824\\librarylwjglopenal-20100824.jar;" + - $"libraries\\com\\paulscode\\soundsystem\\20120107\\soundsystem-20120107.jar;" + - $"libraries\\io\\netty\\netty-all\\4.1.9.Final\\netty-all-4.1.9.Final.jar;" + - $"libraries\\com\\google\\guava\\guava\\21.0\\guava-21.0.jar;" + - $"libraries\\org\\apache\\commons\\commons-lang3\\3.5\\commons-lang3-3.5.jar;" + - $"libraries\\commons-io\\commons-io\\2.5\\commons-io-2.5.jar;" + - $"libraries\\commons-codec\\commons-codec\\1.10\\commons-codec-1.10.jar;" + - $"libraries\\net\\java\\jinput\\jinput\\2.0.5\\jinput-2.0.5.jar;" + - $"libraries\\net\\java\\jutils\\jutils\\1.0.0\\jutils-1.0.0.jar;" + - $"libraries\\com\\google\\code\\gson\\gson\\2.8.0\\gson-2.8.0.jar;" + - $"libraries\\com\\mojang\\authlib\\1.5.25\\authlib-1.5.25.jar;" + - $"libraries\\com\\mojang\\realms\\1.10.22\\realms-1.10.22.jar;" + - $"libraries\\org\\apache\\commons\\commons-compress\\1.8.1\\commons-compress-1.8.1.jar;" + - $"libraries\\org\\apache\\httpcomponents\\httpclient\\4.3.3\\httpclient-4.3.3.jar;" + - $"libraries\\commons-logging\\commons-logging\\1.1.3\\commons-logging-1.1.3.jar;" + - $"libraries\\org\\apache\\httpcomponents\\httpcore\\4.3.2\\httpcore-4.3.2.jar;" + - $"libraries\\it\\unimi\\dsi\\fastutil\\7.1.0\\fastutil-7.1.0.jar;" + - $"libraries\\org\\apache\\logging\\log4j\\log4j-api\\2.8.1\\log4j-api-2.8.1.jar;" + - $"libraries\\org\\apache\\logging\\log4j\\log4j-core\\2.8.1\\log4j-core-2.8.1.jar;" + - $"libraries\\org\\lwjgl\\lwjgl\\lwjgl\\2.9.4-nightly-20150209\\lwjgl-2.9.4-nightly-20150209.jar;" + - $"libraries\\org\\lwjgl\\lwjgl\\lwjgl_util\\2.9.4-nightly-20150209\\lwjgl_util-2.9.4-nightly-20150209.jar;" + - $"libraries\\com\\mojang\\text2speech\\1.10.3\\text2speech-1.10.3.jar;" + - $"version\\1.12.2-forge-14.23.5.2855.jar " + - $"-Dminecraft.applet.TargetDirectory={gamedir} " + - $"-Dfml.ignoreInvalidMinecraftCertificates=true -Dfml.ignorePatchDiscrepancies=true " + - $"net.minecraft.launchwrapper.Launch --username {username} --version 1.12.2-forge-14.23.5.2855 " + - $"--gameDir {gamedir} --assetsDir assets --assetIndex 1.12 " + - $"--uuid {uuid} --accessToken null --userType mojang --tweakClass net.minecraftforge.fml.common.launcher.FMLTweaker " + - $"--versionType Forge --width {width} --height {height}"); - - - - // вывод лога в консоль и файл - public static void Log(params string[] msg) - { - if (msg.Length == 1) msg[0] = "[" + DateTime.Now.ToString() + "]: " + msg[0]; - else msg[1] = "[" + DateTime.Now.ToString() + "]: " + msg[1]; - LogNoTime(msg); - } - - public static void LogNoTime(params string[] msg) - { - ColoredConsole.Write(msg); - if (msg.Length == 1) File.AppendAllText(logfile, msg[0]); - else - { - StringBuilder strB = new(); - for (ushort i = 0; i < msg.Length; i++) - strB.Append(msg[++i]); - File.AppendAllText(logfile, strB.ToString()); - } - } - - - public static void Debug(params string[] msg) - { - if (debug) Log(msg); - } - public static void DebugNoTime(params string[] msg) - { - if (debug) LogNoTime(msg); - } } -} + + private static void LaunchGame(string javapath, string username, string uuid, int maxmemory, int width, + int height) + { + gameProcess = Process.Start($"{javapath}\\javaw.exe ", + "-Djava.net.preferIPv4Stack=true \"-Dos.name=Windows 10\" -Dos.version=10.0 " + + $"-Xmn256M -Xmx{maxmemory}M -Djava.library.path=version\\natives -cp " + + "libraries\\net\\minecraftforge\\forge\\1.12.2-14.23.5.2855\\forge-1.12.2-14.23.5.2855.jar;" + + "libraries\\org\\ow2\\asm\\asm-debug-all\\5.2\\asm-debug-all-5.2.jar;" + + "libraries\\net\\minecraft\\launchwrapper\\1.12\\launchwrapper-1.12.jar;" + + "libraries\\org\\jline\\jline\\3.5.1\\jline-3.5.1.jar;" + + "libraries\\com\\typesafe\\akka\\akka-actor_2.11\\2.3.3\\akka-actor_2.11-2.3.3.jar;" + + "libraries\\com\\typesafe\\config\\1.2.1\\config-1.2.1.jar;" + + "libraries\\org\\scala-lang\\scala-actors-migration_2.11\\1.1.0\\scala-actors-migration_2.11-1.1.0.jar;" + + "libraries\\org\\scala-lang\\scala-compiler\\2.11.1\\scala-compiler-2.11.1.jar;" + + "libraries\\org\\scala-lang\\plugins\\scala-continuations-library_2.11\\1.0.2_mc\\scala-continuations-library_2.11-1.0.2_mc.jar;l" + + "ibraries\\org\\scala-lang\\plugins\\scala-continuations-plugin_2.11.1\\1.0.2_mc\\scala-continuations-plugin_2.11.1-1.0.2_mc.jar;" + + "libraries\\org\\scala-lang\\scala-library\\2.11.1\\scala-library-2.11.1.jar;" + + "libraries\\org\\scala-lang\\scala-parser-combinators_2.11\\1.0.1\\scala-parser-combinators_2.11-1.0.1.jar;" + + "libraries\\org\\scala-lang\\scala-reflect\\2.11.1\\scala-reflect-2.11.1.jar;" + + "libraries\\org\\scala-lang\\scala-swing_2.11\\1.0.1\\scala-swing_2.11-1.0.1.jar;" + + "libraries\\org\\scala-lang\\scala-xml_2.11\\1.0.2\\scala-xml_2.11-1.0.2.jar;" + + "libraries\\lzma\\lzma\\0.0.1\\lzma-0.0.1.jar;" + + "libraries\\java3d\\vecmath\\1.5.2\\vecmath-1.5.2.jar;" + + "libraries\\net\\sf\\trove4j\\trove4j\\3.0.3\\trove4j-3.0.3.jar;" + + "libraries\\org\\apache\\maven\\maven-artifact\\3.5.3\\maven-artifact-3.5.3.jar;" + + "libraries\\net\\sf\\jopt-simple\\jopt-simple\\5.0.3\\jopt-simple-5.0.3.jar;" + + "libraries\\oshi-project\\oshi-core\\1.1\\oshi-core-1.1.jar;" + + "libraries\\net\\java\\dev\\jna\\jna\\4.4.0\\jna-4.4.0.jar;" + + "libraries\\net\\java\\dev\\jna\\platform\\3.4.0\\platform-3.4.0.jar;" + + "libraries\\com\\ibm\\icu\\icu4j-core-mojang\\51.2\\icu4j-core-mojang-51.2.jar;" + + "libraries\\net\\sf\\jopt-simple\\jopt-simple\\5.0.3\\jopt-simple-5.0.3.jar;" + + "libraries\\com\\paulscode\\codecjorbis\\20101023\\codecjorbis-20101023.jar;" + + "libraries\\com\\paulscode\\codecwav\\20101023\\codecwav-20101023.jar;" + + "libraries\\com\\paulscode\\libraryjavasound\\20101123\\libraryjavasound-20101123.jar;" + + "libraries\\com\\paulscode\\librarylwjglopenal\\20100824\\librarylwjglopenal-20100824.jar;" + + "libraries\\com\\paulscode\\soundsystem\\20120107\\soundsystem-20120107.jar;" + + "libraries\\io\\netty\\netty-all\\4.1.9.Final\\netty-all-4.1.9.Final.jar;" + + "libraries\\com\\google\\guava\\guava\\21.0\\guava-21.0.jar;" + + "libraries\\org\\apache\\commons\\commons-lang3\\3.5\\commons-lang3-3.5.jar;" + + "libraries\\commons-io\\commons-io\\2.5\\commons-io-2.5.jar;" + + "libraries\\commons-codec\\commons-codec\\1.10\\commons-codec-1.10.jar;" + + "libraries\\net\\java\\jinput\\jinput\\2.0.5\\jinput-2.0.5.jar;" + + "libraries\\net\\java\\jutils\\jutils\\1.0.0\\jutils-1.0.0.jar;" + + "libraries\\com\\google\\code\\gson\\gson\\2.8.0\\gson-2.8.0.jar;" + + "libraries\\com\\mojang\\authlib\\1.5.25\\authlib-1.5.25.jar;" + + "libraries\\com\\mojang\\realms\\1.10.22\\realms-1.10.22.jar;" + + "libraries\\org\\apache\\commons\\commons-compress\\1.8.1\\commons-compress-1.8.1.jar;" + + "libraries\\org\\apache\\httpcomponents\\httpclient\\4.3.3\\httpclient-4.3.3.jar;" + + "libraries\\commons-logging\\commons-logging\\1.1.3\\commons-logging-1.1.3.jar;" + + "libraries\\org\\apache\\httpcomponents\\httpcore\\4.3.2\\httpcore-4.3.2.jar;" + + "libraries\\it\\unimi\\dsi\\fastutil\\7.1.0\\fastutil-7.1.0.jar;" + + "libraries\\org\\apache\\logging\\log4j\\log4j-api\\2.8.1\\log4j-api-2.8.1.jar;" + + "libraries\\org\\apache\\logging\\log4j\\log4j-core\\2.8.1\\log4j-core-2.8.1.jar;" + + "libraries\\org\\lwjgl\\lwjgl\\lwjgl\\2.9.4-nightly-20150209\\lwjgl-2.9.4-nightly-20150209.jar;" + + "libraries\\org\\lwjgl\\lwjgl\\lwjgl_util\\2.9.4-nightly-20150209\\lwjgl_util-2.9.4-nightly-20150209.jar;" + + "libraries\\com\\mojang\\text2speech\\1.10.3\\text2speech-1.10.3.jar;" + + "version\\1.12.2-forge-14.23.5.2855.jar " + + $"-Dminecraft.applet.TargetDirectory=.\\ " + + "-Dfml.ignoreInvalidMinecraftCertificates=true -Dfml.ignorePatchDiscrepancies=true " + + $"net.minecraft.launchwrapper.Launch --username {username} --version 1.12.2-forge-14.23.5.2855 " + + $"--gameDir .\\ --assetsDir assets --assetIndex 1.12 " + + $"--uuid {uuid} --accessToken null --userType mojang --tweakClass net.minecraftforge.fml.common.launcher.FMLTweaker " + + $"--versionType Forge --width {width} --height {height}"); + } +} \ No newline at end of file diff --git a/minecraft-launcher-client/LauncherConfig.cs b/minecraft-launcher-client/LauncherConfig.cs new file mode 100644 index 0000000..09b69e1 --- /dev/null +++ b/minecraft-launcher-client/LauncherConfig.cs @@ -0,0 +1,69 @@ +using DTLib.Dtsod; +using DTLib.Filesystem; + +namespace launcher_client; + +public class LauncherConfig +{ + public int GameMemory = 3000; + public int GameWindowHeight = 1600; + public int GameWindowWidth = 900; + public string JavaPath = $"java{Путь.Разд}bin"; + public string ServerAddress = "127.0.0.1"; + public int ServerPort = 25000; + public string Username = ""; + public string UUID = ""; + + public string ConfigPath; + + + public LauncherConfig(){} + + public LauncherConfig(DtsodV23 dtsod, string configPath) + { + GameMemory = dtsod["gameMemory"]; + GameWindowHeight = dtsod["gameWindowHeight"]; + GameWindowWidth = dtsod["gameWindowWidth"]; + JavaPath = dtsod["javaPath"]; + ServerAddress = dtsod["serverAddress"]; + ServerPort = dtsod["serverPort"]; + Username = dtsod["username"]; + UUID = dtsod["uuid"]; + + ConfigPath = configPath; + } + + public LauncherConfig(string configPath) : + this(new DtsodV23(File.ReadAllText(configPath)), configPath) + { } + + public DtsodV23 ToDtsod() + { + return new() + { + { "gameMemory", GameMemory }, + { "gameWindowHeight", GameWindowHeight }, + { "gameWindowWidth", GameWindowWidth }, + { "javaPath", JavaPath }, + { "serverAddress", ServerAddress }, + { "serverPort", ServerPort }, + { "username", Username }, + { "uuid", UUID } + }; + } + + public void Save() + { + File.WriteAllText(ConfigPath, ToDtsod().ToString()); + } + + public static LauncherConfig CreateDefault(string configPath) + { + var c = new LauncherConfig + { + ConfigPath = configPath + }; + c.Save(); + return c; + } +} \ No newline at end of file diff --git a/minecraft-launcher-client/Properties/AssemblyInfo.cs b/minecraft-launcher-client/Properties/AssemblyInfo.cs deleted file mode 100644 index c4b4f4d..0000000 --- a/minecraft-launcher-client/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,35 +0,0 @@ -using System.Reflection; -using System.Runtime.InteropServices; - -// Общие сведения об этой сборке предоставляются следующим набором -// набора атрибутов. Измените значения этих атрибутов для изменения сведений, -// связанные с этой сборкой. -[assembly: AssemblyTitle("minecraft-launcher-client")] -[assembly: AssemblyDescription("")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("")] -[assembly: AssemblyProduct("minecraft-launcher-client")] -[assembly: AssemblyCopyright("Copyright © 2021")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] - -// Установка значения False для параметра ComVisible делает типы в этой сборке невидимыми -// для компонентов COM. Если необходимо обратиться к типу в этой сборке через -// из модели COM задайте для атрибута ComVisible этого типа значение true. -[assembly: ComVisible(false)] - -// Следующий GUID представляет идентификатор typelib, если этот проект доступен из модели COM -[assembly: Guid("49adefce-da46-4229-997c-3d43dd600627")] - -// Сведения о версии сборки состоят из указанных ниже четырех значений: -// -// Основной номер версии -// Дополнительный номер версии -// Номер сборки -// Номер редакции -// -// Можно задать все значения или принять номера сборки и редакции по умолчанию -// используя "*", как показано ниже: -// [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("1.0.0.0")] -[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/minecraft-launcher-client/launcher-client.csproj b/minecraft-launcher-client/launcher-client.csproj index 68e9552..2e3709b 100644 --- a/minecraft-launcher-client/launcher-client.csproj +++ b/minecraft-launcher-client/launcher-client.csproj @@ -1,79 +1,15 @@ - - - - - Debug - AnyCPU - {49ADEFCE-DA46-4229-997C-3D43DD600627} - Exe - launcher_client - launcher - v4.8 - 9.0 - 512 - true - true - - - launcher_client.Launcher - - - logo-D.ico - - - true - - - bin\ - DEBUG;TRACE - true - AnyCPU - 9.0 - prompt - true - - - - - - - - - - - - - - - - - - - .editorconfig - - - - Always - - - - - - - - - - - {57cdc0ef-31c9-4859-90e5-ad0b302c5eae} - DTLib - - - - - del /f /q launcher.exe.config -rmdir /s /q C:\projects\c#\minecraft-launcher\release\src -mkdir C:\projects\c#\minecraft-launcher\release\src -copy launcher.exe C:\projects\c#\minecraft-launcher\release\src\launcher.exe -copy DTLib.dll C:\projects\c#\minecraft-launcher\release\src\DTLib.dll - + + + net6.0 + disable + disable + Exe + launcher_client + minecraft-launcher-client + + + + + + \ No newline at end of file diff --git a/minecraft-launcher-client/launcher.dtsod b/minecraft-launcher-client/launcher.dtsod index 8963b58..98759aa 100644 --- a/minecraft-launcher-client/launcher.dtsod +++ b/minecraft-launcher-client/launcher.dtsod @@ -1,4 +1,8 @@ -maxmemory: "3000"; -width: "1600"; -height: "1000"; -javapath: "jre\bin"; \ No newline at end of file +gameMemory: "3000"; +gameWindowWidth: "1600"; +gameWinowHeight: "1000"; +javaPath: "java\bin"; +serverAddress: "127.0.0.1"; +serverPort: 25000; +username: ""; +uuid: ""; diff --git a/minecraft-launcher-client/logo-D.ico b/minecraft-launcher-client/logo-D.ico deleted file mode 100644 index 9b68a7e..0000000 Binary files a/minecraft-launcher-client/logo-D.ico and /dev/null differ diff --git a/minecraft-launcher-server/App.config b/minecraft-launcher-server/App.config deleted file mode 100644 index 3916e0e..0000000 --- a/minecraft-launcher-server/App.config +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/minecraft-launcher-server/Properties/AssemblyInfo.cs b/minecraft-launcher-server/Properties/AssemblyInfo.cs deleted file mode 100644 index 003995d..0000000 --- a/minecraft-launcher-server/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,35 +0,0 @@ -using System.Reflection; -using System.Runtime.InteropServices; - -// Общие сведения об этой сборке предоставляются следующим набором -// набора атрибутов. Измените значения этих атрибутов для изменения сведений, -// связанные с этой сборкой. -[assembly: AssemblyTitle("minecraft-launcher-server")] -[assembly: AssemblyDescription("")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("")] -[assembly: AssemblyProduct("minecraft-launcher-server")] -[assembly: AssemblyCopyright("Copyright © 2021")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] - -// Установка значения False для параметра ComVisible делает типы в этой сборке невидимыми -// для компонентов COM. Если необходимо обратиться к типу в этой сборке через -// из модели COM задайте для атрибута ComVisible этого типа значение true. -[assembly: ComVisible(false)] - -// Следующий GUID представляет идентификатор typelib, если этот проект доступен из модели COM -[assembly: Guid("1dc6892c-5dc8-4c1c-94c1-ce695bd2dbc2")] - -// Сведения о версии сборки состоят из указанных ниже четырех значений: -// -// Основной номер версии -// Дополнительный номер версии -// Номер сборки -// Номер редакции -// -// Можно задать все значения или принять номера сборки и редакции по умолчанию -// используя "*", как показано ниже: -// [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("1.0.0.0")] -[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/minecraft-launcher-server/Server.cs b/minecraft-launcher-server/Server.cs index be7aedc..dc214d8 100644 --- a/minecraft-launcher-server/Server.cs +++ b/minecraft-launcher-server/Server.cs @@ -1,22 +1,25 @@ -using DTLib; -using DTLib.Dtsod; -using DTLib.Filesystem; -using DTLib.Network; -using System; +using System; +using System.Linq; using System.Net; using System.Net.Sockets; using System.Text; using System.Threading; -using System.Linq; +using DTLib; +using DTLib.Dtsod; +using DTLib.Extensions; +using DTLib.Filesystem; +using DTLib.Logging; +using DTLib.Network; namespace launcher_server { - class Server + static class Server { - static readonly string logfile = $"logs\\launcher-server_{DateTime.Now}.log".Replace(':', '-').Replace(' ', '_'); + private static ConsoleLogger Info = new("logs","info"); + private static ConsoleLogger Error = new("logs","error"); static readonly Socket mainSocket = new(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); - static DtsodV22 config; - static bool debug = false; + static DtsodV23 config; + static bool debug; static object manifestLocker = new(); @@ -27,64 +30,37 @@ namespace launcher_server Console.Title = "minecraft_launcher_server"; Console.InputEncoding = Encoding.Unicode; Console.OutputEncoding = Encoding.Unicode; - PublicLog.LogEvent += Log; - PublicLog.LogNoTimeEvent += LogNoTime; - config = new DtsodV22(File.ReadAllText("launcher-server.dtsod")); + PublicLog.LogEvent += Info.Log; + config = new DtsodV23(File.ReadAllText("launcher-server.dtsod")); if (args.Contains("debug")) debug = true; - Log("b", "local address: <", "c", config["local_ip"], "b", + Info.Log("b", "local address: <", "c", config["local_ip"], "b", ">\npublic address: <", "c", OldNetwork.GetPublicIP(), "b", - ">\nport: <", "c", config["local_port"].ToString(), "b", ">\n"); + ">\nport: <", "c", config["local_port"].ToString(), "b", ">"); mainSocket.Bind(new IPEndPoint(IPAddress.Parse(config["local_ip"]), config["local_port"])); mainSocket.Listen(1000); CreateManifestы(); - Log("g", "server started succesfully\n"); + Info.Log("g", "server started succesfully"); // запуск отдельного потока для каждого юзера - Log("b", "waiting for users\n"); + Info.Log("b", "waiting for users"); while (true) { var userSocket = mainSocket.Accept(); - var userThread = new Thread(new ParameterizedThreadStart((obj) => UserHandle((Socket)obj))); + var userThread = new Thread(obj => UserHandle((Socket)obj)); userThread.Start(userSocket); } } catch (Exception ex) { - Log("r", $"Server.Main() error:\n{ex.Message}\n{ex.StackTrace}\n"); + Error.Log("r", $"{ex.Message}\n{ex.StackTrace}"); mainSocket.Close(); } - Log("press any key to close... "); - Console.ReadKey(); - Log("gray", "\n"); - } - - // вывод лога в консоль и файл - public static void Log(params string[] msg) - { - if (msg.Length == 1) msg[0] = "[" + DateTime.Now.ToString() + "]: " + msg[0]; - else msg[1] = "[" + DateTime.Now.ToString() + "]: " + msg[1]; - LogNoTime(msg); - } - - public static void LogNoTime(params string[] msg) - { - lock (new object()) - { - ColoredConsole.Write(msg); - if (msg.Length == 1) File.AppendAllText(logfile, msg[0]); - else - { - StringBuilder strB = new(); - for (ushort i = 0; i < msg.Length; i++) - strB.Append(msg[++i]); - File.AppendAllText(logfile, strB.ToString()); - } - } + Info.Log("gray", ""); } // запускается для каждого юзера в отдельном потоке static void UserHandle(Socket handlerSocket) { - Log("b", "user connecting... "); + Info.Log("b", "user connecting... "); try { // тут запрос пароля заменён запросом заглушки @@ -96,7 +72,7 @@ namespace launcher_server // запрос от апдейтера if (hash.HashToString() == "39368b9c9ca9a74007acd2358fb7945cf172fc86c93969d0933e40aee6c10ca8") { - LogNoTime("b", "user is ", "c", "updater\n"); + Info.Log("b", "user is ", "c", "updater"); handlerSocket.SendPackage("updater".ToBytes()); // обработка запросов while (true) @@ -107,19 +83,19 @@ namespace launcher_server switch (request) { case "requesting launcher update": - Log("b", "updater requested client.exe\n"); + Info.Log("b", "updater requested client.exe"); fsp.UploadFile("share\\launcher.exe"); break; case "register new user": - Log("b", "new user registration requested\n"); + Info.Log("b", "new user registration requested"); handlerSocket.SendPackage("ready".ToBytes()); - var req = FrameworkFix.MergeToString( + var req = StringConverter.MergeToString( hasher.HashCycled(handlerSocket.GetPackage(), 64).HashToString(), ":\n{\n\tusername: \"", handlerSocket.GetPackage().ToString(), - "\";\n\tuuid: \"null\";\n};\n"); - var filepath = $"registration_requests\\{DateTime.Now.ToString().Replace(':', '-').Replace(' ', '_')}.req"; + "\";\n\tuuid: \"null\";\n};"); + var filepath = $"registration_requests\\{DateTime.Now.ToString(MyTimeFormat.ForFileNames)}.req"; File.WriteAllText(filepath, req); - Log("b", $"text wrote to file <", "c", $"registration_requests\\{filepath}", "b", ">\n"); + Info.Log("b", "text wrote to file <", "c", $"registration_requests\\{filepath}", "b", ">"); break; default: throw new Exception("unknown request: " + request); @@ -129,9 +105,10 @@ namespace launcher_server } } // запрос от юзера - else if (FindUser(hash, out var user)) + + if (FindUser(hash, out var user)) { - LogNoTime("b", $"user is ", "c", user.name + "\n"); + Info.Log("b", "user is ", "c", user.name); handlerSocket.SendPackage("launcher".ToBytes()); // обработка запросов while (true) @@ -143,7 +120,7 @@ namespace launcher_server { case "requesting file download": var file = handlerSocket.GetPackage().ToString(); - Log("b", $"user ", "c", user.name, "b", " requested file ", "c", file + "\n"); + Info.Log("b", "user ", "c", user.name, "b", " requested file ", "c", file + ""); if (file == "manifest.dtsod") { lock (manifestLocker) fsp.UploadFile("share\\manifest.dtsod"); @@ -151,17 +128,17 @@ namespace launcher_server else fsp.UploadFile("share\\" + file); break; case "requesting uuid": - Log("b", $"user ", "c", user.name, "b", " requested uuid\n"); + Info.Log("b", "user ", "c", user.name, "b", " requested uuid"); handlerSocket.SendPackage(user.uuid.ToBytes()); break; case "excess files found": - Log("b", $"user ", "c", user.name, "b", " sent excess files list\n"); - fsp.DownloadFile($"excesses\\{user.name}-{DateTime.Now.ToString().Replace(':', '-').Replace(' ', '_')}.txt"); + Info.Log("b", "user ", "c", user.name, "b", " sent excess files list"); + fsp.DownloadFile($"excesses\\{user.name}-{DateTime.Now.ToString(MyTimeFormat.ForFileNames)}.txt"); break; case "sending launcher error": - Log("y", "user ", "c", user.name, "y", "is sending error:\n"); + Info.Log("y", "user ", "c", user.name, "y", "is sending error:"); string error = handlerSocket.GetPackage().ToString(); - Log("y", error + '\n'); + Info.Log("y", error + '\n'); break; default: throw new Exception("unknown request: " + request); @@ -171,21 +148,19 @@ namespace launcher_server } } // неизвестный юзер - else - { - LogNoTime("y", $"user with hash <{hash.HashToString()}> not found\n"); - handlerSocket.SendPackage("user not found".ToBytes()); - } + + Error.Log("y", $"user with hash <{hash.HashToString()}> not found"); + handlerSocket.SendPackage("user not found".ToBytes()); } catch (Exception ex) { - Log("y", $"UserStart() error:\n message:\n {ex.Message}\n{ex.StackTrace}\n"); + Error.Log("y", $"{ex.Message}\n{ex.StackTrace}"); } finally { if (handlerSocket.Connected) handlerSocket.Shutdown(SocketShutdown.Both); handlerSocket.Close(); - Log("g", "user disconnected\n"); + Info.Log("g", "user disconnected"); } } @@ -198,13 +173,16 @@ namespace launcher_server foreach (string dir in Directory.GetDirectories("share\\sync_and_remove")) FSP.CreateManifest(dir); File.WriteAllText("share\\sync_and_remove\\dirlist.dtsod", - $"dirs: [\"{Directory.GetDirectories("share\\sync_and_remove").MergeToString("\",\"").Replace("share\\sync_and_remove\\", "")}\"];\n"); - }; + "dirs: [\"" + +Directory.GetDirectories("share\\sync_and_remove") + .MergeToString("\", \"").Replace("share\\sync_and_remove\\", "") + +"\"];"); + } } static bool FindUser(byte[] hash, out (string name, string uuid) user) { - DtsodV22 usersdb = new(File.ReadAllText("users.dtsod")); + DtsodV23 usersdb = new(File.ReadAllText("users.dtsod")); user = new(); if (usersdb.ContainsKey(hash.HashToString())) { @@ -212,7 +190,8 @@ namespace launcher_server user.uuid = usersdb[hash.HashToString()]["uuid"]; return true; } - else return false; + + return false; } } } diff --git a/minecraft-launcher-server/launcher-server.csproj b/minecraft-launcher-server/launcher-server.csproj index e6daf15..6a52580 100644 --- a/minecraft-launcher-server/launcher-server.csproj +++ b/minecraft-launcher-server/launcher-server.csproj @@ -1,59 +1,15 @@ - - - + - Debug - AnyCPU - {1DC6892C-5DC8-4C1C-94C1-CE695BD2DBC2} + net6.0 + disable + disable Exe launcher_server minecraft-launcher-server - v4.8 - 9.0 - 512 - true - true - - - AnyCPU - none - true - bin\ - DEBUG;TRACE - prompt - 4 - - - launcher_server.Server - - - - - - - - + + + - - - - - - - - Always - - - - - {57cdc0ef-31c9-4859-90e5-ad0b302c5eae} - DTLib - - - - - del /f /q minecraft-launcher-server.exe.config - \ No newline at end of file diff --git a/minecraft-launcher.sln b/minecraft-launcher.sln index 323f38d..13f9ee1 100644 --- a/minecraft-launcher.sln +++ b/minecraft-launcher.sln @@ -7,7 +7,11 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "launcher-client", "minecraf EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "launcher-server", "minecraft-launcher-server\launcher-server.csproj", "{1DC6892C-5DC8-4C1C-94C1-CE695BD2DBC2}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DTLib", "..\DTLib\DTLib\DTLib.csproj", "{57CDC0EF-31C9-4859-90E5-AD0B302C5EAE}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DTLib", "..\..\DTLib\DTLib\DTLib.csproj", "{57CDC0EF-31C9-4859-90E5-AD0B302C5EAE}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DTLib.Dtsod", "..\..\DTLib\DTLib.Dtsod\DTLib.Dtsod.csproj", "{1F6C1C6E-59A4-4C49-90ED-6D8A9F55F349}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DTLib.Network", "..\..\DTLib\DTLib.Network\DTLib.Network.csproj", "{876103FA-6B0D-4322-B66D-0DFEEEFABD82}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -41,6 +45,22 @@ Global {57CDC0EF-31C9-4859-90E5-AD0B302C5EAE}.Release|Any CPU.Build.0 = Release|Any CPU {57CDC0EF-31C9-4859-90E5-AD0B302C5EAE}.Release-net48|Any CPU.ActiveCfg = Release-net48|Any CPU {57CDC0EF-31C9-4859-90E5-AD0B302C5EAE}.Release-net48|Any CPU.Build.0 = Release-net48|Any CPU + {1F6C1C6E-59A4-4C49-90ED-6D8A9F55F349}.Build|Any CPU.ActiveCfg = Debug|Any CPU + {1F6C1C6E-59A4-4C49-90ED-6D8A9F55F349}.Build|Any CPU.Build.0 = Debug|Any CPU + {1F6C1C6E-59A4-4C49-90ED-6D8A9F55F349}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {1F6C1C6E-59A4-4C49-90ED-6D8A9F55F349}.Debug|Any CPU.Build.0 = Debug|Any CPU + {1F6C1C6E-59A4-4C49-90ED-6D8A9F55F349}.Release|Any CPU.ActiveCfg = Release|Any CPU + {1F6C1C6E-59A4-4C49-90ED-6D8A9F55F349}.Release|Any CPU.Build.0 = Release|Any CPU + {1F6C1C6E-59A4-4C49-90ED-6D8A9F55F349}.Release-net48|Any CPU.ActiveCfg = Debug|Any CPU + {1F6C1C6E-59A4-4C49-90ED-6D8A9F55F349}.Release-net48|Any CPU.Build.0 = Debug|Any CPU + {876103FA-6B0D-4322-B66D-0DFEEEFABD82}.Build|Any CPU.ActiveCfg = Debug|Any CPU + {876103FA-6B0D-4322-B66D-0DFEEEFABD82}.Build|Any CPU.Build.0 = Debug|Any CPU + {876103FA-6B0D-4322-B66D-0DFEEEFABD82}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {876103FA-6B0D-4322-B66D-0DFEEEFABD82}.Debug|Any CPU.Build.0 = Debug|Any CPU + {876103FA-6B0D-4322-B66D-0DFEEEFABD82}.Release|Any CPU.ActiveCfg = Release|Any CPU + {876103FA-6B0D-4322-B66D-0DFEEEFABD82}.Release|Any CPU.Build.0 = Release|Any CPU + {876103FA-6B0D-4322-B66D-0DFEEEFABD82}.Release-net48|Any CPU.ActiveCfg = Release-net48|Any CPU + {876103FA-6B0D-4322-B66D-0DFEEEFABD82}.Release-net48|Any CPU.Build.0 = Release-net48|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE