diff --git a/MinecraftClient/ChatBots/WebSocketBot.cs b/MinecraftClient/ChatBots/WebSocketBot.cs
index 6ba4395e..1aa6caa9 100644
--- a/MinecraftClient/ChatBots/WebSocketBot.cs
+++ b/MinecraftClient/ChatBots/WebSocketBot.cs
@@ -287,13 +287,21 @@ public class WebSocketBot : ChatBot
[TomlInlineComment("$ChatBot.WebSocketBot.DebugMode$")]
public bool DebugMode = false;
+
+ [TomlInlineComment("$ChatBot.WebSocketBot.AllowIpAlias$")]
+ public bool AllowIpAlias = false;
}
public WebSocketBot()
{
+ _password = Config.Password;
+ _authenticatedSessions = new();
+ _waitingEvents = new();
+
var match = Regex.Match(Config.Ip!, @"\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}");
- if (!match.Success)
+ // If AllowIpAlias is set to true in the config, then always ignore this check
+ if (!match.Success & !Config.AllowIpAlias!)
{
LogToConsole(Translations.bot_WebSocketBot_failed_to_start_ip);
return;
@@ -307,9 +315,6 @@ public class WebSocketBot : ChatBot
_ip = Config.Ip;
_port = Config.Port;
- _password = Config.Password;
- _authenticatedSessions = new();
- _waitingEvents = new();
}
public override void Initialize()
@@ -420,6 +425,9 @@ public class WebSocketBot : ChatBot
_authenticatedSessions.Add(newId);
}
+ // Update the responder to the new session id
+ responder = new WsCommandResponder(this, newId, cmd.Command, cmd.RequestId);
+
responder.SendSuccessResponse(
responder.Quote("The session ID was successfully changed to: '" + newId + "'"), true);
LogToConsole(string.Format(Translations.bot_WebSocketBot_session_id_changed, sessionId, newId));
diff --git a/MinecraftClient/McClient.cs b/MinecraftClient/McClient.cs
index f9bd5546..c7296d52 100644
--- a/MinecraftClient/McClient.cs
+++ b/MinecraftClient/McClient.cs
@@ -3438,6 +3438,16 @@ namespace MinecraftClient
{
DispatchBotEvent(bot => bot.OnUpdateScore(entityname, action, objectivename, value));
}
+
+ ///
+ /// Called when the client received the Tab Header and Footer
+ ///
+ /// Header
+ /// Footer
+ public void OnTabListHeaderAndFooter(string header, string footer)
+ {
+ DispatchBotEvent(bot => bot.OnTabListHeaderAndFooter(header, footer));
+ }
///
/// Called when the health of an entity changed
diff --git a/MinecraftClient/Program.cs b/MinecraftClient/Program.cs
index 445996bd..f0d8f0b8 100644
--- a/MinecraftClient/Program.cs
+++ b/MinecraftClient/Program.cs
@@ -416,7 +416,7 @@ namespace MinecraftClient
else
{
// Validate cached session or login new session.
- if (Config.Main.Advanced.SessionCache != CacheType.none && SessionCache.Contains(loginLower))
+ if (Config.Main.Advanced.SessionCache != CacheType.none && SessionCache.Contains(loginLower) && Config.Main.General.AccountType != LoginType.yggdrasil)
{
session = SessionCache.Get(loginLower);
result = ProtocolHandler.GetTokenValidation(session);
@@ -447,7 +447,7 @@ namespace MinecraftClient
if (result != ProtocolHandler.LoginResult.Success)
{
- ConsoleIO.WriteLine(string.Format(Translations.mcc_connecting, Config.Main.General.AccountType == LoginType.mojang ? "Minecraft.net" : "Microsoft"));
+ ConsoleIO.WriteLine(string.Format(Translations.mcc_connecting, Config.Main.General.AccountType == LoginType.mojang ? "Minecraft.net" : (Config.Main.General.AccountType == LoginType.microsoft ? "Microsoft" : Config.Main.General.AuthServer.Host)));
result = ProtocolHandler.GetLogin(InternalConfig.Account.Login, InternalConfig.Account.Password, Config.Main.General.AccountType, out session);
}
@@ -455,7 +455,7 @@ namespace MinecraftClient
SessionCache.Store(loginLower, session);
if (result == ProtocolHandler.LoginResult.Success)
- session.SessionPreCheckTask = Task.Factory.StartNew(() => session.SessionPreCheck());
+ session.SessionPreCheckTask = Task.Factory.StartNew(() => session.SessionPreCheck(Config.Main.General.AccountType));
}
if (result == ProtocolHandler.LoginResult.Success)
@@ -649,6 +649,7 @@ namespace MinecraftClient
ProtocolHandler.LoginResult.OtherError => Translations.error_login_network,
ProtocolHandler.LoginResult.SSLError => Translations.error_login_ssl,
ProtocolHandler.LoginResult.UserCancel => Translations.error_login_cancel,
+ ProtocolHandler.LoginResult.WrongSelection => Translations.error_login_blocked,
_ => Translations.error_login_unknown,
#pragma warning restore format // @formatter:on
};
diff --git a/MinecraftClient/Protocol/Handlers/Protocol16.cs b/MinecraftClient/Protocol/Handlers/Protocol16.cs
index 53813e14..7910cf56 100644
--- a/MinecraftClient/Protocol/Handlers/Protocol16.cs
+++ b/MinecraftClient/Protocol/Handlers/Protocol16.cs
@@ -15,6 +15,7 @@ using MinecraftClient.Protocol.Session;
using MinecraftClient.Proxy;
using MinecraftClient.Scripting;
using static MinecraftClient.Settings;
+using static MinecraftClient.Settings.MainConfigHealper.MainConfig.GeneralConfig;
namespace MinecraftClient.Protocol.Handlers
{
@@ -504,7 +505,7 @@ namespace MinecraftClient.Protocol.Handlers
else if (Settings.Config.Logging.DebugMessages)
ConsoleIO.WriteLineFormatted("§8" + string.Format(Translations.mcc_handshake, serverID));
- return StartEncryption(uuid, username, sessionID, token, serverID, PublicServerkey, session);
+ return StartEncryption(uuid, username, sessionID, Config.Main.General.AccountType, token, serverID, PublicServerkey, session);
}
else
{
@@ -513,7 +514,7 @@ namespace MinecraftClient.Protocol.Handlers
}
}
- private bool StartEncryption(string uuid, string username, string sessionID, byte[] token, string serverIDhash, byte[] serverPublicKey, SessionToken session)
+ private bool StartEncryption(string uuid, string username, string sessionID, LoginType type, byte[] token, string serverIDhash, byte[] serverPublicKey, SessionToken session)
{
RSACryptoServiceProvider RSAService = CryptoHandler.DecodeRSAPublicKey(serverPublicKey)!;
byte[] secretKey = CryptoHandler.ClientAESPrivateKey ?? CryptoHandler.GenerateAESPrivateKey();
@@ -537,7 +538,7 @@ namespace MinecraftClient.Protocol.Handlers
if (needCheckSession)
{
- if (ProtocolHandler.SessionCheck(uuid, sessionID, serverHash))
+ if (ProtocolHandler.SessionCheck(uuid, sessionID, serverHash, type))
{
session.ServerIDhash = serverIDhash;
session.ServerPublicKey = serverPublicKey;
diff --git a/MinecraftClient/Protocol/Handlers/Protocol18.cs b/MinecraftClient/Protocol/Handlers/Protocol18.cs
index 4c906784..3c610193 100644
--- a/MinecraftClient/Protocol/Handlers/Protocol18.cs
+++ b/MinecraftClient/Protocol/Handlers/Protocol18.cs
@@ -25,6 +25,7 @@ using MinecraftClient.Protocol.Session;
using MinecraftClient.Proxy;
using MinecraftClient.Scripting;
using static MinecraftClient.Settings;
+using static MinecraftClient.Settings.MainConfigHealper.MainConfig.GeneralConfig;
namespace MinecraftClient.Protocol.Handlers
{
@@ -337,7 +338,7 @@ namespace MinecraftClient.Protocol.Handlers
{
var toDecompress = packetData.ToArray();
var uncompressed = ZlibUtils.Decompress(toDecompress, sizeUncompressed);
- packetData = new(uncompressed);
+ packetData = new Queue(uncompressed);
}
}
@@ -912,8 +913,7 @@ namespace MinecraftClient.Protocol.Handlers
.StringValue;
string? senderTeamName = null;
if (targetName != null &&
- (messageTypeEnum == ChatParser.MessageType.TEAM_MSG_COMMAND_INCOMING ||
- messageTypeEnum == ChatParser.MessageType.TEAM_MSG_COMMAND_OUTGOING))
+ messageTypeEnum is ChatParser.MessageType.TEAM_MSG_COMMAND_INCOMING or ChatParser.MessageType.TEAM_MSG_COMMAND_OUTGOING)
senderTeamName = Json.ParseJson(targetName).Properties["with"].DataArray[0]
.Properties["text"].StringValue;
@@ -1311,7 +1311,7 @@ namespace MinecraftClient.Protocol.Handlers
else
{
var chunksContinuous = dataTypes.ReadNextBool(packetData);
- if (protocolVersion >= MC_1_16_Version && protocolVersion <= MC_1_16_1_Version)
+ if (protocolVersion is >= MC_1_16_Version and <= MC_1_16_1_Version)
dataTypes.ReadNextBool(packetData); // Ignore old data - 1.16 to 1.16.1 only
var chunkMask = protocolVersion >= MC_1_9_Version
? (ushort)dataTypes.ReadNextVarInt(packetData)
@@ -2758,7 +2758,8 @@ namespace MinecraftClient.Protocol.Handlers
var serverId = dataTypes.ReadNextString(packetData);
var serverPublicKey = dataTypes.ReadNextByteArray(packetData);
var token = dataTypes.ReadNextByteArray(packetData);
- return StartEncryption(handler.GetUserUuidStr(), handler.GetSessionID(), token, serverId,
+ return StartEncryption(handler.GetUserUuidStr(), handler.GetSessionID(),
+ Config.Main.General.AccountType, token, serverId,
serverPublicKey, playerKeyPair, session);
}
@@ -2793,7 +2794,7 @@ namespace MinecraftClient.Protocol.Handlers
/// Start network encryption. Automatically called by Login() if the server requests encryption.
///
/// True if encryption was successful
- private bool StartEncryption(string uuid, string sessionID, byte[] token, string serverIDhash,
+ private bool StartEncryption(string uuid, string sessionID, LoginType type, byte[] token, string serverIDhash,
byte[] serverPublicKey, PlayerKeyPair? playerKeyPair, SessionToken session)
{
var RSAService = CryptoHandler.DecodeRSAPublicKey(serverPublicKey)!;
@@ -2818,8 +2819,7 @@ namespace MinecraftClient.Protocol.Handlers
if (needCheckSession)
{
var serverHash = CryptoHandler.GetServerHash(serverIDhash, serverPublicKey, secretKey);
-
- if (ProtocolHandler.SessionCheck(uuid, sessionID, serverHash))
+ if (ProtocolHandler.SessionCheck(uuid, sessionID, serverHash, type))
{
session.ServerIDhash = serverIDhash;
session.ServerPublicKey = serverPublicKey;
@@ -4142,9 +4142,11 @@ namespace MinecraftClient.Protocol.Handlers
{
try
{
- List packet = new();
- packet.Add((byte)windowId);
- packet.Add((byte)buttonId);
+ var packet = new List
+ {
+ (byte)windowId,
+ (byte)buttonId
+ };
SendPacket(PacketTypesOut.ClickWindowButton, packet);
return true;
}
@@ -4271,32 +4273,27 @@ namespace MinecraftClient.Protocol.Handlers
public bool UpdateCommandBlock(Location location, string command, CommandBlockMode mode,
CommandBlockFlags flags)
{
- if (protocolVersion <= MC_1_13_Version)
+ if (protocolVersion > MC_1_13_Version) return false;
+
+ try
{
- try
- {
- List packet = new();
- packet.AddRange(dataTypes.GetLocation(location));
- packet.AddRange(dataTypes.GetString(command));
- packet.AddRange(DataTypes.GetVarInt((int)mode));
- packet.Add((byte)flags);
- SendPacket(PacketTypesOut.UpdateSign, packet);
- return true;
- }
- catch (SocketException)
- {
- return false;
- }
- catch (System.IO.IOException)
- {
- return false;
- }
- catch (ObjectDisposedException)
- {
- return false;
- }
+ List packet = new();
+ packet.AddRange(dataTypes.GetLocation(location));
+ packet.AddRange(dataTypes.GetString(command));
+ packet.AddRange(DataTypes.GetVarInt((int)mode));
+ packet.Add((byte)flags);
+ SendPacket(PacketTypesOut.UpdateSign, packet);
+ return true;
}
- else
+ catch (SocketException)
+ {
+ return false;
+ }
+ catch (System.IO.IOException)
+ {
+ return false;
+ }
+ catch (ObjectDisposedException)
{
return false;
}
@@ -4306,8 +4303,7 @@ namespace MinecraftClient.Protocol.Handlers
{
try
{
- List packet = new();
- packet.Add(windowID);
+ var packet = new List() { windowID };
packet.AddRange(dataTypes.GetShort(actionID));
packet.Add(accepted ? (byte)1 : (byte)0);
SendPacket(PacketTypesOut.WindowConfirmation, packet);
@@ -4330,60 +4326,50 @@ namespace MinecraftClient.Protocol.Handlers
public bool SelectTrade(int selectedSlot)
{
// MC 1.13 or greater
- if (protocolVersion >= MC_1_13_Version)
+ if (protocolVersion < MC_1_13_Version) return false;
+
+ try
{
- try
- {
- List packet = new();
- packet.AddRange(DataTypes.GetVarInt(selectedSlot));
- SendPacket(PacketTypesOut.SelectTrade, packet);
- return true;
- }
- catch (SocketException)
- {
- return false;
- }
- catch (System.IO.IOException)
- {
- return false;
- }
- catch (ObjectDisposedException)
- {
- return false;
- }
+ List packet = new();
+ packet.AddRange(DataTypes.GetVarInt(selectedSlot));
+ SendPacket(PacketTypesOut.SelectTrade, packet);
+ return true;
}
- else
+ catch (SocketException)
+ {
+ return false;
+ }
+ catch (System.IO.IOException)
+ {
+ return false;
+ }
+ catch (ObjectDisposedException)
{
return false;
}
}
- public bool SendSpectate(Guid UUID)
+ public bool SendSpectate(Guid uuid)
{
// MC 1.8 or greater
- if (protocolVersion >= MC_1_8_Version)
+ if (protocolVersion < MC_1_8_Version) return false;
+
+ try
{
- try
- {
- List packet = new();
- packet.AddRange(DataTypes.GetUUID(UUID));
- SendPacket(PacketTypesOut.Spectate, packet);
- return true;
- }
- catch (SocketException)
- {
- return false;
- }
- catch (System.IO.IOException)
- {
- return false;
- }
- catch (ObjectDisposedException)
- {
- return false;
- }
+ List packet = new();
+ packet.AddRange(DataTypes.GetUUID(uuid));
+ SendPacket(PacketTypesOut.Spectate, packet);
+ return true;
}
- else
+ catch (SocketException)
+ {
+ return false;
+ }
+ catch (System.IO.IOException)
+ {
+ return false;
+ }
+ catch (ObjectDisposedException)
{
return false;
}
@@ -4462,7 +4448,7 @@ namespace MinecraftClient.Protocol.Handlers
return salt;
}
- public static long GetNanos()
+ private static long GetNanos()
{
var nano = 10000L * Stopwatch.GetTimestamp();
nano /= TimeSpan.TicksPerMillisecond;
diff --git a/MinecraftClient/Protocol/IMinecraftComHandler.cs b/MinecraftClient/Protocol/IMinecraftComHandler.cs
index e2a5be5c..dcc991a5 100644
--- a/MinecraftClient/Protocol/IMinecraftComHandler.cs
+++ b/MinecraftClient/Protocol/IMinecraftComHandler.cs
@@ -447,6 +447,13 @@ namespace MinecraftClient.Protocol
/// he score to be displayed next to the entry. Only sent when Action does not equal 1.
void OnUpdateScore(string entityname, int action, string objectivename, int value);
+ ///
+ /// Called when the client received the Tab Header and Footer
+ ///
+ /// Header
+ /// Footer
+ void OnTabListHeaderAndFooter(string header, string footer);
+
///
/// Called when tradeList is received from server
///
diff --git a/MinecraftClient/Protocol/ProtocolHandler.cs b/MinecraftClient/Protocol/ProtocolHandler.cs
index 86fd8ce7..92e53ce2 100644
--- a/MinecraftClient/Protocol/ProtocolHandler.cs
+++ b/MinecraftClient/Protocol/ProtocolHandler.cs
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
+using System.Data.Odbc;
using System.Globalization;
using System.Linq;
using System.Net.Security;
@@ -11,6 +12,7 @@ using MinecraftClient.Protocol.Handlers;
using MinecraftClient.Protocol.Handlers.Forge;
using MinecraftClient.Protocol.Session;
using MinecraftClient.Proxy;
+using static MinecraftClient.Protocol.Microsoft;
using static MinecraftClient.Settings;
using static MinecraftClient.Settings.MainConfigHealper.MainConfig.GeneralConfig;
@@ -41,39 +43,32 @@ namespace MinecraftClient.Protocol
if (!String.IsNullOrEmpty(domain) && domain.Any(c => char.IsLetter(c)))
{
AutoTimeout.Perform(() =>
+ {
+ try
{
- try
+ ConsoleIO.WriteLine(string.Format(Translations.mcc_resolve, domainVal));
+ var lookupClient = new LookupClient();
+ var response = lookupClient.Query(new DnsQuestion($"_minecraft._tcp.{domainVal}", QueryType.SRV));
+ if (response.HasError != true && response.Answers.SrvRecords().Any())
{
- ConsoleIO.WriteLine(string.Format(Translations.mcc_resolve, domainVal));
- var lookupClient = new LookupClient();
- var response =
- lookupClient.Query(new DnsQuestion($"_minecraft._tcp.{domainVal}", QueryType.SRV));
- if (response.HasError != true && response.Answers.SrvRecords().Any())
- {
- //Order SRV records by priority and weight, then randomly
- var result = response.Answers.SrvRecords()
- .OrderBy(record => record.Priority)
- .ThenByDescending(record => record.Weight)
- .ThenBy(record => Guid.NewGuid())
- .First();
- string target = result.Target.Value.Trim('.');
- ConsoleIO.WriteLineFormatted("§8" + string.Format(Translations.mcc_found, target,
- result.Port, domainVal));
- domainVal = target;
- portVal = result.Port;
- foundService = true;
- }
+ //Order SRV records by priority and weight, then randomly
+ var result = response.Answers.SrvRecords()
+ .OrderBy(record => record.Priority)
+ .ThenByDescending(record => record.Weight)
+ .ThenBy(record => Guid.NewGuid())
+ .First();
+ string target = result.Target.Value.Trim('.');
+ ConsoleIO.WriteLineFormatted("§8" + string.Format(Translations.mcc_found, target, result.Port, domainVal));
+ domainVal = target;
+ portVal = result.Port;
+ foundService = true;
}
- catch (Exception e)
- {
- ConsoleIO.WriteLineFormatted("§8" + string.Format(Translations.mcc_not_found, domainVal,
- e.GetType().FullName, e.Message));
- }
- },
- TimeSpan.FromSeconds(Config.Main.Advanced.ResolveSrvRecords ==
- MainConfigHealper.MainConfig.AdvancedConfig.ResolveSrvRecordType.fast
- ? 10
- : 30));
+ }
+ catch (Exception e)
+ {
+ ConsoleIO.WriteLineFormatted("§8" + string.Format(Translations.mcc_not_found, domainVal, e.GetType().FullName, e.Message));
+ }
+ }, TimeSpan.FromSeconds(Config.Main.Advanced.ResolveSrvRecords == MainConfigHealper.MainConfig.AdvancedConfig.ResolveSrvRecordType.fast ? 10 : 30));
}
domain = domainVal;
@@ -88,34 +83,28 @@ namespace MinecraftClient.Protocol
/// Server Port to ping
/// Will contain protocol version, if ping successful
/// TRUE if ping was successful
- public static bool GetServerInfo(string serverIP, ushort serverPort, ref int protocolversion,
- ref ForgeInfo? forgeInfo)
+ public static bool GetServerInfo(string serverIP, ushort serverPort, ref int protocolversion, ref ForgeInfo? forgeInfo)
{
bool success = false;
int protocolversionTmp = 0;
ForgeInfo? forgeInfoTmp = null;
if (AutoTimeout.Perform(() =>
+ {
+ try
+ {
+ if (Protocol18Handler.DoPing(serverIP, serverPort, ref protocolversionTmp, ref forgeInfoTmp)
+ || Protocol16Handler.DoPing(serverIP, serverPort, ref protocolversionTmp))
{
- try
- {
- if (Protocol18Handler.DoPing(serverIP, serverPort, ref protocolversionTmp, ref forgeInfoTmp)
- || Protocol16Handler.DoPing(serverIP, serverPort, ref protocolversionTmp))
- {
- success = true;
- }
- else
- ConsoleIO.WriteLineFormatted("§8" + Translations.error_unexpect_response,
- acceptnewlines: true);
- }
- catch (Exception e)
- {
- ConsoleIO.WriteLineFormatted(String.Format("§8{0}: {1}", e.GetType().FullName, e.Message));
- }
- },
- TimeSpan.FromSeconds(Config.Main.Advanced.ResolveSrvRecords ==
- MainConfigHealper.MainConfig.AdvancedConfig.ResolveSrvRecordType.fast
- ? 10
- : 30)))
+ success = true;
+ }
+ else
+ ConsoleIO.WriteLineFormatted("§8" + Translations.error_unexpect_response, acceptnewlines: true);
+ }
+ catch (Exception e)
+ {
+ ConsoleIO.WriteLineFormatted(String.Format("§8{0}: {1}", e.GetType().FullName, e.Message));
+ }
+ }, TimeSpan.FromSeconds(Config.Main.Advanced.ResolveSrvRecords == MainConfigHealper.MainConfig.AdvancedConfig.ResolveSrvRecordType.fast ? 10 : 30)))
{
if (protocolversion != 0 && protocolversion != protocolversionTmp)
ConsoleIO.WriteLineFormatted("§8" + Translations.error_version_different, acceptnewlines: true);
@@ -140,19 +129,14 @@ namespace MinecraftClient.Protocol
/// Protocol version to handle
/// Handler with the appropriate callbacks
///
- public static IMinecraftCom GetProtocolHandler(TcpClient Client, int ProtocolVersion, ForgeInfo? forgeInfo,
- IMinecraftComHandler Handler)
+ public static IMinecraftCom GetProtocolHandler(TcpClient Client, int ProtocolVersion, ForgeInfo? forgeInfo, IMinecraftComHandler Handler)
{
int[] supportedVersions_Protocol16 = { 51, 60, 61, 72, 73, 74, 78 };
if (Array.IndexOf(supportedVersions_Protocol16, ProtocolVersion) > -1)
return new Protocol16Handler(Client, ProtocolVersion, Handler);
- int[] supportedVersions_Protocol18 =
- {
- 4, 5, 47, 107, 108, 109, 110, 210, 315, 316, 335, 338, 340, 393, 401, 404, 477, 480, 485, 490, 498, 573,
- 575, 578, 735, 736, 751, 753, 754, 755, 756, 757, 758, 759, 760, 761, 762, 763, 764
- };
+ int[] supportedVersions_Protocol18 = { 4, 5, 47, 107, 108, 109, 110, 210, 315, 316, 335, 338, 340, 393, 401, 404, 477, 480, 485, 490, 498, 573, 575, 578, 735, 736, 751, 753, 754, 755, 756, 757, 758, 759, 760, 761, 762, 763, 764};
if (Array.IndexOf(supportedVersions_Protocol18, ProtocolVersion) > -1)
return new Protocol18Handler(Client, ProtocolVersion, Handler, forgeInfo);
@@ -444,27 +428,8 @@ namespace MinecraftClient.Protocol
return Protocol18Forge.ServerForceForge(protocol);
}
- public enum LoginResult
- {
- OtherError,
- ServiceUnavailable,
- SSLError,
- Success,
- WrongPassword,
- AccountMigrated,
- NotPremium,
- LoginRequired,
- InvalidToken,
- InvalidResponse,
- NullError,
- UserCancel
- };
-
- public enum AccountType
- {
- Mojang,
- Microsoft
- };
+ public enum LoginResult { OtherError, ServiceUnavailable, SSLError, Success, WrongPassword, AccountMigrated, NotPremium, LoginRequired, InvalidToken, InvalidResponse, NullError, UserCancel, WrongSelection };
+ public enum AccountType { Mojang, Microsoft };
///
/// Allows to login to a premium Minecraft account using the Yggdrasil authentication scheme.
@@ -486,7 +451,11 @@ namespace MinecraftClient.Protocol
{
return MojangLogin(user, pass, out session);
}
- else throw new InvalidOperationException("Account type must be Mojang or Microsoft");
+ else if (type == LoginType.yggdrasil)
+ {
+ return YggdrasiLogin(user, pass, out session);
+ }
+ else throw new InvalidOperationException("Account type must be Mojang or Microsoft or valid authlib 3rd Servers!");
}
///
@@ -503,10 +472,8 @@ namespace MinecraftClient.Protocol
try
{
string result = "";
- string json_request = "{\"agent\": { \"name\": \"Minecraft\", \"version\": 1 }, \"username\": \"" +
- JsonEncode(user) + "\", \"password\": \"" + JsonEncode(pass) +
- "\", \"clientToken\": \"" + JsonEncode(session.ClientID) + "\" }";
- int code = DoHTTPSPost("authserver.mojang.com", "/authenticate", json_request, ref result);
+ string json_request = "{\"agent\": { \"name\": \"Minecraft\", \"version\": 1 }, \"username\": \"" + JsonEncode(user) + "\", \"password\": \"" + JsonEncode(pass) + "\", \"clientToken\": \"" + JsonEncode(session.ClientID) + "\" }";
+ int code = DoHTTPSPost("authserver.mojang.com",443, "/authenticate", json_request, ref result);
if (code == 200)
{
if (result.Contains("availableProfiles\":[]}"))
@@ -523,8 +490,7 @@ namespace MinecraftClient.Protocol
{
session.ID = loginResponse.Properties["accessToken"].StringValue;
session.PlayerID = loginResponse.Properties["selectedProfile"].Properties["id"].StringValue;
- session.PlayerName = loginResponse.Properties["selectedProfile"].Properties["name"]
- .StringValue;
+ session.PlayerName = loginResponse.Properties["selectedProfile"].Properties["name"].StringValue;
return LoginResult.Success;
}
else return LoginResult.InvalidResponse;
@@ -554,7 +520,6 @@ namespace MinecraftClient.Protocol
{
ConsoleIO.WriteLineFormatted("§8" + e.ToString());
}
-
return LoginResult.SSLError;
}
catch (System.IO.IOException e)
@@ -563,7 +528,6 @@ namespace MinecraftClient.Protocol
{
ConsoleIO.WriteLineFormatted("§8" + e.ToString());
}
-
if (e.Message.Contains("authentication"))
{
return LoginResult.SSLError;
@@ -576,11 +540,119 @@ namespace MinecraftClient.Protocol
{
ConsoleIO.WriteLineFormatted("§8" + e.ToString());
}
-
return LoginResult.OtherError;
}
}
+ private static LoginResult YggdrasiLogin(string user, string pass, out SessionToken session)
+ {
+ session = new SessionToken() { ClientID = Guid.NewGuid().ToString().Replace("-", "") };
+ try
+ {
+ string result = "";
+ string json_request = "{\"agent\": { \"name\": \"Minecraft\", \"version\": 1 }, \"username\": \"" + JsonEncode(user) + "\", \"password\": \"" + JsonEncode(pass) + "\", \"clientToken\": \"" + JsonEncode(session.ClientID) + "\" }";
+ int code = DoHTTPSPost(Config.Main.General.AuthServer.Host,Config.Main.General.AuthServer.Port, "/api/yggdrasil/authserver/authenticate", json_request, ref result);
+ if (code == 200)
+ {
+ if (result.Contains("availableProfiles\":[]}"))
+ {
+ return LoginResult.NotPremium;
+ }
+ else
+ {
+ Json.JSONData loginResponse = Json.ParseJson(result);
+ if (loginResponse.Properties.ContainsKey("accessToken"))
+ {
+ session.ID = loginResponse.Properties["accessToken"].StringValue;
+ if (loginResponse.Properties.ContainsKey("selectedProfile")
+ && loginResponse.Properties["selectedProfile"].Properties.ContainsKey("id")
+ && loginResponse.Properties["selectedProfile"].Properties.ContainsKey("name"))
+ {
+ session.PlayerID = loginResponse.Properties["selectedProfile"].Properties["id"].StringValue;
+ session.PlayerName = loginResponse.Properties["selectedProfile"].Properties["name"].StringValue;
+ return LoginResult.Success;
+ }
+ else
+ {
+ string availableProfiles = "";
+ foreach (Json.JSONData profile in loginResponse.Properties["availableProfiles"].DataArray)
+ {
+ availableProfiles += " " + profile.Properties["name"].StringValue;
+ }
+ ConsoleIO.WriteLine(Translations.mcc_avaliable_profiles + availableProfiles);
+
+ ConsoleIO.WriteLine(Translations.mcc_select_profile);
+ string selectedProfileName = ConsoleIO.ReadLine();
+ ConsoleIO.WriteLine(Translations.mcc_selected_profile + " " + selectedProfileName);
+ Json.JSONData? selectedProfile = null;
+ foreach (Json.JSONData profile in loginResponse.Properties["availableProfiles"].DataArray)
+ {
+ selectedProfile = profile.Properties["name"].StringValue == selectedProfileName ? profile : selectedProfile;
+ }
+
+ if (selectedProfile != null)
+ {
+ session.PlayerID = selectedProfile.Properties["id"].StringValue;
+ session.PlayerName = selectedProfile.Properties["name"].StringValue;
+ SessionToken currentsession = session;
+ return GetNewYggdrasilToken(currentsession, out session);
+ }
+ else
+ {
+ return LoginResult.WrongSelection;
+ }
+ }
+ }
+ else return LoginResult.InvalidResponse;
+ }
+ }
+ else if (code == 403)
+ {
+ if (result.Contains("UserMigratedException"))
+ {
+ return LoginResult.AccountMigrated;
+ }
+ else return LoginResult.WrongPassword;
+ }
+ else if (code == 503)
+ {
+ return LoginResult.ServiceUnavailable;
+ }
+ else
+ {
+ ConsoleIO.WriteLineFormatted("§8" + string.Format(Translations.error_http_code, code));
+ return LoginResult.OtherError;
+ }
+ }
+ catch (System.Security.Authentication.AuthenticationException e)
+ {
+ if (Settings.Config.Logging.DebugMessages)
+ {
+ ConsoleIO.WriteLineFormatted("§8" + e.ToString());
+ }
+ return LoginResult.SSLError;
+ }
+ catch (System.IO.IOException e)
+ {
+ if (Settings.Config.Logging.DebugMessages)
+ {
+ ConsoleIO.WriteLineFormatted("§8" + e.ToString());
+ }
+ if (e.Message.Contains("authentication"))
+ {
+ return LoginResult.SSLError;
+ }
+ else return LoginResult.OtherError;
+ }
+ catch (Exception e)
+ {
+ if (Settings.Config.Logging.DebugMessages)
+ {
+ ConsoleIO.WriteLineFormatted("§8" + e.ToString());
+ }
+ return LoginResult.OtherError;
+ }
+ }
///
/// Sign-in to Microsoft Account without using browser. Only works if 2FA is disabled.
/// Might not work well in some rare cases.
@@ -606,7 +678,6 @@ namespace MinecraftClient.Protocol
{
ConsoleIO.WriteLineFormatted("§c" + e.StackTrace);
}
-
return LoginResult.WrongPassword; // Might not always be wrong password
}
}
@@ -677,7 +748,6 @@ namespace MinecraftClient.Protocol
{
ConsoleIO.WriteLineFormatted("§c" + e.StackTrace);
}
-
return LoginResult.WrongPassword; // Might not always be wrong password
}
}
@@ -691,15 +761,13 @@ namespace MinecraftClient.Protocol
{
var payload = JwtPayloadDecode.GetPayload(session.ID);
var json = Json.ParseJson(payload);
- var expTimestamp = long.Parse(json.Properties["exp"].StringValue, NumberStyles.Any,
- CultureInfo.CurrentCulture);
+ var expTimestamp = long.Parse(json.Properties["exp"].StringValue, NumberStyles.Any, CultureInfo.CurrentCulture);
var now = DateTime.Now;
var tokenExp = UnixTimeStampToDateTime(expTimestamp);
if (Settings.Config.Logging.DebugMessages)
{
ConsoleIO.WriteLine("Access token expiration time is " + tokenExp.ToString());
}
-
if (now < tokenExp)
{
// Still valid
@@ -724,11 +792,8 @@ namespace MinecraftClient.Protocol
try
{
string result = "";
- string json_request = "{ \"accessToken\": \"" + JsonEncode(currentsession.ID) +
- "\", \"clientToken\": \"" + JsonEncode(currentsession.ClientID) +
- "\", \"selectedProfile\": { \"id\": \"" + JsonEncode(currentsession.PlayerID) +
- "\", \"name\": \"" + JsonEncode(currentsession.PlayerName) + "\" } }";
- int code = DoHTTPSPost("authserver.mojang.com", "/refresh", json_request, ref result);
+ string json_request = "{ \"accessToken\": \"" + JsonEncode(currentsession.ID) + "\", \"clientToken\": \"" + JsonEncode(currentsession.ClientID) + "\", \"selectedProfile\": { \"id\": \"" + JsonEncode(currentsession.PlayerID) + "\", \"name\": \"" + JsonEncode(currentsession.PlayerName) + "\" } }";
+ int code = DoHTTPSPost("authserver.mojang.com",443, "/refresh", json_request, ref result);
if (code == 200)
{
if (result == null)
@@ -745,8 +810,53 @@ namespace MinecraftClient.Protocol
{
session.ID = loginResponse.Properties["accessToken"].StringValue;
session.PlayerID = loginResponse.Properties["selectedProfile"].Properties["id"].StringValue;
- session.PlayerName = loginResponse.Properties["selectedProfile"].Properties["name"]
- .StringValue;
+ session.PlayerName = loginResponse.Properties["selectedProfile"].Properties["name"].StringValue;
+ return LoginResult.Success;
+ }
+ else return LoginResult.InvalidResponse;
+ }
+ }
+ else if (code == 403 && result.Contains("InvalidToken"))
+ {
+ return LoginResult.InvalidToken;
+ }
+ else
+ {
+ ConsoleIO.WriteLineFormatted("§8" + string.Format(Translations.error_auth, code));
+ return LoginResult.OtherError;
+ }
+ }
+ catch
+ {
+ return LoginResult.OtherError;
+ }
+ }
+
+ public static LoginResult GetNewYggdrasilToken(SessionToken currentsession, out SessionToken session)
+ {
+ session = new SessionToken();
+ try
+ {
+ string result = "";
+ string json_request = "{ \"accessToken\": \"" + JsonEncode(currentsession.ID) + "\", \"clientToken\": \"" + JsonEncode(currentsession.ClientID) + "\", \"selectedProfile\": { \"id\": \"" + JsonEncode(currentsession.PlayerID) + "\", \"name\": \"" + JsonEncode(currentsession.PlayerName) + "\" } }";
+ int code = DoHTTPSPost(Config.Main.General.AuthServer.Host, Config.Main.General.AuthServer.Port, "/api/yggdrasil/authserver/refresh", json_request, ref result);
+ if (code == 200)
+ {
+ if (result == null)
+ {
+ return LoginResult.NullError;
+ }
+ else
+ {
+ Json.JSONData loginResponse = Json.ParseJson(result);
+ if (loginResponse.Properties.ContainsKey("accessToken")
+ && loginResponse.Properties.ContainsKey("selectedProfile")
+ && loginResponse.Properties["selectedProfile"].Properties.ContainsKey("id")
+ && loginResponse.Properties["selectedProfile"].Properties.ContainsKey("name"))
+ {
+ session.ID = loginResponse.Properties["accessToken"].StringValue;
+ session.PlayerID = loginResponse.Properties["selectedProfile"].Properties["id"].StringValue;
+ session.PlayerName = loginResponse.Properties["selectedProfile"].Properties["name"].StringValue;
return LoginResult.Success;
}
else return LoginResult.InvalidResponse;
@@ -774,21 +884,22 @@ namespace MinecraftClient.Protocol
/// Username
/// Session ID
/// Server ID
+ /// LoginType
/// TRUE if session was successfully checked
- public static bool SessionCheck(string uuid, string accesstoken, string serverhash)
+ public static bool SessionCheck(string uuid, string accesstoken, string serverhash, LoginType type)
{
try
{
string result = "";
- string json_request = "{\"accessToken\":\"" + accesstoken + "\",\"selectedProfile\":\"" + uuid +
- "\",\"serverId\":\"" + serverhash + "\"}";
- int code = DoHTTPSPost("sessionserver.mojang.com", "/session/minecraft/join", json_request, ref result);
+ string json_request = "{\"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 ? "/api/yggdrasil/sessionserver/session/minecraft/join" : "/session/minecraft/join";
+
+ int code = DoHTTPSPost(host, port, endpoint, json_request, ref result);
return (code >= 200 && code < 300);
}
- catch
- {
- return false;
- }
+ catch { return false; }
}
///
@@ -804,9 +915,8 @@ namespace MinecraftClient.Protocol
try
{
string result = "";
- string cookies = String.Format("sid=token:{0}:{1};user={2};version={3}", accesstoken, uuid, username,
- Program.MCHighestVersion);
- DoHTTPSGet("pc.realms.minecraft.net", "/worlds", cookies, ref result);
+ string cookies = String.Format("sid=token:{0}:{1};user={2};version={3}", accesstoken, uuid, username, Program.MCHighestVersion);
+ DoHTTPSGet("pc.realms.minecraft.net", 443,"/worlds", cookies, ref result);
Json.JSONData realmsWorlds = Json.ParseJson(result);
if (realmsWorlds.Properties.ContainsKey("servers")
&& realmsWorlds.Properties["servers"].Type == Json.JSONData.DataType.Array
@@ -832,7 +942,6 @@ namespace MinecraftClient.Protocol
}
}
}
-
if (availableWorlds.Count > 0)
{
ConsoleIO.WriteLine(Translations.mcc_realms_available);
@@ -841,6 +950,7 @@ namespace MinecraftClient.Protocol
ConsoleIO.WriteLine(Translations.mcc_realms_join);
}
}
+
}
catch (Exception e)
{
@@ -850,7 +960,6 @@ namespace MinecraftClient.Protocol
ConsoleIO.WriteLineFormatted("§8" + e.StackTrace);
}
}
-
return realmsWorldsResult;
}
@@ -862,16 +971,13 @@ namespace MinecraftClient.Protocol
/// Player UUID
/// Access token
/// Server address (host:port) or empty string if failure
- public static string GetRealmsWorldServerAddress(string worldId, string username, string uuid,
- string accesstoken)
+ public static string GetRealmsWorldServerAddress(string worldId, string username, string uuid, string accesstoken)
{
try
{
string result = "";
- string cookies = String.Format("sid=token:{0}:{1};user={2};version={3}", accesstoken, uuid, username,
- Program.MCHighestVersion);
- int statusCode = DoHTTPSGet("pc.realms.minecraft.net", "/worlds/v1/" + worldId + "/join/pc", cookies,
- ref result);
+ string cookies = String.Format("sid=token:{0}:{1};user={2};version={3}", accesstoken, uuid, username, Program.MCHighestVersion);
+ int statusCode = DoHTTPSGet("pc.realms.minecraft.net",443, "/worlds/v1/" + worldId + "/join/pc", cookies, ref result);
if (statusCode == 200)
{
Json.JSONData serverAddress = Json.ParseJson(result);
@@ -896,7 +1002,6 @@ namespace MinecraftClient.Protocol
{
ConsoleIO.WriteLineFormatted("§8" + e.StackTrace);
}
-
return "";
}
}
@@ -909,7 +1014,7 @@ namespace MinecraftClient.Protocol
/// Cookies for making the request
/// Request result
/// HTTP Status code
- private static int DoHTTPSGet(string host, string endpoint, string cookies, ref string result)
+ private static int DoHTTPSGet(string host,int port, string endpoint, string cookies, ref string result)
{
List http_request = new()
{
@@ -924,7 +1029,7 @@ namespace MinecraftClient.Protocol
"",
""
};
- return DoHTTPSRequest(http_request, host, ref result);
+ return DoHTTPSRequest(http_request, host,port, ref result);
}
///
@@ -935,7 +1040,7 @@ namespace MinecraftClient.Protocol
/// Request payload
/// Request result
/// HTTP Status code
- private static int DoHTTPSPost(string host, string endpoint, string request, ref string result)
+ private static int DoHTTPSPost(string host, int port, string endpoint, string request, ref string result)
{
List http_request = new()
{
@@ -948,7 +1053,7 @@ namespace MinecraftClient.Protocol
"",
request
};
- return DoHTTPSRequest(http_request, host, ref result);
+ return DoHTTPSRequest(http_request, host,port, ref result);
}
///
@@ -959,7 +1064,7 @@ namespace MinecraftClient.Protocol
/// Host to connect to
/// Request result
/// HTTP Status code
- private static int DoHTTPSRequest(List headers, string host, ref string result)
+ private static int DoHTTPSRequest(List headers, string host,int port, ref string result)
{
string? postResult = null;
int statusCode = 520;
@@ -971,10 +1076,9 @@ namespace MinecraftClient.Protocol
if (Settings.Config.Logging.DebugMessages)
ConsoleIO.WriteLineFormatted("§8" + string.Format(Translations.debug_request, host));
- TcpClient client = ProxyHandler.NewTcpClient(host, 443, true);
+ TcpClient client = ProxyHandler.NewTcpClient(host, port, true);
SslStream stream = new(client.GetStream());
- stream.AuthenticateAsClient(host, null, SslProtocols.Tls12,
- true); // Enable TLS 1.2. Hotfix for #1780
+ stream.AuthenticateAsClient(host, null, SslProtocols.Tls12, true); // Enable TLS 1.2. Hotfix for #1780
if (Settings.Config.Logging.DebugMessages)
foreach (string line in headers)
@@ -993,8 +1097,15 @@ namespace MinecraftClient.Protocol
if (raw_result.StartsWith("HTTP/1.1"))
{
- postResult = raw_result[(raw_result.IndexOf("\r\n\r\n") + 4)..];
statusCode = int.Parse(raw_result.Split(' ')[1], NumberStyles.Any, CultureInfo.CurrentCulture);
+ if (statusCode != 204)
+ {
+ postResult = raw_result[(raw_result.IndexOf("\r\n\r\n") + 4)..].Split("\r\n")[1];
+ }
+ else
+ {
+ postResult = "No Content";
+ }
}
else statusCode = 520; //Web server is returning an unknown error
}
@@ -1053,4 +1164,4 @@ namespace MinecraftClient.Protocol
return dateTime;
}
}
-}
\ No newline at end of file
+}
diff --git a/MinecraftClient/Protocol/Session/SessionToken.cs b/MinecraftClient/Protocol/Session/SessionToken.cs
index c3c0aee9..1df31146 100644
--- a/MinecraftClient/Protocol/Session/SessionToken.cs
+++ b/MinecraftClient/Protocol/Session/SessionToken.cs
@@ -3,6 +3,7 @@ using System.IO;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using MinecraftClient.Scripting;
+using static MinecraftClient.Settings.MainConfigHealper.MainConfig.GeneralConfig;
namespace MinecraftClient.Protocol.Session
{
@@ -32,13 +33,13 @@ namespace MinecraftClient.Protocol.Session
ServerPublicKey = null;
}
- public bool SessionPreCheck()
+ public bool SessionPreCheck(LoginType type)
{
if (ID == string.Empty || PlayerID == String.Empty || ServerPublicKey == null)
return false;
Crypto.CryptoHandler.ClientAESPrivateKey ??= Crypto.CryptoHandler.GenerateAESPrivateKey();
string serverHash = Crypto.CryptoHandler.GetServerHash(ServerIDhash, ServerPublicKey, Crypto.CryptoHandler.ClientAESPrivateKey);
- if (ProtocolHandler.SessionCheck(PlayerID, ID, serverHash))
+ if (ProtocolHandler.SessionCheck(PlayerID, ID, serverHash, type))
return true;
return false;
}
diff --git a/MinecraftClient/Resources/ConfigComments/ConfigComments.Designer.cs b/MinecraftClient/Resources/ConfigComments/ConfigComments.Designer.cs
index eec9c25d..762b4d2e 100644
--- a/MinecraftClient/Resources/ConfigComments/ConfigComments.Designer.cs
+++ b/MinecraftClient/Resources/ConfigComments/ConfigComments.Designer.cs
@@ -799,7 +799,8 @@ namespace MinecraftClient {
///NOTE: This is an experimental feature, the bot can be slow at times, you need to walk with a normal speed and to sometimes stop for it to be able to keep up with you
///It's similar to making animals follow you when you're holding food in your hand.
///This is due to a slow pathfinding algorithm, we're working on getting a better one
- ///You can tweak the update limit and find what works best for you. (NOTE: Do not but a very low one, because you might achieve the opposite,
/// [rest of string was truncated]";.
+ ///You can tweak the update limit and find what works best for you. (NOTE: Do not but a very low one, because you might achieve the opposite,
+ /// [rest of string was truncated]";.
///
internal static string ChatBot_FollowPlayer {
get {
@@ -1128,6 +1129,15 @@ namespace MinecraftClient {
}
}
+ ///
+ /// Looks up a localized string similar to Allow IP aliases, such as "localhost" or if using containers then the container name can be used....
+ ///
+ internal static string ChatBot_WebSocketBot_AllowIpAlias {
+ get {
+ return ResourceManager.GetString("ChatBot.WebSocketBot.AllowIpAlias", resourceCulture);
+ }
+ }
+
///
/// Looks up a localized string similar to This setting is for developers who are developing a library that uses this chat bot to remotely execute procedures/commands/functions..
///
@@ -1722,6 +1732,15 @@ namespace MinecraftClient {
}
}
+ ///
+ /// Looks up a localized string similar to Yggdrasil authlib server domain name and port..
+ ///
+ internal static string Main_General_AuthlibServer {
+ get {
+ return ResourceManager.GetString("Main.General.AuthlibServer", resourceCulture);
+ }
+ }
+
///
/// Looks up a localized string similar to The address of the game server, "Host" can be filled in with domain name or IP address. (The "Port" field can be deleted, it will be resolved automatically).
///
@@ -1741,7 +1760,7 @@ namespace MinecraftClient {
}
///
- /// Looks up a localized string similar to Account type: "mojang" OR "microsoft". Also affects interactive login in console..
+ /// Looks up a localized string similar to Account type: "mojang" OR "microsoft" OR "yggdrasil". Also affects interactive login in console..
///
internal static string Main_General_server_info {
get {
@@ -1986,4 +2005,4 @@ namespace MinecraftClient {
}
}
}
-}
+}
\ No newline at end of file
diff --git a/MinecraftClient/Resources/ConfigComments/ConfigComments.resx b/MinecraftClient/Resources/ConfigComments/ConfigComments.resx
index 8ad6001f..7e9e3b09 100644
--- a/MinecraftClient/Resources/ConfigComments/ConfigComments.resx
+++ b/MinecraftClient/Resources/ConfigComments/ConfigComments.resx
@@ -724,7 +724,7 @@ Usage examples: "/tell <mybot> connect Server1", "/connect Server2"Microsoft Account sign-in method: "mcc" OR "browser". If the login always fails, please try to use the "browser" once.
- Account type: "mojang" OR "microsoft". Also affects interactive login in console.
+ Account type: "mojang" OR "microsoft" OR "yggdrasil". Also affects interactive login in console.
Settings below are sent to the server and only affect server-side things like your skin.
@@ -843,7 +843,13 @@ If the connection to the Minecraft game server is blocked by the firewall, set E
This setting is for developers who are developing a library that uses this chat bot to remotely execute procedures/commands/functions.
+
+ Allow IP aliases, such as "localhost" or if using containers then the container name can be used...
+
Ignore invalid player name
+
+ Yggdrasil authlib server domain name and port.
+
\ No newline at end of file
diff --git a/MinecraftClient/Resources/Translations/Translations.Designer.cs b/MinecraftClient/Resources/Translations/Translations.Designer.cs
index 08a5b472..7d4cd17b 100644
--- a/MinecraftClient/Resources/Translations/Translations.Designer.cs
+++ b/MinecraftClient/Resources/Translations/Translations.Designer.cs
@@ -2450,6 +2450,15 @@ namespace MinecraftClient {
return ResourceManager.GetString("chatbot.reconnect", resourceCulture);
}
}
+
+ ///
+ /// Looks up a localized string similar to .
+ ///
+ internal static string ChatBot_WebSocketBot_AllowIpAlias {
+ get {
+ return ResourceManager.GetString("ChatBot.WebSocketBot.AllowIpAlias", resourceCulture);
+ }
+ }
///
/// Looks up a localized string similar to .
@@ -5373,6 +5382,15 @@ namespace MinecraftClient {
}
}
+ ///
+ /// Looks up a localized string similar to Avaliable profiles:.
+ ///
+ internal static string mcc_avaliable_profiles {
+ get {
+ return ResourceManager.GetString("mcc.avaliable_profiles", resourceCulture);
+ }
+ }
+
///
/// Looks up a localized string similar to The old MinecraftClient.ini has been backed up as {0}.
///
@@ -5746,6 +5764,24 @@ namespace MinecraftClient {
}
}
+ ///
+ /// Looks up a localized string similar to Select a profile from available profiles:.
+ ///
+ internal static string mcc_select_profile {
+ get {
+ return ResourceManager.GetString("mcc.select_profile", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Selected profile:.
+ ///
+ internal static string mcc_selected_profile {
+ get {
+ return ResourceManager.GetString("mcc.selected_profile", resourceCulture);
+ }
+ }
+
///
/// Looks up a localized string similar to Server is in offline mode..
///
diff --git a/MinecraftClient/Resources/Translations/Translations.resx b/MinecraftClient/Resources/Translations/Translations.resx
index 414b08cd..abc5c08b 100644
--- a/MinecraftClient/Resources/Translations/Translations.resx
+++ b/MinecraftClient/Resources/Translations/Translations.resx
@@ -2121,4 +2121,13 @@ Logging in...
Shift right-clicking slot {0} in window #{1}
+
+ Avaliable profiles:
+
+
+ Selected profile:
+
+
+ Select a profile from available profiles:
+
\ No newline at end of file
diff --git a/MinecraftClient/Resources/en_us.json b/MinecraftClient/Resources/en_us.json
index f02b7bf1..72aa260c 100644
--- a/MinecraftClient/Resources/en_us.json
+++ b/MinecraftClient/Resources/en_us.json
@@ -4632,6 +4632,8 @@
"advancements.adventure.avoid_vibration.description": "Sneak near a Sculk Sensor or Warden to prevent it from detecting you",
"advancements.adventure.bullseye.title": "Bullseye",
"advancements.adventure.bullseye.description": "Hit the bullseye of a Target block from at least 30 meters away",
+ "advancements.adventure.craft_decorated_pot_using_only_sherds.title": "Careful Restoration",
+ "advancements.adventure.craft_decorated_pot_using_only_sherds.description": "Make a Decorated Pot out of 4 Pottery Sherds",
"advancements.adventure.fall_from_world_height.title": "Caves & Cliffs",
"advancements.adventure.fall_from_world_height.description": "Free fall from the top of the world (build limit) to the bottom of the world and survive",
"advancements.adventure.kill_mob_near_sculk_catalyst.title": "It Spreads",
@@ -4660,6 +4662,10 @@
"advancements.adventure.play_jukebox_in_meadows.description": "Make the Meadows come alive with the sound of music from a Jukebox",
"advancements.adventure.root.title": "Adventure",
"advancements.adventure.root.description": "Adventure, exploration and combat",
+ "advancements.adventure.read_power_of_chiseled_bookshelf.title": "The Power of Books",
+ "advancements.adventure.read_power_of_chiseled_bookshelf.description": "Read the power signal of a Chiseled Bookshelf using a Comparator",
+ "advancements.adventure.salvage_sherd.title": "Respecting the Remnants",
+ "advancements.adventure.salvage_sherd.description": "Brush a Suspicious block to obtain a Pottery Sherd",
"advancements.adventure.shoot_arrow.title": "Take Aim",
"advancements.adventure.shoot_arrow.description": "Shoot something with an Arrow",
"advancements.adventure.sleep_in_bed.title": "Sweet Dreams",
@@ -4674,6 +4680,10 @@
"advancements.adventure.trade.description": "Successfully trade with a Villager",
"advancements.adventure.trade_at_world_height.title": "Star Trader",
"advancements.adventure.trade_at_world_height.description": "Trade with a Villager at the build height limit",
+ "advancements.adventure.trim_with_all_exclusive_armor_patterns.title": "Smithing with Style",
+ "advancements.adventure.trim_with_all_exclusive_armor_patterns.description": "Apply these smithing templates at least once: Spire, Snout, Rib, Ward, Silence, Vex, Tide, Wayfinder",
+ "advancements.adventure.trim_with_any_armor_pattern.title": "Crafting a New Look",
+ "advancements.adventure.trim_with_any_armor_pattern.description": "Craft a trimmed armor at a Smithing Table",
"advancements.adventure.throw_trident.title": "A Throwaway Joke",
"advancements.adventure.throw_trident.description": "Throw a Trident at something.\nNote: Throwing away your only weapon is not a good idea.",
"advancements.adventure.two_birds_one_arrow.title": "Two Birds, One Arrow",
@@ -4730,6 +4740,12 @@
"advancements.husbandry.allay_deliver_item_to_player.description": "Have an Allay deliver items to you",
"advancements.husbandry.allay_deliver_cake_to_note_block.title": "Birthday Song",
"advancements.husbandry.allay_deliver_cake_to_note_block.description": "Have an Allay drop a Cake at a Note Block",
+ "advancements.husbandry.obtain_sniffer_egg.title": "Smells Interesting",
+ "advancements.husbandry.obtain_sniffer_egg.description": "Obtain a Sniffer Egg",
+ "advancements.husbandry.plant_any_sniffer_seed.title": "Planting the Past",
+ "advancements.husbandry.plant_any_sniffer_seed.description": "Plant any Sniffer seed",
+ "advancements.husbandry.obtain_netherite_hoe.title": "Serious Dedication",
+ "advancements.husbandry.obtain_netherite_hoe.description": "Use a Netherite Ingot to upgrade a Hoe, and then reevaluate your life choices",
"advancements.end.dragon_breath.title": "You Need a Mint",
"advancements.end.dragon_breath.description": "Collect Dragon's Breath in a Glass Bottle",
"advancements.end.dragon_egg.title": "The Next Generation",
diff --git a/MinecraftClient/Scripting/ChatBot.cs b/MinecraftClient/Scripting/ChatBot.cs
index af5b5a43..36c365be 100644
--- a/MinecraftClient/Scripting/ChatBot.cs
+++ b/MinecraftClient/Scripting/ChatBot.cs
@@ -347,6 +347,13 @@ namespace MinecraftClient.Scripting
/// The score to be displayed next to the entry. Only sent when Action does not equal 1.
public virtual void OnUpdateScore(string entityname, int action, string objectivename, int value) { }
+ ///
+ /// Called when the client received the Tab Header and Footer
+ ///
+ /// Header
+ /// Footer
+ public virtual void OnTabListHeaderAndFooter(string header, string footer) { }
+
///
/// Called when an inventory/container was updated by server
///
diff --git a/MinecraftClient/Settings.cs b/MinecraftClient/Settings.cs
index c0d51028..7982b057 100644
--- a/MinecraftClient/Settings.cs
+++ b/MinecraftClient/Settings.cs
@@ -494,8 +494,11 @@ namespace MinecraftClient
[TomlInlineComment("$Main.General.method$")]
public LoginMethod Method = LoginMethod.mcc;
+ [TomlInlineComment("$Main.General.AuthlibServer$")]
+ public AuthlibServer AuthServer = new(string.Empty);
+
- public enum LoginType { mojang, microsoft };
+ public enum LoginType { mojang, microsoft,yggdrasil };
public enum LoginMethod { mcc, browser };
}
@@ -688,6 +691,29 @@ namespace MinecraftClient
this.Port = Port;
}
}
+ public struct AuthlibServer
+ {
+ public string Host = string.Empty;
+ public int Port = 443;
+
+ public AuthlibServer(string Host)
+ {
+ string[] sip = Host.Split(new[] { ":", ":" }, StringSplitOptions.None);
+ this.Host = sip[0];
+
+ if (sip.Length > 1)
+ {
+ try { this.Port = Convert.ToUInt16(sip[1]); }
+ catch (FormatException) { }
+ }
+ }
+
+ public AuthlibServer(string Host, ushort Port)
+ {
+ this.Host = Host.Split(new[] { ":", ":" }, StringSplitOptions.None)[0];
+ this.Port = Port;
+ }
+ }
}
}