Botcraft 1.21.11
Loading...
Searching...
No Matches
NetworkManager.cpp
Go to the documentation of this file.
1#include <functional>
2#include <optional>
3
9#if USE_COMPRESSION
11#endif
14#if PROTOCOL_VERSION > 758 /* > 1.18.2 */
16#endif
17
18
21
22using namespace ProtocolCraft;
23
24namespace Botcraft
25{
26 NetworkManager::NetworkManager(const std::string& address, const std::string& login_or_microsoft_cache_key_or_mc_token, const AuthType auth_type, const std::vector<Handler*>& handlers)
27 {
28 com = nullptr;
29
30 switch (auth_type)
31 {
33 authentifier = nullptr;
34 name = login_or_microsoft_cache_key_or_mc_token;
35 break;
37 authentifier = std::make_shared<Authentifier>();
38 if (!authentifier->AuthMicrosoft(login_or_microsoft_cache_key_or_mc_token))
39 {
40 throw std::runtime_error("Error trying to authenticate on Mojang server using Microsoft auth flow");
41 }
42 name = authentifier->GetPlayerDisplayName();
43 break;
45 authentifier = std::make_shared<Authentifier>();
46 if (!authentifier->AuthMCToken(login_or_microsoft_cache_key_or_mc_token))
47 {
48 throw std::runtime_error("Error trying to authenticate on Mojang server using provided mc token");
49 }
50 name = authentifier->GetPlayerDisplayName();
51 break;
52 }
53
54 compression = -1;
55 AddHandler(this);
56 for (Handler* p : handlers)
57 {
58 AddHandler(p);
59 }
60
61 state = ConnectionState::Handshake;
62
63 //Start the thread to process the incoming packets
65
66 com = std::make_shared<TCP_Com>(address, std::bind(&NetworkManager::OnNewRawData, this, std::placeholders::_1));
67
68 // Wait for the communication to be ready before sending any data
70 return com->IsInitialized();
71 }, 500, 0);
72
73 std::shared_ptr<ServerboundClientIntentionPacket> handshake_packet = std::make_shared<ServerboundClientIntentionPacket>();
74 handshake_packet->SetProtocolVersion(PROTOCOL_VERSION);
75 handshake_packet->SetHostName(com->GetIp());
76 handshake_packet->SetPort(com->GetPort());
77 handshake_packet->SetIntention(static_cast<int>(ConnectionState::Login));
78 Send(handshake_packet);
79
80 state = ConnectionState::Login;
81
82 std::shared_ptr<ServerboundHelloPacket> loginstart_packet = std::make_shared<ServerboundHelloPacket>();
83#if PROTOCOL_VERSION < 759 /* < 1.19 */
84 loginstart_packet->SetGameProfile(name);
85#else
86 loginstart_packet->SetName_(name);
87 if (authentifier)
88 {
89#if PROTOCOL_VERSION < 761 /* < 1.19.3 */
91 key.SetTimestamp(authentifier->GetKeyTimestamp());
92 key.SetKey(Utilities::RSAToBytes(authentifier->GetPublicKey()));
93 key.SetSignature(Utilities::DecodeBase64(authentifier->GetKeySignature()));
94
95 loginstart_packet->SetPublicKey(key);
96#else
98#endif
99#if PROTOCOL_VERSION > 759 /* > 1.19 */
100 loginstart_packet->SetProfileId(authentifier->GetPlayerUUID());
101#endif
102 }
103#endif
104 Send(loginstart_packet);
105 }
106
107 NetworkManager::NetworkManager(const ConnectionState constant_connection_state)
108 {
109 state = constant_connection_state;
110 compression = -1;
111 }
112
117
119 {
120 state = ConnectionState::None;
121
122 if (com)
123 {
124 com->close();
125 }
126
127 process_condition.notify_all();
128
129 if (m_thread_process.joinable())
130 {
131 m_thread_process.join();
132 }
133 compression = -1;
134
135 com.reset();
136 }
137
139 {
140 subscribed.push_back(h);
141 }
142
143 void NetworkManager::Send(const std::shared_ptr<Packet> packet)
144 {
145 if (com)
146 {
147 std::lock_guard<std::mutex> lock(mutex_send);
148 std::vector<unsigned char> packet_data;
149 packet_data.reserve(256);
150 packet->Write(packet_data);
151 if (compression == -1)
152 {
153 com->SendPacket(packet_data);
154 }
155 else
156 {
157#ifdef USE_COMPRESSION
158 if (packet_data.size() < compression)
159 {
160 packet_data.insert(packet_data.begin(), 0x00);
161 com->SendPacket(packet_data);
162 }
163 else
164 {
165 std::vector<unsigned char> compressed_packet;
166 compressed_packet.reserve(packet_data.size() + 5);
167 WriteData<VarInt>(static_cast<int>(packet_data.size()), compressed_packet);
168 std::vector<unsigned char> compressed_data = Compress(packet_data);
169 compressed_packet.insert(compressed_packet.end(), compressed_data.begin(), compressed_data.end());
170 com->SendPacket(compressed_packet);
171 }
172#else
173 throw std::runtime_error("Program compiled without ZLIB. Cannot send compressed message");
174#endif
175 }
176 }
177 }
178
180 {
181 return state;
182 }
183
184 const std::string& NetworkManager::GetMyName() const
185 {
186 return name;
187 }
188
189 void NetworkManager::SendChatMessage(const std::string& message)
190 {
191#if PROTOCOL_VERSION > 758 /* > 1.18.2 */
192 if (message[0] == '/')
193 {
194 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.");
195 }
196#endif
197
198 std::shared_ptr<ServerboundChatPacket> chat_message = std::make_shared<ServerboundChatPacket>();
199 chat_message->SetMessage(message);
200#if PROTOCOL_VERSION > 758 /* > 1.18.2 */
201#if PROTOCOL_VERSION < 761 /* < 1.19.3 */
202 chat_message->SetSignedPreview(false);
203#endif
204 if (authentifier)
205 {
206 long long int salt, timestamp;
207 std::vector<unsigned char> signature;
208#if PROTOCOL_VERSION == 759 /* 1.19 */
209 // 1.19
210 signature = authentifier->GetMessageSignature(message, salt, timestamp);
211#elif PROTOCOL_VERSION == 760 /* 1.19.1/2 */
212 // 1.19.1 and 1.19.2
213 LastSeenMessagesUpdate last_seen_update;
214 {
215 std::scoped_lock<std::mutex> lock_messages(chat_context.GetMutex());
216 last_seen_update = chat_context.GetLastSeenMessagesUpdate();
217 signature = authentifier->GetMessageSignature(message, chat_context.GetLastSignature(), last_seen_update.GetLastSeen(), salt, timestamp);
218 // Update last signature with current one for the next message
219 chat_context.SetLastSignature(signature);
220 }
221 chat_message->SetLastSeenMessages(last_seen_update);
222#else
223 // 1.19.3+
224 const auto [signatures, updates] = chat_context.GetLastSeenMessagesUpdate();
225 const int current_message_sent_index = message_sent_index++;
226 signature = authentifier->GetMessageSignature(message, current_message_sent_index, chat_session_uuid, signatures, salt, timestamp);
227 chat_message->SetLastSeenMessages(updates);
228#endif
229 if (signature.empty())
230 {
231 throw std::runtime_error("Empty chat message signature.");
232 }
233 chat_message->SetTimestamp(timestamp);
234
235#if PROTOCOL_VERSION < 760 /* < 1.19.1 */
236 SaltSignature salt_signature;
237 salt_signature.SetSalt(salt);
238 salt_signature.SetSignature(signature);
239
240 chat_message->SetSaltSignature(salt_signature);
241#else
242 chat_message->SetSalt(salt);
243 chat_message->SetSignature(signature);
244#endif
245 }
246 // Offline mode, empty signature
247 else
248 {
249 chat_message->SetTimestamp(std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch()).count());
250 }
251#endif
252 Send(chat_message);
253 }
254
255 void NetworkManager::SendChatCommand(const std::string& command)
256 {
257#if PROTOCOL_VERSION > 765 /* > 1.20.4 */
258 if (authentifier == nullptr)
259 {
260 std::shared_ptr<ServerboundChatCommandPacket> chat_command = std::make_shared<ServerboundChatCommandPacket>();
261 chat_command->SetCommand(command);
262 Send(chat_command);
263 return;
264 }
265#endif
266#if PROTOCOL_VERSION > 758 /* > 1.18.2 */
267#if PROTOCOL_VERSION > 765 /* > 1.20.4 */
268 std::shared_ptr<ServerboundChatCommandSignedPacket> chat_command = std::make_shared<ServerboundChatCommandSignedPacket>();
269#else
270 std::shared_ptr<ServerboundChatCommandPacket> chat_command = std::make_shared<ServerboundChatCommandPacket>();
271#endif
272 chat_command->SetCommand(command);
273 chat_command->SetTimestamp(std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch()).count());
274#if PROTOCOL_VERSION > 759 /* > 1.19 */
275 std::mt19937 rnd(static_cast<unsigned int>(std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::high_resolution_clock::now().time_since_epoch()).count()));
276 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#endif
278#if PROTOCOL_VERSION < 761 /* < 1.19.3 */
279 chat_command->SetSignedPreview(false);
280#endif
281#if PROTOCOL_VERSION == 760 /* 1.19.1/2 */
282 LastSeenMessagesUpdate last_seen_update;
283 if (authentifier)
284 {
285 std::scoped_lock<std::mutex> lock_messages(chat_context.GetMutex());
286 last_seen_update = chat_context.GetLastSeenMessagesUpdate();
287 }
288 chat_command->SetLastSeenMessages(last_seen_update);
289#elif PROTOCOL_VERSION > 760 /* > 1.19.2 */
290 const auto [signatures, updates] = chat_context.GetLastSeenMessagesUpdate();
291 chat_command->SetLastSeenMessages(updates);
292#endif
293 // TODO: when this shouldn't be empty? Can't find a situation where it's filled with something
294 chat_command->SetArgumentSignatures({});
295#else
296 std::shared_ptr<ServerboundChatPacket> chat_command = std::make_shared<ServerboundChatPacket>();
297 chat_command->SetMessage("/" + command);
298#endif
299 Send(chat_command);
300 }
301
303 {
304 return m_thread_process.get_id();
305 }
306
308 {
309 Logger::GetInstance().RegisterThread("NetworkPacketProcessing - " + name);
310 try
311 {
312 while (state != ConnectionState::None)
313 {
314 {
315 std::unique_lock<std::mutex> lck(mutex_process);
316 process_condition.wait(lck);
317 }
318 while (!packets_to_process.empty())
319 {
320 std::vector<unsigned char> packet;
321 { // process_guard scope
322 std::lock_guard<std::mutex> process_guard(mutex_process);
323 if (!packets_to_process.empty())
324 {
325 packet = packets_to_process.front();
326 packets_to_process.pop();
327 }
328 }
329 if (packet.size() > 0)
330 {
331 if (compression == -1)
332 {
333 ProcessPacket(packet);
334 }
335 else
336 {
337#ifdef USE_COMPRESSION
338 size_t length = packet.size();
339 ReadIterator iter = packet.begin();
340 int data_length = ReadData<VarInt>(iter, length);
341
342 //Packet not compressed
343 if (data_length == 0)
344 {
345 //Erase the first 0
346 packet.erase(packet.begin());
347 ProcessPacket(packet);
348 }
349 //Packet compressed
350 else
351 {
352 const int size_varint = static_cast<int>(packet.size() - length);
353
354 std::vector<unsigned char> uncompressed_packet = Decompress(packet, size_varint);
355 ProcessPacket(uncompressed_packet);
356 }
357#else
358 throw std::runtime_error("Program compiled without USE_COMPRESSION. Cannot read compressed message");
359#endif
360 }
361 }
362 }
363 }
364 }
365 catch (const std::exception& e)
366 {
367 LOG_FATAL("Exception:\n" << e.what());
368 throw;
369 }
370 catch (...)
371 {
372 LOG_FATAL("Unknown exception");
373 throw;
374 }
375 }
376
377 void NetworkManager::ProcessPacket(const std::vector<unsigned char>& bytes)
378 {
379 if (bytes.empty())
380 {
381 return;
382 }
383
384 std::vector<unsigned char>::const_iterator packet_iterator = bytes.begin();
385 size_t length = bytes.size();
386
387 const int packet_id = ReadData<VarInt>(packet_iterator, length);
388
389 std::shared_ptr<Packet> packet = CreateClientboundPacket(state, packet_id);
390
391 if (packet != nullptr)
392 {
393 try
394 {
395 packet->Read(packet_iterator, length);
396 }
397 catch (const std::exception& e)
398 {
399 LOG_FATAL("Parsing exception while parsing message \"" << packet->GetName() << "\"\n" << e.what());
400 throw;
401 }
402 for (size_t i = 0; i < subscribed.size(); i++)
403 {
404 packet->Dispatch(subscribed[i]);
405 }
406 }
407 }
408
409 void NetworkManager::OnNewRawData(const std::vector<unsigned char>& bytes)
410 {
411 {
412 std::unique_lock<std::mutex> lck(mutex_process);
413 packets_to_process.push(bytes);
414 }
415 process_condition.notify_all();
416 }
417
418
420 {
421 compression = packet.GetCompressionThreshold();
422 }
423
424#if PROTOCOL_VERSION < 768 /* < 1.21.2 */
425 void NetworkManager::Handle(ClientboundGameProfilePacket& packet)
426#else
428#endif
429 {
430#if PROTOCOL_VERSION < 764 /* < 1.20.2 */
431 state = ConnectionState::Play;
432#else
433 state = ConnectionState::Configuration;
434 std::shared_ptr<ServerboundLoginAcknowledgedPacket> login_ack_packet = std::make_shared<ServerboundLoginAcknowledgedPacket>();
435 Send(login_ack_packet);
436
437 std::shared_ptr<ServerboundCustomPayloadConfigurationPacket> custom_payload_packet = std::make_shared<ServerboundCustomPayloadConfigurationPacket>();
438 custom_payload_packet->SetIdentifier("minecraft:brand");
439 std::vector<unsigned char> payload;
440 WriteData<std::string>("vanilla", payload);
441 custom_payload_packet->SetRawData(payload);
442 Send(custom_payload_packet);
443
444 std::shared_ptr<ServerboundClientInformationConfigurationPacket> client_info_packet = std::make_shared<ServerboundClientInformationConfigurationPacket>();
446 info.SetLanguage("fr_FR");
447 info.SetViewDistance(10);
448 info.SetChatVisibility(static_cast<int>(ChatMode::Enabled));
449 info.SetChatColors(true);
450 info.SetModelCustomisation(0xFF);
451 info.SetMainHand(1); // 1 is right handed, 0 is left handed
452#if PROTOCOL_VERSION > 767 /* > 1.21.1 */
453 info.SetParticleStatus(2); // 0 is "all", 1 is "decreased" and 2 is "minimal"
454#endif
455 client_info_packet->SetClientInformation(info);
456
457 Send(client_info_packet);
458#endif
459 }
460
462 {
463 if (authentifier == nullptr
464#if PROTOCOL_VERSION > 765 /* > 1.20.4 */
465 && packet.GetShouldAuthenticate()
466#endif
467 )
468 {
469 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");
470 }
471
472#ifdef USE_ENCRYPTION
473 std::shared_ptr<AESEncrypter> encrypter = std::make_shared<AESEncrypter>();
474
475 std::vector<unsigned char> raw_shared_secret;
476 std::vector<unsigned char> encrypted_shared_secret;
477
478#if PROTOCOL_VERSION < 759 /* < 1.19 */
479 std::vector<unsigned char> encrypted_nonce;
480 encrypter->Init(packet.GetPublicKey(), packet.GetNonce(),
481 raw_shared_secret, encrypted_nonce, encrypted_shared_secret);
482#elif PROTOCOL_VERSION < 761 /* < 1.19.3 */
483 std::vector<unsigned char> salted_nonce_signature;
484 long long int salt;
485 encrypter->Init(packet.GetPublicKey(), packet.GetNonce(), authentifier->GetPrivateKey(),
486 raw_shared_secret, encrypted_shared_secret,
487 salt, salted_nonce_signature);
488#else
489 std::vector<unsigned char> encrypted_challenge;
490 encrypter->Init(packet.GetPublicKey(), packet.GetChallenge(),
491 raw_shared_secret, encrypted_shared_secret,
492 encrypted_challenge);
493#endif
494
495 // In 1.20.5+, encryption can be enabled even in offline mode
496#if PROTOCOL_VERSION > 765 /* > 1.20.4 */
497 if (packet.GetShouldAuthenticate())
498#endif
499 {
500 authentifier->JoinServer(packet.GetServerId(), raw_shared_secret, packet.GetPublicKey());
501 }
502
503 std::shared_ptr<ServerboundKeyPacket> response_packet = std::make_shared<ServerboundKeyPacket>();
504 response_packet->SetKeyBytes(encrypted_shared_secret);
505
506#if PROTOCOL_VERSION < 759 /* < 1.19 */
507 // Pre-1.19 behaviour, send encrypted nonce
508 response_packet->SetNonce(encrypted_nonce);
509#elif PROTOCOL_VERSION < 761 /* < 1.19.3 */
510 // 1.19, 1.19.1, 1.19.2 behaviour, send salted nonce signature
511 SaltSignature salt_signature;
512 salt_signature.SetSalt(salt);
513 salt_signature.SetSignature(salted_nonce_signature);
514 response_packet->SetSaltSignature(salt_signature);
515#else
516 // 1.19.3+ behaviour, send encrypted challenge
517 response_packet->SetEncryptedChallenge(encrypted_challenge);
518#endif
519
520 Send(response_packet);
521
522 // Enable encryption from now on
523 com->SetEncrypter(encrypter);
524#else
525 throw std::runtime_error("Your version of botcraft doesn't support encryption. Either run your server with online-mode=false or recompile botcraft");
526#endif
527 }
528
530 {
531 std::shared_ptr<ServerboundKeepAlivePacket> keep_alive_packet = std::make_shared<ServerboundKeepAlivePacket>();
532 keep_alive_packet->SetId_(packet.GetId_());
533 Send(keep_alive_packet);
534 }
535
536#if PROTOCOL_VERSION > 754 /* > 1.16.5 */
538 {
539 std::shared_ptr<ServerboundPongPacket> pong_packet = std::make_shared<ServerboundPongPacket>();
540 pong_packet->SetId_(packet.GetId_());
541 Send(pong_packet);
542 }
543#endif
544
545#if PROTOCOL_VERSION > 340 /* > 1.12.2 */
547 {
548 // Vanilla like response when asked by fabric API
549 // Not implemented in fabric before December 05 2020,
550 // so not necessary before version 1.16.4
551#if PROTOCOL_VERSION > 753 /* > 1.16.3 */
552 if (packet.GetIdentifier().GetFull() == "fabric-networking-api-v1:early_registration")
553 {
554#if PROTOCOL_VERSION < 764 /* < 1.20.2 */
555 std::shared_ptr<ServerboundCustomQueryPacket> custom_query_anwser = std::make_shared<ServerboundCustomQueryPacket>();
556 custom_query_anwser->SetTransactionId(packet.GetTransactionId());
557 custom_query_anwser->SetData(std::nullopt);
558#else
559 std::shared_ptr<ServerboundCustomQueryAnswerPacket> custom_query_anwser = std::make_shared<ServerboundCustomQueryAnswerPacket>();
560 custom_query_anwser->SetTransactionId(packet.GetTransactionId());
561 custom_query_anwser->SetPayload(std::nullopt);
562#endif
563 Send(custom_query_anwser);
564 return;
565 }
566#endif
567 }
568#endif
569
570#if PROTOCOL_VERSION > 759 /* > 1.19 */
572 {
573#if PROTOCOL_VERSION < 761 /* < 1.19.3 */
574 // Ugly stuff because there is a GetMessage macro in Windows API somewhere :)
575#if _MSC_VER || __MINGW32__
576#pragma push_macro("GetMessage")
577#undef GetMessage
578#endif
579 chat_context.AddSeenMessage(packet.GetMessage().GetHeaderSignature(), packet.GetMessage().GetSignedHeader().GetSender());
580#if _MSC_VER || __MINGW32__
581#pragma pop_macro("GetMessage")
582#endif
583#else
584 if (packet.GetSignature().has_value())
585 {
586 std::scoped_lock<std::mutex> lock_messages(chat_context.GetMutex());
587
588 chat_context.AddSeenMessage(std::vector<unsigned char>(packet.GetSignature().value().begin(), packet.GetSignature().value().end()));
589
590 if (chat_context.GetOffset() > 64)
591 {
592 std::shared_ptr<ServerboundChatAckPacket> ack_packet = std::make_shared<ServerboundChatAckPacket>();
593 ack_packet->SetOffset(chat_context.GetAndResetOffset());
594 Send(ack_packet);
595 }
596 }
597#endif
598 }
599
600#if PROTOCOL_VERSION < 761 /* < 1.19.3 */
601 void NetworkManager::Handle(ClientboundPlayerChatHeaderPacket& packet)
602 {
603 chat_context.AddSeenMessage(packet.GetHeaderSignature(), packet.GetHeader().GetSender());
604 }
605#endif
606#endif
607
609 {
610#if PROTOCOL_VERSION < 764 /* < 1.20.2 */
611 {
612 // In 1.20.2+ it is sent during configuration instead
613 std::shared_ptr<ServerboundCustomPayloadPacket> custom_payload_packet = std::make_shared<ServerboundCustomPayloadPacket>();
614 custom_payload_packet->SetIdentifier("minecraft:brand");
615 std::vector<unsigned char> payload;
616 WriteData<std::string>("vanilla", payload);
617 custom_payload_packet->SetRawData(payload);
618 Send(custom_payload_packet);
619 }
620#endif
621#if PROTOCOL_VERSION > 760 /* > 1.19.2 */
622 if (authentifier)
623 {
624 std::shared_ptr<ServerboundChatSessionUpdatePacket> chat_session_packet = std::make_shared<ServerboundChatSessionUpdatePacket>();
625 RemoteChatSessionData chat_session_data;
626
628 key.SetTimestamp(authentifier->GetKeyTimestamp());
629 key.SetKey(Utilities::RSAToBytes(authentifier->GetPublicKey()));
630 key.SetSignature(Utilities::DecodeBase64(authentifier->GetKeySignature()));
631
632 chat_session_data.SetProfilePublicKey(key);
634 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()));
635 std::uniform_int_distribution<int> distrib(std::numeric_limits<unsigned char>::min(), std::numeric_limits<unsigned char>::max());
636 for (size_t i = 0; i < chat_session_uuid.size(); ++i)
637 {
638 chat_session_uuid[i] = static_cast<unsigned char>(distrib(rnd));
639 }
640 chat_session_data.SetUuid(chat_session_uuid);
641
642 chat_session_packet->SetChatSession(chat_session_data);
643 Send(chat_session_packet);
644 }
645#endif
646 }
647
648#if PROTOCOL_VERSION > 763 /* > 1.20.1 */
650 {
651 state = ConnectionState::Play;
652 std::shared_ptr<ServerboundFinishConfigurationPacket> finish_config_packet = std::make_shared<ServerboundFinishConfigurationPacket>();
653 Send(finish_config_packet);
654 }
655
657 {
658 std::shared_ptr<ServerboundKeepAliveConfigurationPacket> keep_alive_packet = std::make_shared<ServerboundKeepAliveConfigurationPacket>();
659 keep_alive_packet->SetId_(packet.GetId_());
660 Send(keep_alive_packet);
661 }
662
664 {
665 std::shared_ptr<ServerboundPongConfigurationPacket> pong_packet = std::make_shared<ServerboundPongConfigurationPacket>();
666 pong_packet->SetId_(packet.GetId_());
667 Send(pong_packet);
668 }
669
671 {
672 state = ConnectionState::Configuration;
673 std::shared_ptr<ServerboundConfigurationAcknowledgedPacket> config_ack_packet = std::make_shared<ServerboundConfigurationAcknowledgedPacket>();
674 Send(config_ack_packet);
675 }
676
678 {
679 chunk_batch_start_time = std::chrono::steady_clock::now();
680 }
681
683 {
684 using count_return = decltype(std::declval<std::chrono::milliseconds>().count());
685 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());
686 std::shared_ptr<ServerboundChunkBatchReceivedPacket> chunk_per_tick_packet = std::make_shared<ServerboundChunkBatchReceivedPacket>();
687 // Ask as many chunks as we can process in one tick (50 ms)
688 chunk_per_tick_packet->SetDesiredChunksPerTick(packet.GetBatchSize() * 50.0f / time_elapsed_ms);
689 Send(chunk_per_tick_packet);
690 }
691#endif
692
693#if PROTOCOL_VERSION > 765 /* > 1.20.4 */
695 {
696 std::shared_ptr<ServerboundSelectKnownPacksPacket> select_known_packs = std::make_shared<ServerboundSelectKnownPacksPacket>();
697 // Datapacks are not supported by Botcraft
698 select_known_packs->SetKnownPacks({});
699
700 Send(select_known_packs);
701 }
702#endif
703
704#if PROTOCOL_VERSION < 764 /* < 1.20.2 */
705 // In 1.20.2+ it is sent during configuration instead
707 {
708 std::shared_ptr<ServerboundClientInformationPacket> settings_packet = std::make_shared<ServerboundClientInformationPacket>();
709 settings_packet->SetLanguage("fr_FR");
710 settings_packet->SetViewDistance(10);
711 settings_packet->SetChatVisibility(static_cast<int>(ChatMode::Enabled));
712 settings_packet->SetChatColors(true);
713 settings_packet->SetModelCustomisation(0xFF);
714 settings_packet->SetMainHand(1); // 1 is right handed, 0 is left handed
715
716 network_manager->Send(settings_packet);
717 }
718#endif
719}
#define LOG_INFO(osstream)
Definition Logger.hpp:43
#define LOG_FATAL(osstream)
Definition Logger.hpp:46
std::shared_ptr< NetworkManager > network_manager
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.
Definition Logger.cpp:104
static Logger & GetInstance()
Definition Logger.cpp:36
virtual void Handle(ProtocolCraft::ClientboundLoginFinishedPacket &packet) override
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)
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