2 Star 0 Fork 0

蛋白后宫/DBMC_Core

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
克隆/下载
LauncherCore.cs 38.46 KB
一键复制 编辑 原始数据 按行查看 历史
小阿狼是也 提交于 2024-03-14 04:29 . update
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977
using MailKit.Net.Smtp;
using MailKit.Security;
using MimeKit;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using RestSharp;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
namespace DBMC_Core
{
public class LauncherCore
{
public static readonly DateTime startTime = DateTime.Now;
public string ConfigFile => Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "DBMC.json");
public static string Data => Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "data");
public static string DeLog => Path.Combine(Data, "logs");
public bool ConfigFileExists => File.Exists(ConfigFile);
public bool DeLogExists
{
get
{
if (!Directory.Exists(DeLog))
{
Directory.CreateDirectory(DeLog);
return true;
}
else
{
return true;
}
}
}
public long GenerateTimeStamp => new DateTimeOffset(DateTime.UtcNow).ToUnixTimeSeconds();
public bool HasMoreThan24HoursPassed(long timestamp)
{
// 转换时间戳为 DateTime
DateTime specifiedTime = DateTimeOffset.FromUnixTimeSeconds(timestamp).UtcDateTime;
// 获取当前 UTC 时间
DateTime currentTime = DateTime.UtcNow;
// 计算时间差
TimeSpan difference = currentTime - specifiedTime;
// 如果过去的时间超过24小时,则返回 true
return difference.TotalHours > 24;
}
public static void WriteGameLog(string message)
{
string logDirectory = Path.Combine(DeLog, "Game");
string logFile = Path.Combine(logDirectory, $"{startTime:yyyy-MM-dd_HH-mm-ss}.log");
if (!Directory.Exists(logDirectory))
{
Directory.CreateDirectory(logDirectory);
}
using (StreamWriter writer = new StreamWriter(logFile, true))
{
writer.WriteLine($"{DateTime.Now:yyyy-MM-dd HH:mm:ss} - {message}");
}
}
public static void WriteLog(string message)
{
string logDirectory = Path.Combine(DeLog, "App");
string logFile = Path.Combine(logDirectory, $"{startTime:yyyy-MM-dd_HH-mm-ss}.log");
if (!Directory.Exists(logDirectory))
{
Directory.CreateDirectory(logDirectory);
}
using (StreamWriter writer = new StreamWriter(logFile, true))
{
writer.WriteLine($"{DateTime.Now:yyyy-MM-dd HH:mm:ss} - {message}");
}
}
}
public class LauncherTools
{
public static string ToolsPath => Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "data", "tools");
public static string SavePath => Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "data", "saves");
public static string SaveBackupPath => Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "data", "saves", "backup");
public class NBTExplorer
{
public static Process process = null;
public static string NBTExplorerPath => Path.Combine(ToolsPath, "NBTExplorer");
public static string NBTExplorerExe => Path.Combine(NBTExplorerPath, "NBTExplorer.exe");
public static bool Use(string LevelPath)
{
ProcessStartInfo startInfo = new ProcessStartInfo
{
FileName = NBTExplorerExe,
Arguments = "\"" + LevelPath + "\"", // 为路径添加双引号,以防路径中有空格
UseShellExecute = false
};
try
{
process = Process.Start(startInfo); // 这里不使用using, 因为我们想保持进程开启
return process != null; // 返回进程是否启动成功
}
catch (Exception e)
{
Console.WriteLine($"启动失败: {e.Message}");
return false;
}
}
public static bool Close(bool Kill = false)
{
if (process == null) return false; // 如果进程不存在,无法关闭
if (!process.HasExited) // 检查进程是否还在运行
{
if (Kill)
{
process.Kill(); // 强制关闭进程
}
else
{
if (!process.CloseMainWindow()) // 尝试正常关闭进程
{
process.Kill(); // 如果无法正常关闭,则执行强制关闭
}
}
}
process.WaitForExit(); // 等待进程退出
process.Dispose(); // 释放进程资源
process = null; // 清空进程变量,以便下次再使用
return true;
}
}
public static bool CheckAndOutputLockedFolders(DirectoryInfo directoryPath)
{
string regionPath = Path.Combine(directoryPath.FullName, "region");
if (Directory.Exists(regionPath))
{
string distPath = directoryPath.FullName;
string tempPath = directoryPath.FullName + "_temp";
try
{
directoryPath.MoveTo(tempPath);
DirectoryInfo tempDirInfo = new DirectoryInfo(tempPath);
tempDirInfo.MoveTo(distPath);
return true;
}
catch (IOException)
{
// 如果出现 IOException,可能是因为文件夹正在被占用
Console.WriteLine($"文件夹被占用: {directoryPath.FullName}");
}
catch (UnauthorizedAccessException)
{
// 如果出现 UnauthorizedAccessException,可能是因为没有足够的权限来重命名文件夹
Console.WriteLine($"没有权限访问: {directoryPath.FullName}");
}
}
return false;
}
/// <summary>
/// 异步将指定文件夹打包成zip文件,并放到指定文件夹内
/// </summary>
/// <param name="sourceFolder">要打包的文件夹路径</param>
/// <param name="destinationFolder">压缩包需要保存的目标文件夹路径</param>
public static async Task CreateZipFromFolderAsync(string sourceFolder, string destinationFolder)
{
await Task.Run(() =>
{
string zipFileName = Path.GetFileName(sourceFolder) + ".zip";
string zipFilePath = Path.Combine(destinationFolder, zipFileName);
if (File.Exists(zipFilePath))
{
File.Delete(zipFilePath);
}
ZipFile.CreateFromDirectory(sourceFolder, zipFilePath);
});
}
/// <summary>
/// 异步将指定文件夹打包成zip文件,并放到指定文件夹内,并返回zip路径
/// </summary>
/// <param name="sourceFolder">要打包的文件夹路径</param>
/// <param name="destinationFolder">压缩包需要保存的目标文件夹路径</param>
public static async Task<string> CreateZipFromFolderAsync2(string sourceFolder, string destinationFolder)
{
return await Task.Run(() =>
{
string zipFileName = Path.GetFileName(sourceFolder) + ".zip";
string zipFilePath = Path.Combine(destinationFolder, zipFileName);
if (File.Exists(zipFilePath))
{
File.Delete(zipFilePath);
}
// 尽管ZipFile.CreateFromDirectory在这里是同步运行的,但我们仍然在Task.Run中运行它以避免阻塞主线程
ZipFile.CreateFromDirectory(sourceFolder, zipFilePath);
return zipFilePath;
});
}
public static async Task CreateBackupAsync(string sourceFolder)
{
await Task.Run(() =>
{
try
{
string newFolderName = Path.GetFileName(sourceFolder); // 新文件夹的名称
string newFolderPath = Path.Combine(SaveBackupPath, newFolderName); // 合并路径和文件夹名称
// 如果文件夹不存在,则创建它
if (!Directory.Exists(newFolderPath))
{
// 获取当前时间
DateTime now = DateTime.Now;
string formattedTime = now.ToString("yyyy-MM-dd HH:mm:ss");
Directory.CreateDirectory(newFolderPath);
string zipFileName = $"{Path.GetFileName(sourceFolder)}_{formattedTime}.zip";
string zipFilePath = Path.Combine(newFolderPath, zipFileName);
if (File.Exists(zipFilePath))
{
File.Delete(zipFilePath);
}
ZipFile.CreateFromDirectory(sourceFolder, zipFilePath);
}
else
{
}
}
catch (Exception)
{
}
});
}
public static List<SavePath> TraverseDirectories(string path)
{
DirectoryInfo directoryInfo = new DirectoryInfo(path);
List<SavePath> validSubDirectories = new List<SavePath>();
if (!directoryInfo.Exists)
{
Console.WriteLine("Directory does not exist.");
return validSubDirectories;
}
DirectoryInfo[] subDirectories = directoryInfo.GetDirectories();
foreach (DirectoryInfo subDir in subDirectories)
{
// 排除特定名称的文件夹
if (subDir.Name.Equals("mapwriter_mp_worlds", StringComparison.OrdinalIgnoreCase) ||
subDir.Name.Equals("mapwriter_sp_worlds", StringComparison.OrdinalIgnoreCase) ||
subDir.Name.Equals("NEI", StringComparison.OrdinalIgnoreCase))
{
continue;
}
validSubDirectories.Add(new SavePath
{
Name = subDir.Name,
Path = subDir.FullName,
Locked = !CheckAndOutputLockedFolders(subDir)
});
}
return validSubDirectories;
}
public static List<AllSavePath> GetSavePaths(string path)
{
DirectoryInfo directoryInfo = new DirectoryInfo(path);
List<AllSavePath> validSubDirectories = new List<AllSavePath>();
if (!directoryInfo.Exists)
{
Console.WriteLine("Directory does not exist.");
return validSubDirectories;
}
DirectoryInfo[] subDirectories = directoryInfo.GetDirectories();
foreach (DirectoryInfo subDir in subDirectories)
{
// 排除特定名称的文件夹
if (subDir.Name.Equals("mapwriter_mp_worlds", StringComparison.OrdinalIgnoreCase) ||
subDir.Name.Equals("mapwriter_sp_worlds", StringComparison.OrdinalIgnoreCase) ||
subDir.Name.Equals("NEI", StringComparison.OrdinalIgnoreCase))
{
continue;
}
validSubDirectories.Add(new AllSavePath
{
Name = subDir.Name,
Path = subDir.FullName,
Size = GetDirectorySize(subDir.FullName)
});
}
return validSubDirectories;
}
private static long GetDirectorySize(string directoryPath)
{
// 递归计算目录大小
DirectoryInfo di = new DirectoryInfo(directoryPath);
return di.EnumerateFiles("*", SearchOption.AllDirectories).Sum(fi => fi.Length);
}
}
public class EmailService
{
private string smtpHost => "smtp.exmail.qq.com";
private int smtpPort => 465;
public string smtpUsername => "y_alang@dbhg.top";
private string smtpPassword => "08230050aL@";
private bool enableSsl => true;
private string displayName => "蛋白后宫代投服务商";
private string toAddress => "505351348@qq.com";
private long maxEmailSize => 50 * 1024 * 1024;
private bool IsUrl(string input)
{
if (string.IsNullOrWhiteSpace(input))
{
return false;
}
string pattern = @"^((https|http)?:\/\/)[^\s]+";
return Regex.IsMatch(input, pattern, RegexOptions.IgnoreCase);
}
public async Task SubmissionAsync(string toAddress2, string subject, MapData mapData, string Save = null, string ResourcePack = null)
{
MimeMessage email = new MimeMessage();
email.From.Add(new MailboxAddress(displayName, smtpUsername));
email.To.Add(MailboxAddress.Parse(toAddress));
email.To.Add(MailboxAddress.Parse(toAddress2));
email.Subject = subject;
string htmlTemplate = @"
<html lang=""zh"">
<head>
<meta charset=""UTF-8"">
<meta name=""viewport"" content=""width=device-width, initial-scale=1.0"">
<style>
*{
margin: 0;
padding: 0;
}
</style>
</head>
<body>
<div style=""width: 100%;height: 100%;display: flex;flex-direction: column;justify-content: center;align-items: center;background-position: center center;background-size: cover;"">
<div class=""card"" style=""width: 80%;background-color: rgba(255, 255, 255, 0.5);border: 1px solid #ccc;box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);padding: 30px;box-sizing: border-box;border-radius: 10px;font-size: 20px;"">
<h1 style=""text-align: center"">水友图投稿</h1>
<p style=""margin-top: 10px;"">地图名称:{MapName}</p>
<p style=""margin-top: 10px;"">附属资源包:{MapResourcePack}</p>
<p style=""margin-top: 10px;"">作者名称:{MapAuthor}</p>
<p style=""margin-top: 10px;"">地图介绍:{MapIntroduce}</p>
<p style=""margin-top: 10px;"">作者斗鱼昵称:{MapDouyuName}</p>
<p style=""margin-top: 10px;"">作者的话:{MapAuthorTalk}</p>
<p style=""margin-top: 10px;"">如果地图有问题的话请使用 作者的邮箱:{MapAuthorMail} 进行回复。</p>
</div>
<div class=""card"" style=""width: 80%;background-color: rgba(255, 255, 255, 0.5);border: 1px solid #ccc;box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);padding: 20px;box-sizing: border-box;border-radius: 10px;font-size: 20px;margin-top: 10px;text-align: center;"">
<span> 本条邮件由“蛋白后宫代投服务”代发,请勿直接回复!!!</span>
</div>
</div>
</body>
</html>";
htmlTemplate = htmlTemplate.Replace("{MapName}", mapData.MapName)
.Replace("{MapResourcePack}", IsUrl(mapData.MapResourcePack) ? $@"<a href=""{mapData.MapResourcePack}"">点击下载</a>" : Path.GetFileName(mapData.MapResourcePack))
.Replace("{MapAuthor}", mapData.MapAuthor)
.Replace("{MapIntroduce}", mapData.MapIntroduce)
.Replace("{MapDouyuName}", mapData.MapDouyuName)
.Replace("{MapAuthorTalk}", string.IsNullOrEmpty(mapData.MapAuthorTalk) ? "无" : mapData.MapAuthorTalk)
.Replace("{MapAuthorMail}", mapData.MapAuthorMail);
BodyBuilder builder = new BodyBuilder { HtmlBody = htmlTemplate };
long totalFileSize = 0;
Action<string> addFileSize = (string filePath) => {
if (!string.IsNullOrEmpty(filePath) && File.Exists(filePath))
{
FileInfo fileInfo = new FileInfo(filePath);
totalFileSize += fileInfo.Length;
}
};
addFileSize(Save);
addFileSize(ResourcePack);
if (totalFileSize >= maxEmailSize)
{
throw new InvalidOperationException("文件尺寸之和太大,不能超过50MB。");
}
if (totalFileSize > 0)
{
if (!string.IsNullOrEmpty(Save) && File.Exists(Save))
{
// 只传递文件路径的字符串
builder.Attachments.Add(Save);
}
if (!string.IsNullOrEmpty(ResourcePack) && File.Exists(ResourcePack))
{
// 只传递文件路径的字符串
builder.Attachments.Add(ResourcePack);
}
}
// 构建最终邮件正文
email.Body = builder.ToMessageBody();
email.Priority = MessagePriority.Urgent;
// 使用SMTP客户端发送邮件
using (SmtpClient client = new SmtpClient())
{
try
{
// 连接到SMTP服务器
await client.ConnectAsync(smtpHost, smtpPort, enableSsl ? SecureSocketOptions.SslOnConnect : SecureSocketOptions.StartTls).ConfigureAwait(false);
// 如果需要的话,进行身份验证
await client.AuthenticateAsync(smtpUsername, smtpPassword).ConfigureAwait(false);
// 发送邮件
await client.SendAsync(email).ConfigureAwait(false);
// 断开连接
await client.DisconnectAsync(true).ConfigureAwait(false);
}
catch (Exception ex)
{
// 如果发送邮件过程中发生异常,抛出异常
throw new Exception("发送失败。", ex);
}
finally
{
// 确保流被关闭,即使发生错误
foreach (MimeEntity attachment in builder.Attachments)
{
if (attachment is MimePart part)
{
part.Content.Stream.Dispose();
}
}
}
}
}
public class MapData
{
public string MapName;
public string MapResourcePack;
public string MapAuthor;
public string MapIntroduce;
public string MapDouyuName;
public string MapAuthorTalk;
public string MapAuthorMail;
}
}
public class SavePath
{
public string Name { get; set; }
public string Path { get; set; }
public bool Locked { get; set; }
}
public class AllSavePath : INotifyPropertyChanged
{
private string name;
private string path;
private long size;
public string Name
{
get => name;
set { name = value; OnPropertyChanged(nameof(Name)); }
}
public string Path
{
get => path;
set { path = value; OnPropertyChanged(nameof(Path)); }
}
public long Size
{
get => size;
set
{
size = value;
SizeFormatted = FormatSize(value);
OnPropertyChanged(nameof(Size));
}
}
public string SizeFormatted { get; private set; }
private string FormatSize(long size)
{
string[] sizes = { "B", "KB", "MB", "GB", "TB" };
double formattedSize = size;
int order = 0;
while (formattedSize >= 1024 && order < sizes.Length - 1)
{
order++;
formattedSize /= 1024;
}
// 保留两位小数
return String.Format("{0:0.##} {1}", formattedSize, sizes[order]);
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
public class MinecraftServerConnection : IDisposable
{
public TcpClient client;
public MinecraftServerInfo ServerInfo { get; private set; }
public MinecraftServerConnection(IPAddress ip, int port)
{
client = new TcpClient();
client.Connect(new IPEndPoint(ip, port));
ServerInfo = MinecraftServerInfo.GetServerInformation(client);
}
public void Disconnect()
{
if (client != null && client.Connected)
{
client.GetStream().Close();
client.Close();
}
}
public void Dispose()
{
Disconnect();
}
}
public sealed class MinecraftServerInfo
{
/// <summary>
/// 获取服务器/房间的 MOTD
/// </summary>
public string ServerMotd { get; private set; }
/// <summary>
/// 获取服务器/房间的 MOTD 转换为 HTML
/// </summary>
public string ServerMotdHtml => MotdHtml();
/// <summary>
/// 获取服务器/房间的最大玩家数
/// </summary>
public int MaxPlayerCount { get; private set; }
/// <summary>
/// 获取服务器/房间当前玩家人数
/// </summary>
public int CurrentPlayerCount { get; private set; }
/// <summary>
/// 获取服务器/房间的 Minecraft 版本
/// </summary>
public Version MinecraftVersion { get; private set; }
/// <summary>
/// 获取与特定格式代码关联的 HTML 颜色
/// </summary>
private static Dictionary<char, string> MinecraftColors { get { return new Dictionary<char, string>() { { '0', "#000000" }, { '1', "#0000AA" }, { '2', "#00AA00" }, { '3', "#00AAAA" }, { '4', "#AA0000" }, { '5', "#AA00AA" }, { '6', "#FFAA00" }, { '7', "#AAAAAA" }, { '8', "#555555" }, { '9', "#5555FF" }, { 'a', "#55FF55" }, { 'b', "#55FFFF" }, { 'c', "#FF5555" }, { 'd', "#FF55FF" }, { 'e', "#FFFF55" }, { 'f', "#FFFFFF" } }; } }
/// <summary>
/// 获取与特定格式代码关联的 HTML 样式
/// </summary>
private static Dictionary<char, string> MinecraftStyles => new Dictionary<char, string>() { { 'k', "none;font-weight:normal;font-style:normal" }, { 'm', "line-through;font-weight:normal;font-style:normal" }, { 'l', "none;font-weight:900;font-style:normal" }, { 'n', "underline;font-weight:normal;font-style:normal;" }, { 'o', "none;font-weight:normal;font-style:italic;" }, { 'r', "none;font-weight:normal;font-style:normal;color:#FFFFFF;" } };
/// <summary>
/// 使用指定值创建 <see cref="MinecraftServerInfo"/> 的新实例
/// </summary>
/// <param name="motd">MOTD(标题)</param>
/// <param name="maxplayers">最大玩家数</param>
/// <param name="playercount">当前玩家人数</param>
/// <param name="version">Minecraft 版本</param>
private MinecraftServerInfo(string motd, int maxplayers, int playercount, Version mcversion)
{
ServerMotd = motd;
MaxPlayerCount = maxplayers;
CurrentPlayerCount = playercount;
MinecraftVersion = mcversion;
}
/// <summary>
/// 获取服务器/房间的 MOTD 格式为 HTML
/// </summary>
/// <returns>HTML 格式的 MOTD</returns>
private string MotdHtml()
{
Regex regex = new Regex("§([k-oK-O])(.*?)(§[0-9a-fA-Fk-oK-OrR]|$)");
string s = this.ServerMotd;
while (regex.IsMatch(s))
s = regex.Replace(s, m =>
{
string ast = "text-decoration:" + MinecraftStyles[m.Groups[1].Value[0]];
string html = "<span style=\"" + ast + "\">" + m.Groups[2].Value + "</span>" + m.Groups[3].Value;
return html;
});
regex = new Regex("§([0-9a-fA-F])(.*?)(§[0-9a-fA-FrR]|$)");
while (regex.IsMatch(s))
s = regex.Replace(s, m =>
{
string ast = "color:" + MinecraftColors[m.Groups[1].Value[0]];
string html = "<span style=\"" + ast + "\">" + m.Groups[2].Value + "</span>" + m.Groups[3].Value;
return html;
});
return s;
}
/// <summary>
///从指定服务器/房间获取信息
/// </summary>
/// <param name="endpoint">获取信息的服务器/房间的IP和端口</param>
/// <returns>A <see cref="MinecraftServerInformation"/>具有检索数据的实例</returns>
/// <exception cref="System.Exception">失败时,抛出带有描述信息的异常和带有详细信息的 InnerException</exception>
public static MinecraftServerInfo GetServerInformation(TcpClient client)
{
try
{
string[] packetdat = null;
using (NetworkStream ns = client.GetStream())
{
ns.Write(new byte[] { 0xFE, 0x01 }, 0, 2);
byte[] buff = new byte[2048];
int br = ns.Read(buff, 0, buff.Length);
if (buff[0] != 0xFF)
throw new InvalidDataException("Received invalid packet");
string packet = Encoding.BigEndianUnicode.GetString(buff, 3, br - 3);
if (!packet.StartsWith("§"))
throw new InvalidDataException("Received invalid data");
packetdat = packet.Split('\u0000');
ns.Close();
}
client.Close();
return new MinecraftServerInfo(packetdat[3], int.Parse(packetdat[5]), int.Parse(packetdat[4]), Version.Parse(packetdat[2]));
}
catch (SocketException ex)
{
throw new Exception("连接出现问题,请查看 InnerException 了解详细信息", ex);
}
catch (InvalidDataException ex)
{
throw new Exception("收到的数据无效,查看 InnerException 了解详细信息", ex);
}
catch (Exception ex)
{
throw new Exception("出现问题,查看 InnerException 了解详细信息", ex);
}
}
/// <summary>
/// 从指定服务器/房间获取信息
/// </summary>
/// <param name="ip">服务器/房间的IP</param>
/// <param name="port">服务器/房间的端口</param>
/// <returns>A <see cref="MinecraftServerInformation"/> 具有检索数据的实例</returns>
/// <exception cref="System.Exception">失败时,抛出带有描述信息的异常和带有详细信息的 InnerException</exception>
//public static MinecraftServerInfo GetServerInformation(IPAddress ip, int port)
//{
// return GetServerInformation(new IPEndPoint(ip, port));
//}
}
public class MicrosoftOAuth
{
public string DeviceCodeApi => "https://login.microsoftonline.com/consumers/oauth2/v2.0/devicecode";
public string DeviceCodeTokenApi => "https://login.microsoftonline.com/consumers/oauth2/v2.0/token";
public string XboxTokenApi => "https://user.auth.xboxlive.com/user/authenticate";
public string XstsTokenApi => "https://xsts.auth.xboxlive.com/xsts/authorize";
public string MinecraftTokenApi => "https://api.minecraftservices.com/authentication/login_with_xbox";
public string ClientId => "eddd02fb-122b-4065-a56f-5c68fa2d3afe";
public string ClientSecret => "ZcY8Q~vz2c8wO~_NgMGtMMJejFU~WaBJW3MaybhU";
public string GetDeviceCode()
{
RestClient client = new RestClient(DeviceCodeApi);
RestRequest request = new RestRequest
{
Method = Method.Post,
Timeout = 30000,
};
request.AddHeader("Host", "login.microsoftonline.com");
request.AddHeader("Content-Type", "application/x-www-form-urlencoded");
request.AddParameter("client_id", ClientId);
request.AddParameter("scope", "XboxLive.offline_access XboxLive.signin");
RestResponse response = client.Execute(request);
if (response.IsSuccessful)
{
return response.Content;
}
else
{
return null;
}
}
public async Task<string> GetDeviceCodeToken(string Code)
{
RestClient client = new RestClient(DeviceCodeTokenApi);
RestRequest request = new RestRequest
{
Method = Method.Post,
Timeout = 30000,
};
request.AddHeader("Host", "login.microsoftonline.com");
request.AddHeader("Content-Type", "application/x-www-form-urlencoded");
request.AddParameter("client_id", ClientId);
request.AddParameter("grant_type", "urn:ietf:params:oauth:grant-type:device_code");
request.AddParameter("code", Code);
RestResponse response = await client.ExecuteAsync(request);
return response.Content;
}
/// <summary>
/// 刷新微软Token
/// </summary>
/// <param name="refresh_token">微软 Refresh_Token</param>
/// <returns>返回Json数据</returns>
public async Task<string> RefreshToToken(string refresh_token)
{
RestClient client = new RestClient(DeviceCodeTokenApi);
RestRequest request = new RestRequest
{
Method = Method.Post,
Timeout = 30000,
};
request.AddHeader("Host", "login.microsoftonline.com");
request.AddHeader("Content-Type", "application/x-www-form-urlencoded");
request.AddParameter("client_id", ClientId);
request.AddParameter("grant_type", "refresh_token");
request.AddParameter("refresh_token", refresh_token);
request.AddParameter("scope", "XboxLive.offline_access XboxLive.signin");
RestResponse response = await client.ExecuteAsync(request);
if (response.IsSuccessful)
{
return response.Content;
}
else
{
Console.WriteLine($"RefreshToToken error: {response.StatusCode} - {response.ErrorMessage}");
return null;
}
}
/// <summary>
/// 获取XboxToken
/// </summary>
/// <param name="Access_Token">微软Access_Token</param>
/// <returns>返回Json数据</returns>
public async Task<string> GetXboxToken(string Access_Token)
{
RestClient client = new RestClient(XboxTokenApi);
RestRequest request = new RestRequest
{
Method = Method.Post,
Timeout = 30000,
};
request.AddHeader("Accept", "application/json");
request.AddHeader("Content-Type", "application/json");
// 构建请求体对象
var requestBody = new
{
Properties = new
{
AuthMethod = "RPS",
SiteName = "user.auth.xboxlive.com",
RpsTicket = $@"d={Access_Token}" // 替换为实际的 RpsTicket
},
RelyingParty = "http://auth.xboxlive.com",
TokenType = "JWT"
};
request.AddJsonBody(JsonConvert.SerializeObject(requestBody));
RestResponse response = await client.ExecuteAsync(request);
if (response.IsSuccessful)
{
return response.Content;
}
else
{
Console.WriteLine($"XboxToken error: {response.StatusCode} - {response.ErrorMessage}");
return null;
}
}
/// <summary>
/// 获取XstsToken
/// </summary>
/// <param name="Access_Token">Xbox RpsTicket</param>
/// <returns>返回Json数据</returns>
public async Task<string> GetXsts(string RpsTicket)
{
RestClient client = new RestClient(XstsTokenApi);
RestRequest request = new RestRequest
{
Method = Method.Post,
Timeout = 30000,
};
request.AddHeader("Accept", "application/json");
request.AddHeader("Content-Type", "application/json");
var requestBody = new
{
Properties = new
{
SandboxId = "RETAIL",
UserTokens = new string[] { RpsTicket }
},
RelyingParty = "rp://api.minecraftservices.com/",
TokenType = "JWT"
};
request.AddJsonBody(JsonConvert.SerializeObject(requestBody));
RestResponse response = await client.ExecuteAsync(request);
if (response.IsSuccessful)
{
return response.Content;
}
else
{
Console.WriteLine($"Xsts error: {response.StatusCode} - {response.ErrorMessage}");
return null;
}
}
/// <summary>
/// 获取MinecraftToken
/// </summary>
/// <param name="uhs">Xsts uhs</param>
/// <param name="token">Xsts Token</param>
/// <returns>返回Json数据</returns>
public async Task<string> GetMinecraftToken(string uhs, string token)
{
RestClient client = new RestClient(MinecraftTokenApi);
RestRequest request = new RestRequest
{
Method = Method.Post,
Timeout = 30000,
};
request.AddHeader("Accept", "application/json");
request.AddHeader("Content-Type", "application/json");
// 构建请求体对象
var requestBody = new
{
identityToken = $@"XBL3.0 x={uhs};{token}",
ensureLegacyEnabled = true
};
request.AddJsonBody(JsonConvert.SerializeObject(requestBody));
RestResponse response = await client.ExecuteAsync(request);
if (response.IsSuccessful)
{
return response.Content;
}
else
{
Console.WriteLine($"MinecraftToken error: {response.StatusCode} - {response.ErrorMessage}");
return null;
}
}
/// <summary>
/// 获取Minecraft档案
/// </summary>
/// <param name="token">MinecraftToken</param>
/// <returns>返回Json数据</returns>
public async Task<string> GetMinecraftProfile(string token)
{
RestClient client = new RestClient("https://api.minecraftservices.com/minecraft/profile");
RestRequest request = new RestRequest
{
Method = Method.Get,
Timeout = 30000,
};
request.AddHeader("Authorization", $@"Bearer {token}");
request.AddHeader("Host", "api.minecraftservices.com");
RestResponse response = await client.ExecuteAsync(request);
if (response.IsSuccessful)
{
return response.Content;
}
else
{
Console.WriteLine($"MinecraftProfile error: {response.StatusCode} - {response.ErrorMessage}");
return null;
}
}
public async Task<dynamic> LoginAsync(string xboxtoken)
{
Console.WriteLine(xboxtoken);
string XboxToken = await GetXboxToken(xboxtoken);
if (XboxToken != null)
{
dynamic XboxTokenRes = JsonConvert.DeserializeObject(XboxToken);
if (XboxTokenRes.Token != null)
{
Console.WriteLine("XboxToken", XboxTokenRes.Token);
string Xsts = await GetXsts((string)XboxTokenRes.Token);
if (Xsts != null)
{
Console.WriteLine("Xsts");
JObject jsonResponse = JObject.Parse(Xsts);
string token = jsonResponse["Token"].ToString();
string uhs = jsonResponse["DisplayClaims"]["xui"][0]["uhs"].ToString();
if (uhs != null && token != null)
{
string MinecraftToken = await GetMinecraftToken(uhs, token);
if (MinecraftToken != null)
{
Console.WriteLine("MinecraftToken");
dynamic MinecraftTokenRes = JsonConvert.DeserializeObject(MinecraftToken);
if (MinecraftTokenRes.access_token != null)
{
string MinecraftProfile = await GetMinecraftProfile((string)MinecraftTokenRes.access_token);
if (MinecraftProfile != null)
{
Console.WriteLine("MinecraftProfile");
dynamic MinecraftProfileRes = JsonConvert.DeserializeObject(MinecraftProfile);
if (MinecraftProfileRes.name != null && MinecraftProfileRes.id != null)
{
return MinecraftProfileRes;
}
}
}
}
}
}
}
}
return null;
}
}
}
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
1
https://gitee.com/dbhg/dbmc_core.git
git@gitee.com:dbhg/dbmc_core.git
dbhg
dbmc_core
DBMC_Core
master

搜索帮助