commit 4e897d3031abe79be0a2aa065d4f86d4d8fc3883 Author: Timerix22 Date: Sun Mar 13 17:13:47 2022 +0300 added minecraft launcher files diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..c65ebad --- /dev/null +++ b/.gitignore @@ -0,0 +1,365 @@ +## 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 +[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/ + +# Visual Studio 2015/2017 cache/options directory +.vs/ +.vshistory/ +# Uncomment if you have tasks that create the project's static files in wwwroot +#wwwroot/ + +# 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 diff --git a/minecraft-launcher-client/App.config b/minecraft-launcher-client/App.config new file mode 100644 index 0000000..3916e0e --- /dev/null +++ b/minecraft-launcher-client/App.config @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/minecraft-launcher-client/InternalServer.cs b/minecraft-launcher-client/InternalServer.cs new file mode 100644 index 0000000..ec8ba8b --- /dev/null +++ b/minecraft-launcher-client/InternalServer.cs @@ -0,0 +1,71 @@ +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 new file mode 100644 index 0000000..887928a --- /dev/null +++ b/minecraft-launcher-client/Launcher.cs @@ -0,0 +1,529 @@ +using DTLib; +using DTLib.Dtsod; +using DTLib.Filesystem; +using DTLib.Network; +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Net; +using System.Net.Sockets; +using System.Text; +using System.Threading; +using System.Linq; + +namespace launcher_client +{ + 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; + + static void Main(string[] args) + { + 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"); + } + catch (Exception ex) + { + Log("r", $"Client.Main() error:\n{ex.Message}\n{ex.StackTrace}\n"); + ColoredConsole.Write("gray", "press any key to close..."); + Console.ReadKey(); + } + } + + // подключение серверу + static void Connect(byte[] hash, string server_answer) + { + 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); + } + + 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) + { + string output = ""; + tabs.Current = tabs.Current.Remove(y * 80 + x, maxlength).Insert(y * 80 + x, " ".Multiply(maxlength)); + while (true) + { + 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; + } + 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); + } + } +} diff --git a/minecraft-launcher-client/Properties/AssemblyInfo.cs b/minecraft-launcher-client/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..c4b4f4d --- /dev/null +++ b/minecraft-launcher-client/Properties/AssemblyInfo.cs @@ -0,0 +1,35 @@ +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/gui/exit.gui b/minecraft-launcher-client/gui/exit.gui new file mode 100644 index 0000000..d8232ad --- /dev/null +++ b/minecraft-launcher-client/gui/exit.gui @@ -0,0 +1,29 @@ +┏━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┓ +┃ [F1] login ┃ [F2] log ┃ [F3] settings ┃ [F4] EXIT ┃ [F5] refresh ┃ +┣━━━━━━━━━━━━━━┻━━━━━━━━━━━━━━┻━━━━━━━━━━━━━━━━┻━━━━━━━━━━━━━━┻━━━━━━━━━━━━━━━┫ +┃ ┃ +┃ ┃ +┃ ┃ +┃ ┃ +┃ ┃ +┃ ┃ +┃ ┃ +┃ ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ ┃ +┃ ┃ ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ ┃ ┃ +┃ ┃ ┃ ┃ ┃ ┃ +┃ ┃ ┃ press [ENTER] to exit ┃ ┃ ┃ +┃ ┃ ┃ ┃ ┃ ┃ +┃ ┃ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ┃ ┃ +┃ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ┃ +┃ ┃ +┃ ┃ +┃ ┃ +┃ ┃ +┃ ┃ +┃ ┃ +┃ ┃ +┃ ┃ +┃ ┃ +┃ ┃ +┃ ┃ +┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ \ No newline at end of file diff --git a/minecraft-launcher-client/gui/login.gui b/minecraft-launcher-client/gui/login.gui new file mode 100644 index 0000000..48ff9ff --- /dev/null +++ b/minecraft-launcher-client/gui/login.gui @@ -0,0 +1,29 @@ +┏━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┓ +┃ [F1] LOGIN ┃ [F2] log ┃ [F3] settings ┃ [F4] exit ┃ [F5] refresh ┃ +┣━━━━━━━━━━━━━━┻━━━━━━━━━━━━━━┻━━━━━━━━━━━━━━━━┻━━━━━━━━━━━━━━┻━━━━━━━━━━━━━━━┫ +┃ ┃ +┃ ┃ +┃ ┃ +┃ ┃ +┃ ┃ +┃ ┃ +┃ ┌──────────────────┐ ┃ +┃ [N] nickname:│ │ ┃ +┃ └──────────────────┘ ┃ +┃ ┌──────────────────┐ ┃ +┃ [P] password:│ │ ┃ +┃ └──────────────────┘ ┃ +┃ ┃ +┃ ┏━━━━━━━━━━━━━━━┓ ┏━━━━━━━━━━━━━━┓ ┃ +┃ ┃ [L] login ┃ ┃ [R] register ┃ ┃ +┃ ┗━━━━━━━━━━━━━━━┛ ┗━━━━━━━━━━━━━━┛ ┃ +┃ ┃ +┃ ┃ +┃ ┃ +┃ ┃ +┃ ┃ +┃ ┃ +┃ ┃ +┃ ┃ +┃ ┃ +┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ \ No newline at end of file diff --git a/minecraft-launcher-client/gui/settings.gui b/minecraft-launcher-client/gui/settings.gui new file mode 100644 index 0000000..d97b0b3 --- /dev/null +++ b/minecraft-launcher-client/gui/settings.gui @@ -0,0 +1,29 @@ +┏━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┓ +┃ [F1] login ┃ [F2] log ┃ [F3] SETTINGS ┃ [F4] exit ┃ [F5] refresh ┃ +┣━━━━━━━━━━━━━━┻━━━━━━━━━━━━━━┻━━━━━━━━━━━━━━━━┻━━━━━━━━━━━━━━┻━━━━━━━━━━━━━━━┫ +┃ ┃ +┃ ┃ +┃ гыгыг ┃ +┃ ┃ +┃ я ещё не добавил настройки ┃ +┃ ┃ +┃ приходите позже ┃ +┃ ┃ +┃ ┃ +┃ ┃ +┃ ■ ■ ■ ■ ┃ +┃ ■ ■ ■ ■ ┃ +┃ ■ ■ ■ ■ ■ ■ ■ ┃ +┃ ■ ■ ■ ■ ■ ■ ■ ┃ +┃ ■ ■ ■ ┃ +┃ ┃ +┃ ┃ +┃ ┃ +┃ ┃ +┃ ┃ +┃ ┃ +┃ ┃ +┃ ┃ +┃ ┃ +┃ ┃ +┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ \ No newline at end of file diff --git a/minecraft-launcher-client/gui/test_label.colormap b/minecraft-launcher-client/gui/test_label.colormap new file mode 100644 index 0000000..e69de29 diff --git a/minecraft-launcher-client/gui/test_label.textmap b/minecraft-launcher-client/gui/test_label.textmap new file mode 100644 index 0000000..9d1c046 --- /dev/null +++ b/minecraft-launcher-client/gui/test_label.textmap @@ -0,0 +1,3 @@ +┏━━━━━━━━━┓ +┃ ejejeje ┃ +┗━━━━━━━━━┛ diff --git a/minecraft-launcher-client/gui/window.dtsod b/minecraft-launcher-client/gui/window.dtsod new file mode 100644 index 0000000..6585c34 --- /dev/null +++ b/minecraft-launcher-client/gui/window.dtsod @@ -0,0 +1,16 @@ +window: +{ + type: "container"; + anchor: [0us, 0us]; + width: 90us; + height: 30us; + children: + { + test_label: + { + type: "label"; + anchor: [0us, 0us]; + resdir: "gui"; + }; + }; +}; \ No newline at end of file diff --git a/minecraft-launcher-client/launcher-client.csproj b/minecraft-launcher-client/launcher-client.csproj new file mode 100644 index 0000000..68e9552 --- /dev/null +++ b/minecraft-launcher-client/launcher-client.csproj @@ -0,0 +1,79 @@ + + + + + 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 + + \ No newline at end of file diff --git a/minecraft-launcher-client/launcher.dtsod b/minecraft-launcher-client/launcher.dtsod new file mode 100644 index 0000000..8963b58 --- /dev/null +++ b/minecraft-launcher-client/launcher.dtsod @@ -0,0 +1,4 @@ +maxmemory: "3000"; +width: "1600"; +height: "1000"; +javapath: "jre\bin"; \ No newline at end of file diff --git a/minecraft-launcher-client/logo-D.ico b/minecraft-launcher-client/logo-D.ico new file mode 100644 index 0000000..9b68a7e Binary files /dev/null and b/minecraft-launcher-client/logo-D.ico differ diff --git a/minecraft-launcher-server/App.config b/minecraft-launcher-server/App.config new file mode 100644 index 0000000..3916e0e --- /dev/null +++ b/minecraft-launcher-server/App.config @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/minecraft-launcher-server/Properties/AssemblyInfo.cs b/minecraft-launcher-server/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..003995d --- /dev/null +++ b/minecraft-launcher-server/Properties/AssemblyInfo.cs @@ -0,0 +1,35 @@ +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 new file mode 100644 index 0000000..be7aedc --- /dev/null +++ b/minecraft-launcher-server/Server.cs @@ -0,0 +1,218 @@ +using DTLib; +using DTLib.Dtsod; +using DTLib.Filesystem; +using DTLib.Network; +using System; +using System.Net; +using System.Net.Sockets; +using System.Text; +using System.Threading; +using System.Linq; + +namespace launcher_server +{ + class Server + { + static readonly string logfile = $"logs\\launcher-server_{DateTime.Now}.log".Replace(':', '-').Replace(' ', '_'); + static readonly Socket mainSocket = new(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); + static DtsodV22 config; + static bool debug = false; + + static object manifestLocker = new(); + + static void Main(string[] args) + { + try + { + 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")); + if (args.Contains("debug")) debug = true; + Log("b", "local address: <", "c", config["local_ip"], "b", + ">\npublic address: <", "c", OldNetwork.GetPublicIP(), "b", + ">\nport: <", "c", config["local_port"].ToString(), "b", ">\n"); + mainSocket.Bind(new IPEndPoint(IPAddress.Parse(config["local_ip"]), config["local_port"])); + mainSocket.Listen(1000); + CreateManifestы(); + Log("g", "server started succesfully\n"); + // запуск отдельного потока для каждого юзера + Log("b", "waiting for users\n"); + while (true) + { + var userSocket = mainSocket.Accept(); + var userThread = new Thread(new ParameterizedThreadStart((obj) => UserHandle((Socket)obj))); + userThread.Start(userSocket); + } + } + catch (Exception ex) + { + Log("r", $"Server.Main() error:\n{ex.Message}\n{ex.StackTrace}\n"); + 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()); + } + } + } + + // запускается для каждого юзера в отдельном потоке + static void UserHandle(Socket handlerSocket) + { + Log("b", "user connecting... "); + try + { + // тут запрос пароля заменён запросом заглушки + handlerSocket.SendPackage("requesting hash".ToBytes()); + var hasher = new Hasher(); + var hash = hasher.HashCycled(handlerSocket.GetPackage(), 64); + FSP fsp = new(handlerSocket); + FSP.debug = debug; + // запрос от апдейтера + if (hash.HashToString() == "39368b9c9ca9a74007acd2358fb7945cf172fc86c93969d0933e40aee6c10ca8") + { + LogNoTime("b", "user is ", "c", "updater\n"); + handlerSocket.SendPackage("updater".ToBytes()); + // обработка запросов + while (true) + { + if (handlerSocket.Available >= 2) + { + var request = handlerSocket.GetPackage().ToString(); + switch (request) + { + case "requesting launcher update": + Log("b", "updater requested client.exe\n"); + fsp.UploadFile("share\\launcher.exe"); + break; + case "register new user": + Log("b", "new user registration requested\n"); + handlerSocket.SendPackage("ready".ToBytes()); + var req = FrameworkFix.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"; + File.WriteAllText(filepath, req); + Log("b", $"text wrote to file <", "c", $"registration_requests\\{filepath}", "b", ">\n"); + break; + default: + throw new Exception("unknown request: " + request); + } + } + else Thread.Sleep(10); + } + } + // запрос от юзера + else if (FindUser(hash, out var user)) + { + LogNoTime("b", $"user is ", "c", user.name + "\n"); + handlerSocket.SendPackage("launcher".ToBytes()); + // обработка запросов + while (true) + { + if (handlerSocket.Available >= 2) + { + var request = handlerSocket.GetPackage().ToString(); + switch (request) + { + case "requesting file download": + var file = handlerSocket.GetPackage().ToString(); + Log("b", $"user ", "c", user.name, "b", " requested file ", "c", file + "\n"); + if (file == "manifest.dtsod") + { + lock (manifestLocker) fsp.UploadFile("share\\manifest.dtsod"); + } + else fsp.UploadFile("share\\" + file); + break; + case "requesting uuid": + Log("b", $"user ", "c", user.name, "b", " requested uuid\n"); + 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"); + break; + case "sending launcher error": + Log("y", "user ", "c", user.name, "y", "is sending error:\n"); + string error = handlerSocket.GetPackage().ToString(); + Log("y", error + '\n'); + break; + default: + throw new Exception("unknown request: " + request); + } + } + else Thread.Sleep(10); + } + } + // неизвестный юзер + else + { + LogNoTime("y", $"user with hash <{hash.HashToString()}> not found\n"); + handlerSocket.SendPackage("user not found".ToBytes()); + } + } + catch (Exception ex) + { + Log("y", $"UserStart() error:\n message:\n {ex.Message}\n{ex.StackTrace}\n"); + } + finally + { + if (handlerSocket.Connected) handlerSocket.Shutdown(SocketShutdown.Both); + handlerSocket.Close(); + Log("g", "user disconnected\n"); + } + } + + static void CreateManifestы() + { + lock (manifestLocker) + { + FSP.CreateManifest("share\\download_if_not_exist"); + FSP.CreateManifest("share\\sync_always"); + 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"); + }; + } + + static bool FindUser(byte[] hash, out (string name, string uuid) user) + { + DtsodV22 usersdb = new(File.ReadAllText("users.dtsod")); + user = new(); + if (usersdb.ContainsKey(hash.HashToString())) + { + user.name = usersdb[hash.HashToString()]["username"]; + user.uuid = usersdb[hash.HashToString()]["uuid"]; + return true; + } + else return false; + } + } +} diff --git a/minecraft-launcher-server/launcher-server.csproj b/minecraft-launcher-server/launcher-server.csproj new file mode 100644 index 0000000..e6daf15 --- /dev/null +++ b/minecraft-launcher-server/launcher-server.csproj @@ -0,0 +1,59 @@ + + + + + Debug + AnyCPU + {1DC6892C-5DC8-4C1C-94C1-CE695BD2DBC2} + 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-server/launcher-server.dtsod b/minecraft-launcher-server/launcher-server.dtsod new file mode 100644 index 0000000..61ed54f --- /dev/null +++ b/minecraft-launcher-server/launcher-server.dtsod @@ -0,0 +1,2 @@ +local_ip: ""; +local_port: 25000; \ No newline at end of file diff --git a/minecraft-launcher.sln b/minecraft-launcher.sln new file mode 100644 index 0000000..323f38d --- /dev/null +++ b/minecraft-launcher.sln @@ -0,0 +1,51 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.1.32104.313 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "launcher-client", "minecraft-launcher-client\launcher-client.csproj", "{49ADEFCE-DA46-4229-997C-3D43DD600627}" +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}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Build|Any CPU = Build|Any CPU + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + Release-net48|Any CPU = Release-net48|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {49ADEFCE-DA46-4229-997C-3D43DD600627}.Build|Any CPU.ActiveCfg = Build|Any CPU + {49ADEFCE-DA46-4229-997C-3D43DD600627}.Build|Any CPU.Build.0 = Build|Any CPU + {49ADEFCE-DA46-4229-997C-3D43DD600627}.Debug|Any CPU.ActiveCfg = Build|Any CPU + {49ADEFCE-DA46-4229-997C-3D43DD600627}.Debug|Any CPU.Build.0 = Build|Any CPU + {49ADEFCE-DA46-4229-997C-3D43DD600627}.Release|Any CPU.ActiveCfg = Build|Any CPU + {49ADEFCE-DA46-4229-997C-3D43DD600627}.Release|Any CPU.Build.0 = Build|Any CPU + {49ADEFCE-DA46-4229-997C-3D43DD600627}.Release-net48|Any CPU.ActiveCfg = Build|Any CPU + {49ADEFCE-DA46-4229-997C-3D43DD600627}.Release-net48|Any CPU.Build.0 = Build|Any CPU + {1DC6892C-5DC8-4C1C-94C1-CE695BD2DBC2}.Build|Any CPU.ActiveCfg = Build|Any CPU + {1DC6892C-5DC8-4C1C-94C1-CE695BD2DBC2}.Build|Any CPU.Build.0 = Build|Any CPU + {1DC6892C-5DC8-4C1C-94C1-CE695BD2DBC2}.Debug|Any CPU.ActiveCfg = Build|Any CPU + {1DC6892C-5DC8-4C1C-94C1-CE695BD2DBC2}.Debug|Any CPU.Build.0 = Build|Any CPU + {1DC6892C-5DC8-4C1C-94C1-CE695BD2DBC2}.Release|Any CPU.ActiveCfg = Build|Any CPU + {1DC6892C-5DC8-4C1C-94C1-CE695BD2DBC2}.Release|Any CPU.Build.0 = Build|Any CPU + {1DC6892C-5DC8-4C1C-94C1-CE695BD2DBC2}.Release-net48|Any CPU.ActiveCfg = Build|Any CPU + {1DC6892C-5DC8-4C1C-94C1-CE695BD2DBC2}.Release-net48|Any CPU.Build.0 = Build|Any CPU + {57CDC0EF-31C9-4859-90E5-AD0B302C5EAE}.Build|Any CPU.ActiveCfg = Debug|Any CPU + {57CDC0EF-31C9-4859-90E5-AD0B302C5EAE}.Build|Any CPU.Build.0 = Debug|Any CPU + {57CDC0EF-31C9-4859-90E5-AD0B302C5EAE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {57CDC0EF-31C9-4859-90E5-AD0B302C5EAE}.Debug|Any CPU.Build.0 = Debug|Any CPU + {57CDC0EF-31C9-4859-90E5-AD0B302C5EAE}.Release|Any CPU.ActiveCfg = Release|Any CPU + {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 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {5D358070-7ABE-4BD6-9A87-6A5BE8CB6BC9} + EndGlobalSection +EndGlobal