13#if PROTOCOL_VERSION > 758
30 if (login.empty() || force_microsoft_auth)
35 throw std::runtime_error(
"Error trying to authenticate on Mojang server using Microsoft auth flow");
53 state = ConnectionState::Handshake;
62 return com->IsInitialized();
65 std::shared_ptr<ServerboundClientIntentionPacket> handshake_msg = std::make_shared<ServerboundClientIntentionPacket>();
66 handshake_msg->SetProtocolVersion(PROTOCOL_VERSION);
67 handshake_msg->SetHostName(
com->GetIp());
68 handshake_msg->SetPort(
com->GetPort());
69 handshake_msg->SetIntention(
static_cast<int>(ConnectionState::Login));
72 state = ConnectionState::Login;
74 std::shared_ptr<ServerboundHelloPacket> loginstart_msg = std::make_shared<ServerboundHelloPacket>();
75#if PROTOCOL_VERSION < 759
76 loginstart_msg->SetGameProfile(
name);
78 loginstart_msg->SetName_(
name);
81#if PROTOCOL_VERSION < 761
87 loginstart_msg->SetPublicKey(key);
91#if PROTOCOL_VERSION > 759
92 loginstart_msg->SetProfileId(
authentifier->GetPlayerUUID());
101 state = constant_connection_state;
112 state = ConnectionState::None;
140 std::vector<unsigned char> msg_data;
141 msg_data.reserve(256);
142 msg->Write(msg_data);
145 com->SendPacket(msg_data);
149#ifdef USE_COMPRESSION
152 msg_data.insert(msg_data.begin(), 0x00);
153 com->SendPacket(msg_data);
157 std::vector<unsigned char> compressed_msg;
158 compressed_msg.reserve(msg_data.size() + 5);
159 WriteData<VarInt>(
static_cast<int>(msg_data.size()), compressed_msg);
160 std::vector<unsigned char> compressed_data =
Compress(msg_data);
161 compressed_msg.insert(compressed_msg.end(), compressed_data.begin(), compressed_data.end());
162 com->SendPacket(compressed_msg);
165 throw std::runtime_error(
"Program compiled without ZLIB. Cannot send compressed message");
183#if PROTOCOL_VERSION > 758
184 if (message[0] ==
'/')
186 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.");
190 std::shared_ptr<ServerboundChatPacket> chat_message = std::make_shared<ServerboundChatPacket>();
191 chat_message->SetMessage(message);
192#if PROTOCOL_VERSION > 758
193#if PROTOCOL_VERSION < 761
194 chat_message->SetSignedPreview(
false);
198 long long int salt, timestamp;
199 std::vector<unsigned char> signature;
200#if PROTOCOL_VERSION == 759
202 signature =
authentifier->GetMessageSignature(message, salt, timestamp);
203#elif PROTOCOL_VERSION == 760
209 signature =
authentifier->GetMessageSignature(message,
chat_context.GetLastSignature(), last_seen_update.GetLastSeen(), salt, timestamp);
213 chat_message->SetLastSeenMessages(last_seen_update);
219 chat_message->SetLastSeenMessages(updates);
221 if (signature.empty())
223 throw std::runtime_error(
"Empty chat message signature.");
225 chat_message->SetTimestamp(timestamp);
227#if PROTOCOL_VERSION < 760
229 salt_signature.SetSalt(salt);
230 salt_signature.SetSignature(signature);
232 chat_message->SetSaltSignature(salt_signature);
234 chat_message->SetSalt(salt);
235 chat_message->SetSignature(signature);
241 chat_message->SetTimestamp(std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch()).count());
249#if PROTOCOL_VERSION > 765
252 std::shared_ptr<ServerboundChatCommandPacket> chat_command = std::make_shared<ServerboundChatCommandPacket>();
253 chat_command->SetCommand(command);
258#if PROTOCOL_VERSION > 758
259#if PROTOCOL_VERSION > 765
260 std::shared_ptr<ServerboundChatCommandSignedPacket> chat_command = std::make_shared<ServerboundChatCommandSignedPacket>();
262 std::shared_ptr<ServerboundChatCommandPacket> chat_command = std::make_shared<ServerboundChatCommandPacket>();
264 chat_command->SetCommand(command);
265 chat_command->SetTimestamp(std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch()).count());
266#if PROTOCOL_VERSION > 759
267 std::mt19937 rnd(
static_cast<unsigned int>(std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::high_resolution_clock::now().time_since_epoch()).count()));
268 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));
270#if PROTOCOL_VERSION < 761
271 chat_command->SetSignedPreview(
false);
273#if PROTOCOL_VERSION == 760
280 chat_command->SetLastSeenMessages(last_seen_update);
281#elif PROTOCOL_VERSION > 760
283 chat_command->SetLastSeenMessages(updates);
286 chat_command->SetArgumentSignatures({});
288 std::shared_ptr<ServerboundChatPacket> chat_command = std::make_shared<ServerboundChatPacket>();
289 chat_command->SetMessage(
"/" + command);
304 while (
state != ConnectionState::None)
312 std::vector<unsigned char> packet;
321 if (packet.size() > 0)
329#ifdef USE_COMPRESSION
330 size_t length = packet.size();
332 int data_length = ReadData<VarInt>(iter, length);
335 if (data_length == 0)
338 packet.erase(packet.begin());
344 const int size_varint =
static_cast<int>(packet.size() - length);
346 std::vector<unsigned char> uncompressed_msg =
Decompress(packet, size_varint);
350 throw std::runtime_error(
"Program compiled without USE_COMPRESSION. Cannot read compressed message");
357 catch (
const std::exception& e)
376 std::vector<unsigned char>::const_iterator packet_iterator = packet.begin();
377 size_t length = packet.size();
379 const int packet_id = ReadData<VarInt>(packet_iterator, length);
387 msg->Read(packet_iterator, length);
389 catch (
const std::exception&)
391 LOG_FATAL(
"Parsing exception while parsing message \"" << msg->GetName() <<
'"');
394 for (
size_t i = 0; i <
subscribed.size(); i++)
416#if PROTOCOL_VERSION < 768
422#if PROTOCOL_VERSION < 764
423 state = ConnectionState::Play;
425 state = ConnectionState::Configuration;
426 std::shared_ptr<ServerboundLoginAcknowledgedPacket> login_ack_msg = std::make_shared<ServerboundLoginAcknowledgedPacket>();
435 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");
439 std::shared_ptr<AESEncrypter> encrypter = std::make_shared<AESEncrypter>();
441 std::vector<unsigned char> raw_shared_secret;
442 std::vector<unsigned char> encrypted_shared_secret;
444#if PROTOCOL_VERSION < 759
445 std::vector<unsigned char> encrypted_nonce;
446 encrypter->Init(msg.GetPublicKey(), msg.GetNonce(),
447 raw_shared_secret, encrypted_nonce, encrypted_shared_secret);
448#elif PROTOCOL_VERSION < 761
449 std::vector<unsigned char> salted_nonce_signature;
451 encrypter->Init(msg.GetPublicKey(), msg.GetNonce(),
authentifier->GetPrivateKey(),
452 raw_shared_secret, encrypted_shared_secret,
453 salt, salted_nonce_signature);
455 std::vector<unsigned char> encrypted_challenge;
456 encrypter->Init(msg.GetPublicKey(), msg.GetChallenge(),
457 raw_shared_secret, encrypted_shared_secret,
458 encrypted_challenge);
461 authentifier->JoinServer(msg.GetServerId(), raw_shared_secret, msg.GetPublicKey());
463 std::shared_ptr<ServerboundKeyPacket> response_msg = std::make_shared<ServerboundKeyPacket>();
464 response_msg->SetKeyBytes(encrypted_shared_secret);
466#if PROTOCOL_VERSION < 759
468 response_msg->SetNonce(encrypted_nonce);
469#elif PROTOCOL_VERSION < 761
472 salt_signature.SetSalt(salt);
473 salt_signature.SetSignature(salted_nonce_signature);
474 response_msg->SetSaltSignature(salt_signature);
477 response_msg->SetEncryptedChallenge(encrypted_challenge);
483 com->SetEncrypter(encrypter);
485 throw std::runtime_error(
"Your version of botcraft doesn't support encryption. Either run your server with online-mode=false or recompile botcraft");
491 std::shared_ptr<ServerboundKeepAlivePacket> keep_alive_msg = std::make_shared<ServerboundKeepAlivePacket>();
492 keep_alive_msg->SetId_(msg.GetId_());
493 Send(keep_alive_msg);
496#if PROTOCOL_VERSION > 754
499 std::shared_ptr<ServerboundPongPacket> pong_msg = std::make_shared<ServerboundPongPacket>();
500 pong_msg->SetId_(msg.GetId_());
505#if PROTOCOL_VERSION > 340
511#if PROTOCOL_VERSION > 753
512 if (msg.GetIdentifier().GetFull() ==
"fabric-networking-api-v1:early_registration")
514#if PROTOCOL_VERSION < 764
515 std::shared_ptr<ServerboundCustomQueryPacket> custom_query_anwser = std::make_shared<ServerboundCustomQueryPacket>();
516 custom_query_anwser->SetTransactionId(msg.GetTransactionId());
517 custom_query_anwser->SetData(std::nullopt);
519 std::shared_ptr<ServerboundCustomQueryAnswerPacket> custom_query_anwser = std::make_shared<ServerboundCustomQueryAnswerPacket>();
520 custom_query_anwser->SetTransactionId(msg.GetTransactionId());
521 custom_query_anwser->SetPayload(std::nullopt);
523 Send(custom_query_anwser);
530#if PROTOCOL_VERSION > 759
533#if PROTOCOL_VERSION < 761
536 if (msg.GetSignature().has_value())
540 chat_context.
AddSeenMessage(std::vector<unsigned char>(msg.GetSignature().value().begin(), msg.GetSignature().value().end()));
544 std::shared_ptr<ServerboundChatAckPacket> ack_msg = std::make_shared<ServerboundChatAckPacket>();
552#if PROTOCOL_VERSION < 761
560#if PROTOCOL_VERSION > 760
565 std::shared_ptr<ServerboundChatSessionUpdatePacket> chat_session_msg = std::make_shared<ServerboundChatSessionUpdatePacket>();
573 chat_session_data.SetProfilePublicKey(key);
575 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()));
576 std::uniform_int_distribution<int> distrib(std::numeric_limits<unsigned char>::min(), std::numeric_limits<unsigned char>::max());
583 chat_session_msg->SetChatSession(chat_session_data);
584 Send(chat_session_msg);
589#if PROTOCOL_VERSION > 763
592 state = ConnectionState::Play;
593 std::shared_ptr<ServerboundFinishConfigurationPacket> finish_config_msg = std::make_shared<ServerboundFinishConfigurationPacket>();
594 Send(finish_config_msg);
599 std::shared_ptr<ServerboundKeepAliveConfigurationPacket> keep_alive_msg = std::make_shared<ServerboundKeepAliveConfigurationPacket>();
600 keep_alive_msg->SetId_(msg.GetId_());
601 Send(keep_alive_msg);
606 std::shared_ptr<ServerboundPongConfigurationPacket> pong_msg = std::make_shared<ServerboundPongConfigurationPacket>();
607 pong_msg->SetId_(msg.GetId_());
613 state = ConnectionState::Configuration;
614 std::shared_ptr<ServerboundConfigurationAcknowledgedPacket> config_ack_msg = std::make_shared<ServerboundConfigurationAcknowledgedPacket>();
615 Send(config_ack_msg);
625 using count_return =
decltype(std::declval<std::chrono::milliseconds>().count());
626 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());
627 std::shared_ptr<ServerboundChunkBatchReceivedPacket> chunk_per_tick_msg = std::make_shared<ServerboundChunkBatchReceivedPacket>();
629 chunk_per_tick_msg->SetDesiredChunksPerTick(msg.GetBatchSize() * 50.0f / time_elapsed_ms);
630 Send(chunk_per_tick_msg);
634#if PROTOCOL_VERSION > 765
637 std::shared_ptr<ServerboundSelectKnownPacksPacket> select_known_packs = std::make_shared<ServerboundSelectKnownPacksPacket>();
639 select_known_packs->SetKnownPacks({});
641 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)
std::thread::id GetProcessingThreadId() const
void SendChatCommand(const std::string &command)
virtual void Handle(ProtocolCraft::ClientboundLoginCompressionPacket &msg) override
std::thread m_thread_process
void SendChatMessage(const std::string &message)
LastSeenMessagesTracker chat_context
void Send(const std::shared_ptr< ProtocolCraft::Message > msg)
std::shared_ptr< TCP_Com > com
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
NetworkManager(const std::string &address, const std::string &login, const bool force_microsoft_auth, const std::vector< ProtocolCraft::Handler * > &handlers={})
std::atomic< int > message_sent_index
ProtocolCraft::ConnectionState state
void ProcessPacket(const std::vector< unsigned char > &packet)
std::queue< std::vector< unsigned char > > packets_to_process
ProtocolCraft::UUID chat_session_uuid
void OnNewRawData(const std::vector< unsigned char > &packet)
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::array< unsigned char, 16 > UUID
std::shared_ptr< Message > CreateClientboundMessage(const ConnectionState state, const int id)
std::vector< unsigned char >::const_iterator ReadIterator