13#if PROTOCOL_VERSION > 758
33 name = login_or_microsoft_cache_key_or_mc_token;
37 if (!
authentifier->AuthMicrosoft(login_or_microsoft_cache_key_or_mc_token))
39 throw std::runtime_error(
"Error trying to authenticate on Mojang server using Microsoft auth flow");
45 if (!
authentifier->AuthMCToken(login_or_microsoft_cache_key_or_mc_token))
47 throw std::runtime_error(
"Error trying to authenticate on Mojang server using provided mc token");
60 state = ConnectionState::Handshake;
69 return com->IsInitialized();
72 std::shared_ptr<ServerboundClientIntentionPacket> handshake_packet = std::make_shared<ServerboundClientIntentionPacket>();
73 handshake_packet->SetProtocolVersion(PROTOCOL_VERSION);
74 handshake_packet->SetHostName(
com->GetIp());
75 handshake_packet->SetPort(
com->GetPort());
76 handshake_packet->SetIntention(
static_cast<int>(ConnectionState::Login));
77 Send(handshake_packet);
79 state = ConnectionState::Login;
81 std::shared_ptr<ServerboundHelloPacket> loginstart_packet = std::make_shared<ServerboundHelloPacket>();
82#if PROTOCOL_VERSION < 759
83 loginstart_packet->SetGameProfile(
name);
85 loginstart_packet->SetName_(
name);
88#if PROTOCOL_VERSION < 761
94 loginstart_packet->SetPublicKey(key);
98#if PROTOCOL_VERSION > 759
99 loginstart_packet->SetProfileId(
authentifier->GetPlayerUUID());
103 Send(loginstart_packet);
108 state = constant_connection_state;
119 state = ConnectionState::None;
147 std::vector<unsigned char> packet_data;
148 packet_data.reserve(256);
149 packet->Write(packet_data);
152 com->SendPacket(packet_data);
156#ifdef USE_COMPRESSION
159 packet_data.insert(packet_data.begin(), 0x00);
160 com->SendPacket(packet_data);
164 std::vector<unsigned char> compressed_packet;
165 compressed_packet.reserve(packet_data.size() + 5);
166 WriteData<VarInt>(
static_cast<int>(packet_data.size()), compressed_packet);
167 std::vector<unsigned char> compressed_data =
Compress(packet_data);
168 compressed_packet.insert(compressed_packet.end(), compressed_data.begin(), compressed_data.end());
169 com->SendPacket(compressed_packet);
172 throw std::runtime_error(
"Program compiled without ZLIB. Cannot send compressed message");
190#if PROTOCOL_VERSION > 758
191 if (message[0] ==
'/')
193 LOG_INFO(
"You're trying to send a message starting with '/'. Use SendChatCommand instead if you want the server to interprete it as a command.");
197 std::shared_ptr<ServerboundChatPacket> chat_message = std::make_shared<ServerboundChatPacket>();
198 chat_message->SetMessage(message);
199#if PROTOCOL_VERSION > 758
200#if PROTOCOL_VERSION < 761
201 chat_message->SetSignedPreview(
false);
205 long long int salt, timestamp;
206 std::vector<unsigned char> signature;
207#if PROTOCOL_VERSION == 759
209 signature =
authentifier->GetMessageSignature(message, salt, timestamp);
210#elif PROTOCOL_VERSION == 760
216 signature =
authentifier->GetMessageSignature(message,
chat_context.GetLastSignature(), last_seen_update.GetLastSeen(), salt, timestamp);
220 chat_message->SetLastSeenMessages(last_seen_update);
226 chat_message->SetLastSeenMessages(updates);
228 if (signature.empty())
230 throw std::runtime_error(
"Empty chat message signature.");
232 chat_message->SetTimestamp(timestamp);
234#if PROTOCOL_VERSION < 760
236 salt_signature.SetSalt(salt);
237 salt_signature.SetSignature(signature);
239 chat_message->SetSaltSignature(salt_signature);
241 chat_message->SetSalt(salt);
242 chat_message->SetSignature(signature);
248 chat_message->SetTimestamp(std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch()).count());
256#if PROTOCOL_VERSION > 765
259 std::shared_ptr<ServerboundChatCommandPacket> chat_command = std::make_shared<ServerboundChatCommandPacket>();
260 chat_command->SetCommand(command);
265#if PROTOCOL_VERSION > 758
266#if PROTOCOL_VERSION > 765
267 std::shared_ptr<ServerboundChatCommandSignedPacket> chat_command = std::make_shared<ServerboundChatCommandSignedPacket>();
269 std::shared_ptr<ServerboundChatCommandPacket> chat_command = std::make_shared<ServerboundChatCommandPacket>();
271 chat_command->SetCommand(command);
272 chat_command->SetTimestamp(std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch()).count());
273#if PROTOCOL_VERSION > 759
274 std::mt19937 rnd(
static_cast<unsigned int>(std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::high_resolution_clock::now().time_since_epoch()).count()));
275 chat_command->SetSalt(std::uniform_int_distribution<long long int>(std::numeric_limits<long long int>::min(), std::numeric_limits<long long int>::max())(rnd));
277#if PROTOCOL_VERSION < 761
278 chat_command->SetSignedPreview(
false);
280#if PROTOCOL_VERSION == 760
287 chat_command->SetLastSeenMessages(last_seen_update);
288#elif PROTOCOL_VERSION > 760
290 chat_command->SetLastSeenMessages(updates);
293 chat_command->SetArgumentSignatures({});
295 std::shared_ptr<ServerboundChatPacket> chat_command = std::make_shared<ServerboundChatPacket>();
296 chat_command->SetMessage(
"/" + command);
311 while (
state != ConnectionState::None)
319 std::vector<unsigned char> packet;
328 if (packet.size() > 0)
336#ifdef USE_COMPRESSION
337 size_t length = packet.size();
339 int data_length = ReadData<VarInt>(iter, length);
342 if (data_length == 0)
345 packet.erase(packet.begin());
351 const int size_varint =
static_cast<int>(packet.size() - length);
353 std::vector<unsigned char> uncompressed_packet =
Decompress(packet, size_varint);
357 throw std::runtime_error(
"Program compiled without USE_COMPRESSION. Cannot read compressed message");
364 catch (
const std::exception& e)
383 std::vector<unsigned char>::const_iterator packet_iterator = bytes.begin();
384 size_t length = bytes.size();
386 const int packet_id = ReadData<VarInt>(packet_iterator, length);
390 if (packet !=
nullptr)
394 packet->Read(packet_iterator, length);
396 catch (
const std::exception& e)
398 LOG_FATAL(
"Parsing exception while parsing message \"" << packet->GetName() <<
"\"\n" << e.what());
401 for (
size_t i = 0; i <
subscribed.size(); i++)
423#if PROTOCOL_VERSION < 768
429#if PROTOCOL_VERSION < 764
430 state = ConnectionState::Play;
432 state = ConnectionState::Configuration;
433 std::shared_ptr<ServerboundLoginAcknowledgedPacket> login_ack_packet = std::make_shared<ServerboundLoginAcknowledgedPacket>();
434 Send(login_ack_packet);
441#
if PROTOCOL_VERSION > 765
442 && packet.GetShouldAuthenticate()
446 throw std::runtime_error(
"Authentication asked while no valid account has been provided, make sure to connect with a valid Microsoft Account, or to a server with online-mode=false");
450 std::shared_ptr<AESEncrypter> encrypter = std::make_shared<AESEncrypter>();
452 std::vector<unsigned char> raw_shared_secret;
453 std::vector<unsigned char> encrypted_shared_secret;
455#if PROTOCOL_VERSION < 759
456 std::vector<unsigned char> encrypted_nonce;
457 encrypter->Init(packet.GetPublicKey(), packet.GetNonce(),
458 raw_shared_secret, encrypted_nonce, encrypted_shared_secret);
459#elif PROTOCOL_VERSION < 761
460 std::vector<unsigned char> salted_nonce_signature;
462 encrypter->Init(packet.GetPublicKey(), packet.GetNonce(),
authentifier->GetPrivateKey(),
463 raw_shared_secret, encrypted_shared_secret,
464 salt, salted_nonce_signature);
466 std::vector<unsigned char> encrypted_challenge;
467 encrypter->Init(packet.GetPublicKey(), packet.GetChallenge(),
468 raw_shared_secret, encrypted_shared_secret,
469 encrypted_challenge);
473#if PROTOCOL_VERSION > 765
474 if (packet.GetShouldAuthenticate())
477 authentifier->JoinServer(packet.GetServerId(), raw_shared_secret, packet.GetPublicKey());
480 std::shared_ptr<ServerboundKeyPacket> response_packet = std::make_shared<ServerboundKeyPacket>();
481 response_packet->SetKeyBytes(encrypted_shared_secret);
483#if PROTOCOL_VERSION < 759
485 response_packet->SetNonce(encrypted_nonce);
486#elif PROTOCOL_VERSION < 761
489 salt_signature.SetSalt(salt);
490 salt_signature.SetSignature(salted_nonce_signature);
491 response_packet->SetSaltSignature(salt_signature);
494 response_packet->SetEncryptedChallenge(encrypted_challenge);
497 Send(response_packet);
500 com->SetEncrypter(encrypter);
502 throw std::runtime_error(
"Your version of botcraft doesn't support encryption. Either run your server with online-mode=false or recompile botcraft");
508 std::shared_ptr<ServerboundKeepAlivePacket> keep_alive_packet = std::make_shared<ServerboundKeepAlivePacket>();
509 keep_alive_packet->SetId_(packet.GetId_());
510 Send(keep_alive_packet);
513#if PROTOCOL_VERSION > 754
516 std::shared_ptr<ServerboundPongPacket> pong_packet = std::make_shared<ServerboundPongPacket>();
517 pong_packet->SetId_(packet.GetId_());
522#if PROTOCOL_VERSION > 340
528#if PROTOCOL_VERSION > 753
529 if (packet.GetIdentifier().GetFull() ==
"fabric-networking-api-v1:early_registration")
531#if PROTOCOL_VERSION < 764
532 std::shared_ptr<ServerboundCustomQueryPacket> custom_query_anwser = std::make_shared<ServerboundCustomQueryPacket>();
533 custom_query_anwser->SetTransactionId(packet.GetTransactionId());
534 custom_query_anwser->SetData(std::nullopt);
536 std::shared_ptr<ServerboundCustomQueryAnswerPacket> custom_query_anwser = std::make_shared<ServerboundCustomQueryAnswerPacket>();
537 custom_query_anwser->SetTransactionId(packet.GetTransactionId());
538 custom_query_anwser->SetPayload(std::nullopt);
540 Send(custom_query_anwser);
547#if PROTOCOL_VERSION > 759
550#if PROTOCOL_VERSION < 761
552#if _MSC_VER || __MINGW32__
553#pragma push_macro("GetMessage")
557#if _MSC_VER || __MINGW32__
558#pragma pop_macro("GetMessage")
561 if (packet.GetSignature().has_value())
565 chat_context.
AddSeenMessage(std::vector<unsigned char>(packet.GetSignature().value().begin(), packet.GetSignature().value().end()));
569 std::shared_ptr<ServerboundChatAckPacket> ack_packet = std::make_shared<ServerboundChatAckPacket>();
577#if PROTOCOL_VERSION < 761
585#if PROTOCOL_VERSION > 760
590 std::shared_ptr<ServerboundChatSessionUpdatePacket> chat_session_packet = std::make_shared<ServerboundChatSessionUpdatePacket>();
598 chat_session_data.SetProfilePublicKey(key);
600 std::mt19937 rnd = std::mt19937(
static_cast<unsigned int>(std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::high_resolution_clock::now().time_since_epoch()).count()));
601 std::uniform_int_distribution<int> distrib(std::numeric_limits<unsigned char>::min(), std::numeric_limits<unsigned char>::max());
608 chat_session_packet->SetChatSession(chat_session_data);
609 Send(chat_session_packet);
614#if PROTOCOL_VERSION > 763
617 state = ConnectionState::Play;
618 std::shared_ptr<ServerboundFinishConfigurationPacket> finish_config_packet = std::make_shared<ServerboundFinishConfigurationPacket>();
619 Send(finish_config_packet);
624 std::shared_ptr<ServerboundKeepAliveConfigurationPacket> keep_alive_packet = std::make_shared<ServerboundKeepAliveConfigurationPacket>();
625 keep_alive_packet->SetId_(packet.GetId_());
626 Send(keep_alive_packet);
631 std::shared_ptr<ServerboundPongConfigurationPacket> pong_packet = std::make_shared<ServerboundPongConfigurationPacket>();
632 pong_packet->SetId_(packet.GetId_());
638 state = ConnectionState::Configuration;
639 std::shared_ptr<ServerboundConfigurationAcknowledgedPacket> config_ack_packet = std::make_shared<ServerboundConfigurationAcknowledgedPacket>();
640 Send(config_ack_packet);
650 using count_return =
decltype(std::declval<std::chrono::milliseconds>().count());
651 const count_return time_elapsed_ms = std::max(
static_cast<count_return
>(1), std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::steady_clock::now() -
chunk_batch_start_time).count());
652 std::shared_ptr<ServerboundChunkBatchReceivedPacket> chunk_per_tick_packet = std::make_shared<ServerboundChunkBatchReceivedPacket>();
654 chunk_per_tick_packet->SetDesiredChunksPerTick(packet.GetBatchSize() * 50.0f / time_elapsed_ms);
655 Send(chunk_per_tick_packet);
659#if PROTOCOL_VERSION > 765
662 std::shared_ptr<ServerboundSelectKnownPacksPacket> select_known_packs = std::make_shared<ServerboundSelectKnownPacksPacket>();
664 select_known_packs->SetKnownPacks({});
666 Send(select_known_packs);
#define LOG_INFO(osstream)
#define LOG_FATAL(osstream)
void AddSeenMessage(const std::vector< unsigned char > &signature)
std::pair< std::vector< std::vector< unsigned char > >, ProtocolCraft::LastSeenMessagesUpdate > GetLastSeenMessagesUpdate()
Get both a vector of previous messages signatures and the LastSeenMessagesUpdate object.
void RegisterThread(const std::string &name)
Register the current thread in the map.
static Logger & GetInstance()
std::condition_variable process_condition
void AddHandler(ProtocolCraft::Handler *h)
virtual void Handle(ProtocolCraft::ClientboundLoginCompressionPacket &packet) override
std::thread::id GetProcessingThreadId() const
void SendChatCommand(const std::string &command)
std::thread m_thread_process
void Send(const std::shared_ptr< ProtocolCraft::Packet > packet)
void SendChatMessage(const std::string &message)
void ProcessPacket(const std::vector< unsigned char > &bytes)
LastSeenMessagesTracker chat_context
std::shared_ptr< TCP_Com > com
void OnNewRawData(const std::vector< unsigned char > &bytes)
std::chrono::steady_clock::time_point chunk_batch_start_time
const std::string & GetMyName() const
std::shared_ptr< Authentifier > authentifier
const ProtocolCraft::ConnectionState GetConnectionState() const
std::vector< ProtocolCraft::Handler * > subscribed
std::atomic< int > message_sent_index
ProtocolCraft::ConnectionState state
std::queue< std::vector< unsigned char > > packets_to_process
ProtocolCraft::UUID chat_session_uuid
NetworkManager(const std::string &address, const std::string &login_or_microsoft_cache_key_or_mc_token, const AuthType auth_type, const std::vector< ProtocolCraft::Handler * > &handlers={})
std::vector< unsigned char > RSAToBytes(const std::string &s)
std::vector< unsigned char > DecodeBase64(const std::string &s)
bool WaitForCondition(const std::function< bool()> &condition, const long long int timeout_ms=0, const long long int check_interval_ms=10)
std::vector< unsigned char > Decompress(const std::vector< unsigned char > &compressed, const int start=0)
std::vector< unsigned char > Compress(const std::vector< unsigned char > &raw)
std::shared_ptr< Packet > CreateClientboundPacket(const ConnectionState state, const int id)
std::array< unsigned char, 16 > UUID
std::vector< unsigned char >::const_iterator ReadIterator