mirror of
https://github.com/MCCTeam/Minecraft-Console-Client
synced 2026-08-15 13:04:36 +00:00
Stage 1
This commit is contained in:
parent
1ca023be36
commit
3a4d8951d5
20 changed files with 1511 additions and 389 deletions
|
|
@ -2,6 +2,8 @@ using System;
|
|||
using System.Collections.Generic;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using MinecraftClient.Inventory;
|
||||
using MinecraftClient.Inventory.ItemPalettes;
|
||||
using MinecraftClient.Mapping;
|
||||
|
|
@ -313,6 +315,27 @@ namespace MinecraftClient.Protocol.Handlers
|
|||
return i;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read an integer from the network asynchronously.
|
||||
/// </summary>
|
||||
/// <returns>The integer</returns>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public async Task<int> ReadNextVarIntRAWAsync(SocketWrapper socket, CancellationToken cancellationToken)
|
||||
{
|
||||
int i = 0;
|
||||
int j = 0;
|
||||
byte b;
|
||||
while (true)
|
||||
{
|
||||
b = (await socket.ReadDataRAWAsync(1, cancellationToken))[0];
|
||||
i |= (b & 0x7F) << j++ * 7;
|
||||
if (j > 5) throw new OverflowException("VarInt too big");
|
||||
if ((b & 0x80) != 128) break;
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read an integer from a cache of bytes and remove it from the cache
|
||||
/// </summary>
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ using System.Net.Sockets;
|
|||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using MinecraftClient.Crypto;
|
||||
using MinecraftClient.Inventory;
|
||||
using MinecraftClient.Mapping;
|
||||
|
|
@ -29,7 +30,9 @@ namespace MinecraftClient.Protocol.Handlers
|
|||
readonly IMinecraftComHandler handler;
|
||||
private bool encrypted = false;
|
||||
private readonly int protocolversion;
|
||||
private Tuple<Thread, CancellationTokenSource>? netRead = null;
|
||||
private Task? netReadTask;
|
||||
private CancellationTokenSource? netReadCancellationTokenSource;
|
||||
private int netReadThreadId = -1;
|
||||
Crypto.AesCfb8Stream? s;
|
||||
readonly TcpClient c;
|
||||
|
||||
|
|
@ -69,15 +72,15 @@ namespace MinecraftClient.Protocol.Handlers
|
|||
c = Client;
|
||||
}
|
||||
|
||||
private void Updater(object? o)
|
||||
private void Updater(CancellationToken cancelToken)
|
||||
{
|
||||
var cancelToken = (CancellationToken)o!;
|
||||
|
||||
if (cancelToken.IsCancellationRequested)
|
||||
return;
|
||||
|
||||
try
|
||||
{
|
||||
netReadThreadId = Environment.CurrentManagedThreadId;
|
||||
using IDisposable _ = MainThreadExecutionScope.Enter(handler);
|
||||
Stopwatch stopWatch = Stopwatch.StartNew();
|
||||
long nextUpdateDue = 0;
|
||||
|
||||
|
|
@ -104,6 +107,8 @@ namespace MinecraftClient.Protocol.Handlers
|
|||
catch (SocketException) { }
|
||||
catch (ObjectDisposedException) { }
|
||||
catch (OperationCanceledException) { }
|
||||
catch (Exception) { }
|
||||
finally { netReadThreadId = -1; }
|
||||
|
||||
if (cancelToken.IsCancellationRequested)
|
||||
return;
|
||||
|
|
@ -240,9 +245,13 @@ namespace MinecraftClient.Protocol.Handlers
|
|||
|
||||
private void StartUpdating()
|
||||
{
|
||||
netRead = new(new Thread(new ParameterizedThreadStart(Updater)), new CancellationTokenSource());
|
||||
netRead.Item1.Name = "ProtocolPacketHandler";
|
||||
netRead.Item1.Start(netRead.Item2.Token);
|
||||
CancellationTokenSource netReadCts = new();
|
||||
netReadCancellationTokenSource = netReadCts;
|
||||
netReadTask = Task.Factory.StartNew(
|
||||
() => Updater(netReadCts.Token),
|
||||
netReadCts.Token,
|
||||
TaskCreationOptions.LongRunning,
|
||||
TaskScheduler.Default);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -251,7 +260,7 @@ namespace MinecraftClient.Protocol.Handlers
|
|||
/// <returns>Net read thread ID</returns>
|
||||
public int GetNetMainThreadId()
|
||||
{
|
||||
return netRead is not null ? netRead.Item1.ManagedThreadId : -1;
|
||||
return netReadThreadId;
|
||||
}
|
||||
|
||||
public bool SendCookieResponse(string name, byte[]? data)
|
||||
|
|
@ -268,9 +277,9 @@ namespace MinecraftClient.Protocol.Handlers
|
|||
{
|
||||
try
|
||||
{
|
||||
if (netRead is not null)
|
||||
if (netReadCancellationTokenSource is not null)
|
||||
{
|
||||
netRead.Item2.Cancel();
|
||||
netReadCancellationTokenSource.Cancel();
|
||||
c.Close();
|
||||
}
|
||||
}
|
||||
|
|
@ -519,7 +528,8 @@ namespace MinecraftClient.Protocol.Handlers
|
|||
Receive(pid, 0, 1, SocketFlags.None);
|
||||
while (pid[0] == 0xFA) //Skip some early plugin messages
|
||||
{
|
||||
ProcessPacket(pid[0]);
|
||||
using (MainThreadExecutionScope.Enter(handler))
|
||||
ProcessPacket(pid[0]);
|
||||
Receive(pid, 0, 1, SocketFlags.None);
|
||||
}
|
||||
if (pid[0] == 0xFD)
|
||||
|
|
@ -559,8 +569,7 @@ namespace MinecraftClient.Protocol.Handlers
|
|||
if (session.ServerPublicKey is not null && session.SessionPreCheckTask is not null
|
||||
&& serverIDhash == session.ServerIDhash && Enumerable.SequenceEqual(serverPublicKey, session.ServerPublicKey))
|
||||
{
|
||||
session.SessionPreCheckTask.Wait();
|
||||
if (session.SessionPreCheckTask.Result) // PreCheck Successed
|
||||
if (session.SessionPreCheckTask.IsCompletedSuccessfully && session.SessionPreCheckTask.Result)
|
||||
needCheckSession = false;
|
||||
}
|
||||
|
||||
|
|
@ -633,7 +642,8 @@ namespace MinecraftClient.Protocol.Handlers
|
|||
Receive(pid, 0, 1, SocketFlags.None);
|
||||
while (pid[0] >= 0xC0 && pid[0] != 0xFF) //Skip some early packets or plugin messages
|
||||
{
|
||||
ProcessPacket(pid[0]);
|
||||
using (MainThreadExecutionScope.Enter(handler))
|
||||
ProcessPacket(pid[0]);
|
||||
Receive(pid, 0, 1, SocketFlags.None);
|
||||
}
|
||||
if (pid[0] == (byte)1)
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ using System.Security.Cryptography;
|
|||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using MinecraftClient.Crypto;
|
||||
using MinecraftClient.Inventory;
|
||||
using MinecraftClient.Inventory.ItemPalettes;
|
||||
|
|
@ -117,8 +118,11 @@ namespace MinecraftClient.Protocol.Handlers
|
|||
readonly PacketTypePalette packetPalette;
|
||||
readonly SocketWrapper socketWrapper;
|
||||
readonly DataTypes dataTypes;
|
||||
Tuple<Thread, CancellationTokenSource>? netMain = null; // main thread
|
||||
Tuple<Thread, CancellationTokenSource>? netReader = null; // reader thread
|
||||
private Task? netMainTask;
|
||||
private CancellationTokenSource? netMainCancellationTokenSource;
|
||||
private int netMainThreadId = -1;
|
||||
private Task? netReaderTask;
|
||||
private CancellationTokenSource? netReaderCancellationTokenSource;
|
||||
readonly ILogger log;
|
||||
readonly RandomNumberGenerator randomGen;
|
||||
private bool legacyAchievementsInitialized;
|
||||
|
|
@ -278,17 +282,17 @@ namespace MinecraftClient.Protocol.Handlers
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// Separate thread. Network reading loop.
|
||||
/// Serialized packet/tick loop.
|
||||
/// </summary>
|
||||
private void Updater(object? o)
|
||||
private void Updater(CancellationToken cancelToken)
|
||||
{
|
||||
var cancelToken = (CancellationToken)o!;
|
||||
|
||||
if (cancelToken.IsCancellationRequested)
|
||||
return;
|
||||
|
||||
try
|
||||
{
|
||||
netMainThreadId = Environment.CurrentManagedThreadId;
|
||||
using IDisposable _ = MainThreadExecutionScope.Enter(handler);
|
||||
Stopwatch stopWatch = Stopwatch.StartNew();
|
||||
long nextUpdateDue = 0;
|
||||
while (!packetQueue.IsAddingCompleted)
|
||||
|
|
@ -330,6 +334,13 @@ namespace MinecraftClient.Protocol.Handlers
|
|||
catch (System.IO.IOException)
|
||||
{
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
}
|
||||
finally
|
||||
{
|
||||
netMainThreadId = -1;
|
||||
}
|
||||
|
||||
if (cancelToken.IsCancellationRequested)
|
||||
return;
|
||||
|
|
@ -340,20 +351,13 @@ namespace MinecraftClient.Protocol.Handlers
|
|||
/// <summary>
|
||||
/// Read and decompress packets.
|
||||
/// </summary>
|
||||
internal void PacketReader(object? o)
|
||||
internal async Task PacketReaderAsync(CancellationToken cancelToken)
|
||||
{
|
||||
var cancelToken = (CancellationToken)o!;
|
||||
while (socketWrapper.IsConnected() && !cancelToken.IsCancellationRequested)
|
||||
while (!cancelToken.IsCancellationRequested)
|
||||
{
|
||||
try
|
||||
{
|
||||
while (socketWrapper.HasDataAvailable())
|
||||
{
|
||||
packetQueue.Add(ReadNextPacket(), cancelToken);
|
||||
|
||||
if (cancelToken.IsCancellationRequested)
|
||||
break;
|
||||
}
|
||||
packetQueue.Add(await ReadNextPacketAsync(cancelToken), cancelToken);
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
|
|
@ -375,11 +379,10 @@ namespace MinecraftClient.Protocol.Handlers
|
|||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if (cancelToken.IsCancellationRequested)
|
||||
catch (Exception)
|
||||
{
|
||||
break;
|
||||
|
||||
Thread.Sleep(10);
|
||||
}
|
||||
}
|
||||
|
||||
packetQueue.CompleteAdding();
|
||||
|
|
@ -415,6 +418,30 @@ namespace MinecraftClient.Protocol.Handlers
|
|||
return new(packetId, packetData);
|
||||
}
|
||||
|
||||
internal async Task<Tuple<int, Queue<byte>>> ReadNextPacketAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
var size = await dataTypes.ReadNextVarIntRAWAsync(socketWrapper, cancellationToken); //Packet size
|
||||
Queue<byte> packetData = new(await socketWrapper.ReadDataRAWAsync(size, cancellationToken)); //Packet contents
|
||||
|
||||
if (protocolVersion >= MC_1_8_Version
|
||||
&& compression_treshold >= 0)
|
||||
{
|
||||
var sizeUncompressed = dataTypes.ReadNextVarInt(packetData);
|
||||
if (sizeUncompressed != 0)
|
||||
{
|
||||
var toDecompress = packetData.ToArray();
|
||||
var uncompressed = ZlibUtils.Decompress(toDecompress, sizeUncompressed);
|
||||
packetData = new Queue<byte>(uncompressed);
|
||||
}
|
||||
}
|
||||
|
||||
var packetId = dataTypes.ReadNextVarInt(packetData);
|
||||
if (handler.GetNetworkPacketCaptureEnabled())
|
||||
handler.OnNetworkPacket(packetId, packetData.ToList(), currentState == CurrentState.Login, true);
|
||||
|
||||
return new(packetId, packetData);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handle the given packet
|
||||
/// </summary>
|
||||
|
|
@ -3844,19 +3871,17 @@ namespace MinecraftClient.Protocol.Handlers
|
|||
/// </summary>
|
||||
private void StartUpdating()
|
||||
{
|
||||
Thread threadUpdater = new(new ParameterizedThreadStart(Updater))
|
||||
{
|
||||
Name = "ProtocolPacketHandler"
|
||||
};
|
||||
netMain = new Tuple<Thread, CancellationTokenSource>(threadUpdater, new CancellationTokenSource());
|
||||
threadUpdater.Start(netMain.Item2.Token);
|
||||
CancellationTokenSource netMainCts = new();
|
||||
netMainCancellationTokenSource = netMainCts;
|
||||
netMainTask = Task.Factory.StartNew(
|
||||
() => Updater(netMainCts.Token),
|
||||
netMainCts.Token,
|
||||
TaskCreationOptions.LongRunning,
|
||||
TaskScheduler.Default);
|
||||
|
||||
Thread threadReader = new(new ParameterizedThreadStart(PacketReader))
|
||||
{
|
||||
Name = "ProtocolPacketReader"
|
||||
};
|
||||
netReader = new Tuple<Thread, CancellationTokenSource>(threadReader, new CancellationTokenSource());
|
||||
threadReader.Start(netReader.Item2.Token);
|
||||
CancellationTokenSource netReaderCts = new();
|
||||
netReaderCancellationTokenSource = netReaderCts;
|
||||
netReaderTask = PacketReaderAsync(netReaderCts.Token);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -3865,7 +3890,7 @@ namespace MinecraftClient.Protocol.Handlers
|
|||
/// <returns>Net read thread ID</returns>
|
||||
public int GetNetMainThreadId()
|
||||
{
|
||||
return netMain is not null ? netMain.Item1.ManagedThreadId : -1;
|
||||
return netMainThreadId;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -3875,14 +3900,14 @@ namespace MinecraftClient.Protocol.Handlers
|
|||
{
|
||||
try
|
||||
{
|
||||
if (netMain is not null)
|
||||
if (netMainCancellationTokenSource is not null)
|
||||
{
|
||||
netMain.Item2.Cancel();
|
||||
netMainCancellationTokenSource.Cancel();
|
||||
}
|
||||
|
||||
if (netReader is not null)
|
||||
if (netReaderCancellationTokenSource is not null)
|
||||
{
|
||||
netReader.Item2.Cancel();
|
||||
netReaderCancellationTokenSource.Cancel();
|
||||
socketWrapper.Disconnect();
|
||||
}
|
||||
}
|
||||
|
|
@ -4106,7 +4131,8 @@ namespace MinecraftClient.Protocol.Handlers
|
|||
return true; //No need to check session or start encryption
|
||||
}
|
||||
default:
|
||||
HandlePacket(packetId, packetData);
|
||||
using (MainThreadExecutionScope.Enter(handler))
|
||||
HandlePacket(packetId, packetData);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
@ -4133,8 +4159,7 @@ namespace MinecraftClient.Protocol.Handlers
|
|||
&& serverIDhash == session.ServerIDhash &&
|
||||
serverPublicKey.SequenceEqual(session.ServerPublicKey))
|
||||
{
|
||||
session.SessionPreCheckTask.Wait();
|
||||
if (session.SessionPreCheckTask.Result) // PreCheck Success
|
||||
if (session.SessionPreCheckTask.IsCompletedSuccessfully && session.SessionPreCheckTask.Result)
|
||||
needCheckSession = false;
|
||||
}
|
||||
|
||||
|
|
@ -4256,7 +4281,8 @@ namespace MinecraftClient.Protocol.Handlers
|
|||
return true;
|
||||
}
|
||||
default:
|
||||
HandlePacket(packetId, packetData);
|
||||
using (MainThreadExecutionScope.Enter(handler))
|
||||
HandlePacket(packetId, packetData);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,8 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
using System.Net.Sockets;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using MinecraftClient.Crypto;
|
||||
|
||||
namespace MinecraftClient.Protocol.Handlers
|
||||
|
|
@ -68,6 +71,22 @@ namespace MinecraftClient.Protocol.Handlers
|
|||
}
|
||||
}
|
||||
|
||||
private async Task ReceiveAsync(Memory<byte> buffer, CancellationToken cancellationToken)
|
||||
{
|
||||
int read = 0;
|
||||
while (read < buffer.Length)
|
||||
{
|
||||
int currentRead = encrypted
|
||||
? await s!.ReadAsync(buffer[read..], cancellationToken)
|
||||
: await c.GetStream().ReadAsync(buffer[read..], cancellationToken);
|
||||
|
||||
if (currentRead == 0)
|
||||
throw new IOException("Connection closed.");
|
||||
|
||||
read += currentRead;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read some data from the server.
|
||||
/// </summary>
|
||||
|
|
@ -84,6 +103,18 @@ namespace MinecraftClient.Protocol.Handlers
|
|||
return Array.Empty<byte>();
|
||||
}
|
||||
|
||||
public async Task<byte[]> ReadDataRAWAsync(int length, CancellationToken cancellationToken)
|
||||
{
|
||||
if (length > 0)
|
||||
{
|
||||
byte[] cache = new byte[length];
|
||||
await ReceiveAsync(cache, cancellationToken);
|
||||
return cache;
|
||||
}
|
||||
|
||||
return Array.Empty<byte>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Send raw data to the server.
|
||||
/// </summary>
|
||||
|
|
@ -99,6 +130,17 @@ namespace MinecraftClient.Protocol.Handlers
|
|||
c.Client.Send(buffer);
|
||||
}
|
||||
|
||||
public async Task SendDataRAWAsync(ReadOnlyMemory<byte> buffer, CancellationToken cancellationToken)
|
||||
{
|
||||
if (!IsConnected())
|
||||
throw new SocketException((int)SocketError.NotConnected);
|
||||
|
||||
if (encrypted)
|
||||
await s!.WriteAsync(buffer, cancellationToken);
|
||||
else
|
||||
await c.GetStream().WriteAsync(buffer, cancellationToken);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Disconnect from the server
|
||||
/// </summary>
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ using System.Net.Http.Json;
|
|||
using System.Text;
|
||||
using System.Text.Json;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using static MinecraftClient.Settings;
|
||||
|
||||
|
|
@ -231,6 +232,8 @@ namespace MinecraftClient.Protocol.Message
|
|||
/// Specify whether translation rules have been loaded
|
||||
/// </summary>
|
||||
private static bool RulesInitialized = false;
|
||||
private static readonly Lock RulesInitializationLock = new();
|
||||
private static Task? RulesRefreshTask = null;
|
||||
|
||||
/// <summary>
|
||||
/// Set of translation rules for formatting text
|
||||
|
|
@ -243,23 +246,25 @@ namespace MinecraftClient.Protocol.Message
|
|||
/// </summary>
|
||||
public static void InitTranslations()
|
||||
{
|
||||
if (!RulesInitialized)
|
||||
lock (RulesInitializationLock)
|
||||
{
|
||||
InitRules();
|
||||
if (RulesInitialized)
|
||||
return;
|
||||
|
||||
RulesInitialized = true;
|
||||
RulesRefreshTask = InitRulesAsync();
|
||||
_ = ObserveInitRulesAsync(RulesRefreshTask);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Internal rule initialization method. Looks for local rule file or download it from Mojang asset servers.
|
||||
/// Internal rule initialization method. Looks for local rule file and refreshes it from Mojang asset servers if needed.
|
||||
/// </summary>
|
||||
private static void InitRules()
|
||||
private static async Task InitRulesAsync()
|
||||
{
|
||||
if (Config.Main.Advanced.Language == "en_us")
|
||||
{
|
||||
TranslationRules =
|
||||
JsonSerializer.Deserialize<Dictionary<string, string>>(
|
||||
(byte[])MinecraftAssets.ResourceManager.GetObject("en_us.json")!)!;
|
||||
TranslationRules = LoadEmbeddedTranslationRules();
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -269,21 +274,9 @@ namespace MinecraftClient.Protocol.Message
|
|||
|
||||
string languageFilePath = "lang" + Path.DirectorySeparatorChar + Config.Main.Advanced.Language + ".json";
|
||||
|
||||
// Load the external dictionary of translation rules or display an error message
|
||||
if (File.Exists(languageFilePath))
|
||||
{
|
||||
try
|
||||
{
|
||||
TranslationRules =
|
||||
JsonSerializer.Deserialize<Dictionary<string, string>>(File.OpenRead(languageFilePath))!;
|
||||
}
|
||||
catch (IOException)
|
||||
{
|
||||
}
|
||||
catch (JsonException)
|
||||
{
|
||||
}
|
||||
}
|
||||
if (TryLoadTranslationRulesFromFile(languageFilePath, out Dictionary<string, string>? translationRules))
|
||||
TranslationRules = translationRules;
|
||||
else TranslationRules = LoadEmbeddedTranslationRules();
|
||||
|
||||
if (TranslationRules.TryGetValue("Version", out string? version) &&
|
||||
version == Settings.TranslationsFile_Version)
|
||||
|
|
@ -296,14 +289,12 @@ namespace MinecraftClient.Protocol.Message
|
|||
// Try downloading language file from Mojang's servers?
|
||||
ConsoleIO.WriteLineFormatted(
|
||||
"§8" + string.Format(Translations.chat_download, Config.Main.Advanced.Language));
|
||||
HttpClient httpClient = new();
|
||||
using HttpClient httpClient = new();
|
||||
try
|
||||
{
|
||||
Task<string> fetch_index = httpClient.GetStringAsync(TranslationsFile_Website_Index);
|
||||
fetch_index.Wait();
|
||||
Match match = Regex.Match(fetch_index.Result,
|
||||
string fetchIndex = await httpClient.GetStringAsync(TranslationsFile_Website_Index);
|
||||
Match match = Regex.Match(fetchIndex,
|
||||
$"minecraft/lang/{Config.Main.Advanced.Language}.json" + @""":\s\{""hash"":\s""([\d\w]{40})""");
|
||||
fetch_index.Dispose();
|
||||
if (match.Success && match.Groups.Count == 2)
|
||||
{
|
||||
string hash = match.Groups[1].Value;
|
||||
|
|
@ -312,22 +303,19 @@ namespace MinecraftClient.Protocol.Message
|
|||
ConsoleIO.WriteLineFormatted(
|
||||
string.Format(Translations.chat_request, translation_file_location));
|
||||
|
||||
Task<Dictionary<string, string>?> fetckFileTask =
|
||||
httpClient.GetFromJsonAsync<Dictionary<string, string>>(translation_file_location);
|
||||
fetckFileTask.Wait();
|
||||
if (fetckFileTask.Result is not null && fetckFileTask.Result.Count > 0)
|
||||
Dictionary<string, string>? fetchedFile =
|
||||
await httpClient.GetFromJsonAsync<Dictionary<string, string>>(translation_file_location);
|
||||
if (fetchedFile is not null && fetchedFile.Count > 0)
|
||||
{
|
||||
TranslationRules = fetckFileTask.Result;
|
||||
TranslationRules = fetchedFile;
|
||||
TranslationRules["Version"] = TranslationsFile_Version;
|
||||
File.WriteAllText(languageFilePath,
|
||||
await File.WriteAllTextAsync(languageFilePath,
|
||||
JsonSerializer.Serialize(TranslationRules, typeof(Dictionary<string, string>)),
|
||||
Encoding.UTF8);
|
||||
|
||||
ConsoleIO.WriteLineFormatted("§8" + string.Format(Translations.chat_done, languageFilePath));
|
||||
return;
|
||||
}
|
||||
|
||||
fetckFileTask.Dispose();
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -350,17 +338,52 @@ namespace MinecraftClient.Protocol.Message
|
|||
if (Config.Logging.DebugMessages && !string.IsNullOrEmpty(e.StackTrace))
|
||||
ConsoleIO.WriteLine(e.StackTrace);
|
||||
}
|
||||
finally
|
||||
{
|
||||
httpClient.Dispose();
|
||||
}
|
||||
|
||||
TranslationRules =
|
||||
JsonSerializer.Deserialize<Dictionary<string, string>>(
|
||||
(byte[])MinecraftAssets.ResourceManager.GetObject("en_us.json")!)!;
|
||||
TranslationRules = LoadEmbeddedTranslationRules();
|
||||
ConsoleIO.WriteLine(Translations.chat_use_default);
|
||||
}
|
||||
|
||||
private static async Task ObserveInitRulesAsync(Task initRulesTask)
|
||||
{
|
||||
try
|
||||
{
|
||||
await initRulesTask;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
TranslationRules = LoadEmbeddedTranslationRules();
|
||||
if (Config.Logging.DebugMessages)
|
||||
ConsoleIO.WriteLine(e.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
private static Dictionary<string, string> LoadEmbeddedTranslationRules()
|
||||
{
|
||||
return JsonSerializer.Deserialize<Dictionary<string, string>>(
|
||||
(byte[])MinecraftAssets.ResourceManager.GetObject("en_us.json")!)!;
|
||||
}
|
||||
|
||||
private static bool TryLoadTranslationRulesFromFile(string languageFilePath, out Dictionary<string, string>? translationRules)
|
||||
{
|
||||
translationRules = null;
|
||||
if (!File.Exists(languageFilePath))
|
||||
return false;
|
||||
|
||||
try
|
||||
{
|
||||
translationRules =
|
||||
JsonSerializer.Deserialize<Dictionary<string, string>>(File.OpenRead(languageFilePath))!;
|
||||
return translationRules is not null;
|
||||
}
|
||||
catch (IOException)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
catch (JsonException)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static string? TranslateString(string rulename)
|
||||
{
|
||||
if (TranslationRules.TryGetValue(rulename, out string? result))
|
||||
|
|
@ -617,4 +640,4 @@ namespace MinecraftClient.Protocol.Message
|
|||
return formatting + message + extraBuilder.ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ using System.Globalization;
|
|||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MinecraftClient.Protocol
|
||||
{
|
||||
|
|
@ -37,7 +38,13 @@ namespace MinecraftClient.Protocol
|
|||
{
|
||||
string postData = "client_id={0}&grant_type=authorization_code&redirect_uri=https%3A%2F%2Fmccteam.github.io%2Fredirect.html&code={1}";
|
||||
postData = string.Format(postData, clientId, code);
|
||||
return RequestToken(postData);
|
||||
return RequestTokenAsync(postData).GetAwaiter().GetResult();
|
||||
}
|
||||
|
||||
public static Task<LoginResponse> RequestAccessTokenAsync(string code)
|
||||
{
|
||||
string postData = "client_id={0}&grant_type=authorization_code&redirect_uri=https%3A%2F%2Fmccteam.github.io%2Fredirect.html&code={1}";
|
||||
return RequestTokenAsync(string.Format(postData, clientId, code));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -49,7 +56,13 @@ namespace MinecraftClient.Protocol
|
|||
{
|
||||
string postData = "client_id={0}&grant_type=refresh_token&redirect_uri=https%3A%2F%2Fmccteam.github.io%2Fredirect.html&refresh_token={1}";
|
||||
postData = string.Format(postData, clientId, refreshToken);
|
||||
return RequestToken(postData);
|
||||
return RequestTokenAsync(postData).GetAwaiter().GetResult();
|
||||
}
|
||||
|
||||
public static Task<LoginResponse> RefreshAccessTokenAsync(string refreshToken)
|
||||
{
|
||||
string postData = "client_id={0}&grant_type=refresh_token&redirect_uri=https%3A%2F%2Fmccteam.github.io%2Fredirect.html&refresh_token={1}";
|
||||
return RequestTokenAsync(string.Format(postData, clientId, refreshToken));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -58,6 +71,11 @@ namespace MinecraftClient.Protocol
|
|||
/// </summary>
|
||||
/// <returns>Device code response for user to complete authentication</returns>
|
||||
public static DeviceCodeResponse RequestDeviceCode()
|
||||
{
|
||||
return RequestDeviceCodeAsync().GetAwaiter().GetResult();
|
||||
}
|
||||
|
||||
public static async Task<DeviceCodeResponse> RequestDeviceCodeAsync(CancellationToken cancellationToken = default)
|
||||
{
|
||||
string postData = string.Format("client_id={0}&scope=XboxLive.signin%20offline_access%20openid%20email", clientId);
|
||||
|
||||
|
|
@ -65,7 +83,7 @@ namespace MinecraftClient.Protocol
|
|||
{
|
||||
UserAgent = "MCC/" + Program.Version
|
||||
};
|
||||
var response = request.Post("application/x-www-form-urlencoded", postData);
|
||||
var response = await request.PostAsync("application/x-www-form-urlencoded", postData, cancellationToken);
|
||||
var jsonData = Json.ParseJson(response.Body);
|
||||
|
||||
if (jsonData?["error"] is not null)
|
||||
|
|
@ -93,6 +111,11 @@ namespace MinecraftClient.Protocol
|
|||
/// <param name="interval">Polling interval in seconds</param>
|
||||
/// <returns>Login response with access token and refresh token</returns>
|
||||
public static LoginResponse PollDeviceCodeToken(string deviceCode, int expiresIn, int interval)
|
||||
{
|
||||
return PollDeviceCodeTokenAsync(deviceCode, expiresIn, interval).GetAwaiter().GetResult();
|
||||
}
|
||||
|
||||
public static async Task<LoginResponse> PollDeviceCodeTokenAsync(string deviceCode, int expiresIn, int interval, CancellationToken cancellationToken = default)
|
||||
{
|
||||
// Per OAuth 2.0 device code spec, server may respond with "slow_down" requiring
|
||||
// the client to increase its polling interval by this amount
|
||||
|
|
@ -107,13 +130,13 @@ namespace MinecraftClient.Protocol
|
|||
|
||||
while (stopwatch.Elapsed.TotalSeconds < expiresIn)
|
||||
{
|
||||
Thread.Sleep(pollInterval * 1000);
|
||||
await Task.Delay(TimeSpan.FromSeconds(pollInterval), cancellationToken);
|
||||
|
||||
var request = new ProxiedWebRequest(tokenUrl)
|
||||
{
|
||||
UserAgent = "MCC/" + Program.Version
|
||||
};
|
||||
var response = request.Post("application/x-www-form-urlencoded", postData);
|
||||
var response = await request.PostAsync("application/x-www-form-urlencoded", postData, cancellationToken);
|
||||
var jsonData = Json.ParseJson(response.Body);
|
||||
|
||||
if (jsonData?["error"] is not null)
|
||||
|
|
@ -173,12 +196,17 @@ namespace MinecraftClient.Protocol
|
|||
/// <param name="postData">Complete POST data for the request</param>
|
||||
/// <returns></returns>
|
||||
private static LoginResponse RequestToken(string postData)
|
||||
{
|
||||
return RequestTokenAsync(postData).GetAwaiter().GetResult();
|
||||
}
|
||||
|
||||
private static async Task<LoginResponse> RequestTokenAsync(string postData, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var request = new ProxiedWebRequest(tokenUrl)
|
||||
{
|
||||
UserAgent = "MCC/" + Program.Version
|
||||
};
|
||||
var response = request.Post("application/x-www-form-urlencoded", postData);
|
||||
var response = await request.PostAsync("application/x-www-form-urlencoded", postData, cancellationToken);
|
||||
var jsonData = Json.ParseJson(response.Body);
|
||||
|
||||
// Error handling
|
||||
|
|
@ -271,6 +299,11 @@ namespace MinecraftClient.Protocol
|
|||
/// <param name="loginResponse"></param>
|
||||
/// <returns></returns>
|
||||
public static XblAuthenticateResponse XblAuthenticate(Microsoft.LoginResponse loginResponse)
|
||||
{
|
||||
return XblAuthenticateAsync(loginResponse).GetAwaiter().GetResult();
|
||||
}
|
||||
|
||||
public static async Task<XblAuthenticateResponse> XblAuthenticateAsync(Microsoft.LoginResponse loginResponse, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var request = new ProxiedWebRequest(xbl)
|
||||
{
|
||||
|
|
@ -291,7 +324,7 @@ namespace MinecraftClient.Protocol
|
|||
+ "\"RelyingParty\": \"http://auth.xboxlive.com\","
|
||||
+ "\"TokenType\": \"JWT\""
|
||||
+ "}";
|
||||
var response = request.Post("application/json", payload);
|
||||
var response = await request.PostAsync("application/json", payload, cancellationToken);
|
||||
if (Settings.Config.Logging.DebugMessages)
|
||||
{
|
||||
ConsoleIO.WriteLine(response.ToString());
|
||||
|
|
@ -321,6 +354,11 @@ namespace MinecraftClient.Protocol
|
|||
/// <param name="xblResponse"></param>
|
||||
/// <returns></returns>
|
||||
public static XSTSAuthenticateResponse XSTSAuthenticate(XblAuthenticateResponse xblResponse)
|
||||
{
|
||||
return XSTSAuthenticateAsync(xblResponse).GetAwaiter().GetResult();
|
||||
}
|
||||
|
||||
public static async Task<XSTSAuthenticateResponse> XSTSAuthenticateAsync(XblAuthenticateResponse xblResponse, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var request = new ProxiedWebRequest(xsts)
|
||||
{
|
||||
|
|
@ -339,7 +377,7 @@ namespace MinecraftClient.Protocol
|
|||
+ "\"RelyingParty\": \"rp://api.minecraftservices.com/\","
|
||||
+ "\"TokenType\": \"JWT\""
|
||||
+ "}";
|
||||
var response = request.Post("application/json", payload);
|
||||
var response = await request.PostAsync("application/json", payload, cancellationToken);
|
||||
if (Settings.Config.Logging.DebugMessages)
|
||||
{
|
||||
ConsoleIO.WriteLine(response.ToString());
|
||||
|
|
@ -404,6 +442,11 @@ namespace MinecraftClient.Protocol
|
|||
/// <param name="xstsToken"></param>
|
||||
/// <returns></returns>
|
||||
public static string LoginWithXbox(string userHash, string xstsToken)
|
||||
{
|
||||
return LoginWithXboxAsync(userHash, xstsToken).GetAwaiter().GetResult();
|
||||
}
|
||||
|
||||
public static async Task<string> LoginWithXboxAsync(string userHash, string xstsToken, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var request = new ProxiedWebRequest(loginWithXbox)
|
||||
{
|
||||
|
|
@ -411,7 +454,7 @@ namespace MinecraftClient.Protocol
|
|||
};
|
||||
|
||||
string payload = "{\"identityToken\": \"XBL3.0 x=" + userHash + ";" + xstsToken + "\"}";
|
||||
var response = request.Post("application/json", payload);
|
||||
var response = await request.PostAsync("application/json", payload, cancellationToken);
|
||||
|
||||
if (Settings.Config.Logging.DebugMessages)
|
||||
{
|
||||
|
|
@ -430,10 +473,15 @@ namespace MinecraftClient.Protocol
|
|||
/// <param name="accessToken"></param>
|
||||
/// <returns>True if the user own the game</returns>
|
||||
public static bool UserHasGame(string accessToken)
|
||||
{
|
||||
return UserHasGameAsync(accessToken).GetAwaiter().GetResult();
|
||||
}
|
||||
|
||||
public static async Task<bool> UserHasGameAsync(string accessToken, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var request = new ProxiedWebRequest(ownership);
|
||||
request.Headers.Add("Authorization", string.Format("Bearer {0}", accessToken));
|
||||
var response = request.Get();
|
||||
var response = await request.GetAsync(cancellationToken);
|
||||
|
||||
if (Settings.Config.Logging.DebugMessages)
|
||||
{
|
||||
|
|
@ -446,10 +494,15 @@ namespace MinecraftClient.Protocol
|
|||
}
|
||||
|
||||
public static UserProfile GetUserProfile(string accessToken)
|
||||
{
|
||||
return GetUserProfileAsync(accessToken).GetAwaiter().GetResult();
|
||||
}
|
||||
|
||||
public static async Task<UserProfile> GetUserProfileAsync(string accessToken, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var request = new ProxiedWebRequest(profile);
|
||||
request.Headers.Add("Authorization", string.Format("Bearer {0}", accessToken));
|
||||
var response = request.Get();
|
||||
var response = await request.GetAsync(cancellationToken);
|
||||
|
||||
if (Settings.Config.Logging.DebugMessages)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -7,6 +7,8 @@ using System.Net.Http;
|
|||
using System.Net.Sockets;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using DnsClient;
|
||||
using MinecraftClient.Protocol.Handlers;
|
||||
using MinecraftClient.Protocol.Handlers.Forge;
|
||||
|
|
@ -1108,6 +1110,43 @@ namespace MinecraftClient.Protocol
|
|||
}
|
||||
}
|
||||
|
||||
public static async Task<bool> SessionCheckAsync(string uuid, string accesstoken, string serverhash, LoginType type)
|
||||
{
|
||||
try
|
||||
{
|
||||
string jsonRequest = "{\"accessToken\":\"" + accesstoken + "\",\"selectedProfile\":\"" + uuid +
|
||||
"\",\"serverId\":\"" + serverhash + "\"}";
|
||||
string host = type == LoginType.yggdrasil
|
||||
? Config.Main.General.AuthServer.Host
|
||||
: "sessionserver.mojang.com";
|
||||
int port = type == LoginType.yggdrasil ? Config.Main.General.AuthServer.Port : 443;
|
||||
string endpoint = type == LoginType.yggdrasil
|
||||
? Config.Main.General.AuthServer.AuthlibInjectorAPIPath + "/sessionserver/session/minecraft/join"
|
||||
: "/session/minecraft/join";
|
||||
|
||||
bool useHttps = type == LoginType.yggdrasil ? Config.Main.General.AuthServer.UseHttps : true;
|
||||
var response = await DoHTTPSRequestAsync(
|
||||
HttpMethod.Post,
|
||||
host,
|
||||
port,
|
||||
endpoint,
|
||||
new Dictionary<string, string>
|
||||
{
|
||||
{ "Accept", "application/json" },
|
||||
{ "Content-Type", "application/json" }
|
||||
},
|
||||
jsonRequest,
|
||||
useHttps,
|
||||
CancellationToken.None);
|
||||
|
||||
return response.StatusCode >= 200 && response.StatusCode < 300;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Retrieve available Realms worlds of a player and display them
|
||||
/// </summary>
|
||||
|
|
@ -1349,6 +1388,57 @@ namespace MinecraftClient.Protocol
|
|||
return statusCode;
|
||||
}
|
||||
|
||||
private static async Task<(int StatusCode, string Result)> DoHTTPSRequestAsync(HttpMethod method, string host, int port, string path, Dictionary<string, string> headers, string? body, bool useHttps, CancellationToken cancellationToken)
|
||||
{
|
||||
if (Settings.Config.Logging.DebugMessages)
|
||||
ConsoleIO.WriteLineFormatted("§8" + string.Format(Translations.debug_request, host));
|
||||
|
||||
using SocketsHttpHandler handler = new();
|
||||
handler.ConnectCallback = async (ctx, ct) =>
|
||||
{
|
||||
TcpClient client = ProxyHandler.NewTcpClient(host, port, true);
|
||||
return client.GetStream();
|
||||
};
|
||||
|
||||
using HttpClient client = new(handler);
|
||||
|
||||
string scheme = useHttps ? "https" : "http";
|
||||
using HttpRequestMessage request = new(method, scheme + "://" + host + ":" + port + path);
|
||||
|
||||
string contentType = "text/plain";
|
||||
foreach (var header in headers)
|
||||
{
|
||||
request.Headers.TryAddWithoutValidation(header.Key, header.Value);
|
||||
if (header.Key.Equals("Content-Type", StringComparison.OrdinalIgnoreCase))
|
||||
contentType = header.Value;
|
||||
}
|
||||
|
||||
if (body is not null)
|
||||
request.Content = new StringContent(body, Encoding.UTF8, contentType);
|
||||
|
||||
if (Settings.Config.Logging.DebugMessages)
|
||||
ConsoleIO.WriteLineFormatted("§8> " + request);
|
||||
|
||||
using CancellationTokenSource timeoutCancellationTokenSource =
|
||||
CancellationTokenSource.CreateLinkedTokenSource(cancellationToken);
|
||||
timeoutCancellationTokenSource.CancelAfter(TimeSpan.FromSeconds(30));
|
||||
|
||||
using HttpResponseMessage response = await client.SendAsync(request, timeoutCancellationTokenSource.Token);
|
||||
int statusCode = (int)response.StatusCode;
|
||||
string responseBody = statusCode == 204
|
||||
? "No Content"
|
||||
: await response.Content.ReadAsStringAsync(timeoutCancellationTokenSource.Token);
|
||||
|
||||
if (Settings.Config.Logging.DebugMessages)
|
||||
{
|
||||
ConsoleIO.WriteLine("");
|
||||
foreach (string line in responseBody.Split('\n'))
|
||||
ConsoleIO.WriteLineFormatted("§8< " + line);
|
||||
}
|
||||
|
||||
return (statusCode, responseBody);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Encode a string to a json string.
|
||||
/// Will convert special chars to \u0000 unicode escape sequences.
|
||||
|
|
@ -1389,4 +1479,4 @@ namespace MinecraftClient.Protocol
|
|||
return dateTime;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,6 +3,8 @@ using System.Collections.Specialized;
|
|||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using MinecraftClient.Proxy;
|
||||
|
||||
namespace MinecraftClient.Protocol
|
||||
|
|
@ -72,6 +74,12 @@ namespace MinecraftClient.Protocol
|
|||
/// </summary>
|
||||
public Response Get() => Send(HttpMethod.Get);
|
||||
|
||||
/// <summary>
|
||||
/// Perform GET request asynchronously. Proxy is handled automatically.
|
||||
/// </summary>
|
||||
public Task<Response> GetAsync(CancellationToken cancellationToken = default) =>
|
||||
SendAsync(HttpMethod.Get, cancellationToken: cancellationToken);
|
||||
|
||||
/// <summary>
|
||||
/// Perform POST request. Proxy is handled automatically.
|
||||
/// </summary>
|
||||
|
|
@ -79,6 +87,14 @@ namespace MinecraftClient.Protocol
|
|||
/// <param name="body">Request body</param>
|
||||
public Response Post(string contentType, string body) => Send(HttpMethod.Post, contentType, body);
|
||||
|
||||
/// <summary>
|
||||
/// Perform POST request asynchronously. Proxy is handled automatically.
|
||||
/// </summary>
|
||||
/// <param name="contentType">The content type of request body</param>
|
||||
/// <param name="body">Request body</param>
|
||||
public Task<Response> PostAsync(string contentType, string body, CancellationToken cancellationToken = default) =>
|
||||
SendAsync(HttpMethod.Post, contentType, body, cancellationToken);
|
||||
|
||||
/// <summary>
|
||||
/// Send an HTTP request. Proxy is configured automatically from Settings.
|
||||
/// </summary>
|
||||
|
|
@ -144,6 +160,66 @@ namespace MinecraftClient.Protocol
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Send an HTTP request asynchronously. Proxy is configured automatically from Settings.
|
||||
/// </summary>
|
||||
private async Task<Response> SendAsync(HttpMethod method, string? contentType = null, string? body = null, CancellationToken cancellationToken = default)
|
||||
{
|
||||
using var handler = CreateHandler();
|
||||
using var client = new HttpClient(handler);
|
||||
|
||||
using var request = new HttpRequestMessage(method, _uri);
|
||||
|
||||
foreach (string key in Headers)
|
||||
{
|
||||
if (key.Equals("Content-Type", StringComparison.OrdinalIgnoreCase) ||
|
||||
key.Equals("Content-Length", StringComparison.OrdinalIgnoreCase) ||
|
||||
key.Equals("Host", StringComparison.OrdinalIgnoreCase))
|
||||
continue;
|
||||
|
||||
request.Headers.TryAddWithoutValidation(key, Headers[key]);
|
||||
}
|
||||
|
||||
if (body is not null)
|
||||
request.Content = new StringContent(body, Encoding.UTF8, contentType ?? "text/plain");
|
||||
|
||||
if (Debug)
|
||||
{
|
||||
ConsoleIO.WriteLine($"< {method} {_uri}");
|
||||
foreach (string key in Headers)
|
||||
ConsoleIO.WriteLine($"< {key}: {Headers[key]}");
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
using var httpResponse = await client.SendAsync(request, cancellationToken);
|
||||
string responseBody = await httpResponse.Content.ReadAsStringAsync(cancellationToken);
|
||||
|
||||
var responseHeaders = new NameValueCollection();
|
||||
foreach (var header in httpResponse.Headers)
|
||||
foreach (var val in header.Value)
|
||||
responseHeaders.Add(header.Key.ToLowerInvariant(), val);
|
||||
foreach (var header in httpResponse.Content.Headers)
|
||||
foreach (var val in header.Value)
|
||||
responseHeaders.Add(header.Key.ToLowerInvariant(), val);
|
||||
|
||||
var cookies = new NameValueCollection();
|
||||
foreach (Cookie cookie in handler.CookieContainer.GetCookies(_uri))
|
||||
{
|
||||
if (!cookie.Expired)
|
||||
cookies.Add(cookie.Name, cookie.Value);
|
||||
}
|
||||
|
||||
return new Response((int)httpResponse.StatusCode, responseBody, responseHeaders, cookies);
|
||||
}
|
||||
catch (HttpRequestException ex)
|
||||
{
|
||||
if (Debug)
|
||||
ConsoleIO.WriteLine("HTTP error: " + ex.Message);
|
||||
return Response.Empty();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create a SocketsHttpHandler with proxy support from ProxyHandler settings.
|
||||
/// </summary>
|
||||
|
|
@ -231,4 +307,4 @@ namespace MinecraftClient.Protocol
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -54,6 +54,16 @@ namespace MinecraftClient.Protocol.Session
|
|||
return false;
|
||||
}
|
||||
|
||||
public async Task<bool> SessionPreCheckAsync(LoginType type)
|
||||
{
|
||||
if (ID == string.Empty || PlayerID == String.Empty || ServerPublicKey is null)
|
||||
return false;
|
||||
|
||||
Crypto.CryptoHandler.ClientAESPrivateKey ??= Crypto.CryptoHandler.GenerateAESPrivateKey();
|
||||
string serverHash = Crypto.CryptoHandler.GetServerHash(ServerIDhash, ServerPublicKey, Crypto.CryptoHandler.ClientAESPrivateKey);
|
||||
return await ProtocolHandler.SessionCheckAsync(PlayerID, ID, serverHash, type);
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return String.Join(",", ID, PlayerName, PlayerID, ClientID, RefreshToken, ServerIDhash,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue